lldbutil.py revision 4c70f287ea336c4a0c599431bfc2b5a9a618ab5e
1""" 2This LLDB module contains miscellaneous utilities. 3""" 4 5import lldb 6import sys 7import StringIO 8 9# ========================================================== 10# Integer (byte size 1, 2, 4, and 8) to bytearray conversion 11# ========================================================== 12 13def int_to_bytearray(val, bytesize): 14 """Utility function to convert an integer into a bytearray. 15 16 It returns the bytearray in the little endian format. 17 It is easy to get the big endian representation, just do 18 ba.reverse() on the returned bytearray object. 19 """ 20 from struct import * 21 22 if bytesize == 1: 23 return bytearray([val]) 24 25 # Little endian followed by a format character. 26 template = "<%c" 27 if bytesize == 2: 28 fmt = template % 'h' 29 elif bytesize == 4: 30 fmt = template % 'i' 31 elif bytesize == 4: 32 fmt = template % 'q' 33 else: 34 return None 35 36 packed = pack(fmt, val) 37 return bytearray(map(ord, packed)) 38 39def bytearray_to_int(bytes, bytesize): 40 """Utility function to convert a bytearray into an integer. 41 42 It interprets the bytearray in the little endian format. 43 It is easy to get the big endian representation, just do 44 ba.reverse() on the bytearray object before passing it in. 45 """ 46 from struct import * 47 48 if bytesize == 1: 49 return ba[0] 50 51 # Little endian followed by a format character. 52 template = "<%c" 53 if bytesize == 2: 54 fmt = template % 'h' 55 elif bytesize == 4: 56 fmt = template % 'i' 57 elif bytesize == 4: 58 fmt = template % 'q' 59 else: 60 return None 61 62 unpacked = unpack(fmt, str(bytes)) 63 return unpacked[0] 64 65 66# =========================================== 67# Iterator for lldb aggregate data structures 68# =========================================== 69 70def lldb_iter(obj, getsize, getelem): 71 """A generator adaptor for lldb aggregate data structures. 72 73 API clients pass in an aggregate object or a container of it, the name of 74 the method to get the size of the aggregate, and the name of the method to 75 get the element by index. 76 77 Example usages: 78 79 1. Pass an aggregate as the first argument: 80 81 def disassemble_instructions (insts): 82 from lldbutil import lldb_iter 83 for i in lldb_iter(insts, 'GetSize', 'GetInstructionAtIndex'): 84 print i 85 86 2. Pass a container of aggregate which provides APIs to get to the size and 87 the element of the aggregate: 88 89 # Module is a container of symbol table 90 module = target.FindModule(filespec) 91 for symbol in lldb_iter(module, 'GetNumSymbols', 'GetSymbolAtIndex'): 92 name = symbol.GetName() 93 ... 94 """ 95 size = getattr(obj, getsize) 96 elem = getattr(obj, getelem) 97 for i in range(size()): 98 yield elem(i) 99 100 101# ================================================= 102# Convert some enum value to its string counterpart 103# ================================================= 104 105def StateTypeString(enum): 106 """Returns the stateType string given an enum.""" 107 if enum == lldb.eStateInvalid: 108 return "invalid" 109 elif enum == lldb.eStateUnloaded: 110 return "unloaded" 111 elif enum == lldb.eStateAttaching: 112 return "attaching" 113 elif enum == lldb.eStateLaunching: 114 return "launching" 115 elif enum == lldb.eStateStopped: 116 return "stopped" 117 elif enum == lldb.eStateRunning: 118 return "running" 119 elif enum == lldb.eStateStepping: 120 return "stepping" 121 elif enum == lldb.eStateCrashed: 122 return "crashed" 123 elif enum == lldb.eStateDetached: 124 return "detached" 125 elif enum == lldb.eStateExited: 126 return "exited" 127 elif enum == lldb.eStateSuspended: 128 return "suspended" 129 else: 130 raise Exception("Unknown stopReason enum") 131 132def StopReasonString(enum): 133 """Returns the stopReason string given an enum.""" 134 if enum == lldb.eStopReasonInvalid: 135 return "invalid" 136 elif enum == lldb.eStopReasonNone: 137 return "none" 138 elif enum == lldb.eStopReasonTrace: 139 return "trace" 140 elif enum == lldb.eStopReasonBreakpoint: 141 return "breakpoint" 142 elif enum == lldb.eStopReasonWatchpoint: 143 return "watchpoint" 144 elif enum == lldb.eStopReasonSignal: 145 return "signal" 146 elif enum == lldb.eStopReasonException: 147 return "exception" 148 elif enum == lldb.eStopReasonPlanComplete: 149 return "plancomplete" 150 else: 151 raise Exception("Unknown stopReason enum") 152 153def ValueTypeString(enum): 154 """Returns the valueType string given an enum.""" 155 if enum == lldb.eValueTypeInvalid: 156 return "invalid" 157 elif enum == lldb.eValueTypeVariableGlobal: 158 return "global_variable" 159 elif enum == lldb.eValueTypeVariableStatic: 160 return "static_variable" 161 elif enum == lldb.eValueTypeVariableArgument: 162 return "argument_variable" 163 elif enum == lldb.eValueTypeVariableLocal: 164 return "local_variable" 165 elif enum == lldb.eValueTypeRegister: 166 return "register" 167 elif enum == lldb.eValueTypeRegisterSet: 168 return "register_set" 169 elif enum == lldb.eValueTypeConstResult: 170 return "constant_result" 171 else: 172 raise Exception("Unknown valueType enum") 173 174 175# ================================================== 176# Utility functions related to Threads and Processes 177# ================================================== 178 179def GetFunctionNames(thread): 180 """ 181 Returns a sequence of function names from the stack frames of this thread. 182 """ 183 def GetFuncName(i): 184 return thread.GetFrameAtIndex(i).GetFunction().GetName() 185 186 return map(GetFuncName, range(thread.GetNumFrames())) 187 188 189def GetSymbolNames(thread): 190 """ 191 Returns a sequence of symbols for this thread. 192 """ 193 def GetSymbol(i): 194 return thread.GetFrameAtIndex(i).GetSymbol().GetName() 195 196 return map(GetSymbol, range(thread.GetNumFrames())) 197 198 199def GetPCAddresses(thread): 200 """ 201 Returns a sequence of pc addresses for this thread. 202 """ 203 def GetPCAddress(i): 204 return thread.GetFrameAtIndex(i).GetPCAddress() 205 206 return map(GetPCAddress, range(thread.GetNumFrames())) 207 208 209def GetFilenames(thread): 210 """ 211 Returns a sequence of file names from the stack frames of this thread. 212 """ 213 def GetFilename(i): 214 return thread.GetFrameAtIndex(i).GetLineEntry().GetFileSpec().GetFilename() 215 216 return map(GetFilename, range(thread.GetNumFrames())) 217 218 219def GetLineNumbers(thread): 220 """ 221 Returns a sequence of line numbers from the stack frames of this thread. 222 """ 223 def GetLineNumber(i): 224 return thread.GetFrameAtIndex(i).GetLineEntry().GetLine() 225 226 return map(GetLineNumber, range(thread.GetNumFrames())) 227 228 229def GetModuleNames(thread): 230 """ 231 Returns a sequence of module names from the stack frames of this thread. 232 """ 233 def GetModuleName(i): 234 return thread.GetFrameAtIndex(i).GetModule().GetFileSpec().GetFilename() 235 236 return map(GetModuleName, range(thread.GetNumFrames())) 237 238 239def GetStackFrames(thread): 240 """ 241 Returns a sequence of stack frames for this thread. 242 """ 243 def GetStackFrame(i): 244 return thread.GetFrameAtIndex(i) 245 246 return map(GetStackFrame, range(thread.GetNumFrames())) 247 248 249def PrintStackTrace(thread, string_buffer = False): 250 """Prints a simple stack trace of this thread.""" 251 252 output = StringIO.StringIO() if string_buffer else sys.stdout 253 target = thread.GetProcess().GetTarget() 254 255 depth = thread.GetNumFrames() 256 257 mods = GetModuleNames(thread) 258 funcs = GetFunctionNames(thread) 259 symbols = GetSymbolNames(thread) 260 files = GetFilenames(thread) 261 lines = GetLineNumbers(thread) 262 addrs = GetPCAddresses(thread) 263 264 if thread.GetStopReason() != lldb.eStopReasonInvalid: 265 desc = "stop reason=" + StopReasonString(thread.GetStopReason()) 266 else: 267 desc = "" 268 print >> output, "Stack trace for thread id={0:#x} name={1} queue={2} ".format( 269 thread.GetThreadID(), thread.GetName(), thread.GetQueueName()) + desc 270 271 for i in range(depth): 272 frame = thread.GetFrameAtIndex(i) 273 function = frame.GetFunction() 274 275 load_addr = addrs[i].GetLoadAddress(target) 276 if not function.IsValid(): 277 file_addr = addrs[i].GetFileAddress() 278 print >> output, " frame #{num}: {addr:#016x} {mod}`{symbol} + ????".format( 279 num=i, addr=load_addr, mod=mods[i], symbol=symbols[i]) 280 else: 281 print >> output, " frame #{num}: {addr:#016x} {mod}`{func} at {file}:{line}".format( 282 num=i, addr=load_addr, mod=mods[i], func=funcs[i], file=files[i], line=lines[i]) 283 284 if string_buffer: 285 return output.getvalue() 286 287 288def PrintStackTraces(process, string_buffer = False): 289 """Prints the stack traces of all the threads.""" 290 291 output = StringIO.StringIO() if string_buffer else sys.stdout 292 293 print >> output, "Stack traces for " + repr(process) 294 295 for i in range(process.GetNumThreads()): 296 print >> output, PrintStackTrace(process.GetThreadAtIndex(i), string_buffer=True) 297 298 if string_buffer: 299 return output.getvalue() 300