forked from OSchip/llvm-project
Added the ability to search through sections for pointer data.
llvm-svn: 160083
This commit is contained in:
parent
26b8e1d03f
commit
e04cfd2180
|
@ -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.'
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue