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
{