Added a new "heap.py" module that adds a new command line command that can find values on the heap and print out the dynamic type of the malloc block that contains the data. I will be modifying this a bit more to tweak the output and make the output more useful.



git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@154504 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/examples/darwin/heap_find/Makefile b/examples/darwin/heap_find/Makefile
index 75fcbc8..1d03674 100644
--- a/examples/darwin/heap_find/Makefile
+++ b/examples/darwin/heap_find/Makefile
@@ -2,6 +2,6 @@
 
 DYLIB_NAME := heap
 DYLIB_ONLY := YES
-DYLIB_C_SOURCES := heap_find.cpp
+DYLIB_CXX_SOURCES := heap_find.cpp
 
 include $(LEVEL)/Makefile.rules
diff --git a/examples/darwin/heap_find/heap.py b/examples/darwin/heap_find/heap.py
new file mode 100644
index 0000000..e5405da
--- /dev/null
+++ b/examples/darwin/heap_find/heap.py
@@ -0,0 +1,131 @@
+#!/usr/bin/python
+
+#----------------------------------------------------------------------
+# Be sure to add the python path that points to the LLDB shared library.
+#
+# # To use this in the embedded python interpreter using "lldb" just
+# import it with the full path using the "command script import" 
+# command
+#   (lldb) command script import /path/to/heap.py
+#
+# For the shells csh, tcsh:
+#   ( setenv PYTHONPATH /path/to/LLDB.framework/Resources/Python ; ./heap.py )
+#
+# For the shells sh, bash:
+#   PYTHONPATH=/path/to/LLDB.framework/Resources/Python ./heap.py 
+#----------------------------------------------------------------------
+
+import lldb
+import commands
+import optparse
+import shlex
+
+def heap_search(debugger, command, result, dict):
+    command_args = shlex.split(command)
+    usage = "usage: %prog [options] <PATH> [PATH ...]"
+    description='''This command lets you run the /bin/ls command from within lldb as a quick and easy example.'''
+    parser = optparse.OptionParser(description=description, prog='heap_search',usage=usage)
+    parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)
+    parser.add_option('-t', '--type', type='string', dest='type', help='the type of data to search for (defaults to "pointer")', default='pointer')
+    parser.add_option('-o', '--po', action='store_true', dest='po', default='print the object descriptions for any matches')
+    try:
+        (options, args) = parser.parse_args(command_args)
+    except:
+        return
+    
+    if args:
+        
+        for data in args:
+            if options.type == 'pointer':
+                ptr = int(data, 0)
+                expr = 'find_pointer_in_heap(0x%x)' % ptr
+                #print 'expr: %s' % expr
+                expr_sbvalue = lldb.frame.EvaluateExpression (expr)
+                if expr_sbvalue.error.Success():
+                    if expr_sbvalue.unsigned:
+                        match_value = lldb.value(expr_sbvalue)  
+                        i = 0
+                        while 1:
+                            match_entry = match_value[i]; i += 1
+                            malloc_addr = int(match_entry.addr)
+                            if malloc_addr == 0:
+                                break
+                            malloc_size = int(match_entry.size)
+                            offset = int(match_entry.offset)
+                            dynamic_value = match_entry.addr.sbvalue.dynamic
+                            # If the type is still 'void *' then we weren't able to figure
+                            # out a dynamic type for the malloc_addr
+                            type_name = dynamic_value.type.name
+                            if type_name == 'void *':
+                                if malloc_size == 4096:
+                                    error = lldb.SBError()
+                                    data = bytearray(lldb.process.ReadMemory(malloc_addr, 16, error))
+                                    if data == '\xa1\xa1\xa1\xa1AUTORELEASE!':
+                                        print 'found %s 0x%x in (autorelease object pool) 0x%x, malloc_size = %u, offset = %u' % (options.type, ptr, malloc_addr, malloc_size, offset)
+                                        continue
+                                print 'found %s 0x%x in malloc block 0x%x, malloc_size = %u, offset = %u' % (options.type, ptr, malloc_addr, malloc_size, offset)
+                            else:
+                                print 'found %s 0x%x in (%s) 0x%x, malloc_size = %u, offset = %u' % (options.type, ptr, type_name, malloc_addr, malloc_size, offset)
+                                if options.po:
+                                    desc = dynamic_value.GetObjectDescription()
+                                    if desc:
+                                        print '  (%s) 0x%x %s\n' % (type_name, malloc_addr, desc)
+                    else:
+                        print '%s 0x%x was not found in any malloc blocks' % (options.type, ptr)
+                else:
+                    print expr_sbvalue.error
+            elif options.type == 'cstring':
+                expr = 'find_cstring_in_heap("%s")' % data
+                #print 'expr: %s' % expr
+                expr_sbvalue = lldb.frame.EvaluateExpression (expr)
+                if expr_sbvalue.error.Success():
+                    if expr_sbvalue.unsigned:
+                        match_value = lldb.value(expr_sbvalue)  
+                        print match_value
+                        i = 0
+                        while 1:
+                            match_entry = match_value[i]; i += 1
+                            malloc_addr = int(match_entry.addr)
+                            if malloc_addr == 0:
+                                break
+                            malloc_size = int(match_entry.size)
+                            offset = int(match_entry.offset)
+                            dynamic_value = match_entry.addr.sbvalue.dynamic
+                            # If the type is still 'void *' then we weren't able to figure
+                            # out a dynamic type for the malloc_addr
+                            type_name = dynamic_value.type.name
+                            if type_name == 'void *':
+                                print 'found %s "%s" in malloc block 0x%x, malloc_size = %u, offset = %u' % (options.type, data, malloc_addr, malloc_size, offset)
+                            else:
+                                print 'found %s "%s" in (%s) 0x%x, malloc_size = %u, offset = %u' % (options.type, data, type_name, malloc_addr, malloc_size, offset)
+                                if options.po:
+                                    desc = dynamic_value.GetObjectDescription()
+                                    if desc:
+                                        print '  (%s) 0x%x %s\n' % (type_name, malloc_addr, desc)
+                    else:
+                        print '%s "%s" was not found in any malloc blocks' % (options.type, data)
+                else:
+                    print expr_sbvalue.error
+                
+            else:
+                print 'error: invalid type "%s"\nvalid values are "pointer", "cstring"' % options.type
+                sys.exit(1)
+    else:
+        print 'error: no arguments were given'
+
+if __name__ == '__main__':
+    # This script is being run from the command line, create a debugger in case we are
+    # going to use any debugger functions in our function.
+    lldb.debugger = lldb.SBDebugger.Create()
+    ls (sys.argv)
+
+def __lldb_init_module (debugger, dict):
+    # This initializer is being run from LLDB in the embedded command interpreter
+    # Add any commands contained in this module to LLDB
+    debugger.HandleCommand('process load /Volumes/work/gclayton/Documents/src/lldb/examples/darwin/heap_find/libheap.dylib')
+    debugger.HandleCommand('command script add -f heap.heap_search heap_search')
+    print '"heap_search" command installed, type "heap_search --help" for detailed help'
+
+
+
+
diff --git a/examples/darwin/heap_find/heap_find.cpp b/examples/darwin/heap_find/heap_find.cpp
index 15d8c77..f98b405 100644
--- a/examples/darwin/heap_find/heap_find.cpp
+++ b/examples/darwin/heap_find/heap_find.cpp
@@ -42,7 +42,7 @@
 // format. The address format shows pointers, and if those pointers point to
 // objects that have symbols or know data contents, it will display information
 // about the pointers:
