forked from OSchip/llvm-project
Cleaned up the code and we now also dump the dynamic object for the malloc block. Using this on the lldb/test/lang/objc/foundation test we can see this in action:
First we can load the module: (lldb) command script import /Volumes/work/gclayton/Documents/src/lldb/examples/darwin/heap_find/heap.py Loading "/Volumes/work/gclayton/Documents/src/lldb/examples/darwin/heap_find/libheap.dylib"...ok Image 0 loaded. "heap_ptr_refs" and "heap_cstr_refs" commands have been installed, use the "--help" options on these commands for detailed help. Lets take a look at the variable "my": (lldb) fr var *my (MyString) *my = { MyBase = { NSObject = { isa = MyString } propertyMovesThings = 0 } str = 0x0000000100301a60 date = 0x0000000100301e60 _desc_pauses = NO } We can see that this contains an ivar "str" which has a pointer value of "0x0000000100301a60". Lets search the heap for this pointer and see what we find: (lldb) heap_ptr_refs 0x0000000100301a60 found pointer 0x0000000100301a60: block = 0x103800270, size = 384, offset = 168, type = 'void *' found pointer 0x0000000100301a60: block = 0x100301cf0, size = 48, offset = 16, type = 'MyString *', ivar = 'str' (MyString) *addr = { MyBase = { NSObject = { isa = MyString } propertyMovesThings = 0 } str = 0x0000000100301a60 date = 0x0000000100301e60 _desc_pauses = NO } found pointer 0x0000000100301a60: block = 0x100820000, size = 4096, offset = 96, type = (autorelease object pool) found pointer 0x0000000100301a60: block = 0x100820000, size = 4096, offset = 104, type = (autorelease object pool) Note that it used dynamic type info to find that it was in "MyString" at offset 16 and it also found the ivar "str"! We can also look for C string values on the heap. Lets look for "a.out": (lldb) heap_cstr_refs "a.out" found cstr a.out: block = 0x10010ce00, size = 96, offset = 85, type = '__NSCFString *' found cstr a.out: block = 0x100112d90, size = 80, offset = 68, type = 'void *' found cstr a.out: block = 0x100114490, size = 96, offset = 85, type = '__NSCFString *' found cstr a.out: block = 0x100114530, size = 112, offset = 97, type = '__NSCFString *' found cstr a.out: block = 0x100114e40, size = 32, offset = 17, type = '__NSCFString *' found cstr a.out: block = 0x100114fa0, size = 32, offset = 17, type = '__NSCFString *' found cstr a.out: block = 0x100300780, size = 160, offset = 128, type = '__NSCFData *' found cstr a.out: block = 0x100301a60, size = 112, offset = 97, type = '__NSCFString *' found cstr a.out: block = 0x100821000, size = 4096, offset = 100, type = 'void *' We see we have some objective C classes that contain this, so lets "po" all of the results by adding the --po option: (lldb) heap_cstr_refs a.out --po found cstr a.out: block = 0x10010ce00, size = 96, offset = 85, type = '__NSCFString *' (__NSCFString *) 0x10010ce00 /Volumes/work/gclayton/Documents/src/lldb/test/lang/objc/foundation/a.out found cstr a.out: block = 0x100112d90, size = 80, offset = 68, type = 'void *' found cstr a.out: block = 0x100114490, size = 96, offset = 85, type = '__NSCFString *' (__NSCFString *) 0x100114490 /Volumes/work/gclayton/Documents/src/lldb/test/lang/objc/foundation/a.out found cstr a.out: block = 0x100114530, size = 112, offset = 97, type = '__NSCFString *' (__NSCFString *) 0x100114530 Hello from '/Volumes/work/gclayton/Documents/src/lldb/test/lang/objc/foundation/a.out' found cstr a.out: block = 0x100114e40, size = 32, offset = 17, type = '__NSCFString *' (__NSCFString *) 0x100114e40 a.out.dSYM found cstr a.out: block = 0x100114fa0, size = 32, offset = 17, type = '__NSCFString *' (__NSCFString *) 0x100114fa0 a.out found cstr a.out: block = 0x100300780, size = 160, offset = 128, type = '__NSCFData *' (__NSCFData *) 0x100300780 <48656c6c 6f206672 6f6d2027 2f566f6c 756d6573 2f776f72 6b2f6763 6c617974 6f6e2f44 6f63756d 656e7473 2f737263 2f6c6c64 622f7465 73742f6c 616e672f 6f626a63 2f666f75 6e646174 696f6e2f 612e6f75 742700> found cstr a.out: block = 0x100301a60, size = 112, offset = 97, type = '__NSCFString *' (__NSCFString *) 0x100301a60 Hello from '/Volumes/work/gclayton/Documents/src/lldb/test/lang/objc/foundation/a.out' found cstr a.out: block = 0x100821000, size = 4096, offset = 100, type = 'void *' llvm-svn: 154519
This commit is contained in:
parent
972541503f
commit
7fb671bac0
|
@ -18,113 +18,150 @@
|
|||
import lldb
|
||||
import commands
|
||||
import optparse
|
||||
import os
|
||||
import shlex
|
||||
|
||||
def heap_search(debugger, command, result, dict):
|
||||
def heap_search(options, arg_str):
|
||||
expr = None
|
||||
if options.type == 'pointer':
|
||||
ptr = int(arg_str, 0)
|
||||
expr = 'find_pointer_in_heap(0x%x)' % ptr
|
||||
elif options.type == 'cstr':
|
||||
expr = 'find_cstring_in_heap("%s")' % arg_str
|
||||
else:
|
||||
print 'error: invalid type "%s"\nvalid values are "pointer", "cstr"' % options.type
|
||||
return
|
||||
|
||||
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 = match_entry.addr.sbvalue.unsigned
|
||||
if malloc_addr == 0:
|
||||
break
|
||||
malloc_size = int(match_entry.size)
|
||||
offset = int(match_entry.offset)
|
||||
dynamic_value = match_entry.addr.sbvalue.GetDynamicValue(lldb.eDynamicCanRunTarget)
|
||||
# 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 options.type == 'pointer' and malloc_size == 4096:
|
||||
error = lldb.SBError()
|
||||
data = bytearray(lldb.process.ReadMemory(malloc_addr, 16, error))
|
||||
if data == '\xa1\xa1\xa1\xa1AUTORELEASE!':
|
||||
print 'found %s %s: block = 0x%x, size = %u, offset = %u, type = (autorelease object pool)' % (options.type, arg_str, malloc_addr, malloc_size, offset)
|
||||
continue
|
||||
|
||||
print 'found %s %s: block = 0x%x, size = %u, offset = %u, type = \'%s\'' % (options.type, arg_str, malloc_addr, malloc_size, offset, type_name),
|
||||
derefed_dynamic_value = dynamic_value.deref
|
||||
ivar_member = None
|
||||
if derefed_dynamic_value:
|
||||
derefed_dynamic_type = derefed_dynamic_value.type
|
||||
member = derefed_dynamic_type.GetFieldAtIndex(0)
|
||||
search_bases = False
|
||||
if member:
|
||||
if member.GetOffsetInBytes() <= offset:
|
||||
for field_idx in range (derefed_dynamic_type.GetNumberOfFields()):
|
||||
member = derefed_dynamic_type.GetFieldAtIndex(field_idx)
|
||||
member_byte_offset = member.GetOffsetInBytes()
|
||||
if member_byte_offset == offset:
|
||||
ivar_member = member
|
||||
break
|
||||
else:
|
||||
search_bases = True
|
||||
else:
|
||||
search_bases = True
|
||||
|
||||
if not ivar_member and search_bases:
|
||||
for field_idx in range (derefed_dynamic_type.GetNumberOfDirectBaseClasses()):
|
||||
member = derefed_dynamic_type.GetDirectBaseClassAtIndex(field_idx)
|
||||
member_byte_offset = member.GetOffsetInBytes()
|
||||
if member_byte_offset == offset:
|
||||
ivar_member = member
|
||||
break
|
||||
if not ivar_member:
|
||||
for field_idx in range (derefed_dynamic_type.GetNumberOfVirtualBaseClasses()):
|
||||
member = derefed_dynamic_type.GetVirtualBaseClassAtIndex(field_idx)
|
||||
member_byte_offset = member.GetOffsetInBytes()
|
||||
if member_byte_offset == offset:
|
||||
ivar_member = member
|
||||
break
|
||||
if ivar_member:
|
||||
print ", ivar = %s" % ivar_member.name,
|
||||
print "\n", dynamic_value.deref
|
||||
else:
|
||||
print
|
||||
if options.print_object_description:
|
||||
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, arg_str)
|
||||
else:
|
||||
print expr_sbvalue.error
|
||||
|
||||
def heap_ptr_refs(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)
|
||||
description='''Searches the heap for pointer references on darwin user space programs.
|
||||
|
||||
Any matches that were found will dump the malloc blocks that contain the pointers
|
||||
and might be able to print what kind of objects the pointers are contained in using
|
||||
dynamic type information from the program.'''
|
||||
parser = optparse.OptionParser(description=description, prog='heap_ptr_refs',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')
|
||||
parser.add_option('-o', '--po', action='store_true', dest='print_object_description', help='print the object descriptions for any matches', default=False)
|
||||
try:
|
||||
(options, args) = parser.parse_args(command_args)
|
||||
except:
|
||||
return
|
||||
|
||||
options.type = 'pointer'
|
||||
|
||||
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)
|
||||
heap_search (options, data)
|
||||
else:
|
||||
print 'error: no arguments were given'
|
||||
print 'error: no pointer 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 heap_cstr_refs(debugger, command, result, dict):
|
||||
command_args = shlex.split(command)
|
||||
usage = "usage: %prog [options] <PATH> [PATH ...]"
|
||||
description='''Searches the heap for C string references on darwin user space programs.
|
||||
|
||||
Any matches that were found will dump the malloc blocks that contain the C strings
|
||||
and might be able to print what kind of objects the pointers are contained in using
|
||||
dynamic type information from the program.'''
|
||||
parser = optparse.OptionParser(description=description, prog='heap_cstr_refs',usage=usage)
|
||||
parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)
|
||||
parser.add_option('-o', '--po', action='store_true', dest='print_object_description', help='print the object descriptions for any matches', default=False)
|
||||
try:
|
||||
(options, args) = parser.parse_args(command_args)
|
||||
except:
|
||||
return
|
||||
|
||||
options.type = 'cstr'
|
||||
|
||||
if args:
|
||||
|
||||
for data in args:
|
||||
heap_search (options, data)
|
||||
else:
|
||||
print 'error: no c string arguments were given to search for'
|
||||
|
||||
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 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'
|
||||
libheap_dylib_path = os.path.dirname(__file__) + '/libheap.dylib'
|
||||
debugger.HandleCommand('process load "%s"' % libheap_dylib_path)
|
||||
debugger.HandleCommand('command script add -f heap.heap_ptr_refs heap_ptr_refs')
|
||||
debugger.HandleCommand('command script add -f heap.heap_cstr_refs heap_cstr_refs')
|
||||
print '"heap_ptr_refs" and "heap_cstr_refs" commands have been installed, use the "--help" options on these commands for detailed help.'
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue