[Lldb-commits] [lldb] r174129 - Allow the target to give out the size of the red zone for given ABIs.
Greg Clayton
gclayton at apple.com
Thu Jan 31 16:47:50 PST 2013
Author: gclayton
Date: Thu Jan 31 18:47:49 2013
New Revision: 174129
URL: http://llvm.org/viewvc/llvm-project?rev=174129&view=rev
Log:
Allow the target to give out the size of the red zone for given ABIs.
A bit of cleanup in the heap module.
Modified:
lldb/trunk/examples/darwin/heap_find/heap.py
lldb/trunk/include/lldb/API/SBTarget.h
lldb/trunk/scripts/Python/interface/SBTarget.i
lldb/trunk/source/API/SBTarget.cpp
Modified: lldb/trunk/examples/darwin/heap_find/heap.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/examples/darwin/heap_find/heap.py?rev=174129&r1=174128&r2=174129&view=diff
==============================================================================
--- lldb/trunk/examples/darwin/heap_find/heap.py (original)
+++ lldb/trunk/examples/darwin/heap_find/heap.py Thu Jan 31 18:47:49 2013
@@ -22,14 +22,93 @@ import lldb.utils.symbolication
g_libheap_dylib_dir = None
g_libheap_dylib_dict = dict()
-def get_iterate_memory_expr(process, user_init_code, user_return_code):
- return '''
+def get_iterate_memory_expr(options, process, user_init_code, user_return_code):
+ expr = '''
typedef unsigned natural_t;
typedef uintptr_t vm_size_t;
typedef uintptr_t vm_address_t;
typedef natural_t task_t;
typedef int kern_return_t;
#define KERN_SUCCESS 0
+typedef void (*range_callback_t)(task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size);
+''';
+ if options.search_vm_regions:
+ expr += '''
+typedef int vm_prot_t;
+typedef unsigned int vm_inherit_t;
+typedef unsigned long long memory_object_offset_t;
+typedef unsigned int boolean_t;
+typedef int vm_behavior_t;
+typedef uint32_t vm32_object_id_t;
+typedef natural_t mach_msg_type_number_t;
+typedef uint64_t mach_vm_address_t;
+typedef uint64_t mach_vm_offset_t;
+typedef uint64_t mach_vm_size_t;
+typedef uint64_t vm_map_offset_t;
+typedef uint64_t vm_map_address_t;
+typedef uint64_t vm_map_size_t;
+#define VM_PROT_NONE ((vm_prot_t) 0x00)
+#define VM_PROT_READ ((vm_prot_t) 0x01)
+#define VM_PROT_WRITE ((vm_prot_t) 0x02)
+#define VM_PROT_EXECUTE ((vm_prot_t) 0x04)
+typedef struct vm_region_submap_short_info_data_64_t {
+ vm_prot_t protection;
+ vm_prot_t max_protection;
+ vm_inherit_t inheritance;
+ memory_object_offset_t offset; // offset into object/map
+ unsigned int user_tag; // user tag on map entry
+ unsigned int ref_count; // obj/map mappers, etc
+ unsigned short shadow_depth; // only for obj
+ unsigned char external_pager; // only for obj
+ unsigned char share_mode; // see enumeration
+ boolean_t is_submap; // submap vs obj
+ vm_behavior_t behavior; // access behavior hint
+ vm32_object_id_t object_id; // obj/map name, not a handle
+ unsigned short user_wired_count;
+} vm_region_submap_short_info_data_64_t;
+#define VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 ((mach_msg_type_number_t)(sizeof(vm_region_submap_short_info_data_64_t)/sizeof(int)))''';
+ if user_init_code:
+ expr += user_init_code;
+ expr += '''
+task_t task = (task_t)mach_task_self();
+mach_vm_address_t vm_region_base_addr;
+mach_vm_size_t vm_region_size;
+natural_t vm_region_depth;
+vm_region_submap_short_info_data_64_t vm_region_info;
+kern_return_t err;
+for (vm_region_base_addr = 0, vm_region_size = 1; vm_region_size != 0; vm_region_base_addr += vm_region_size)
+{
+ mach_msg_type_number_t vm_region_info_size = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
+ err = (kern_return_t)mach_vm_region_recurse (task,
+ &vm_region_base_addr,
+ &vm_region_size,
+ &vm_region_depth,
+ &vm_region_info,
+ &vm_region_info_size);
+ if (err)
+ break;
+ // Check all read + write regions. This will cover the thread stacks
+ // and any regions of memory like __DATA segments, that might contain
+ // data we are looking for
+ if (vm_region_info.protection & VM_PROT_WRITE &&
+ vm_region_info.protection & VM_PROT_READ)
+ {
+ baton.callback (task,
+ &baton,
+ 64,
+ vm_region_base_addr,
+ vm_region_size);
+ }
+}'''
+ else:
+ if options.search_stack:
+ expr += get_thread_stack_ranges_struct (process)
+ if options.search_segments:
+ expr += get_sections_ranges_struct (process)
+ if user_init_code:
+ expr += user_init_code
+ if options.search_heap:
+ expr += '''
#define MALLOC_PTR_IN_USE_RANGE_TYPE 1
typedef struct vm_range_t {
vm_address_t address;
@@ -37,7 +116,6 @@ typedef struct vm_range_t {
} vm_range_t;
typedef kern_return_t (*memory_reader_t)(task_t task, vm_address_t remote_address, vm_size_t size, void **local_memory);
typedef void (*vm_range_recorder_t)(task_t task, void *baton, unsigned type, vm_range_t *range, unsigned size);
-typedef void (*range_callback_t)(task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size);
typedef struct malloc_introspection_t {
kern_return_t (*enumerator)(task_t task, void *, unsigned type_mask, vm_address_t zone_address, memory_reader_t reader, vm_range_recorder_t recorder); /* enumerates all the malloc pointers in use */
} malloc_introspection_t;
@@ -50,11 +128,7 @@ memory_reader_t task_peek = [](task_t ta
return KERN_SUCCESS;
};
vm_address_t *zones = 0;
-unsigned int num_zones = 0;
-%s
-%s
-%s
-task_t task = 0;
+unsigned int num_zones = 0;task_t task = 0;
kern_return_t err = (kern_return_t)malloc_get_all_zones (task, task_peek, &zones, &num_zones);
if (KERN_SUCCESS == err)
{
@@ -76,14 +150,29 @@ if (KERN_SUCCESS == err)
}
});
}
-}
+}'''
+
+ if options.search_stack:
+ expr += '''
// Call the callback for the thread stack ranges
-for (uint32_t i=0; i<NUM_STACKS; ++i)
+for (uint32_t i=0; i<NUM_STACKS; ++i) {
range_callback(task, &baton, 8, stacks[i].base, stacks[i].size);
+ if (STACK_RED_ZONE_SIZE > 0) {
+ range_callback(task, &baton, 16, stacks[i].base - STACK_RED_ZONE_SIZE, STACK_RED_ZONE_SIZE);
+ }
+}
+ '''
+
+ if options.search_segments:
+ expr += '''
// Call the callback for all segments
for (uint32_t i=0; i<NUM_SEGMENTS; ++i)
- range_callback(task, &baton, 16, segments[i].base, segments[i].size);
-%s''' % (get_thread_stack_ranges_struct (process), get_sections_ranges_struct(process), user_init_code, user_return_code)
+ range_callback(task, &baton, 32, segments[i].base, segments[i].size);'''
+
+ if user_return_code:
+ expr += "\n%s" % (user_return_code,)
+
+ return expr
def get_member_types_for_offset(value_type, offset, member_list):
member = value_type.GetFieldAtIndex(0)
@@ -142,7 +231,10 @@ def add_common_options(parser):
parser.add_option('-H', '--max-history', type='int', dest='max_history', help='the maximum number of stack history backtraces to print for each allocation when using the --stack-history option (default=16)', default=16)
parser.add_option('-M', '--max-matches', type='int', dest='max_matches', help='the maximum number of matches to print', default=32)
parser.add_option('-O', '--offset', type='int', dest='offset', help='the matching data must be at this offset', default=-1)
- parser.add_option('-V', '--vm-regions', action='store_true', dest='check_vm_regions', help='Also check the VM regions', default=False)
+ parser.add_option('--ignore-stack', action='store_false', dest='search_stack', help="Don't search the stack when enumerating memory", default=True)
+ parser.add_option('--ignore-heap', action='store_false', dest='search_heap', help="Don't search the heap allocations when enumerating memory", default=True)
+ parser.add_option('--ignore-segments', action='store_false', dest='search_segments', help="Don't search readable executable segments enumerating memory", default=True)
+ parser.add_option('-V', '--vm-regions', action='store_true', dest='search_vm_regions', help='Check all VM regions instead of searching the heap, stack and segments', default=False)
def type_flags_to_string(type_flags):
if type_flags == 0:
@@ -156,7 +248,11 @@ def type_flags_to_string(type_flags):
elif type_flags & 8:
type_str = 'stack'
elif type_flags & 16:
+ type_str = 'stack (red zone)'
+ elif type_flags & 32:
type_str = 'segment'
+ elif type_flags & 64:
+ type_str = 'vm_region'
else:
type_str = hex(type_flags)
return type_str
@@ -171,8 +267,13 @@ def type_flags_to_description(type_flags
elif type_flags & 8:
type_str = 'stack'
elif type_flags & 16:
+ type_str = 'stack (red zone)'
+ elif type_flags & 32:
sb_addr = lldb.debugger.GetSelectedTarget().ResolveLoadAddress(ptr_addr + offset)
type_str = 'segment [%#x - %#x), %s + %u, %s' % (ptr_addr, ptr_addr + ptr_size, sb_addr.section.name, sb_addr.offset, sb_addr)
+ elif type_flags & 64:
+ sb_addr = lldb.debugger.GetSelectedTarget().ResolveLoadAddress(ptr_addr + offset)
+ type_str = 'vm_region [%#x - %#x), %s + %u, %s' % (ptr_addr, ptr_addr + ptr_size, sb_addr.section.name, sb_addr.offset, sb_addr)
else:
type_str = '%#x' % (ptr_addr,)
show_offset = True
@@ -357,66 +458,83 @@ def display_match_results (result, optio
print_entry = False
else:
match_addr = malloc_addr + offset
- dynamic_value = match_entry.addr.sbvalue.GetDynamicValue(lldb.eDynamicCanRunTarget)
type_flags = int(match_entry.type)
- description = '%#16.16x: %s' % (match_addr, type_flags_to_description(type_flags, malloc_addr, malloc_size, offset))
- if options.show_size:
- description += ' <%5u>' % (malloc_size)
- if options.show_range:
- description += ' [%#x - %#x)' % (malloc_addr, malloc_addr + malloc_size)
- derefed_dynamic_value = None
- if dynamic_value.type.name == 'void *':
- if options.type == 'pointer' and malloc_size == 4096:
- error = lldb.SBError()
- process = expr_sbvalue.GetProcess()
- target = expr_sbvalue.GetTarget()
- data = bytearray(process.ReadMemory(malloc_addr, 16, error))
- if data == '\xa1\xa1\xa1\xa1AUTORELEASE!':
- ptr_size = target.addr_size
- thread = process.ReadUnsignedFromMemory (malloc_addr + 16 + ptr_size, ptr_size, error)
- # 4 bytes 0xa1a1a1a1
- # 12 bytes 'AUTORELEASE!'
- # ptr bytes autorelease insertion point
- # ptr bytes pthread_t
- # ptr bytes next colder page
- # ptr bytes next hotter page
- # 4 bytes this page's depth in the list
- # 4 bytes high-water mark
- description += ' AUTORELEASE! for pthread_t %#x' % (thread)
- # else:
- # description += 'malloc(%u)' % (malloc_size)
- # else:
- # description += 'malloc(%u)' % (malloc_size)
- else:
- derefed_dynamic_value = dynamic_value.deref
- if derefed_dynamic_value:
- derefed_dynamic_type = derefed_dynamic_value.type
- derefed_dynamic_type_size = derefed_dynamic_type.size
- derefed_dynamic_type_name = derefed_dynamic_type.name
- description += ' '
- description += derefed_dynamic_type_name
- if offset < derefed_dynamic_type_size:
- member_list = list();
- get_member_types_for_offset (derefed_dynamic_type, offset, member_list)
- if member_list:
- member_path = ''
- for member in member_list:
- member_name = member.name
- if member_name:
- if member_path:
- member_path += '.'
- member_path += member_name
- if member_path:
- if options.ivar_regex_blacklist:
- for ivar_regex in options.ivar_regex_blacklist:
- if ivar_regex.match(member_path):
- print_entry = False
- description += '.%s' % (member_path)
- else:
- description += '%u bytes after %s' % (offset - derefed_dynamic_type_size, derefed_dynamic_type_name)
+ #result.AppendMessage (hex(malloc_addr + offset))
+ if type_flags == 64:
+ search_stack_old = options.search_stack
+ search_segments_old = options.search_segments
+ search_heap_old = options.search_heap
+ search_vm_regions = options.search_vm_regions
+ options.search_stack = True
+ options.search_segments = True
+ options.search_heap = True
+ options.search_vm_regions = False
+ if malloc_info_impl (lldb.debugger, result, options, [hex(malloc_addr + offset)]):
+ print_entry = False
+ options.search_stack = search_stack_old
+ options.search_segments = search_segments_old
+ options.search_heap = search_heap_old
+ options.search_vm_regions = search_vm_regions
+ if print_entry:
+ description = '%#16.16x: %s' % (match_addr, type_flags_to_description(type_flags, malloc_addr, malloc_size, offset))
+ if options.show_size:
+ description += ' <%5u>' % (malloc_size)
+ if options.show_range:
+ description += ' [%#x - %#x)' % (malloc_addr, malloc_addr + malloc_size)
+ derefed_dynamic_value = None
+ dynamic_value = match_entry.addr.sbvalue.GetDynamicValue(lldb.eDynamicCanRunTarget)
+ if dynamic_value.type.name == 'void *':
+ if options.type == 'pointer' and malloc_size == 4096:
+ error = lldb.SBError()
+ process = expr_sbvalue.GetProcess()
+ target = expr_sbvalue.GetTarget()
+ data = bytearray(process.ReadMemory(malloc_addr, 16, error))
+ if data == '\xa1\xa1\xa1\xa1AUTORELEASE!':
+ ptr_size = target.addr_size
+ thread = process.ReadUnsignedFromMemory (malloc_addr + 16 + ptr_size, ptr_size, error)
+ # 4 bytes 0xa1a1a1a1
+ # 12 bytes 'AUTORELEASE!'
+ # ptr bytes autorelease insertion point
+ # ptr bytes pthread_t
+ # ptr bytes next colder page
+ # ptr bytes next hotter page
+ # 4 bytes this page's depth in the list
+ # 4 bytes high-water mark
+ description += ' AUTORELEASE! for pthread_t %#x' % (thread)
+ # else:
+ # description += 'malloc(%u)' % (malloc_size)
+ # else:
+ # description += 'malloc(%u)' % (malloc_size)
else:
- # strip the "*" from the end of the name since we were unable to dereference this
- description += dynamic_value.type.name[0:-1]
+ derefed_dynamic_value = dynamic_value.deref
+ if derefed_dynamic_value:
+ derefed_dynamic_type = derefed_dynamic_value.type
+ derefed_dynamic_type_size = derefed_dynamic_type.size
+ derefed_dynamic_type_name = derefed_dynamic_type.name
+ description += ' '
+ description += derefed_dynamic_type_name
+ if offset < derefed_dynamic_type_size:
+ member_list = list();
+ get_member_types_for_offset (derefed_dynamic_type, offset, member_list)
+ if member_list:
+ member_path = ''
+ for member in member_list:
+ member_name = member.name
+ if member_name:
+ if member_path:
+ member_path += '.'
+ member_path += member_name
+ if member_path:
+ if options.ivar_regex_blacklist:
+ for ivar_regex in options.ivar_regex_blacklist:
+ if ivar_regex.match(member_path):
+ print_entry = False
+ description += '.%s' % (member_path)
+ else:
+ description += '%u bytes after %s' % (offset - derefed_dynamic_type_size, derefed_dynamic_type_name)
+ else:
+ # strip the "*" from the end of the name since we were unable to dereference this
+ description += dynamic_value.type.name[0:-1]
if print_entry:
match_idx += 1
result_output = ''
@@ -536,7 +654,7 @@ baton.matches'''
# Iterate through all of our pointer expressions and display the results
for ptr_expr in args:
user_init_code = user_init_code_format % (options.max_matches, ptr_expr)
- expr = get_iterate_memory_expr(process, user_init_code, user_return_code)
+ expr = get_iterate_memory_expr(options, process, user_init_code, user_return_code)
arg_str_description = 'malloc block containing pointer %s' % ptr_expr
display_match_results (result, options, arg_str_description, expr)
else:
@@ -630,7 +748,7 @@ baton.matches'''
# Iterate through all of our pointer expressions and display the results
for cstr in args:
user_init_code = user_init_code_format % (options.max_matches, cstr)
- expr = get_iterate_memory_expr(process, user_init_code, user_return_code)
+ expr = get_iterate_memory_expr(options, process, user_init_code, user_return_code)
arg_str_description = 'malloc block containing "%s"' % cstr
display_match_results (result, options, arg_str_description, expr)
else:
@@ -655,7 +773,11 @@ def malloc_info(debugger, command, resul
(options, args) = parser.parse_args(command_args)
except:
return
- options.type = 'addr'
+ malloc_info_impl (debugger, result, options, args)
+
+def malloc_info_impl (debugger, result, options, args):
+ # We are specifically looking for something on the heap only
+ options.type = 'malloc_info'
process = lldb.debugger.GetSelectedTarget().GetProcess()
if not process:
@@ -698,13 +820,16 @@ callback_baton_t baton = { range_callbac
baton.matches[0].addr = 0;
baton.matches[1].addr = 0;'''
if args:
+ total_matches = 0
for ptr_expr in args:
user_init_code = user_init_code_format % (ptr_expr)
- expr = get_iterate_memory_expr(process, user_init_code, 'baton.matches')
+ expr = get_iterate_memory_expr(options, process, user_init_code, 'baton.matches')
arg_str_description = 'malloc block that contains %s' % ptr_expr
- display_match_results (result, options, arg_str_description, expr)
+ total_matches += display_match_results (result, options, arg_str_description, expr)
+ return total_matches
else:
result.AppendMessage('error: command takes one or more pointer expressions')
+ return 0
def get_thread_stack_ranges_struct (process):
'''Create code that defines a structure that represents threads stack bounds
@@ -727,8 +852,9 @@ def get_thread_stack_ranges_struct (proc
if stack_dicts_len > 0:
result = '''
#define NUM_STACKS %u
+#define STACK_RED_ZONE_SIZE %u
typedef struct thread_stack_t { uint64_t tid, base, size; } thread_stack_t;
-thread_stack_t stacks[NUM_STACKS];''' % (stack_dicts_len,)
+thread_stack_t stacks[NUM_STACKS];''' % (stack_dicts_len, process.target.GetStackRedZoneSize())
for stack_dict in stack_dicts:
result += '''
stacks[%(index)u].tid = 0x%(tid)x;
@@ -870,7 +996,8 @@ def objc_refs(debugger, command, result,
# a member named "callback" whose type is "range_callback_t". This
# will be used by our zone callbacks to call the range callback for
# each malloc range.
- user_init_code_format = '''#define MAX_MATCHES %u
+ user_init_code_format = '''
+#define MAX_MATCHES %u
struct $malloc_match {
void *addr;
uintptr_t size;
@@ -954,7 +1081,7 @@ int nc = (int)objc_getClassList(baton.cl
options.type = 'isa'
result.AppendMessage('Searching for all instances of classes or subclasses of "%s" (isa=0x%x)' % (class_name, isa))
user_init_code = user_init_code_format % (options.max_matches, num_objc_classes, isa)
- expr = get_iterate_memory_expr(process, user_init_code, user_return_code)
+ expr = get_iterate_memory_expr(options, process, user_init_code, user_return_code)
arg_str_description = 'objective C classes with isa 0x%x' % isa
display_match_results (result, options, arg_str_description, expr)
else:
Modified: lldb/trunk/include/lldb/API/SBTarget.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/API/SBTarget.h?rev=174129&r1=174128&r2=174129&view=diff
==============================================================================
--- lldb/trunk/include/lldb/API/SBTarget.h (original)
+++ lldb/trunk/include/lldb/API/SBTarget.h Thu Jan 31 18:47:49 2013
@@ -765,6 +765,9 @@ public:
lldb::SBValue
EvaluateExpression (const char *expr, const SBExpressionOptions &options);
+ lldb::addr_t
+ GetStackRedZoneSize();
+
protected:
friend class SBAddress;
friend class SBBlock;
Modified: lldb/trunk/scripts/Python/interface/SBTarget.i
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/Python/interface/SBTarget.i?rev=174129&r1=174128&r2=174129&view=diff
==============================================================================
--- lldb/trunk/scripts/Python/interface/SBTarget.i (original)
+++ lldb/trunk/scripts/Python/interface/SBTarget.i Thu Jan 31 18:47:49 2013
@@ -712,6 +712,9 @@ public:
bool
GetDescription (lldb::SBStream &description, lldb::DescriptionLevel description_level);
+ lldb::addr_t
+ GetStackRedZoneSize();
+
lldb::SBValue
EvaluateExpression (const char *expr, const lldb::SBExpressionOptions &options);
%pythoncode %{
Modified: lldb/trunk/source/API/SBTarget.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBTarget.cpp?rev=174129&r1=174128&r2=174129&view=diff
==============================================================================
--- lldb/trunk/source/API/SBTarget.cpp (original)
+++ lldb/trunk/source/API/SBTarget.cpp Thu Jan 31 18:47:49 2013
@@ -2568,3 +2568,22 @@ SBTarget::EvaluateExpression (const char
return expr_result;
}
+
+lldb::addr_t
+SBTarget::GetStackRedZoneSize()
+{
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ ABISP abi_sp;
+ ProcessSP process_sp (target_sp->GetProcessSP());
+ if (process_sp)
+ abi_sp = process_sp->GetABI();
+ else
+ abi_sp = ABI::FindPlugin(target_sp->GetArchitecture());
+ if (abi_sp)
+ return abi_sp->GetRedZoneSize();
+ }
+ return 0;
+}
+
More information about the lldb-commits
mailing list