-/
+//
 // (lldb) memory read --format address --count 1 0x104000730 
 // 0x104000730: 0x0000000100002460 (void *)0x0000000100002488: MyString
 // 
@@ -71,6 +71,7 @@
 #include <stack_logging.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <vector>
 
 struct range_callback_info_t;
 
@@ -91,15 +92,23 @@
     eDataTypeInteger
 };
 
-typedef struct range_contains_data_callback_info_tag
+struct range_contains_data_callback_info_t
 {
     const uint8_t *data;
     const size_t data_len;
     const uint32_t align;
     const data_type_t data_type;
     uint32_t match_count;
-} range_contains_data_callback_info_t;
+};
 
+struct malloc_match
+{
+    void *addr;
+    intptr_t size;
+    intptr_t offset;
+};
+
+std::vector<malloc_match> g_matches;
 
 static kern_return_t
 task_peek (task_t task, vm_address_t remote_address, vm_size_t size, void **local_memory)
@@ -166,6 +175,7 @@
     foreach_zone_in_this_process (&info);
 }
 
+
 static void
 range_contains_ptr_callback (task_t task, void *baton, unsigned type, uint64_t ptr_addr, uint64_t ptr_size)
 {
@@ -191,39 +201,41 @@
             if (memcmp (data_info->data, data, data_info->data_len) == 0)
             {
                 ++data_info->match_count;
-                printf ("0x%llx: ", addr);
-                uint32_t i;
-                switch (data_info->data_type)
-                {
-                case eDataTypeInteger:
-                    {
-                        // NOTE: little endian specific, but all darwin platforms are little endian now..
-                        for (i=0; i<data_info->data_len; ++i)
-                            printf (i ? "%2.2x" : "0x%2.2x", data[data_info->data_len - (i + 1)]);
-                    }
-                    break;
-                case eDataTypeBytes:
-                    {
-                        for (i=0; i<data_info->data_len; ++i)
-                            printf (" %2.2x", data[i]);
-                    }
-                    break;
-                case eDataTypeCStr:
-                    {
-                        putchar ('"');
-                        for (i=0; i<data_info->data_len; ++i)
-                        {
-                            if (isprint (data[i]))
-                                putchar (data[i]);
-                            else
-                                printf ("\\x%2.2x", data[i]);
-                        }
-                        putchar ('"');
-                    }
-                    break;
-                    
-                }
-                printf (" found in malloc block 0x%llx + %llu (malloc_size = %llu)\n", ptr_addr, addr - ptr_addr, ptr_size);
+                malloc_match match = { (void *)ptr_addr, ptr_size, addr - ptr_addr };
+                g_matches.push_back(match);
+                // printf ("0x%llx: ", addr);
+                // uint32_t i;
+                // switch (data_info->data_type)
+                // {
+                // case eDataTypeInteger:
+                //     {
+                //         // NOTE: little endian specific, but all darwin platforms are little endian now..
+                //         for (i=0; i<data_info->data_len; ++i)
+                //             printf (i ? "%2.2x" : "0x%2.2x", data[data_info->data_len - (i + 1)]);
+                //     }
+                //     break;
+                // case eDataTypeBytes:
+                //     {
+                //         for (i=0; i<data_info->data_len; ++i)
+                //             printf (" %2.2x", data[i]);
+                //     }
+                //     break;
+                // case eDataTypeCStr:
+                //     {
+                //         putchar ('"');
+                //         for (i=0; i<data_info->data_len; ++i)
+                //         {
+                //             if (isprint (data[i]))
+                //                 putchar (data[i]);
+                //             else
+                //                 printf ("\\x%2.2x", data[i]);
+                //         }
+                //         putchar ('"');
+                //     }
+                //     break;
+                //     
+                // }
+                // printf (" found in malloc block 0x%llx + %llu (malloc_size = %llu)\n", ptr_addr, addr - ptr_addr, ptr_size);
             }
         }
     }
