[Lldb-commits] [lldb] r165437 - in /lldb/trunk/examples/darwin/heap_find: heap.py heap/heap_find.cpp

Greg Clayton gclayton at apple.com
Mon Oct 8 15:39:38 PDT 2012


Author: gclayton
Date: Mon Oct  8 17:39:38 2012
New Revision: 165437

URL: http://llvm.org/viewvc/llvm-project?rev=165437&view=rev
Log:
Checking in fixes that I used to track down a leaking module. The heap module can now search the vm regions with the --vm-regions options to any of the heap functions. This is currently slow and often will time out when run on a large program since our user expression timeout is set to 500000 usec. We need to add an API to LLDB where we can specify the timeout for an expression.


Modified:
    lldb/trunk/examples/darwin/heap_find/heap.py
    lldb/trunk/examples/darwin/heap_find/heap/heap_find.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=165437&r1=165436&r2=165437&view=diff
==============================================================================
--- lldb/trunk/examples/darwin/heap_find/heap.py (original)
+++ lldb/trunk/examples/darwin/heap_find/heap.py Mon Oct  8 17:39:38 2012
@@ -133,6 +133,7 @@
     parser.add_option('-S', '--stack-history', action='store_true', dest='stack_history', help='gets the stack history for all allocations whose start address matches each malloc block if MallocStackLogging is enabled', default=False)
     parser.add_option('-M', '--max-matches', type='int', dest='max_matches', help='the maximum number of matches to print', default=256)
     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)
 
 def dump_stack_history_entry(result, stack_history_entry, idx):
     address = int(stack_history_entry.address)
@@ -313,22 +314,22 @@
     print_no_matches = True
     arg_str_description = arg_str
     if options.type == 'pointer':
-        expr = 'find_pointer_in_heap((void *)%s)' % (arg_str)
+        expr = 'find_pointer_in_heap((void *)%s, (int)%u)' % (arg_str, options.check_vm_regions)
         arg_str_description = 'malloc block containing pointer %s' % arg_str
         if options.format == None: 
             options.format = "A" # 'A' is "address" format
     elif options.type == 'isa':
-        expr = 'find_objc_objects_in_memory ((void *)%s)' % (arg_str)
+        expr = 'find_objc_objects_in_memory ((void *)%s, (int)%u)' % (arg_str, options.check_vm_regions)
         #result.AppendMessage ('expr -u0 -- %s' % expr) # REMOVE THIS LINE
         arg_str_description = 'objective C classes with isa %s' % arg_str
         options.offset = 0
         if options.format == None: 
             options.format = "A" # 'A' is "address" format
     elif options.type == 'cstr':
-        expr = 'find_cstring_in_heap("%s")' % arg_str
+        expr = 'find_cstring_in_heap("%s", (int)%u)' % (arg_str, options.check_vm_regions)
         arg_str_description = 'malloc block containing "%s"' % arg_str
     elif options.type == 'addr':
-        expr = 'find_block_for_address((void *)%s)' % arg_str
+        expr = 'find_block_for_address((void *)%s, (int)%u)' % (arg_str, options.check_vm_regions)
         arg_str_description = 'malloc block for %s' % arg_str
     elif options.type == 'all':
         expr = 'get_heap_info(1)'
@@ -430,6 +431,56 @@
     else:
         heap_search (result, options, None)
 
+def stack_ptr_refs(debugger, command, result, dict):
+    command_args = shlex.split(command)
+    usage = "usage: %prog [options] <EXPR> [EXPR ...]"
+    description='''Searches thread stack contents for pointer values in darwin user space programs.'''
+    parser = optparse.OptionParser(description=description, prog='section_ptr_refs',usage=usage)
+    add_common_options(parser)
+    try:
+        (options, args) = parser.parse_args(command_args)
+    except:
+        return
+
+    options.type = 'pointer'
+    
+    stack_threads = list()
+    stack_bases = list()
+    stack_sizes = list()
+    for thread in lldb.process:
+        min_sp = thread.frame[0].sp
+        max_sp = min_sp
+        for frame in thread.frames:
+            sp = frame.sp
+            if sp < min_sp: min_sp = sp
+            if sp > max_sp: max_sp = sp
+        result.AppendMessage ('%s stack [%#x - %#x)' % (thread, min_sp, max_sp))
+        if min_sp < max_sp:
+            stack_threads.append (thread)
+            stack_bases.append (min_sp)
+            stack_sizes.append (max_sp-min_sp)
+        
+    if stack_bases:
+        dylid_load_err = load_dylib()
+        if dylid_load_err:
+            result.AppendMessage(dylid_load_err)
+            return
+        for expr_str in args:
+            for (idx, stack_base) in enumerate(stack_bases):
+                stack_size = stack_sizes[idx]
+                expr = 'find_pointer_in_memory(0x%xllu, %ullu, (void *)%s)' % (stack_base, stack_size, expr_str)
+                arg_str_description = 'thead %s stack containing "%s"' % (stack_threads[idx], expr_str)
+                num_matches = display_match_results (result, options, arg_str_description, lldb.frame.EvaluateExpression (expr), False)
+                if num_matches:
+                    if num_matches < options.max_matches:
+                        options.max_matches = options.max_matches - num_matches
+                    else:
+                        options.max_matches = 0
+                if options.max_matches == 0:
+                    return
+    else:
+        result.AppendMessage('error: no thread stacks were found that match any of %s' % (', '.join(options.section_names)))
+
 def section_ptr_refs(debugger, command, result, dict):
     command_args = shlex.split(command)
     usage = "usage: %prog [options] <EXPR> [EXPR ...]"
@@ -443,7 +494,7 @@
         return
 
     options.type = 'pointer'
-    
+
     sections = list()
     section_modules = list()
     if not options.section_names:
@@ -520,8 +571,9 @@
 lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.malloc_info malloc_info')
 lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.heap heap')
 lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.section_ptr_refs section_ptr_refs')
+lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.stack_ptr_refs stack_ptr_refs')
 lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.objc_refs objc_refs')
-print '"ptr_refs", "cstr_refs", "malloc_info", "heap" and "section_ptr_refs" commands have been installed, use the "--help" options on these commands for detailed help.'
+print '"ptr_refs", "cstr_refs", "malloc_info", "heap", "section_ptr_refs" and "stack_ptr_refs" commands have been installed, use the "--help" options on these commands for detailed help.'
 
 
 

Modified: lldb/trunk/examples/darwin/heap_find/heap/heap_find.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/examples/darwin/heap_find/heap/heap_find.cpp?rev=165437&r1=165436&r2=165437&view=diff
==============================================================================
--- lldb/trunk/examples/darwin/heap_find/heap/heap_find.cpp (original)
+++ lldb/trunk/examples/darwin/heap_find/heap/heap_find.cpp Mon Oct  8 17:39:38 2012
@@ -68,6 +68,7 @@
 #include <ctype.h>
 #include <dlfcn.h>
 #include <mach/mach.h>
+#include <mach/mach_vm.h>
 #include <malloc/malloc.h>
 #include <objc/objc-runtime.h>
 #include <stdio.h>
@@ -91,6 +92,8 @@
 #define stack_logging_type_generic	1
 #define stack_logging_type_alloc	2
 #define stack_logging_type_dealloc	4
+// This bit is made up by this code
+#define stack_logging_type_vm_region 8 
 
 //----------------------------------------------------------------------
 // Redefine private function prototypes from 
@@ -130,6 +133,13 @@
 
 extern "C" void *gdb_class_getClass (void *objc_class);
 
+static void
+range_info_callback (task_t task, 
+                     void *baton, 
+                     unsigned type, 
+                     uint64_t ptr_addr, 
+                     uint64_t ptr_size);
+
 //----------------------------------------------------------------------
 // Redefine private gloval variables prototypes from 
 // "/usr/local/include/stack_logging.h"
@@ -153,6 +163,7 @@
     zone_callback_t *zone_callback;
     range_callback_t *range_callback;
     void *baton;
+    int check_vm_regions;
 };
 
 enum data_type_t
@@ -188,6 +199,7 @@
     };
     uint32_t match_count;
     bool done;
+    bool unique;    
 };
 
 struct malloc_match
@@ -195,6 +207,7 @@
     void *addr;
     intptr_t size;
     intptr_t offset;
+    uintptr_t type;
 };
 
 struct malloc_stack_entry
@@ -239,6 +252,7 @@
     clear()
     {
         m_size = 0;
+        bzero (&m_entries, sizeof(m_entries));
     }
     
     bool
@@ -248,8 +262,17 @@
     }
 
     void
