diff --git a/lldb/examples/darwin/heap_find/heap.py b/lldb/examples/darwin/heap_find/heap.py index 2db63f2675d5..c829cc8f0012 100644 --- a/lldb/examples/darwin/heap_find/heap.py +++ b/lldb/examples/darwin/heap_find/heap.py @@ -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.' diff --git a/lldb/examples/darwin/heap_find/heap/heap_find.cpp b/lldb/examples/darwin/heap_find/heap/heap_find.cpp index 41028a107b7d..132fbd888d5b 100644 --- a/lldb/examples/darwin/heap_find/heap/heap_find.cpp +++ b/lldb/examples/darwin/heap_find/heap/heap_find.cpp @@ -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