""" This LLDB module contains miscellaneous utilities. """ import lldb import sys import StringIO ################################################ # # # Iterator for lldb aggregate data structures. # # # ################################################ def lldb_iter(obj, getsize, getelem): """ A generator adaptor for lldb aggregate data structures. API clients pass in the aggregate object, the name of the method to get the size of the object, and the name of the method to get the element given an index. Example usage: def disassemble_instructions (insts): from lldbutil import lldb_iter for i in lldb_iter(insts, 'GetSize', 'GetInstructionAtIndex'): print i """ size = getattr(obj, getsize) elem = getattr(obj, getelem) for i in range(size()): yield elem(i) ######################################################## # # # Convert some enum value to its string's counterpart. # # # ######################################################## def StateTypeString(enum): """Returns the stateType string given an enum.""" if enum == lldb.eStateInvalid: return "invalid" elif enum == lldb.eStateUnloaded: return "unloaded" elif enum == lldb.eStateAttaching: return "attaching" elif enum == lldb.eStateLaunching: return "launching" elif enum == lldb.eStateStopped: return "stopped" elif enum == lldb.eStateRunning: return "running" elif enum == lldb.eStateStepping: return "stepping" elif enum == lldb.eStateCrashed: return "crashed" elif enum == lldb.eStateDetached: return "detached" elif enum == lldb.eStateExited: return "exited" elif enum == lldb.eStateSuspended: return "suspended" else: raise Exception("Unknown stopReason enum") def StopReasonString(enum): """Returns the stopReason string given an enum.""" if enum == lldb.eStopReasonInvalid: return "invalid" elif enum == lldb.eStopReasonNone: return "none" elif enum == lldb.eStopReasonTrace: return "trace" elif enum == lldb.eStopReasonBreakpoint: return "breakpoint" elif enum == lldb.eStopReasonWatchpoint: return "watchpoint" elif enum == lldb.eStopReasonSignal: return "signal" elif enum == lldb.eStopReasonException: return "exception" elif enum == lldb.eStopReasonPlanComplete: return "plancomplete" else: raise Exception("Unknown stopReason enum") ####################################################### # # # Utility functions related to Threads and Processes. # # # ####################################################### def GetFunctionNames(thread): """ Returns a sequence of function names from the stack frames of this thread. """ def GetFuncName(i): return thread.GetFrameAtIndex(i).GetFunction().GetName() return map(GetFuncName, range(thread.GetNumFrames())) def GetSymbolNames(thread): """ Returns a sequence of symbols for this thread. """ def GetSymbol(i): return thread.GetFrameAtIndex(i).GetSymbol().GetName() return map(GetSymbol, range(thread.GetNumFrames())) def GetPCAddresses(thread): """ Returns a sequence of pc addresses for this thread. """ def GetPCAddress(i): return thread.GetFrameAtIndex(i).GetPCAddress() return map(GetPCAddress, range(thread.GetNumFrames())) def GetFilenames(thread): """ Returns a sequence of file names from the stack frames of this thread. """ def GetFilename(i): return thread.GetFrameAtIndex(i).GetLineEntry().GetFileSpec().GetFilename() return map(GetFilename, range(thread.GetNumFrames())) def GetLineNumbers(thread): """ Returns a sequence of line numbers from the stack frames of this thread. """ def GetLineNumber(i): return thread.GetFrameAtIndex(i).GetLineEntry().GetLine() return map(GetLineNumber, range(thread.GetNumFrames())) def GetModuleNames(thread): """ Returns a sequence of module names from the stack frames of this thread. """ def GetModuleName(i): return thread.GetFrameAtIndex(i).GetModule().GetFileSpec().GetFilename() return map(GetModuleName, range(thread.GetNumFrames())) def GetStackFrames(thread): """ Returns a sequence of stack frames for this thread. """ def GetStackFrame(i): return thread.GetFrameAtIndex(i) return map(GetStackFrame, range(thread.GetNumFrames())) def PrintStackTrace(thread, string_buffer = False): """Prints a simple stack trace of this thread.""" output = StringIO.StringIO() if string_buffer else sys.stdout target = thread.GetProcess().GetTarget() depth = thread.GetNumFrames() mods = GetModuleNames(thread) funcs = GetFunctionNames(thread) symbols = GetSymbolNames(thread) files = GetFilenames(thread) lines = GetLineNumbers(thread) addrs = GetPCAddresses(thread) print >> output, "Stack trace for thread id={0:#x} name={1} queue={2}:".format( thread.GetThreadID(), thread.GetName(), thread.GetQueueName()) for i in range(depth): frame = thread.GetFrameAtIndex(i) function = frame.GetFunction() load_addr = addrs[i].GetLoadAddress(target) if not function.IsValid(): file_addr = addrs[i].GetFileAddress() print >> output, " frame #{num}: {addr:#016x} {mod}`{symbol} + ????".format( num=i, addr=load_addr, mod=mods[i], symbol=symbols[i]) else: print >> output, " frame #{num}: {addr:#016x} {mod}`{func} at {file}:{line}".format( num=i, addr=load_addr, mod=mods[i], func=funcs[i], file=files[i], line=lines[i]) if string_buffer: return output.getvalue() def PrintStackTraces(process, string_buffer = False): """Prints the stack traces of all the threads.""" output = StringIO.StringIO() if string_buffer else sys.stdout print >> output, "Stack traces for " + repr(process) for i in range(process.GetNumThreads()): print >> output, PrintStackTrace(process.GetThreadAtIndex(i), string_buffer=True) if string_buffer: return output.getvalue()