@@ -233,24 +245,35 @@
     }   
 }
 
-uint32_t
+malloc_match *
 find_pointer_in_heap (intptr_t addr)
 {
+    g_matches.clear();
     range_contains_data_callback_info_t data_info = { (uint8_t *)&addr, sizeof(addr), sizeof(addr), eDataTypeInteger, 0};
     range_callback_info_t info = { enumerate_range_in_zone, range_contains_ptr_callback, &data_info };
     foreach_zone_in_this_process (&info);
-    return data_info.match_count;
+    if (g_matches.empty())
+        return NULL;
+    malloc_match match = { NULL, 0, 0 };
+    g_matches.push_back(match);
+    return g_matches.data();
 }
 
-uint32_t
+
+malloc_match *
 find_cstring_in_heap (const char *s)
 {
     if (s && s[0])
     {
+        g_matches.clear();
         range_contains_data_callback_info_t data_info = { (uint8_t *)s, strlen(s), 1, eDataTypeCStr, 0};
         range_callback_info_t info = { enumerate_range_in_zone, range_contains_ptr_callback, &data_info };
         foreach_zone_in_this_process (&info);
-        return data_info.match_count;
+        if (g_matches.empty())
+            return NULL;
+        malloc_match match = { NULL, 0, 0 };
+        g_matches.push_back(match);
+        return g_matches.data();
     }
     else
     {