Added the ability to search through sections for pointer data.

llvm-svn: 160083
This commit is contained in:
Greg Clayton 2012-07-11 22:13:18 +00:00
parent 26b8e1d03f
commit e04cfd2180
2 changed files with 145 additions and 53 deletions

View File

@ -13,6 +13,7 @@ import commands
import optparse
import os
import os.path
import re
import shlex
import string
import tempfile
@ -112,14 +113,24 @@ def get_member_types_for_offset(value_type, offset, member_list):
member_list.append(member)
get_member_types_for_offset (member.type, offset - member_byte_offset, member_list)
return
def append_regex_callback(option, opt, value, parser):
try:
ivar_regex = re.compile(value)
parser.values.ivar_regex_blacklist.append(ivar_regex)
except:
print 'error: an exception was thrown when compiling the ivar regular expression for "%s"' % value
def add_common_options(parser):
parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)
parser.add_option('-t', '--type', action='store_true', dest='print_type', help='print the full value of the type for each matching malloc block', default=False)
parser.add_option('-o', '--po', action='store_true', dest='print_object_description', help='print the object descriptions for any matches', default=False)
parser.add_option('-m', '--memory', action='store_true', dest='memory', help='dump the memory for each matching block', default=False)
parser.add_option('-f', '--format', type='string', dest='format', help='the format to use when dumping memory if --memory is specified', default=None)
parser.add_option('-I', '--omit-ivar-regex', type='string', action='callback', callback=append_regex_callback, dest='ivar_regex_blacklist', default=[], help='specify one or more regular expressions used to backlist any matches that are in ivars')
parser.add_option('-s', '--stack', action='store_true', dest='stack', help='gets the stack that allocated each malloc block if MallocStackLogging is enabled', default=False)
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)
def dump_stack_history_entry(stack_history_entry, idx):
address = int(stack_history_entry.address)
@ -172,43 +183,21 @@ def dump_stack_history_entries(addr, history):
dump_stack_history_entry(stack_history_entry, idx)
idx = idx + 1
stack_history_entry = expr_value[idx]
else:
print 'error: expression returned => %s' % (expr_sbvalue)
else:
print 'error: expression failed "%s" => %s' % (expr, expr_sbvalue.error)
def heap_search(options, arg_str):
dylid_load_err = load_dylib()
if dylid_load_err:
print dylid_load_err
return
expr = None
arg_str_description = arg_str
default_memory_format = "Y" # 'Y' is "bytes with ASCII" format
#memory_chunk_size = 1
if options.type == 'pointer':
expr = 'find_pointer_in_heap((void *)%s)' % (arg_str)
arg_str_description = 'malloc block containing pointer %s' % arg_str
default_memory_format = "A" # 'A' is "address" format
#memory_chunk_size = lldb.process.GetAddressByteSize()
elif options.type == 'cstr':
expr = 'find_cstring_in_heap("%s")' % arg_str
arg_str_description = 'malloc block containing "%s"' % arg_str
elif options.type == 'addr':
expr = 'find_block_for_address((void *)%s)' % arg_str
arg_str_description = 'malloc block for %s' % arg_str
else:
print 'error: invalid type "%s"\nvalid values are "pointer", "cstr"' % options.type
return
expr_sbvalue = lldb.frame.EvaluateExpression (expr)
def display_match_results (options, arg_str_description, expr_sbvalue, print_no_matches = True):
if expr_sbvalue.error.Success():
if expr_sbvalue.unsigned:
match_value = lldb.value(expr_sbvalue)
i = 0
while 1:
print_entry = True
match_entry = match_value[i]; i += 1
if i >= options.max_matches:
print 'error: the max number of matches (%u) was reached, use the --max-matches option to get more results' % (options.max_matches)
break
malloc_addr = match_entry.addr.sbvalue.unsigned
if malloc_addr == 0:
break
@ -220,13 +209,13 @@ def heap_search(options, arg_str):
if offset != 0:
description += ' + %u' % (offset)
description += ', size = %u' % (malloc_size)
derefed_dynamic_value = None
if dynamic_value.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!':
description += ', type = (AUTORELEASE!)'
print description
else:
derefed_dynamic_value = dynamic_value.deref
if derefed_dynamic_value:
@ -246,32 +235,61 @@ def heap_search(options, arg_str):
member_path += '.'
member_path += member_name
if member_path:
if options.ivar_regex_blacklist:
for ivar_regex in options.ivar_regex_blacklist:
if ivar_regex.match(member_path):
print_entry = False
description += ', ivar = %s' % (member_path)
print description
if derefed_dynamic_value:
print derefed_dynamic_value
if options.print_object_description:
desc = dynamic_value.GetObjectDescription()
if desc:
print ' (%s) 0x%x %s\n' % (type_name, malloc_addr, desc)
if options.memory:
memory_format = options.format
if not memory_format:
memory_format = default_memory_format
cmd_result = lldb.SBCommandReturnObject()
#count = malloc_size / memory_chunk_size
memory_command = "memory read -f %s 0x%x 0x%x" % (memory_format, malloc_addr, malloc_addr + malloc_size)
lldb.debugger.GetCommandInterpreter().HandleCommand(memory_command, cmd_result)
print cmd_result.GetOutput()
if options.stack_history:
dump_stack_history_entries(malloc_addr, 1)
elif options.stack:
dump_stack_history_entries(malloc_addr, 0)
else:
print '%s %s was not found in any malloc blocks' % (options.type, arg_str)
if print_entry:
if description:
print description
if options.print_type and derefed_dynamic_value:
print derefed_dynamic_value
if options.print_object_description and dynamic_value:
desc = dynamic_value.GetObjectDescription()
if desc:
print ' (%s) 0x%x %s\n' % (type_name, malloc_addr, desc)
if options.memory:
cmd_result = lldb.SBCommandReturnObject()
memory_command = "memory read -f %s 0x%x 0x%x" % (options.format, malloc_addr, malloc_addr + malloc_size)
lldb.debugger.GetCommandInterpreter().HandleCommand(memory_command, cmd_result)
print cmd_result.GetOutput()
if options.stack_history:
dump_stack_history_entries(malloc_addr, 1)
elif options.stack:
dump_stack_history_entries(malloc_addr, 0)
return i
elif print_no_matches:
print 'no matches found for %s' % (arg_str_description)
else:
print expr_sbvalue.error
print
return 0
def heap_search(options, arg_str):
dylid_load_err = load_dylib()
if dylid_load_err:
print dylid_load_err
return
expr = None
arg_str_description = arg_str
if options.format == None:
options.format = "Y" # 'Y' is "bytes with ASCII" format
if options.type == 'pointer':
expr = 'find_pointer_in_heap((void *)%s)' % (arg_str)
arg_str_description = 'malloc block containing pointer %s' % arg_str
if options.format == None:
options.format = "A" # 'A' is "address" format
elif options.type == 'cstr':
expr = 'find_cstring_in_heap("%s")' % arg_str
arg_str_description = 'malloc block containing "%s"' % arg_str
elif options.type == 'addr':
expr = 'find_block_for_address((void *)%s)' % arg_str
arg_str_description = 'malloc block for %s' % arg_str
else:
print 'error: invalid type "%s"\nvalid values are "pointer", "cstr"' % options.type
return
display_match_results (options, arg_str_description, lldb.frame.EvaluateExpression (expr))
def ptr_refs(debugger, command, result, dict):
command_args = shlex.split(command)
@ -366,6 +384,52 @@ def malloc_history(debugger, command, result, dict):
else:
print 'error: no address expressions were specified'
def section_ptr_refs(debugger, command, result, dict):
command_args = shlex.split(command)
usage = "usage: %prog [options] <EXPR> [EXPR ...]"
description='''Searches section contents for pointer values in darwin user space programs.'''
parser = optparse.OptionParser(description=description, prog='section_ptr_refs',usage=usage)
add_common_options(parser)
parser.add_option('--section', action='append', type='string', dest='section_names', help='section name to search', default=list())
try:
(options, args) = parser.parse_args(command_args)
except:
return
options.type = 'pointer'
sections = list()
section_modules = list()
if not options.section_names:
print 'error: at least one section must be specified with the --section option'
return
for module in lldb.target.modules:
for section_name in options.section_names:
section = module.section[section_name]
if section:
sections.append (section)
section_modules.append (module)
if sections:
dylid_load_err = load_dylib()
if dylid_load_err:
print dylid_load_err
return
for expr_str in args:
for (idx, section) in enumerate(sections):
expr = 'find_pointer_in_memory(0x%xllu, %ullu, (void *)%s)' % (section.addr.load_addr, section.size, expr_str)
arg_str_description = 'section %s.%s containing "%s"' % (section_modules[idx].file.fullpath, section.name, expr_str)
num_matches = display_match_results (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:
print 'error: no sections were found that match any of %s' % (', '.join(options.section_names))
if __name__ == '__main__':
lldb.debugger = lldb.SBDebugger.Create()
@ -375,7 +439,8 @@ lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.ptr_refs ptr
lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.cstr_refs cstr_refs')
lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.malloc_info malloc_info')
lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.malloc_history malloc_history')
print '"ptr_refs", "cstr_refs", "malloc_info", and "malloc_history" commands have been installed, use the "--help" options on these commands for detailed help.'
lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.section_ptr_refs section_ptr_refs')
print '"ptr_refs", "cstr_refs", "malloc_info", "malloc_history" and "section_ptr_refs" commands have been installed, use the "--help" options on these commands for detailed help.'

View File

@ -416,6 +416,33 @@ find_pointer_in_heap (const void * addr)
return g_matches.data();
}
//----------------------------------------------------------------------
// find_pointer_in_memory
//
// Finds a pointer value inside one or more currently valid malloc
// blocks.
//----------------------------------------------------------------------
malloc_match *
find_pointer_in_memory (uint64_t memory_addr, uint64_t memory_size, const void * addr)
{
g_matches.clear();
// Setup "info" to look for a malloc block that contains data
// that is the a pointer
range_contains_data_callback_info_t data_info;
data_info.type = eDataTypeContainsData; // Check each block for data
g_lookup_addr = addr;
data_info.data.buffer = (uint8_t *)&addr; // What data? The pointer value passed in
data_info.data.size = sizeof(addr); // How many bytes? The byte size of a pointer
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_info_callback (mach_task_self(), &data_info, stack_logging_type_generic, memory_addr, memory_size);
if (g_matches.empty())
return NULL;
malloc_match match = { NULL, 0, 0 };
g_matches.push_back(match);
return g_matches.data();
}
//----------------------------------------------------------------------
// find_cstring_in_heap