[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