-    push_back (const malloc_match& m)
+    push_back (const malloc_match& m, bool unique = false)
     {
+        if (unique)
+        {
+            // Don't add the entry if there is already a match for this address
+            for (uint32_t i=0; i<m_size; ++i)
+            {
+                if (((uint8_t *)m_entries[i].addr + m_entries[i].offset) == ((uint8_t *)m.addr + m.offset))
+                    return; // Duplicate entry
+            }
+        }
         if (m_size < k_max_entries - 1)
         {
             m_entries[m_size] = m;
@@ -264,7 +287,7 @@
         if (empty())
             return NULL;
         // In not empty, terminate and return the result
-        malloc_match terminator_entry = { NULL, 0, 0 };
+        malloc_match terminator_entry = { NULL, 0, 0, 0 };
         // We always leave room for an empty entry at the end
         m_entries[m_size] = terminator_entry;
         return m_entries;
@@ -584,6 +607,49 @@
             info->zone_callback (info, (const malloc_zone_t *)zones[i]);
         }
     }
+    
+    if (info->check_vm_regions)
+    {
+#if defined (VM_REGION_SUBMAP_SHORT_INFO_COUNT_64)
+        typedef vm_region_submap_short_info_data_64_t RegionInfo;
+        enum { kRegionInfoSize = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 };
+#else
+        typedef vm_region_submap_info_data_64_t RegionInfo;
+        enum { kRegionInfoSize = VM_REGION_SUBMAP_INFO_COUNT_64 };
+#endif
+        task_t task = mach_task_self();
+    	mach_vm_address_t vm_region_base_addr;
+    	mach_vm_size_t vm_region_size;
+    	natural_t vm_region_depth;
+    	RegionInfo vm_region_info;
+
+        ((range_contains_data_callback_info_t *)info->baton)->unique = true;
+
+        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 = kRegionInfoSize;
+            const kern_return_t err = mach_vm_region_recurse (task,
+                                                              &vm_region_base_addr,
+                                                              &vm_region_size,
+                                                              &vm_region_depth,
+                                                              (vm_region_recurse_info_t)&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 that aren't covered by the heap
+            if (vm_region_info.protection & VM_PROT_WRITE && 
+                vm_region_info.protection & VM_PROT_READ)
+            {
+                //printf ("checking vm_region: [0x%16.16llx - 0x%16.16llx)\n", (uint64_t)vm_region_base_addr, (uint64_t)vm_region_base_addr + vm_region_size);
+                range_info_callback (task, 
+                                     info->baton, 
+                                     stack_logging_type_vm_region, 
+                                     vm_region_base_addr, 
+                                     vm_region_size);
+            }
+        }
+    }
 }
 
 //----------------------------------------------------------------------
@@ -635,8 +701,8 @@
         if (ptr_addr <= info->addr && info->addr < end_addr)
         {
             ++info->match_count;
-            malloc_match match = { (void *)ptr_addr, ptr_size, info->addr - ptr_addr };
-            g_matches.push_back(match);
+            malloc_match match = { (void *)ptr_addr, ptr_size, info->addr - ptr_addr, type };
+            g_matches.push_back(match, info->unique);
         }
         break;
     
@@ -659,8 +725,8 @@
                         if (memcmp (buffer, ptr_data, size) == 0)
                         {
                             ++info->match_count;
-                            malloc_match match = { (void *)ptr_addr, ptr_size, addr - ptr_addr };
-                            g_matches.push_back(match);
+                            malloc_match match = { (void *)ptr_addr, ptr_size, addr - ptr_addr, type };
+                            g_matches.push_back(match, info->unique);
                         }
                     }
                 }
@@ -714,8 +780,8 @@
                     {
                         //printf (" success\n");
                         ++info->match_count;
-                        malloc_match match = { (void *)ptr_addr, ptr_size, 0 };
-                        g_matches.push_back(match);                        
+                        malloc_match match = { (void *)ptr_addr, ptr_size, 0, type };
+                        g_matches.push_back(match, info->unique);
                     }
                     else
                     {
@@ -830,7 +896,7 @@
 // blocks.
 //----------------------------------------------------------------------
 malloc_match *
-find_pointer_in_heap (const void * addr)
+find_pointer_in_heap (const void * addr, int check_vm_regions)
 {
     g_matches.clear();
     // Setup "info" to look for a malloc block that contains data
@@ -844,8 +910,11 @@
         data_info.data.align = sizeof(addr);         // Align to a pointer byte size
         data_info.match_count = 0;                   // Initialize the match count to zero
         data_info.done = false;                      // Set done to false so searching doesn't stop
-        range_callback_info_t info = { enumerate_range_in_zone, range_info_callback, &data_info };
+        data_info.unique = false;                    // Set to true when iterating on the vm_regions
+        range_callback_info_t info = { enumerate_range_in_zone, range_info_callback, &data_info, check_vm_regions };
         foreach_zone_in_this_process (&info);
+        
+        
     }
     return g_matches.data();
 }
