forked from OSchip/llvm-project
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.
llvm-svn: 154504
This commit is contained in:
parent
6a0afeb9c8
commit
804de01c33
|
@ -2,6 +2,6 @@ LEVEL = ../../../test/make
|
|||
|
||||
DYLIB_NAME := heap
|
||||
DYLIB_ONLY := YES
|
||||
DYLIB_C_SOURCES := heap_find.cpp
|
||||
DYLIB_CXX_SOURCES := heap_find.cpp
|
||||
|
||||
include $(LEVEL)/Makefile.rules
|
||||
|
|
|
@ -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'
|
||||
|
||||
|
||||
|
||||
|
|
@ -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 @@ enum data_type_t
|
|||
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_range_in_this_process (range_callback_t *callback, void *baton)
|
|||
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 @@ range_contains_ptr_callback (task_t task, void *baton, unsigned type, uint64_t p
|
|||
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 @@ range_contains_ptr_callback (task_t task, void *baton, unsigned type, uint64_t p
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue