def iboot_tasks(debugger, command, result, internal_dict): """Print the list of tasks maintained by the iBoot runtime""" process = debugger.GetSelectedTarget().GetProcess() if not process or not process.target: print 'Not connected' return plugin = OperatingSystemPlugIn(process) current_task = plugin.get_global('current_task') assert current_task is not None current_task_addr = current_task.GetValueAsUnsigned() tasks = plugin.get_task_dict().itervalues() print ' TID Task Name Address' print ' ------ ---- ---------------- ------------------' for t in tasks: task_addr = t.AddressOf().GetValueAsUnsigned() current = "*" if task_addr == current_task_addr else " " tv = lldb.value(t) task_id = int(tv.task_id) tid = task_id + plugin.TID_OFFSET name = plugin.value_to_str(tv.name.sbvalue) print '{} {:#06x} {:<4} {:<16} {:#018x}'.format(current, tid, task_id, name, task_addr)
def summarize_iboot_task(self, task): task_value = lldb.value(task) return { 'name': self.value_to_str(task_value.name.sbvalue).ljust(15), 'tid': int(task_value.task_id) + self.TID_OFFSET, 'state': 'stopped', 'stop_reason': 'none' }
def processStackTraceStringFromAddresses(frameAddresses, target, options=None): frame_string = '' startAddresses = [ target.ResolveLoadAddress(f).symbol.addr.GetLoadAddress(target) for f in frameAddresses ] script = generateExecutableMethodsScript(startAddresses) # New content start 1 methods = target.EvaluateExpression(script, ds.genExpressionOptions()) charPointerType = target.FindFirstType( "char").GetPointerType().GetArrayType(len(frameAddresses)) methods = methods.Cast(charPointerType) methodsVal = lldb.value(methods) # New content end 1 # Enumerate each of the SBFrames in address list pointerType = target.FindFirstType("char").GetPointerType() for index, frameAddr in enumerate(frameAddresses): addr = target.ResolveLoadAddress(frameAddr) symbol = addr.symbol # New content start 2 if symbol.synthetic: # 1 children = methodsVal.sbvalue.GetNumChildren() # 4 name = ds.attrStr(symbol.name + r' ... unresolved womp womp', 'redd') # 2 loadAddr = symbol.addr.GetLoadAddress(target) # 3 k = str(methodsVal[index]).split('"') # 5 if len(k) >= 2: name = ds.attrStr(k[1], 'bold') # 6 else: name = ds.attrStr(str(symbol.name), 'yellow') # 7 # New content end 2 offset_str = '' offset = addr.GetLoadAddress(target) - addr.symbol.addr.GetLoadAddress( target) if offset > 0: offset_str = '+ {}'.format(offset) i = ds.attrStr('frame #{:<2}:'.format(index), 'grey') if options and options.address: frame_string += '{} {}`{} {}\n'.format( ds.attrStr(hex(addr.GetLoadAddress(target)), 'grey'), ds.attrStr(str(addr.module.file.basename), 'cyan'), ds.attrStr(str(name), 'yellow'), ds.attrStr(offset_str, 'grey')) else: frame_string += '{} {} {}`{} {}\n'.format( i, ds.attrStr(str(hex(addr.GetLoadAddress(target))), 'grey'), ds.attrStr(str(addr.module.file.basename), 'cyan'), name, ds.attrStr(str(offset_str), 'grey')) return frame_string
def handle_command(debugger, command, result, internal_dict): ''' msl will produce the stack trace of the most recent deallocations or allocations. Make sure to either call enable_logging or set MallocStackLogging environment variable ''' command_args = shlex.split(command) parser = generateOptionParser() try: (options, args) = parser.parse_args(command_args) except: result.SetError(parser.usage) return cleanCommand = args[0] process = debugger.GetSelectedTarget().GetProcess() frame = process.GetSelectedThread().GetSelectedFrame() target = debugger.GetSelectedTarget() script = generateScript(cleanCommand, options) # 1 sbval = frame.EvaluateExpression(script, generateOptions()) # 2 if sbval.error.fail: result.AppendMessage(str(sbval.error)) return val = lldb.value(sbval) addresses = [] # 3 for i in range(val.count.sbvalue.unsigned): address = val.addresses[i].sbvalue.unsigned sbaddr = target.ResolveLoadAddress(address) loadAddr = sbaddr.GetLoadAddress(target) addresses.append(loadAddr) # 4 if options.resymbolicate: retString = sbt.processStackTraceStringFromAddresses( addresses, target) else: retString = processStackTraceStringFromAddresses( addresses, target) # 5 freeExpr = 'free('+str(val.addresses.sbvalue.unsigned)+')' frame.EvaluateExpression(freeExpr, generateOptions()) result.AppendMessage(retString)
def execute_in_lldb(ignore_breakpoints, fetch_dynamic, timeout_value, all_threads, expr): frame = lldb.debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame(); if not frame: return 'error: invalid frame'; expr_options = lldb.SBExpressionOptions(); expr_options.SetIgnoreBreakpoints(ignore_breakpoints); expr_options.SetFetchDynamicValue(fetch_dynamic); expr_options.SetTimeoutInMicroSeconds(timeout_value*1000*1000); # N second timeout expr_options.SetTryAllThreads(all_threads); expr_sbvalue = frame.EvaluateExpression(expr, expr_options); if expr_sbvalue.error.Success(): return lldb.value(expr_sbvalue); else: return expr_sbvalue.error;
def iboot_task_iter(self, head, skip_task=None): task_type = self.process.target.FindFirstType('task') task_members = { member.name : member for member in task_type.get_members_array() } list_offset = task_members['task_list_node'].byte_offset if not skip_task is None: skip_addr = skip_task.GetValueAsUnsigned() else: skip_addr = 0 for node in head.AddressOf().linked_list_iter('next'): task_addr = node.GetValueAsUnsigned() - list_offset if task_addr == skip_addr: continue task = node.CreateValueFromAddress('task', task_addr, task_type) tid = int(lldb.value(task).task_id) yield tid, task
def execute_in_lldb(ignore_breakpoints, fetch_dynamic, timeout_value, all_threads, expr): frame = lldb.debugger.GetSelectedTarget().GetProcess().GetSelectedThread( ).GetSelectedFrame() if not frame: return 'error: invalid frame' expr_options = lldb.SBExpressionOptions() expr_options.SetIgnoreBreakpoints(ignore_breakpoints) expr_options.SetFetchDynamicValue(fetch_dynamic) expr_options.SetTimeoutInMicroSeconds(timeout_value * 1000 * 1000) # N second timeout expr_options.SetTryAllThreads(all_threads) expr_sbvalue = frame.EvaluateExpression(expr, expr_options) if expr_sbvalue.error.Success(): return lldb.value(expr_sbvalue) else: return expr_sbvalue.error
def dump_stack_history_entries(addr, history): # malloc_stack_entry *get_stack_history_for_address (const void * addr) expr = 'get_stack_history_for_address((void *)0x%x, %u)' % (addr, history) expr_sbvalue = lldb.frame.EvaluateExpression (expr) if expr_sbvalue.error.Success(): if expr_sbvalue.unsigned: expr_value = lldb.value(expr_sbvalue) idx = 0; stack_history_entry = expr_value[idx] while int(stack_history_entry.address) != 0: 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 handle_command(debugger, command, exe_ctx, result, internal_dict): ''' msl 0xadd7E55 msl or malloc stack logging will take an address and try and obtain the stack trace to when it was created. You will need to set the env var to MallocStackLogging, or execute turn_on_stack_logging(1) while the process is active ''' command_args = shlex.split(command) parser = generateOptionParser() try: (options, args) = parser.parse_args(command_args) except: result.SetError(parser.usage) return cleanCommand = args[0] frame = exe_ctx.frame target = exe_ctx.target script = generateScript(cleanCommand, options) sbval = frame.EvaluateExpression(script, generateOptions()) if sbval.error.fail: result.AppendMessage(str(sbval.error)) return val = lldb.value(sbval) addresses = [] for i in range(val.count.sbvalue.unsigned): address = val.addresses[i].sbvalue.unsigned loadAddr = target.ResolveLoadAddress(address).GetLoadAddress(target) addresses.append(loadAddr) # stackString = str(target.ResolveLoadAddress(address).symbol) # result.AppendMessage(stackString) if options.resymbolicate: retString = sbt.processStackTraceStringFromAddresses(addresses, target) else: retString = processStackTraceStringFromAddresses(addresses, target) frame.EvaluateExpression( 'free(' + str(val.addresses.sbvalue.unsigned) + ')', generateOptions()) result.AppendMessage(retString)
def dump_stack_history_entries(result, addr, history): # malloc_stack_entry *get_stack_history_for_address (const void * addr) expr = 'get_stack_history_for_address((void *)0x%x, %u)' % (addr, history) expr_sbvalue = lldb.frame.EvaluateExpression(expr) if expr_sbvalue.error.Success(): if expr_sbvalue.unsigned: expr_value = lldb.value(expr_sbvalue) idx = 0 stack_history_entry = expr_value[idx] while int(stack_history_entry.address) != 0: dump_stack_history_entry(result, stack_history_entry, idx) idx = idx + 1 stack_history_entry = expr_value[idx] else: result.AppendMessage('"%s" returned zero' % (expr)) else: result.AppendMessage('error: expression failed "%s" => %s' % (expr, expr_sbvalue.error))
def processStackTraceStringFromAddresses(frameAddresses, target): frame_string = '' startAddresses = [ target.ResolveLoadAddress(f).symbol.addr.GetLoadAddress(target) for f in frameAddresses ] script = generateExecutableMethodsScript(startAddresses) # New content start 1 methods = target.EvaluateExpression(script, generateOptions()) methodsVal = lldb.value(methods.deref) # New content end 1 # Enumerate each of the SBFrames in address list for index, frameAddr in enumerate(frameAddresses): addr = target.ResolveLoadAddress(frameAddr) symbol = addr.symbol # New content start 2 if symbol.synthetic: # 1 children = methodsVal.sbvalue.GetNumChildren() # 2 name = symbol.name + r' ... unresolved womp womp' # 3 loadAddr = symbol.addr.GetLoadAddress(target) # 4 for i in range(children): key = long(methodsVal[i].key.sbvalue.description) # 5 if key == loadAddr: name = methodsVal[i].value.sbvalue.description # 6 break else: name = symbol.name # 7 # New content end 2 offset_str = '' offset = addr.GetLoadAddress(target) - addr.symbol.addr.GetLoadAddress( target) if offset > 0: offset_str = '+ {}'.format(offset) frame_string += 'frame #{:<2}: {} {}`{} {}\n'.format( index, hex(addr.GetLoadAddress(target)), addr.module.file.basename, name, offset_str) return frame_string
def handle_command(debugger, command, result, internal_dict): ''' Documentation for how to use msl goes here ''' command_args = shlex.split(command) parser = generateOptionParser() try: (options, args) = parser.parse_args(command_args) except: result.SetError(parser.usage) return cleanCommand = args[0] frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread( ).GetSelectedFrame() target = debugger.GetSelectedTarget() script = generateScript(cleanCommand, options) sbval = frame.EvaluateExpression(script, generateOptions()) if sbval.error.fail: result.AppendMessage(str(sbval.error)) return val = lldb.value(sbval) addresses = [] for i in range(val.count.sbvalue.unsigned): address = val.addresses[i].sbvalue.unsigned loadAddr = target.ResolveLoadAddress(address).GetLoadAddress(target) addresses.append(loadAddr) # stackString = str(target.ResolveLoadAddress(address).symbol) # result.AppendMessage(stackString) if options.resymbolicate: retString = sbt.processStackTraceStringFromAddresses(addresses, target) else: retString = processStackTraceStringFromAddresses(addresses, target) frame.EvaluateExpression( 'free(' + str(val.addresses.sbvalue.unsigned) + ')', generateOptions()) result.AppendMessage(retString)
def get_task_dict(self, skip_current=False): if self.task_dict is None: task_list = self.get_global('task_list') assert task_list is not None if skip_current: skip_task = self.get_global('current_task') else: skip_task = None task_tuples = list(self.iboot_task_iter(task_list, skip_task)) # The first entry in the list isn't a task, so remove it from the list task_tuples = task_tuples[1:] # If there aren't any tasks in the list, we must still be # in the bootstrap task, which we can get through current_task if len(task_tuples) == 0 and not skip_current: current_task = self.get_global('current_task').Dereference() current_tid = int(lldb.value(current_task).task_id) task_tuples = [(current_tid, current_task)] self.task_dict = {tid : thread for tid,thread in task_tuples} return self.task_dict
def get_register_data(self, tid): assert tid >= self.TID_OFFSET tasks = self.get_task_dict() task = tasks[tid - self.TID_OFFSET] task_arch_value = lldb.value(task).arch if self.arch == 'arm64': regs = task_arch_value.regs.sbvalue fp = task_arch_value.fp.sbvalue lr = task_arch_value.lr.sbvalue sp = task_arch_value.sp.sbvalue # We don't know the PC, so use the LR instead to keep LLDB happy pc = task_arch_value.lr.sbvalue registers = [regs, fp, lr, sp, pc] else: regs = task_arch_value.regs.sbvalue # We don't know the PC, so use the LR instead to keep LLDB happy pc = task_arch_value.regs[9].sbvalue registers = [regs, pc] result = "".join(map(self.value_to_bytes, registers)) return result
def test(self): """Exercise some SBValue APIs.""" d = {'EXE': self.exe_name} self.build(dictionary=d) self.setTearDownCleanup(dictionary=d) exe = self.getBuildArtifact(self.exe_name) # Create a target by the debugger. target = self.dbg.CreateTarget(exe) self.assertTrue(target, VALID_TARGET) # Create the breakpoint inside function 'main'. breakpoint = target.BreakpointCreateByLocation('main.c', self.line) self.assertTrue(breakpoint, VALID_BREAKPOINT) # Now launch the process, and do not stop at entry point. process = target.LaunchSimple(None, None, self.get_process_working_directory()) self.assertTrue(process, PROCESS_IS_VALID) # Get Frame #0. self.assertTrue(process.GetState() == lldb.eStateStopped) thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint) self.assertTrue( thread.IsValid(), "There should be a thread stopped due to breakpoint condition") frame0 = thread.GetFrameAtIndex(0) # Get global variable 'days_of_week'. list = target.FindGlobalVariables('days_of_week', 1) days_of_week = list.GetValueAtIndex(0) self.assertTrue(days_of_week, VALID_VARIABLE) self.assertEqual(days_of_week.GetNumChildren(), 7, VALID_VARIABLE) self.DebugSBValue(days_of_week) # Use this to test the "child" and "children" accessors: children = days_of_week.children self.assertEqual(len(children), 7, VALID_VARIABLE) for i in range(0, len(children)): day = days_of_week.child[i] list_day = children[i] self.assertNotEqual(day, None) self.assertNotEqual(list_day, None) self.assertEqual(day.GetSummary(), list_day.GetSummary(), VALID_VARIABLE) # Spot check the actual value: first_day = days_of_week.child[1] self.assertEqual(first_day.GetSummary(), '"Monday"', VALID_VARIABLE) # Get global variable 'weekdays'. list = target.FindGlobalVariables('weekdays', 1) weekdays = list.GetValueAtIndex(0) self.assertTrue(weekdays, VALID_VARIABLE) self.assertTrue(weekdays.GetNumChildren() == 5, VALID_VARIABLE) self.DebugSBValue(weekdays) # Get global variable 'g_table'. list = target.FindGlobalVariables('g_table', 1) g_table = list.GetValueAtIndex(0) self.assertTrue(g_table, VALID_VARIABLE) self.assertTrue(g_table.GetNumChildren() == 2, VALID_VARIABLE) self.DebugSBValue(g_table) fmt = lldbutil.BasicFormatter() cvf = lldbutil.ChildVisitingFormatter(indent_child=2) rdf = lldbutil.RecursiveDecentFormatter(indent_child=2) if self.TraceOn(): print(fmt.format(days_of_week)) print(cvf.format(days_of_week)) print(cvf.format(weekdays)) print(rdf.format(g_table)) # Get variable 'my_int_ptr'. value = frame0.FindVariable('my_int_ptr') self.assertTrue(value, VALID_VARIABLE) self.DebugSBValue(value) # Get what 'my_int_ptr' points to. pointed = value.GetChildAtIndex(0) self.assertTrue(pointed, VALID_VARIABLE) self.DebugSBValue(pointed) # While we are at it, verify that 'my_int_ptr' points to 'g_my_int'. symbol = target.ResolveLoadAddress(int(pointed.GetLocation(), 0)).GetSymbol() self.assertTrue(symbol) self.expect(symbol.GetName(), exe=False, startstr='g_my_int') # Get variable 'str_ptr'. value = frame0.FindVariable('str_ptr') self.assertTrue(value, VALID_VARIABLE) self.DebugSBValue(value) # SBValue::TypeIsPointerType() should return true. self.assertTrue(value.TypeIsPointerType()) # Verify the SBValue::GetByteSize() API is working correctly. arch = self.getArchitecture() if arch == 'i386': self.assertTrue(value.GetByteSize() == 4) elif arch == 'x86_64': self.assertTrue(value.GetByteSize() == 8) # Get child at index 5 => 'Friday'. child = value.GetChildAtIndex(5, lldb.eNoDynamicValues, True) self.assertTrue(child, VALID_VARIABLE) self.DebugSBValue(child) self.expect(child.GetSummary(), exe=False, substrs=['Friday']) # Now try to get at the same variable using GetValueForExpressionPath(). # These two SBValue objects should have the same value. val2 = value.GetValueForExpressionPath('[5]') self.assertTrue(val2, VALID_VARIABLE) self.DebugSBValue(val2) self.assertTrue(child.GetValue() == val2.GetValue() and child.GetSummary() == val2.GetSummary()) val_i = target.EvaluateExpression('i') val_s = target.EvaluateExpression('s') val_a = target.EvaluateExpression('a') self.assertTrue( val_s.GetChildMemberWithName('a').AddressOf(), VALID_VARIABLE) self.assertTrue( val_a.Cast(val_i.GetType()).AddressOf(), VALID_VARIABLE) self.assertTrue( int(lldb.value(frame0.FindVariable('uinthex'))) == 3768803088, 'uinthex == 3768803088') self.assertTrue( int(lldb.value(frame0.FindVariable('sinthex'))) == -526164208, 'sinthex == -526164208') self.assertTrue( frame0.FindVariable('uinthex').GetValueAsUnsigned() == 3768803088, 'unsigned uinthex == 3768803088') self.assertTrue( frame0.FindVariable('sinthex').GetValueAsUnsigned() == 3768803088, 'unsigned sinthex == 3768803088') self.assertTrue( frame0.FindVariable('uinthex').GetValueAsSigned() == -526164208, 'signed uinthex == -526164208') self.assertTrue( frame0.FindVariable('sinthex').GetValueAsSigned() == -526164208, 'signed sinthex == -526164208')
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) 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 description = '[%u] %s: addr = 0x%x' % (i, arg_str_description, malloc_addr) if offset != 0: description += ' + %u' % (offset) description += ', size = %u' % (malloc_size) 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!': description += ', type = (AUTORELEASE!)' print description else: description += ', type = %s' % (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: description +=', ivar = %s' % (ivar_member.name) 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) else: print expr_sbvalue.error print
def display_match_results (result, 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 match_idx = 0 while 1: print_entry = True match_entry = match_value[i]; i += 1 if i >= options.max_matches: result.AppendMessage('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 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 dynamic_value = match_entry.addr.sbvalue.GetDynamicValue(lldb.eDynamicCanRunTarget) description = '[%u] %s: addr = 0x%x' % (match_idx, arg_str_description, malloc_addr) 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!)' 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 += ', type = %s <%u>' % (derefed_dynamic_type_name, derefed_dynamic_type_size) 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 += ', ivar = %s' % (member_path) if print_entry: match_idx += 1 if description: result.AppendMessage(description) if options.print_type and derefed_dynamic_value: result.AppendMessage('%s' % (derefed_dynamic_value)) if options.print_object_description and dynamic_value: desc = dynamic_value.GetObjectDescription() if desc: result.AppendMessage(', po=%s' % (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) result.AppendMessage(cmd_result.GetOutput()) if options.stack_history: dump_stack_history_entries(result, malloc_addr, 1) elif options.stack: dump_stack_history_entries(result, malloc_addr, 0) return i elif print_no_matches: result.AppendMessage('no matches found for %s' % (arg_str_description)) else: result.AppendMessage(expr_sbvalue.error ) return 0
def display_match_results (result, 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 match_idx = 0 while 1: print_entry = True match_entry = match_value[i]; i += 1 if i >= options.max_matches: result.AppendMessage('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 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 dynamic_value = match_entry.addr.sbvalue.GetDynamicValue(lldb.eDynamicCanRunTarget) description = '%#x: ' % (match_addr) if options.show_size: description += '<%5u> ' % (malloc_size) if options.show_range: if offset > 0: description += '[%#x - %#x) + %-6u ' % (malloc_addr, malloc_addr + malloc_size, offset) else: description += '[%#x - %#x)' % (malloc_addr, malloc_addr + malloc_size) else: if options.type != 'isa': description += '%#x + %-6u ' % (malloc_addr, offset) 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!': ptr_size = lldb.target.addr_size thread = lldb.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 += 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() 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) result.AppendMessage(cmd_result.GetOutput()) if options.stack_history: dump_stack_history_entries(result, malloc_addr, 1) elif options.stack: dump_stack_history_entries(result, malloc_addr, 0) return i elif print_no_matches: result.AppendMessage('no matches found for %s' % (arg_str_description)) else: result.AppendMessage(str(expr_sbvalue.error)) 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 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) 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) match_addr = malloc_addr + offset dynamic_value = match_entry.addr.sbvalue.GetDynamicValue(lldb.eDynamicCanRunTarget) description = '[%u] %s: addr = 0x%x' % (i, arg_str_description, malloc_addr) if offset != 0: description += ' + %u' % (offset) description += ', size = %u' % (malloc_size) 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: derefed_dynamic_type = derefed_dynamic_value.type derefed_dynamic_type_size = derefed_dynamic_type.size derefed_dynamic_type_name = derefed_dynamic_type.name description += ', type = %s <%u>' % (derefed_dynamic_type_name, derefed_dynamic_type_size) 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: 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) else: print expr_sbvalue.error print
def search(debugger, command, exe_ctx, result, internal_dict): ''' Finds all subclasses of a class. This class must by dynamic (aka inherit from a NSObject class). Currently doesn't work with NSString or NSNumber (tagged pointer objects). NOTE: This script will leak memory Examples: # Find all UIViews and subclasses of UIViews find UIView # Find all UIStatusBar instances find UIStatusBar # Find all UIViews, ignore subclasses find UIView -e # Find all instances of UIViews (and subclasses) where tag == 5 find UIView -c "[obj tag] == 5" ''' if not ds.isProcStopped(): result.SetError( ds.attrStr( 'You must have the process suspended in order to execute this command', 'red')) return command_args = shlex.split(command) parser = generate_option_parser() try: (options, args) = parser.parse_args(command_args) except: result.SetError(parser.usage) return if not args: result.SetError( 'Usage: find NSObjectSubclass\n\nUse \'help find\' for more details' ) return clean_command = ('').join(args) res = lldb.SBCommandReturnObject() interpreter = debugger.GetCommandInterpreter() if options.module: target = exe_ctx.target module = target.FindModule(lldb.SBFileSpec(options.module)) if not module.IsValid(): result.SetError( "Unable to open module name '{}', to see list of images use 'image list -b'" .format(options.module)) return options.module = generate_module_search_sections_string(module, target) if options.pointer_reference: objectiveC_class = '(uintptr_t *){}'.format(clean_command) if options.pointer_reference and (options.exact_match or options.module or options.module or options.condition or options.perform_action): result.SetError( "Can only use the --pointer_reference with --barebones") else: interpreter.HandleCommand( 'expression -lobjc -O -- (Class)NSClassFromString(@\"{}\")'.format( clean_command), res) if 'nil' in res.GetOutput(): result.SetError( 'Can\'t find class named "{}". Womp womp...'.format( clean_command)) return objectiveC_class = 'NSClassFromString(@"{}")'.format(clean_command) command_script = get_command_script(objectiveC_class, options) # print command_script # return 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.SetTrapExceptions(False) expr_options.SetUnwindOnError(True) expr_options.SetGenerateDebugInfo(True) expr_options.SetLanguage(lldb.eLanguageTypeObjC_plus_plus) expr_options.SetCoerceResultToId(True) # expr_options.SetAutoApplyFixIts(True) frame = exe_ctx.frame if frame is None: result.SetError( 'You must have the process suspended in order to execute this command' ) return # debugger.HandleCommand('po ' + command_script) # debugger.HandleCommand('expression -lobjc++ -g -O -- ' + command_script) # return # print(command_script) expr_sbvalue = frame.EvaluateExpression(command_script, expr_options) if not expr_sbvalue.error.success: result.SetError("\n**************************************\nerror: " + str(expr_sbvalue.error)) return val = lldb.value(expr_sbvalue) count = val.count.sbvalue.unsigned global s s = val if count > 100: result.AppendWarning( 'Exceeded 100 hits, try narrowing your search with the --condition option' ) count = 100 if options.pointer_reference: for i in range(count): v = val.values[i].sbvalue offset = val.offsets[i].sbvalue.unsigned val_description = ds.attrStr(str( v.GetTypeName()), 'cyan') + ' [' + ds.attrStr( str(v.GetValue()), 'yellow') + ']' + ' + ' + ds.attrStr( str(offset), 'yellow') result.AppendMessage(val_description) else: if options.barebones: for i in range(count): v = val.values[i].sbvalue val_description = ds.attrStr(str( v.GetTypeName()), 'cyan') + ' [' + ds.attrStr( str(v.GetValue()), 'yellow') + ']' result.AppendMessage(val_description) else: for i in range(count): v = val.values[i].sbvalue if not v.description: continue desc = v.description result.AppendMessage(desc + '\n')
def mama(target, options, args, result): ret = [] needle = None if len(args): needle = exp(" ".join(args)) arch = trgt() 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) max_results = 0x1000 frame = lldb.debugger.GetSelectedTarget().GetProcess().GetSelectedThread( ).GetSelectedFrame() expr_sbvalue = frame.EvaluateExpression( mach_vm_region_expr() % (arch['extra'](), max_results), expr_options) if expr_sbvalue.error.Success(): result_value = lldb.value(expr_sbvalue) starts = [] malloc_tags = [1, 2, 3, 4, 6, 7, 8, 9, 11, 53, 61] for i in range(max_results): region_lol = result_value[i] start = int(region_lol.addr) size = int(region_lol.size) user_tag_int = int(region_lol.info.user_tag) if user_tag_int in malloc_tags and (not needle or in_region( needle, start, size)): starts.append(start) _zones = {} if len(starts): _zones = zone(starts) reached_the_end = False for i in range(max_results): region_lol = result_value[i] size = int(region_lol.size) start = int(region_lol.addr) if start >= arch['shared_region_base']: reached_the_end = True end = start + size info = region_lol.info prot = int(info.protection) user_tag_int = int(info.user_tag) # from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/Kernel.framework/Headers/mach/vm_statistics.h # I only put in the ones I ran into user_tagz = { 0: "unknown", 1: "malloc", 2: "malloc small", 3: "malloc large", 4: "malloc huge", # 5: "sbrk", 6: "realloc", 7: "malloc tiny", 8: "malloc large reusable", 9: "malloc large reused", 10: "memory analysis tool", 11: "malloc nano", 20: "mach msg", 21: "iokit", 30: "stack", 31: "guard", 32: "shared pmap", 33: "dylib", 34: "objc dispatchers", 35: "unshared pmap", 40: "appkit", 41: "foundation", 42: "core graphics", 43: "core services", 44: "java", 45: "coredata", 46: "coredata objectids", 50: "ats", 51: "layerkit", 52: "cgimage", 53: "tcmalloc", 54: "coregraphics data", 55: "coregraphics shared", 56: "coregraphics framebuffers", 57: "coregraphics backingstores", 60: "dyld", 61: "dyld mallco", 62: "sqlite", 63: "javascript core heap", 64: "javascript JIT executable allocator", 65: "javascript JIT register file", 66: "GLSL", 67: "OpenCL", 68: "core image", 69: "webcore purgeable buffers", 70: "imageio", 71: "coreprofile", 72: "assetsd / MobileSlideShow", 73: "kernel alloc once", 74: "libdispatch", 75: "accelerate", 76: "coreui", 242: "application specific 242", 251: "application specific 251" } user_tag = user_tagz.get(user_tag_int) if user_tag_int == 30: user_tag = "".join([user_tag, thread_for_stack(start, end)]) if not user_tag: print "USER TAG NOT FOUDN: %s" % user_tag_int ref_count = int(info.ref_count) object_name = int(region_lol.object_name) if object_name != 0: print "YEHAHA %#x" % object_name share_mode = int(info.share_mode) share_modez = [ '????', 'COW', 'PRV', 'NUL', 'ALI', 'SHM', 'ZER', 'S/A', 'large page' ] share_mode = share_modez[share_mode] if start < arch['shared_region_base']: lookup_output = run_command( "target modules lookup -v -a %#x" % start, True) elif needle: lookup_output = run_command( "target modules lookup -v -a %#x" % needle, True) filename = "" section = "" if lookup_output: if user_tag_int != 0 and user_tag_int != 33 and user_tag_int != 35 and user_tag_int != 32: print "oh shit! %d" % user_tag_int break filename = re_find(r"file = \"([^\"]*)", lookup_output) filename = re.sub(r".*/SDKs", "...", filename) filename = re.sub(r".*/iOS DeviceSupport", "...", filename) section = re_find(r"__[\w]*", lookup_output) if section and filename and user_tag_int == 0: user_tag = "" else: if user_tag_int == 33: print "noh shit! %#x" % user_tag_int break maybe_guard = "guard" if prot == 0 and user_tag_int == 30 else "" maybe_unallocated = "" if ref_count else "(zero refcount)" maybes = [maybe_guard, maybe_unallocated][not maybe_guard] if size == 0xe800000 and user_tag_int == 32 and ref_count == 0: reached_the_end = True else: if not needle or in_region(needle, start, size): _zone = _zones[start] if user_tag_int in malloc_tags else "" ret.append( (start, size, "{:#x} - {:#x} - {:<5s} - {:} SM={:} {:}".format( start, end, human(size), prot_string(prot), share_mode, " ".join( compact([ section, user_tag, maybes, filename, _zone ]))))) if share_mode == "NUL" and ref_count == 0 and prot == 5: break if not reached_the_end: print "didn't reach the end?" return ret else: print "failure, %s" % expr_sbvalue.error
def __call__(self, debugger, command, exe_ctx, result): command_args = shlex.split(command, posix=False) parser = generate_option_parser() debugger.SetAsync(False) try: (options, args) = parser.parse_args(command_args) except: result.SetError(parser.usage) return if not args: result.SetError('TODO make this relevant') return clean_command = ('').join(args) target = debugger.GetSelectedTarget() expr_options = lldb.SBExpressionOptions() expr_options.SetIgnoreBreakpoints(False) expr_options.SetFetchDynamicValue(lldb.eDynamicCanRunTarget) expr_options.SetTimeoutInMicroSeconds(30 * 1000 * 1000) # 30 second timeout expr_options.SetTryAllThreads(True) expr_options.SetUnwindOnError(False) expr_options.SetGenerateDebugInfo(True) expr_options.SetLanguage(lldb.eLanguageTypeObjC_plus_plus) expr_options.SetCoerceResultToId(False) frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread( ).GetSelectedFrame() if frame is None: result.SetError( 'You must have the process suspended in order to execute this command' ) return # debugger.HandleCommand('po ' + command_script) command_script = get_command_script(clean_command, options) # debugger.HandleCommand('expression -lobjc++ -g -O -- ' + command_script) expr_value = frame.EvaluateExpression(command_script, expr_options) if not expr_value.error.success: result.SetError(str(expr_value.error)) return lldb_stackaddress = lldb.value(expr_value) frame_count = lldb_stackaddress.count frame_addresses = [] function_addresses = [] for i in range(lldb_stackaddress.count): val = lldb_stackaddress.addresses[i] load_addr = int(val.sbvalue.GetValue()) frame_addresses.append(load_addr) addr = target.ResolveLoadAddress(load_addr) print(addr) function_addresses.append( addr.GetSymbol().GetStartAddress().GetLoadAddress(target)) # print(addr.GetSymbol().GetStartAddress().GetLoadAddress(target)) # print(addr.GetLineEntry().GetLine()) # # debugger.HandleCommand('expression -g -O -lobjc++ -- ' + command_script) # print (expr_value) print(function_addresses) expr_options.SetCoerceResultToId(True) class_load_address_script = self.generate_main_executable_class_address_script( ) dict_value = frame.EvaluateExpression(class_load_address_script, expr_options)
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) 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 description = '[%u] %s: addr = 0x%x' % (i, arg_str_description, malloc_addr) if offset != 0: description += ' + %u' % (offset) description += ', size = %u' % (malloc_size) 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!': description += ', type = (AUTORELEASE!)' print description else: description += ', type = %s' % (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: description += ', ivar = %s' % (ivar_member.name) 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) else: print expr_sbvalue.error print
def display_match_results(result, 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 match_idx = 0 while 1: print_entry = True match_entry = match_value[i] i += 1 if i >= options.max_matches: result.AppendMessage( '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 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 dynamic_value = match_entry.addr.sbvalue.GetDynamicValue( lldb.eDynamicCanRunTarget) description = '%#x: ' % (match_addr) if options.show_size: description += '<%5u> ' % (malloc_size) if options.show_range: if offset > 0: description += '[%#x - %#x) + %-6u ' % ( malloc_addr, malloc_addr + malloc_size, offset) else: description += '[%#x - %#x)' % ( malloc_addr, malloc_addr + malloc_size) else: if options.type != 'isa': description += '%#x + %-6u ' % (malloc_addr, offset) 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!': ptr_size = lldb.target.addr_size thread = lldb.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 += 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() 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) result.AppendMessage(cmd_result.GetOutput()) if options.stack_history: dump_stack_history_entries(result, malloc_addr, 1) elif options.stack: dump_stack_history_entries(result, malloc_addr, 0) return i elif print_no_matches: result.AppendMessage('no matches found for %s' % (arg_str_description)) else: result.AppendMessage(str(expr_sbvalue.error)) return 0
def display_match_results(result, 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 match_idx = 0 while 1: print_entry = True match_entry = match_value[i] i += 1 if i >= options.max_matches: result.AppendMessage( '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 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 dynamic_value = match_entry.addr.sbvalue.GetDynamicValue( lldb.eDynamicCanRunTarget) description = '[%u] %s: addr = 0x%x' % ( match_idx, arg_str_description, malloc_addr) 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!)' 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 += ', type = %s <%u>' % ( derefed_dynamic_type_name, derefed_dynamic_type_size) 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 += ', ivar = %s' % ( member_path) if print_entry: match_idx += 1 if description: result.AppendMessage(description) if options.print_type and derefed_dynamic_value: result.AppendMessage('%s' % (derefed_dynamic_value)) if options.print_object_description and dynamic_value: desc = dynamic_value.GetObjectDescription() if desc: result.AppendMessage(', po=%s' % (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) result.AppendMessage(cmd_result.GetOutput()) if options.stack_history: dump_stack_history_entries(result, malloc_addr, 1) elif options.stack: dump_stack_history_entries(result, malloc_addr, 0) return i elif print_no_matches: result.AppendMessage('no matches found for %s' % (arg_str_description)) else: result.AppendMessage(expr_sbvalue.error) return 0
def test(self): """Exercise some SBValue APIs.""" d = {'EXE': self.exe_name} self.build(dictionary=d) self.setTearDownCleanup(dictionary=d) exe = os.path.join(os.getcwd(), self.exe_name) # Create a target by the debugger. target = self.dbg.CreateTarget(exe) self.assertTrue(target, VALID_TARGET) # Create the breakpoint inside function 'main'. breakpoint = target.BreakpointCreateByLocation('main.c', self.line) self.assertTrue(breakpoint, VALID_BREAKPOINT) # Now launch the process, and do not stop at entry point. process = target.LaunchSimple( None, None, self.get_process_working_directory()) self.assertTrue(process, PROCESS_IS_VALID) # Get Frame #0. self.assertTrue(process.GetState() == lldb.eStateStopped) thread = lldbutil.get_stopped_thread( process, lldb.eStopReasonBreakpoint) self.assertTrue( thread.IsValid(), "There should be a thread stopped due to breakpoint condition") frame0 = thread.GetFrameAtIndex(0) # Get global variable 'days_of_week'. list = target.FindGlobalVariables('days_of_week', 1) days_of_week = list.GetValueAtIndex(0) self.assertTrue(days_of_week, VALID_VARIABLE) self.assertTrue(days_of_week.GetNumChildren() == 7, VALID_VARIABLE) self.DebugSBValue(days_of_week) # Get global variable 'weekdays'. list = target.FindGlobalVariables('weekdays', 1) weekdays = list.GetValueAtIndex(0) self.assertTrue(weekdays, VALID_VARIABLE) self.assertTrue(weekdays.GetNumChildren() == 5, VALID_VARIABLE) self.DebugSBValue(weekdays) # Get global variable 'g_table'. list = target.FindGlobalVariables('g_table', 1) g_table = list.GetValueAtIndex(0) self.assertTrue(g_table, VALID_VARIABLE) self.assertTrue(g_table.GetNumChildren() == 2, VALID_VARIABLE) self.DebugSBValue(g_table) fmt = lldbutil.BasicFormatter() cvf = lldbutil.ChildVisitingFormatter(indent_child=2) rdf = lldbutil.RecursiveDecentFormatter(indent_child=2) if self.TraceOn(): print(fmt.format(days_of_week)) print(cvf.format(days_of_week)) print(cvf.format(weekdays)) print(rdf.format(g_table)) # Get variable 'my_int_ptr'. value = frame0.FindVariable('my_int_ptr') self.assertTrue(value, VALID_VARIABLE) self.DebugSBValue(value) # Get what 'my_int_ptr' points to. pointed = value.GetChildAtIndex(0) self.assertTrue(pointed, VALID_VARIABLE) self.DebugSBValue(pointed) # While we are at it, verify that 'my_int_ptr' points to 'g_my_int'. symbol = target.ResolveLoadAddress( int(pointed.GetLocation(), 0)).GetSymbol() self.assertTrue(symbol) self.expect(symbol.GetName(), exe=False, startstr='g_my_int') # Get variable 'str_ptr'. value = frame0.FindVariable('str_ptr') self.assertTrue(value, VALID_VARIABLE) self.DebugSBValue(value) # SBValue::TypeIsPointerType() should return true. self.assertTrue(value.TypeIsPointerType()) # Verify the SBValue::GetByteSize() API is working correctly. arch = self.getArchitecture() if arch == 'i386': self.assertTrue(value.GetByteSize() == 4) elif arch == 'x86_64': self.assertTrue(value.GetByteSize() == 8) # Get child at index 5 => 'Friday'. child = value.GetChildAtIndex(5, lldb.eNoDynamicValues, True) self.assertTrue(child, VALID_VARIABLE) self.DebugSBValue(child) self.expect(child.GetSummary(), exe=False, substrs=['Friday']) # Now try to get at the same variable using GetValueForExpressionPath(). # These two SBValue objects should have the same value. val2 = value.GetValueForExpressionPath('[5]') self.assertTrue(val2, VALID_VARIABLE) self.DebugSBValue(val2) self.assertTrue(child.GetValue() == val2.GetValue() and child.GetSummary() == val2.GetSummary()) val_i = target.EvaluateExpression('i') val_s = target.EvaluateExpression('s') val_a = target.EvaluateExpression('a') self.assertTrue( val_s.GetChildMemberWithName('a').AddressOf(), VALID_VARIABLE) self.assertTrue( val_a.Cast( val_i.GetType()).AddressOf(), VALID_VARIABLE) self.assertTrue(int(lldb.value(frame0.FindVariable('uinthex'))) == 3768803088, 'uinthex == 3768803088') self.assertTrue(int(lldb.value(frame0.FindVariable('sinthex'))) == -526164208, 'sinthex == -526164208') self.assertTrue( frame0.FindVariable('uinthex').GetValueAsUnsigned() == 3768803088, 'unsigned uinthex == 3768803088') self.assertTrue( frame0.FindVariable('sinthex').GetValueAsUnsigned() == 3768803088, 'unsigned sinthex == 3768803088') self.assertTrue( frame0.FindVariable('uinthex').GetValueAsSigned() == - 526164208, 'signed uinthex == -526164208') self.assertTrue( frame0.FindVariable('sinthex').GetValueAsSigned() == - 526164208, 'signed sinthex == -526164208')