@@ -869,6 +938,7 @@
     data_info.data.align = sizeof(addr);         // Align to a pointer byte size
     data_info.match_count = 0;                   // Initialize the match count to zero
     data_info.done = false;                      // Set done to false so searching doesn't stop
+    data_info.unique = false;                    // Set to true when iterating on the vm_regions
     range_info_callback (mach_task_self(), &data_info, stack_logging_type_generic, memory_addr, memory_size);
     return g_matches.data();
 }
@@ -881,7 +951,7 @@
 // inherit from 'c'
 //----------------------------------------------------------------------
 malloc_match *
-find_objc_objects_in_memory (void *isa)
+find_objc_objects_in_memory (void *isa, int check_vm_regions)
 {
     g_matches.clear();
     if (g_objc_classes.Update())
@@ -894,7 +964,8 @@
         data_info.objc.match_superclasses = true;
         data_info.match_count = 0;                   // Initialize the match count to zero
         data_info.done = false;                      // Set done to false so searching doesn't stop
-        range_callback_info_t info = { enumerate_range_in_zone, range_info_callback, &data_info };
+        data_info.unique = false;                    // Set to true when iterating on the vm_regions
+        range_callback_info_t info = { enumerate_range_in_zone, range_info_callback, &data_info, check_vm_regions };
         foreach_zone_in_this_process (&info);
     }
     return g_matches.data();
@@ -920,7 +991,9 @@
         data_info.type = eDataTypeHeapInfo; // Check each block for data
         data_info.match_count = 0;          // Initialize the match count to zero
         data_info.done = false;             // Set done to false so searching doesn't stop
-        range_callback_info_t info = { enumerate_range_in_zone, range_info_callback, &data_info };
+        data_info.unique = false;           // Set to true when iterating on the vm_regions
+        const int check_vm_regions = false;
+        range_callback_info_t info = { enumerate_range_in_zone, range_info_callback, &data_info, check_vm_regions };
         foreach_zone_in_this_process (&info);
         
         // Sort and print byte total bytes
@@ -949,7 +1022,7 @@
 // Finds a C string inside one or more currently valid malloc blocks.
 //----------------------------------------------------------------------
 malloc_match *
-find_cstring_in_heap (const char *s)
+find_cstring_in_heap (const char *s, int check_vm_regions)
 {
     g_matches.clear();
     if (s == NULL || s[0] == '\0')
@@ -966,7 +1039,8 @@
     data_info.data.align = 1;                // Data doesn't need to be aligned, so set the alignment to 1
     data_info.match_count = 0;               // Initialize the match count to zero
     data_info.done = false;                  // Set done to false so searching doesn't stop
-    range_callback_info_t info = { enumerate_range_in_zone, range_info_callback, &data_info };
+    data_info.unique = false;                // Set to true when iterating on the vm_regions
+    range_callback_info_t info = { enumerate_range_in_zone, range_info_callback, &data_info, check_vm_regions };
     foreach_zone_in_this_process (&info);
     return g_matches.data();
 }
@@ -977,7 +1051,7 @@
 // Find the malloc block that whose address range contains "addr".
 //----------------------------------------------------------------------
 malloc_match *
-find_block_for_address (const void *addr)
+find_block_for_address (const void *addr, int check_vm_regions)
 {
     g_matches.clear();
     // Setup "info" to look for a malloc block that contains data
@@ -987,7 +1061,8 @@
     data_info.addr = (uintptr_t)addr;   // What data? The C string passed in
     data_info.match_count = 0;          // Initialize the match count to zero
     data_info.done = false;             // Set done to false so searching doesn't stop
-    range_callback_info_t info = { enumerate_range_in_zone, range_info_callback, &data_info };
+    data_info.unique = false;           // Set to true when iterating on the vm_regions
+    range_callback_info_t info = { enumerate_range_in_zone, range_info_callback, &data_info, check_vm_regions };
     foreach_zone_in_this_process (&info);
     return g_matches.data();
 }





More information about the lldb-commits mailing list