forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			243 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			243 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Python
		
	
	
	
| """
 | |
| 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 an aggregate object or a container of it, the name of
 | |
|     the method to get the size of the aggregate, and the name of the method to
 | |
|     get the element by index.
 | |
| 
 | |
|     Example usages:
 | |
| 
 | |
|     1. Pass an aggregate as the first argument:
 | |
| 
 | |
|     def disassemble_instructions (insts):
 | |
|         from lldbutil import lldb_iter
 | |
|         for i in lldb_iter(insts, 'GetSize', 'GetInstructionAtIndex'):
 | |
|             print i
 | |
| 
 | |
|     2. Pass a container of aggregate which provides APIs to get to the size and
 | |
|        the element of the aggregate:
 | |
| 
 | |
|     # Module is a container of symbol table 
 | |
|     module = target.FindModule(filespec)
 | |
|     for symbol in lldb_iter(module, 'GetNumSymbols', 'GetSymbolAtIndex'):
 | |
|         name = symbol.GetName()
 | |
|         ...
 | |
|     """
 | |
|     size = getattr(obj, getsize)
 | |
|     elem = getattr(obj, getelem)
 | |
|     for i in range(size()):
 | |
|         yield elem(i)
 | |
| 
 | |
| 
 | |
| # =================================================
 | |
| # Convert some enum value to its string 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")
 | |
| 
 | |
| def ValueTypeString(enum):
 | |
|     """Returns the valueType string given an enum."""
 | |
|     if enum == lldb.eValueTypeInvalid:
 | |
|         return "invalid"
 | |
|     elif enum == lldb.eValueTypeVariableGlobal:
 | |
|         return "global_variable"
 | |
|     elif enum == lldb.eValueTypeVariableStatic:
 | |
|         return "static_variable"
 | |
|     elif enum == lldb.eValueTypeVariableArgument:
 | |
|         return "argument_variable"
 | |
|     elif enum == lldb.eValueTypeVariableLocal:
 | |
|         return "local_variable"
 | |
|     elif enum == lldb.eValueTypeRegister:
 | |
|         return "register"
 | |
|     elif enum == lldb.eValueTypeRegisterSet:
 | |
|         return "register_set"
 | |
|     elif enum == lldb.eValueTypeConstResult:
 | |
|         return "constant_result"
 | |
|     else:
 | |
|         raise Exception("Unknown valueType 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)
 | |
| 
 | |
|     if thread.GetStopReason() != lldb.eStopReasonInvalid:
 | |
|         desc =  "stop reason=" + StopReasonString(thread.GetStopReason())
 | |
|     else:
 | |
|         desc = ""
 | |
|     print >> output, "Stack trace for thread id={0:#x} name={1} queue={2} ".format(
 | |
|         thread.GetThreadID(), thread.GetName(), thread.GetQueueName()) + desc
 | |
| 
 | |
|     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()
 |