diff options
Diffstat (limited to 'examples/darwin/heap_find/heap.py')
| -rw-r--r-- | examples/darwin/heap_find/heap.py | 1522 |
1 files changed, 0 insertions, 1522 deletions
diff --git a/examples/darwin/heap_find/heap.py b/examples/darwin/heap_find/heap.py deleted file mode 100644 index c463380bf49f..000000000000 --- a/examples/darwin/heap_find/heap.py +++ /dev/null @@ -1,1522 +0,0 @@ -#!/usr/bin/python - -#---------------------------------------------------------------------- -# This module is designed to live inside the "lldb" python package -# in the "lldb.macosx" package. To use this in the embedded python -# interpreter using "lldb" just import it: -# -# (lldb) script import lldb.macosx.heap -#---------------------------------------------------------------------- - -import lldb -import commands -import optparse -import os -import os.path -import re -import shlex -import string -import sys -import tempfile -import lldb.utils.symbolication - -g_libheap_dylib_dir = None -g_libheap_dylib_dict = dict() - - -def get_iterate_memory_expr( - options, - process, - user_init_code, - user_return_code): - expr = ''' -typedef unsigned natural_t; -typedef uintptr_t vm_size_t; -typedef uintptr_t vm_address_t; -typedef natural_t task_t; -typedef int kern_return_t; -#define KERN_SUCCESS 0 -typedef void (*range_callback_t)(task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size); -''' - if options.search_vm_regions: - expr += ''' -typedef int vm_prot_t; -typedef unsigned int vm_inherit_t; -typedef unsigned long long memory_object_offset_t; -typedef unsigned int boolean_t; -typedef int vm_behavior_t; -typedef uint32_t vm32_object_id_t; -typedef natural_t mach_msg_type_number_t; -typedef uint64_t mach_vm_address_t; -typedef uint64_t mach_vm_offset_t; -typedef uint64_t mach_vm_size_t; -typedef uint64_t vm_map_offset_t; -typedef uint64_t vm_map_address_t; -typedef uint64_t vm_map_size_t; -#define VM_PROT_NONE ((vm_prot_t) 0x00) -#define VM_PROT_READ ((vm_prot_t) 0x01) -#define VM_PROT_WRITE ((vm_prot_t) 0x02) -#define VM_PROT_EXECUTE ((vm_prot_t) 0x04) -typedef struct vm_region_submap_short_info_data_64_t { - vm_prot_t protection; - vm_prot_t max_protection; - vm_inherit_t inheritance; - memory_object_offset_t offset; // offset into object/map - unsigned int user_tag; // user tag on map entry - unsigned int ref_count; // obj/map mappers, etc - unsigned short shadow_depth; // only for obj - unsigned char external_pager; // only for obj - unsigned char share_mode; // see enumeration - boolean_t is_submap; // submap vs obj - vm_behavior_t behavior; // access behavior hint - vm32_object_id_t object_id; // obj/map name, not a handle - unsigned short user_wired_count; -} vm_region_submap_short_info_data_64_t; -#define VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 ((mach_msg_type_number_t)(sizeof(vm_region_submap_short_info_data_64_t)/sizeof(int)))''' - if user_init_code: - expr += user_init_code - expr += ''' -task_t task = (task_t)mach_task_self(); -mach_vm_address_t vm_region_base_addr; -mach_vm_size_t vm_region_size; -natural_t vm_region_depth; -vm_region_submap_short_info_data_64_t vm_region_info; -kern_return_t err; -for (vm_region_base_addr = 0, vm_region_size = 1; vm_region_size != 0; vm_region_base_addr += vm_region_size) -{ - mach_msg_type_number_t vm_region_info_size = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64; - err = (kern_return_t)mach_vm_region_recurse (task, - &vm_region_base_addr, - &vm_region_size, - &vm_region_depth, - &vm_region_info, - &vm_region_info_size); - if (err) - break; - // Check all read + write regions. This will cover the thread stacks - // and any regions of memory like __DATA segments, that might contain - // data we are looking for - if (vm_region_info.protection & VM_PROT_WRITE && - vm_region_info.protection & VM_PROT_READ) - { - baton.callback (task, - &baton, - 64, - vm_region_base_addr, - vm_region_size); - } -}''' - else: - if options.search_stack: - expr += get_thread_stack_ranges_struct(process) - if options.search_segments: - expr += get_sections_ranges_struct(process) - if user_init_code: - expr += user_init_code - if options.search_heap: - expr += ''' -#define MALLOC_PTR_IN_USE_RANGE_TYPE 1 -typedef struct vm_range_t { - vm_address_t address; - vm_size_t size; -} vm_range_t; -typedef kern_return_t (*memory_reader_t)(task_t task, vm_address_t remote_address, vm_size_t size, void **local_memory); -typedef void (*vm_range_recorder_t)(task_t task, void *baton, unsigned type, vm_range_t *range, unsigned size); -typedef struct malloc_introspection_t { - kern_return_t (*enumerator)(task_t task, void *, unsigned type_mask, vm_address_t zone_address, memory_reader_t reader, vm_range_recorder_t recorder); /* enumerates all the malloc pointers in use */ -} malloc_introspection_t; -typedef struct malloc_zone_t { - void *reserved1[12]; - struct malloc_introspection_t *introspect; -} malloc_zone_t; -memory_reader_t task_peek = [](task_t task, vm_address_t remote_address, vm_size_t size, void **local_memory) -> kern_return_t { - *local_memory = (void*) remote_address; - return KERN_SUCCESS; -}; -vm_address_t *zones = 0; -unsigned int num_zones = 0;task_t task = 0; -kern_return_t err = (kern_return_t)malloc_get_all_zones (task, task_peek, &zones, &num_zones); -if (KERN_SUCCESS == err) -{ - for (unsigned int i=0; i<num_zones; ++i) - { - const malloc_zone_t *zone = (const malloc_zone_t *)zones[i]; - if (zone && zone->introspect) - zone->introspect->enumerator (task, - &baton, - MALLOC_PTR_IN_USE_RANGE_TYPE, - (vm_address_t)zone, - task_peek, - [] (task_t task, void *baton, unsigned type, vm_range_t *ranges, unsigned size) -> void - { - range_callback_t callback = ((callback_baton_t *)baton)->callback; - for (unsigned i=0; i<size; ++i) - { - callback (task, baton, type, ranges[i].address, ranges[i].size); - } - }); - } -}''' - - if options.search_stack: - expr += ''' -#ifdef NUM_STACKS -// Call the callback for the thread stack ranges -for (uint32_t i=0; i<NUM_STACKS; ++i) { - range_callback(task, &baton, 8, stacks[i].base, stacks[i].size); - if (STACK_RED_ZONE_SIZE > 0) { - range_callback(task, &baton, 16, stacks[i].base - STACK_RED_ZONE_SIZE, STACK_RED_ZONE_SIZE); - } -} -#endif''' - - if options.search_segments: - expr += ''' -#ifdef NUM_SEGMENTS -// Call the callback for all segments -for (uint32_t i=0; i<NUM_SEGMENTS; ++i) - range_callback(task, &baton, 32, segments[i].base, segments[i].size); -#endif''' - - if user_return_code: - expr += "\n%s" % (user_return_code,) - - return expr - - -def get_member_types_for_offset(value_type, offset, member_list): - member = value_type.GetFieldAtIndex(0) - search_bases = False - if member: - if member.GetOffsetInBytes() <= offset: - for field_idx in range(value_type.GetNumberOfFields()): - member = value_type.GetFieldAtIndex(field_idx) - member_byte_offset = member.GetOffsetInBytes() - member_end_byte_offset = member_byte_offset + member.type.size - if member_byte_offset <= offset and offset < member_end_byte_offset: - member_list.append(member) - get_member_types_for_offset( - member.type, offset - member_byte_offset, member_list) - return - else: - search_bases = True - else: - search_bases = True - if search_bases: - for field_idx in range(value_type.GetNumberOfDirectBaseClasses()): - member = value_type.GetDirectBaseClassAtIndex(field_idx) - member_byte_offset = member.GetOffsetInBytes() - member_end_byte_offset = member_byte_offset + member.type.size - if member_byte_offset <= offset and offset < member_end_byte_offset: - member_list.append(member) - get_member_types_for_offset( - member.type, offset - member_byte_offset, member_list) - return - for field_idx in range(value_type.GetNumberOfVirtualBaseClasses()): - member = value_type.GetVirtualBaseClassAtIndex(field_idx) - member_byte_offset = member.GetOffsetInBytes() - member_end_byte_offset = member_byte_offset + member.type.size - if member_byte_offset <= offset and offset < member_end_byte_offset: - 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( - '-z', - '--size', - action='store_true', - dest='show_size', - help='print the allocation size in bytes', - default=False) - parser.add_option( - '-r', - '--range', - action='store_true', - dest='show_range', - help='print the allocation address range instead of just the allocation base address', - 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( - '-F', - '--max-frames', - type='int', - dest='max_frames', - help='the maximum number of stack frames to print when using the --stack or --stack-history options (default=128)', - default=128) - parser.add_option( - '-H', - '--max-history', - type='int', - dest='max_history', - help='the maximum number of stack history backtraces to print for each allocation when using the --stack-history option (default=16)', - default=16) - parser.add_option( - '-M', - '--max-matches', - type='int', - dest='max_matches', - help='the maximum number of matches to print', - default=32) - parser.add_option( - '-O', - '--offset', - type='int', - dest='offset', - help='the matching data must be at this offset', - default=-1) - parser.add_option( - '--ignore-stack', - action='store_false', - dest='search_stack', - help="Don't search the stack when enumerating memory", - default=True) - parser.add_option( - '--ignore-heap', - action='store_false', - dest='search_heap', - help="Don't search the heap allocations when enumerating memory", - default=True) - parser.add_option( - '--ignore-segments', - action='store_false', - dest='search_segments', - help="Don't search readable executable segments enumerating memory", - default=True) - parser.add_option( - '-V', - '--vm-regions', - action='store_true', - dest='search_vm_regions', - help='Check all VM regions instead of searching the heap, stack and segments', - default=False) - - -def type_flags_to_string(type_flags): - if type_flags == 0: - type_str = 'free' - elif type_flags & 2: - type_str = 'malloc' - elif type_flags & 4: - type_str = 'free' - elif type_flags & 1: - type_str = 'generic' - elif type_flags & 8: - type_str = 'stack' - elif type_flags & 16: - type_str = 'stack (red zone)' - elif type_flags & 32: - type_str = 'segment' - elif type_flags & 64: - type_str = 'vm_region' - else: - type_str = hex(type_flags) - return type_str - - -def find_variable_containing_address(verbose, frame, match_addr): - variables = frame.GetVariables(True, True, True, True) - matching_var = None - for var in variables: - var_addr = var.GetLoadAddress() - if var_addr != lldb.LLDB_INVALID_ADDRESS: - byte_size = var.GetType().GetByteSize() - if verbose: - print 'frame #%u: [%#x - %#x) %s' % (frame.GetFrameID(), var.load_addr, var.load_addr + byte_size, var.name) - if var_addr == match_addr: - if verbose: - print 'match' - return var - else: - if byte_size > 0 and var_addr <= match_addr and match_addr < ( - var_addr + byte_size): - if verbose: - print 'match' - return var - return None - - -def find_frame_for_stack_address(process, addr): - closest_delta = sys.maxsize - closest_frame = None - # print 'find_frame_for_stack_address(%#x)' % (addr) - for thread in process: - prev_sp = lldb.LLDB_INVALID_ADDRESS - for frame in thread: - cfa = frame.GetCFA() - # print 'frame #%u: cfa = %#x' % (frame.GetFrameID(), cfa) - if addr < cfa: - delta = cfa - addr - # print '%#x < %#x, delta = %i' % (addr, cfa, delta) - if delta < closest_delta: - # print 'closest' - closest_delta = delta - closest_frame = frame - # else: - # print 'delta >= closest_delta' - return closest_frame - - -def type_flags_to_description( - process, - type_flags, - ptr_addr, - ptr_size, - offset, - match_addr): - show_offset = False - if type_flags == 0 or type_flags & 4: - type_str = 'free(%#x)' % (ptr_addr,) - elif type_flags & 2 or type_flags & 1: - type_str = 'malloc(%6u) -> %#x' % (ptr_size, ptr_addr) - show_offset = True - elif type_flags & 8: - type_str = 'stack' - frame = find_frame_for_stack_address(process, match_addr) - if frame: - type_str += ' in frame #%u of thread #%u: tid %#x' % (frame.GetFrameID( - ), frame.GetThread().GetIndexID(), frame.GetThread().GetThreadID()) - variables = frame.GetVariables(True, True, True, True) - matching_var = None - for var in variables: - var_addr = var.GetLoadAddress() - if var_addr != lldb.LLDB_INVALID_ADDRESS: - # print 'variable "%s" @ %#x (%#x)' % (var.name, var.load_addr, - # match_addr) - if var_addr == match_addr: - matching_var = var - break - else: - byte_size = var.GetType().GetByteSize() - if byte_size > 0 and var_addr <= match_addr and match_addr < ( - var_addr + byte_size): - matching_var = var - break - if matching_var: - type_str += ' in variable at %#x:\n %s' % ( - matching_var.GetLoadAddress(), matching_var) - elif type_flags & 16: - type_str = 'stack (red zone)' - elif type_flags & 32: - sb_addr = process.GetTarget().ResolveLoadAddress(ptr_addr + offset) - type_str = 'segment [%#x - %#x), %s + %u, %s' % ( - ptr_addr, ptr_addr + ptr_size, sb_addr.section.name, sb_addr.offset, sb_addr) - elif type_flags & 64: - sb_addr = process.GetTarget().ResolveLoadAddress(ptr_addr + offset) - type_str = 'vm_region [%#x - %#x), %s + %u, %s' % ( - ptr_addr, ptr_addr + ptr_size, sb_addr.section.name, sb_addr.offset, sb_addr) - else: - type_str = '%#x' % (ptr_addr,) - show_offset = True - if show_offset and offset != 0: - type_str += ' + %-6u' % (offset,) - return type_str - - -def dump_stack_history_entry(options, result, stack_history_entry, idx): - address = int(stack_history_entry.address) - if address: - type_flags = int(stack_history_entry.type_flags) - symbolicator = lldb.utils.symbolication.Symbolicator() - symbolicator.target = lldb.debugger.GetSelectedTarget() - type_str = type_flags_to_string(type_flags) - result.AppendMessage( - 'stack[%u]: addr = 0x%x, type=%s, frames:' % - (idx, address, type_str)) - frame_idx = 0 - idx = 0 - pc = int(stack_history_entry.frames[idx]) - while pc != 0: - if pc >= 0x1000: - frames = symbolicator.symbolicate(pc) - if frames: - for frame in frames: - result.AppendMessage( - ' [%u] %s' % - (frame_idx, frame)) - frame_idx += 1 - else: - result.AppendMessage(' [%u] 0x%x' % (frame_idx, pc)) - frame_idx += 1 - idx = idx + 1 - pc = int(stack_history_entry.frames[idx]) - else: - pc = 0 - if idx >= options.max_frames: - result.AppendMessage( - 'warning: the max number of stack frames (%u) was reached, use the "--max-frames=<COUNT>" option to see more frames' % - (options.max_frames)) - - result.AppendMessage('') - - -def dump_stack_history_entries(options, result, addr, history): - # malloc_stack_entry *get_stack_history_for_address (const void * addr) - expr_prefix = ''' -typedef int kern_return_t; -typedef struct $malloc_stack_entry { - uint64_t address; - uint64_t argument; - uint32_t type_flags; - uint32_t num_frames; - uint64_t frames[512]; - kern_return_t err; -} $malloc_stack_entry; -''' - single_expr = ''' -#define MAX_FRAMES %u -typedef unsigned task_t; -$malloc_stack_entry stack; -stack.address = 0x%x; -stack.type_flags = 2; -stack.num_frames = 0; -stack.frames[0] = 0; -uint32_t max_stack_frames = MAX_FRAMES; -stack.err = (kern_return_t)__mach_stack_logging_get_frames ( - (task_t)mach_task_self(), - stack.address, - &stack.frames[0], - max_stack_frames, - &stack.num_frames); -if (stack.num_frames < MAX_FRAMES) - stack.frames[stack.num_frames] = 0; -else - stack.frames[MAX_FRAMES-1] = 0; -stack''' % (options.max_frames, addr) - - history_expr = ''' -typedef int kern_return_t; -typedef unsigned task_t; -#define MAX_FRAMES %u -#define MAX_HISTORY %u -typedef struct mach_stack_logging_record_t { - uint32_t type_flags; - uint64_t stack_identifier; - uint64_t argument; - uint64_t address; -} mach_stack_logging_record_t; -typedef void (*enumerate_callback_t)(mach_stack_logging_record_t, void *); -typedef struct malloc_stack_entry { - uint64_t address; - uint64_t argument; - uint32_t type_flags; - uint32_t num_frames; - uint64_t frames[MAX_FRAMES]; - kern_return_t frames_err; -} malloc_stack_entry; -typedef struct $malloc_stack_history { - task_t task; - unsigned idx; - malloc_stack_entry entries[MAX_HISTORY]; -} $malloc_stack_history; -$malloc_stack_history lldb_info = { (task_t)mach_task_self(), 0 }; -uint32_t max_stack_frames = MAX_FRAMES; -enumerate_callback_t callback = [] (mach_stack_logging_record_t stack_record, void *baton) -> void { - $malloc_stack_history *lldb_info = ($malloc_stack_history *)baton; - if (lldb_info->idx < MAX_HISTORY) { - malloc_stack_entry *stack_entry = &(lldb_info->entries[lldb_info->idx]); - stack_entry->address = stack_record.address; - stack_entry->type_flags = stack_record.type_flags; - stack_entry->argument = stack_record.argument; - stack_entry->num_frames = 0; - stack_entry->frames[0] = 0; - stack_entry->frames_err = (kern_return_t)__mach_stack_logging_frames_for_uniqued_stack ( - lldb_info->task, - stack_record.stack_identifier, - stack_entry->frames, - (uint32_t)MAX_FRAMES, - &stack_entry->num_frames); - // Terminate the frames with zero if there is room - if (stack_entry->num_frames < MAX_FRAMES) - stack_entry->frames[stack_entry->num_frames] = 0; - } - ++lldb_info->idx; -}; -(kern_return_t)__mach_stack_logging_enumerate_records (lldb_info.task, (uint64_t)0x%x, callback, &lldb_info); -lldb_info''' % (options.max_frames, options.max_history, addr) - - frame = lldb.debugger.GetSelectedTarget().GetProcess( - ).GetSelectedThread().GetSelectedFrame() - if history: - expr = history_expr - else: - expr = single_expr - expr_options = lldb.SBExpressionOptions() - expr_options.SetIgnoreBreakpoints(True) - expr_options.SetTimeoutInMicroSeconds(5 * 1000 * 1000) # 5 second timeout - expr_options.SetTryAllThreads(True) - expr_options.SetLanguage(lldb.eLanguageTypeObjC_plus_plus) - expr_options.SetPrefix(expr_prefix) - expr_sbvalue = frame.EvaluateExpression(expr, expr_options) - if options.verbose: - print "expression:" - print expr - print "expression result:" - print expr_sbvalue - if expr_sbvalue.error.Success(): - if history: - malloc_stack_history = lldb.value(expr_sbvalue) - num_stacks = int(malloc_stack_history.idx) - if num_stacks <= options.max_history: - i_max = num_stacks - else: - i_max = options.max_history - for i in range(i_max): - stack_history_entry = malloc_stack_history.entries[i] - dump_stack_history_entry( - options, result, stack_history_entry, i) - if num_stacks > options.max_history: - result.AppendMessage( - 'warning: the max number of stacks (%u) was reached, use the "--max-history=%u" option to see all of the stacks' % - (options.max_history, num_stacks)) - else: - stack_history_entry = lldb.value(expr_sbvalue) - dump_stack_history_entry(options, result, stack_history_entry, 0) - - else: - result.AppendMessage( - 'error: expression failed "%s" => %s' % - (expr, expr_sbvalue.error)) - - -def display_match_results( - process, - result, - options, - arg_str_description, - expr, - print_no_matches, - expr_prefix=None): - frame = lldb.debugger.GetSelectedTarget().GetProcess( - ).GetSelectedThread().GetSelectedFrame() - if not frame: - result.AppendMessage('error: invalid frame') - return 0 - expr_options = lldb.SBExpressionOptions() - expr_options.SetIgnoreBreakpoints(True) - expr_options.SetFetchDynamicValue(lldb.eNoDynamicValues) - expr_options.SetTimeoutInMicroSeconds( - 30 * 1000 * 1000) # 30 second timeout - expr_options.SetTryAllThreads(False) - expr_options.SetLanguage(lldb.eLanguageTypeObjC_plus_plus) - if expr_prefix: - expr_options.SetPrefix(expr_prefix) - expr_sbvalue = frame.EvaluateExpression(expr, expr_options) - if options.verbose: - print "expression:" - print expr - print "expression result:" - print expr_sbvalue - if expr_sbvalue.error.Success(): - match_value = lldb.value(expr_sbvalue) - i = 0 - match_idx = 0 - while True: - print_entry = True - match_entry = match_value[i] - i += 1 - if i > options.max_matches: - result.AppendMessage( - 'warning: 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 - malloc_size = int(match_entry.size) - offset = int(match_entry.offset) - - if options.offset >= 0 and options.offset != offset: - print_entry = False - else: - match_addr = malloc_addr + offset - type_flags = int(match_entry.type) - #result.AppendMessage (hex(malloc_addr + offset)) - if type_flags == 64: - search_stack_old = options.search_stack - search_segments_old = options.search_segments - search_heap_old = options.search_heap - search_vm_regions = options.search_vm_regions - options.search_stack = True - options.search_segments = True - options.search_heap = True - options.search_vm_regions = False - if malloc_info_impl(lldb.debugger, result, options, [ - hex(malloc_addr + offset)]): - print_entry = False - options.search_stack = search_stack_old - options.search_segments = search_segments_old - options.search_heap = search_heap_old - options.search_vm_regions = search_vm_regions - if print_entry: - description = '%#16.16x: %s' % (match_addr, type_flags_to_description( - process, type_flags, malloc_addr, malloc_size, offset, match_addr)) - if options.show_size: - description += ' <%5u>' % (malloc_size) - if options.show_range: - description += ' [%#x - %#x)' % ( - malloc_addr, malloc_addr + malloc_size) - derefed_dynamic_value = None - dynamic_value = match_entry.addr.sbvalue.GetDynamicValue( - lldb.eDynamicCanRunTarget) - if dynamic_value.type.name == 'void *': - if options.type == 'pointer' and malloc_size == 4096: - error = lldb.SBError() - process = expr_sbvalue.GetProcess() - target = expr_sbvalue.GetTarget() - data = bytearray( - process.ReadMemory( - malloc_addr, 16, error)) - if data == '\xa1\xa1\xa1\xa1AUTORELEASE!': - ptr_size = target.addr_size - thread = process.ReadUnsignedFromMemory( - malloc_addr + 16 + ptr_size, ptr_size, error) - # 4 bytes 0xa1a1a1a1 - # 12 bytes 'AUTORELEASE!' - # ptr bytes autorelease insertion point - # ptr bytes pthread_t - # ptr bytes next colder page - # ptr bytes next hotter page - # 4 bytes this page's depth in the list - # 4 bytes high-water mark - description += ' AUTORELEASE! for pthread_t %#x' % ( - thread) - # else: - # description += 'malloc(%u)' % (malloc_size) - # else: - # description += 'malloc(%u)' % (malloc_size) - else: - derefed_dynamic_value = dynamic_value.deref - if derefed_dynamic_value: - derefed_dynamic_type = derefed_dynamic_value.type - derefed_dynamic_type_size = derefed_dynamic_type.size - derefed_dynamic_type_name = derefed_dynamic_type.name - description += ' ' - description += derefed_dynamic_type_name - if offset < derefed_dynamic_type_size: - member_list = list() - get_member_types_for_offset( - derefed_dynamic_type, offset, member_list) - if member_list: - member_path = '' - for member in member_list: - member_name = member.name - if member_name: - if member_path: - 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 += '.%s' % (member_path) - else: - description += '%u bytes after %s' % ( - offset - derefed_dynamic_type_size, derefed_dynamic_type_name) - else: - # strip the "*" from the end of the name since we - # were unable to dereference this - description += dynamic_value.type.name[0:-1] - if print_entry: - match_idx += 1 - result_output = '' - if description: - result_output += description - if options.print_type and derefed_dynamic_value: - result_output += ' %s' % (derefed_dynamic_value) - if options.print_object_description and dynamic_value: - desc = dynamic_value.GetObjectDescription() - if desc: - result_output += '\n%s' % (desc) - if result_output: - result.AppendMessage(result_output) - if options.memory: - cmd_result = lldb.SBCommandReturnObject() - if options.format is None: - memory_command = "memory read --force 0x%x 0x%x" % ( - malloc_addr, malloc_addr + malloc_size) - else: - memory_command = "memory read --force -f %s 0x%x 0x%x" % ( - options.format, malloc_addr, malloc_addr + malloc_size) - if options.verbose: - result.AppendMessage(memory_command) - lldb.debugger.GetCommandInterpreter().HandleCommand(memory_command, cmd_result) - result.AppendMessage(cmd_result.GetOutput()) - if options.stack_history: - dump_stack_history_entries(options, result, malloc_addr, 1) - elif options.stack: - dump_stack_history_entries(options, result, malloc_addr, 0) - return i - else: - result.AppendMessage(str(expr_sbvalue.error)) - return 0 - - -def get_ptr_refs_options(): - usage = "usage: %prog [options] <EXPR> [EXPR ...]" - description = '''Searches all allocations on the heap for pointer values 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 in the -program.''' - parser = optparse.OptionParser( - description=description, - prog='ptr_refs', - usage=usage) - add_common_options(parser) - return parser - - -def find_variable(debugger, command, result, dict): - usage = "usage: %prog [options] <ADDR> [ADDR ...]" - description = '''Searches for a local variable in all frames that contains a hex ADDR.''' - command_args = shlex.split(command) - parser = optparse.OptionParser( - description=description, - prog='find_variable', - usage=usage) - parser.add_option( - '-v', - '--verbose', - action='store_true', - dest='verbose', - help='display verbose debug info', - default=False) - try: - (options, args) = parser.parse_args(command_args) - except: - return - - process = debugger.GetSelectedTarget().GetProcess() - if not process: - result.AppendMessage('error: invalid process') - return - - for arg in args: - var_addr = int(arg, 16) - print >>result, "Finding a variable with address %#x..." % (var_addr) - done = False - for thread in process: - for frame in thread: - var = find_variable_containing_address( - options.verbose, frame, var_addr) - if var: - print var - done = True - break - if done: - break - - -def ptr_refs(debugger, command, result, dict): - command_args = shlex.split(command) - parser = get_ptr_refs_options() - try: - (options, args) = parser.parse_args(command_args) - except: - return - - process = debugger.GetSelectedTarget().GetProcess() - if not process: - result.AppendMessage('error: invalid process') - return - frame = process.GetSelectedThread().GetSelectedFrame() - if not frame: - result.AppendMessage('error: invalid frame') - return - - options.type = 'pointer' - if options.format is None: - options.format = "A" # 'A' is "address" format - - if args: - # When we initialize the expression, we must define any types that - # we will need when looking at every allocation. We must also define - # a type named callback_baton_t and make an instance named "baton" - # and initialize it how ever we want to. The address of "baton" will - # be passed into our range callback. callback_baton_t must contain - # a member named "callback" whose type is "range_callback_t". This - # will be used by our zone callbacks to call the range callback for - # each malloc range. - expr_prefix = ''' -struct $malloc_match { - void *addr; - uintptr_t size; - uintptr_t offset; - uintptr_t type; -}; -''' - user_init_code_format = ''' -#define MAX_MATCHES %u -typedef struct callback_baton_t { - range_callback_t callback; - unsigned num_matches; - $malloc_match matches[MAX_MATCHES]; - void *ptr; -} callback_baton_t; -range_callback_t range_callback = [](task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size) -> void { - callback_baton_t *lldb_info = (callback_baton_t *)baton; - typedef void* T; - const unsigned size = sizeof(T); - T *array = (T*)ptr_addr; - for (unsigned idx = 0; ((idx + 1) * sizeof(T)) <= ptr_size; ++idx) { - if (array[idx] == lldb_info->ptr) { - if (lldb_info->num_matches < MAX_MATCHES) { - lldb_info->matches[lldb_info->num_matches].addr = (void*)ptr_addr; - lldb_info->matches[lldb_info->num_matches].size = ptr_size; - lldb_info->matches[lldb_info->num_matches].offset = idx*sizeof(T); - lldb_info->matches[lldb_info->num_matches].type = type; - ++lldb_info->num_matches; - } - } - } -}; -callback_baton_t baton = { range_callback, 0, {0}, (void *)%s }; -''' - # We must also define a snippet of code to be run that returns - # the result of the expression we run. - # Here we return NULL if our pointer was not found in any malloc blocks, - # and we return the address of the matches array so we can then access - # the matching results - user_return_code = '''if (baton.num_matches < MAX_MATCHES) - baton.matches[baton.num_matches].addr = 0; // Terminate the matches array -baton.matches''' - # Iterate through all of our pointer expressions and display the - # results - for ptr_expr in args: - user_init_code = user_init_code_format % ( - options.max_matches, ptr_expr) - expr = get_iterate_memory_expr( - options, process, user_init_code, user_return_code) - arg_str_description = 'malloc block containing pointer %s' % ptr_expr - display_match_results( - process, - result, - options, - arg_str_description, - expr, - True, - expr_prefix) - else: - result.AppendMessage('error: no pointer arguments were given') - - -def get_cstr_refs_options(): - usage = "usage: %prog [options] <CSTR> [CSTR ...]" - description = '''Searches all allocations on the heap for C string values 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 in the -program.''' - parser = optparse.OptionParser( - description=description, - prog='cstr_refs', - usage=usage) - add_common_options(parser) - return parser - - -def cstr_refs(debugger, command, result, dict): - command_args = shlex.split(command) - parser = get_cstr_refs_options() - try: - (options, args) = parser.parse_args(command_args) - except: - return - - process = debugger.GetSelectedTarget().GetProcess() - if not process: - result.AppendMessage('error: invalid process') - return - frame = process.GetSelectedThread().GetSelectedFrame() - if not frame: - result.AppendMessage('error: invalid frame') - return - - options.type = 'cstr' - if options.format is None: - options.format = "Y" # 'Y' is "bytes with ASCII" format - - if args: - # When we initialize the expression, we must define any types that - # we will need when looking at every allocation. We must also define - # a type named callback_baton_t and make an instance named "baton" - # and initialize it how ever we want to. The address of "baton" will - # be passed into our range callback. callback_baton_t must contain - # a member named "callback" whose type is "range_callback_t". This - # will be used by our zone callbacks to call the range callback for - # each malloc range. - expr_prefix = ''' -struct $malloc_match { - void *addr; - uintptr_t size; - uintptr_t offset; - uintptr_t type; -}; -''' - user_init_code_format = ''' -#define MAX_MATCHES %u -typedef struct callback_baton_t { - range_callback_t callback; - unsigned num_matches; - $malloc_match matches[MAX_MATCHES]; - const char *cstr; - unsigned cstr_len; -} callback_baton_t; -range_callback_t range_callback = [](task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size) -> void { - callback_baton_t *lldb_info = (callback_baton_t *)baton; - if (lldb_info->cstr_len < ptr_size) { - const char *begin = (const char *)ptr_addr; - const char *end = begin + ptr_size - lldb_info->cstr_len; - for (const char *s = begin; s < end; ++s) { - if ((int)memcmp(s, lldb_info->cstr, lldb_info->cstr_len) == 0) { - if (lldb_info->num_matches < MAX_MATCHES) { - lldb_info->matches[lldb_info->num_matches].addr = (void*)ptr_addr; - lldb_info->matches[lldb_info->num_matches].size = ptr_size; - lldb_info->matches[lldb_info->num_matches].offset = s - begin; - lldb_info->matches[lldb_info->num_matches].type = type; - ++lldb_info->num_matches; - } - } - } - } -}; -const char *cstr = "%s"; -callback_baton_t baton = { range_callback, 0, {0}, cstr, (unsigned)strlen(cstr) };''' - # We must also define a snippet of code to be run that returns - # the result of the expression we run. - # Here we return NULL if our pointer was not found in any malloc blocks, - # and we return the address of the matches array so we can then access - # the matching results - user_return_code = '''if (baton.num_matches < MAX_MATCHES) - baton.matches[baton.num_matches].addr = 0; // Terminate the matches array -baton.matches''' - # Iterate through all of our pointer expressions and display the - # results - for cstr in args: - user_init_code = user_init_code_format % ( - options.max_matches, cstr) - expr = get_iterate_memory_expr( - options, process, user_init_code, user_return_code) - arg_str_description = 'malloc block containing "%s"' % cstr - display_match_results( - process, - result, - options, - arg_str_description, - expr, - True, - expr_prefix) - else: - result.AppendMessage( - 'error: command takes one or more C string arguments') - - -def get_malloc_info_options(): - usage = "usage: %prog [options] <EXPR> [EXPR ...]" - description = '''Searches the heap a malloc block that contains the addresses -specified as one or more address expressions. Any matches that were found will -dump the malloc blocks that match or contain the specified address. The matching -blocks might be able to show what kind of objects they are using dynamic type -information in the program.''' - parser = optparse.OptionParser( - description=description, - prog='malloc_info', - usage=usage) - add_common_options(parser) - return parser - - -def malloc_info(debugger, command, result, dict): - command_args = shlex.split(command) - parser = get_malloc_info_options() - try: - (options, args) = parser.parse_args(command_args) - except: - return - malloc_info_impl(debugger, result, options, args) - - -def malloc_info_impl(debugger, result, options, args): - # We are specifically looking for something on the heap only - options.type = 'malloc_info' - - process = debugger.GetSelectedTarget().GetProcess() - if not process: - result.AppendMessage('error: invalid process') - return - frame = process.GetSelectedThread().GetSelectedFrame() - if not frame: - result.AppendMessage('error: invalid frame') - return - expr_prefix = ''' -struct $malloc_match { - void *addr; - uintptr_t size; - uintptr_t offset; - uintptr_t type; -}; -''' - - user_init_code_format = ''' -typedef struct callback_baton_t { - range_callback_t callback; - unsigned num_matches; - $malloc_match matches[2]; // Two items so they can be NULL terminated - void *ptr; -} callback_baton_t; -range_callback_t range_callback = [](task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size) -> void { - callback_baton_t *lldb_info = (callback_baton_t *)baton; - if (lldb_info->num_matches == 0) { - uint8_t *p = (uint8_t *)lldb_info->ptr; - uint8_t *lo = (uint8_t *)ptr_addr; - uint8_t *hi = lo + ptr_size; - if (lo <= p && p < hi) { - lldb_info->matches[lldb_info->num_matches].addr = (void*)ptr_addr; - lldb_info->matches[lldb_info->num_matches].size = ptr_size; - lldb_info->matches[lldb_info->num_matches].offset = p - lo; - lldb_info->matches[lldb_info->num_matches].type = type; - lldb_info->num_matches = 1; - } - } -}; -callback_baton_t baton = { range_callback, 0, {0}, (void *)%s }; -baton.matches[0].addr = 0; -baton.matches[1].addr = 0;''' - if args: - total_matches = 0 - for ptr_expr in args: - user_init_code = user_init_code_format % (ptr_expr) - expr = get_iterate_memory_expr( - options, process, user_init_code, 'baton.matches') - arg_str_description = 'malloc block that contains %s' % ptr_expr - total_matches += display_match_results( - process, result, options, arg_str_description, expr, True, expr_prefix) - return total_matches - else: - result.AppendMessage( - 'error: command takes one or more pointer expressions') - return 0 - - -def get_thread_stack_ranges_struct(process): - '''Create code that defines a structure that represents threads stack bounds - for all threads. It returns a static sized array initialized with all of - the tid, base, size structs for all the threads.''' - stack_dicts = list() - if process: - i = 0 - for thread in process: - min_sp = thread.frame[0].sp - max_sp = min_sp - for frame in thread.frames: - sp = frame.sp - if sp < min_sp: - min_sp = sp - if sp > max_sp: - max_sp = sp - if min_sp < max_sp: - stack_dicts.append({'tid': thread.GetThreadID( - ), 'base': min_sp, 'size': max_sp - min_sp, 'index': i}) - i += 1 - stack_dicts_len = len(stack_dicts) - if stack_dicts_len > 0: - result = ''' -#define NUM_STACKS %u -#define STACK_RED_ZONE_SIZE %u -typedef struct thread_stack_t { uint64_t tid, base, size; } thread_stack_t; -thread_stack_t stacks[NUM_STACKS];''' % (stack_dicts_len, process.target.GetStackRedZoneSize()) - for stack_dict in stack_dicts: - result += ''' -stacks[%(index)u].tid = 0x%(tid)x; -stacks[%(index)u].base = 0x%(base)x; -stacks[%(index)u].size = 0x%(size)x;''' % stack_dict - return result - else: - return '' - - -def get_sections_ranges_struct(process): - '''Create code that defines a structure that represents all segments that - can contain data for all images in "target". It returns a static sized - array initialized with all of base, size structs for all the threads.''' - target = process.target - segment_dicts = list() - for (module_idx, module) in enumerate(target.modules): - for sect_idx in range(module.GetNumSections()): - section = module.GetSectionAtIndex(sect_idx) - if not section: - break - name = section.name - if name != '__TEXT' and name != '__LINKEDIT' and name != '__PAGEZERO': - base = section.GetLoadAddress(target) - size = section.GetByteSize() - if base != lldb.LLDB_INVALID_ADDRESS and size > 0: - segment_dicts.append({'base': base, 'size': size}) - segment_dicts_len = len(segment_dicts) - if segment_dicts_len > 0: - result = ''' -#define NUM_SEGMENTS %u -typedef struct segment_range_t { uint64_t base; uint32_t size; } segment_range_t; -segment_range_t segments[NUM_SEGMENTS];''' % (segment_dicts_len,) - for (idx, segment_dict) in enumerate(segment_dicts): - segment_dict['index'] = idx - result += ''' -segments[%(index)u].base = 0x%(base)x; -segments[%(index)u].size = 0x%(size)x;''' % segment_dict - return result - else: - return '' - - -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: - result.AppendMessage( - 'error: at least one section must be specified with the --section option') - return - - target = debugger.GetSelectedTarget() - for module in 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: - result.AppendMessage(dylid_load_err) - return - frame = target.GetProcess().GetSelectedThread().GetSelectedFrame() - 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( - target.GetProcess(), result, options, arg_str_description, 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: - result.AppendMessage( - 'error: no sections were found that match any of %s' % - (', '.join( - options.section_names))) - - -def get_objc_refs_options(): - usage = "usage: %prog [options] <CLASS> [CLASS ...]" - description = '''Searches all allocations on the heap for instances of -objective C classes, or any classes that inherit from the specified classes -in 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 in the -program.''' - parser = optparse.OptionParser( - description=description, - prog='objc_refs', - usage=usage) - add_common_options(parser) - return parser - - -def objc_refs(debugger, command, result, dict): - command_args = shlex.split(command) - parser = get_objc_refs_options() - try: - (options, args) = parser.parse_args(command_args) - except: - return - - process = debugger.GetSelectedTarget().GetProcess() - if not process: - result.AppendMessage('error: invalid process') - return - frame = process.GetSelectedThread().GetSelectedFrame() - if not frame: - result.AppendMessage('error: invalid frame') - return - - options.type = 'isa' - if options.format is None: - options.format = "A" # 'A' is "address" format - - expr_options = lldb.SBExpressionOptions() - expr_options.SetIgnoreBreakpoints(True) - expr_options.SetTimeoutInMicroSeconds( - 3 * 1000 * 1000) # 3 second infinite timeout - expr_options.SetTryAllThreads(True) - expr_options.SetLanguage(lldb.eLanguageTypeObjC_plus_plus) - num_objc_classes_value = frame.EvaluateExpression( - "(int)objc_getClassList((void *)0, (int)0)", expr_options) - if not num_objc_classes_value.error.Success(): - result.AppendMessage('error: %s' % - num_objc_classes_value.error.GetCString()) - return - - num_objc_classes = num_objc_classes_value.GetValueAsUnsigned() - if num_objc_classes == 0: - result.AppendMessage('error: no objective C classes in program') - return - - if args: - # When we initialize the expression, we must define any types that - # we will need when looking at every allocation. We must also define - # a type named callback_baton_t and make an instance named "baton" - # and initialize it how ever we want to. The address of "baton" will - # be passed into our range callback. callback_baton_t must contain - # a member named "callback" whose type is "range_callback_t". This - # will be used by our zone callbacks to call the range callback for - # each malloc range. - expr_prefix = ''' -struct $malloc_match { - void *addr; - uintptr_t size; - uintptr_t offset; - uintptr_t type; -}; -''' - - user_init_code_format = ''' -#define MAX_MATCHES %u -typedef int (*compare_callback_t)(const void *a, const void *b); -typedef struct callback_baton_t { - range_callback_t callback; - compare_callback_t compare_callback; - unsigned num_matches; - $malloc_match matches[MAX_MATCHES]; - void *isa; - Class classes[%u]; -} callback_baton_t; -compare_callback_t compare_callback = [](const void *a, const void *b) -> int { - Class a_ptr = *(Class *)a; - Class b_ptr = *(Class *)b; - if (a_ptr < b_ptr) return -1; - if (a_ptr > b_ptr) return +1; - return 0; -}; -typedef Class (*class_getSuperclass_type)(void *isa); -range_callback_t range_callback = [](task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size) -> void { - class_getSuperclass_type class_getSuperclass_impl = (class_getSuperclass_type)class_getSuperclass; - callback_baton_t *lldb_info = (callback_baton_t *)baton; - if (sizeof(Class) <= ptr_size) { - Class *curr_class_ptr = (Class *)ptr_addr; - Class *matching_class_ptr = (Class *)bsearch (curr_class_ptr, - (const void *)lldb_info->classes, - sizeof(lldb_info->classes)/sizeof(Class), - sizeof(Class), - lldb_info->compare_callback); - if (matching_class_ptr) { - bool match = false; - if (lldb_info->isa) { - Class isa = *curr_class_ptr; - if (lldb_info->isa == isa) - match = true; - else { // if (lldb_info->objc.match_superclasses) { - Class super = class_getSuperclass_impl(isa); - while (super) { - if (super == lldb_info->isa) { - match = true; - break; - } - super = class_getSuperclass_impl(super); - } - } - } - else - match = true; - if (match) { - if (lldb_info->num_matches < MAX_MATCHES) { - lldb_info->matches[lldb_info->num_matches].addr = (void*)ptr_addr; - lldb_info->matches[lldb_info->num_matches].size = ptr_size; - lldb_info->matches[lldb_info->num_matches].offset = 0; - lldb_info->matches[lldb_info->num_matches].type = type; - ++lldb_info->num_matches; - } - } - } - } -}; -callback_baton_t baton = { range_callback, compare_callback, 0, {0}, (void *)0x%x, {0} }; -int nc = (int)objc_getClassList(baton.classes, sizeof(baton.classes)/sizeof(Class)); -(void)qsort (baton.classes, sizeof(baton.classes)/sizeof(Class), sizeof(Class), compare_callback);''' - # We must also define a snippet of code to be run that returns - # the result of the expression we run. - # Here we return NULL if our pointer was not found in any malloc blocks, - # and we return the address of the matches array so we can then access - # the matching results - user_return_code = '''if (baton.num_matches < MAX_MATCHES) - baton.matches[baton.num_matches].addr = 0; // Terminate the matches array - baton.matches''' - # Iterate through all of our ObjC class name arguments - for class_name in args: - addr_expr_str = "(void *)[%s class]" % class_name - expr_options = lldb.SBExpressionOptions() - expr_options.SetIgnoreBreakpoints(True) - expr_options.SetTimeoutInMicroSeconds( - 1 * 1000 * 1000) # 1 second timeout - expr_options.SetTryAllThreads(True) - expr_options.SetLanguage(lldb.eLanguageTypeObjC_plus_plus) - expr_sbvalue = frame.EvaluateExpression( - addr_expr_str, expr_options) - if expr_sbvalue.error.Success(): - isa = expr_sbvalue.unsigned - if isa: - options.type = 'isa' - result.AppendMessage( - 'Searching for all instances of classes or subclasses of "%s" (isa=0x%x)' % - (class_name, isa)) - user_init_code = user_init_code_format % ( - options.max_matches, num_objc_classes, isa) - expr = get_iterate_memory_expr( - options, process, user_init_code, user_return_code) - arg_str_description = 'objective C classes with isa 0x%x' % isa - display_match_results( - process, - result, - options, - arg_str_description, - expr, - True, - expr_prefix) - else: - result.AppendMessage( - 'error: Can\'t find isa for an ObjC class named "%s"' % - (class_name)) - else: - result.AppendMessage( - 'error: expression error for "%s": %s' % - (addr_expr_str, expr_sbvalue.error)) - else: - result.AppendMessage( - 'error: command takes one or more C string arguments') - -if __name__ == '__main__': - lldb.debugger = lldb.SBDebugger.Create() - -# Make the options so we can generate the help text for the new LLDB -# command line command prior to registering it with LLDB below. This way -# if clients in LLDB type "help malloc_info", they will see the exact same -# output as typing "malloc_info --help". -ptr_refs.__doc__ = get_ptr_refs_options().format_help() -cstr_refs.__doc__ = get_cstr_refs_options().format_help() -malloc_info.__doc__ = get_malloc_info_options().format_help() -objc_refs.__doc__ = get_objc_refs_options().format_help() -lldb.debugger.HandleCommand( - 'command script add -f %s.ptr_refs ptr_refs' % - __name__) -lldb.debugger.HandleCommand( - 'command script add -f %s.cstr_refs cstr_refs' % - __name__) -lldb.debugger.HandleCommand( - 'command script add -f %s.malloc_info malloc_info' % - __name__) -lldb.debugger.HandleCommand( - 'command script add -f %s.find_variable find_variable' % - __name__) -# lldb.debugger.HandleCommand('command script add -f %s.heap heap' % package_name) -# lldb.debugger.HandleCommand('command script add -f %s.section_ptr_refs section_ptr_refs' % package_name) -# lldb.debugger.HandleCommand('command script add -f %s.stack_ptr_refs stack_ptr_refs' % package_name) -lldb.debugger.HandleCommand( - 'command script add -f %s.objc_refs objc_refs' % - __name__) -print '"malloc_info", "ptr_refs", "cstr_refs", "find_variable", and "objc_refs" commands have been installed, use the "--help" options on these commands for detailed help.' |
