lldbutil.py revision fd1175c5d3152beb6fdee4b3b2ba3461b1ae1e0c
1""" 2This LLDB module contains miscellaneous utilities. 3""" 4 5import lldb 6import os, sys 7import StringIO 8 9# =================================================== 10# Utilities for locating/checking executable programs 11# =================================================== 12 13def is_exe(fpath): 14 """Returns True if fpath is an executable.""" 15 return os.path.isfile(fpath) and os.access(fpath, os.X_OK) 16 17def which(program): 18 """Returns the full path to a program; None otherwise.""" 19 fpath, fname = os.path.split(program) 20 if fpath: 21 if is_exe(program): 22 return program 23 else: 24 for path in os.environ["PATH"].split(os.pathsep): 25 exe_file = os.path.join(path, program) 26 if is_exe(exe_file): 27 return exe_file 28 return None 29 30# =================================================== 31# Disassembly for an SBFunction or an SBSymbol object 32# =================================================== 33 34def disassemble(target, function_or_symbol): 35 """Disassemble the function or symbol given a target. 36 37 It returns the disassembly content in a string object. 38 """ 39 buf = StringIO.StringIO() 40 insts = function_or_symbol.GetInstructions(target) 41 for i in insts: 42 print >> buf, i 43 return buf.getvalue() 44 45 46# ========================================================== 47# Integer (byte size 1, 2, 4, and 8) to bytearray conversion 48# ========================================================== 49 50def int_to_bytearray(val, bytesize): 51 """Utility function to convert an integer into a bytearray. 52 53 It returns the bytearray in the little endian format. It is easy to get the 54 big endian format, just do ba.reverse() on the returned object. 55 """ 56 import struct 57 58 if bytesize == 1: 59 return bytearray([val]) 60 61 # Little endian followed by a format character. 62 template = "<%c" 63 if bytesize == 2: 64 fmt = template % 'h' 65 elif bytesize == 4: 66 fmt = template % 'i' 67 elif bytesize == 4: 68 fmt = template % 'q' 69 else: 70 return None 71 72 packed = struct.pack(fmt, val) 73 return bytearray(map(ord, packed)) 74 75def bytearray_to_int(bytes, bytesize): 76 """Utility function to convert a bytearray into an integer. 77 78 It interprets the bytearray in the little endian format. For a big endian 79 bytearray, just do ba.reverse() on the object before passing it in. 80 """ 81 import struct 82 83 if bytesize == 1: 84 return ba[0] 85 86 # Little endian followed by a format character. 87 template = "<%c" 88 if bytesize == 2: 89 fmt = template % 'h' 90 elif bytesize == 4: 91 fmt = template % 'i' 92 elif bytesize == 4: 93 fmt = template % 'q' 94 else: 95 return None 96 97 unpacked = struct.unpack(fmt, str(bytes)) 98 return unpacked[0] 99 100 101# ============================================================== 102# Get the description of an lldb object or None if not available 103# ============================================================== 104def get_description(obj, option=None): 105 """Calls lldb_obj.GetDescription() and returns a string, or None. 106 107 For SBTarget and SBBreakpointLocation lldb objects, an extra option can be 108 passed in to describe the detailed level of description desired: 109 o lldb.eDescriptionLevelBrief 110 o lldb.eDescriptionLevelFull 111 o lldb.eDescriptionLevelVerbose 112 """ 113 method = getattr(obj, 'GetDescription') 114 if not method: 115 return None 116 if isinstance(obj, lldb.SBTarget) or isinstance(obj, lldb.SBBreakpointLocation): 117 if option is None: 118 option = lldb.eDescriptionLevelBrief 119 120 stream = lldb.SBStream() 121 if option is None: 122 success = method(stream) 123 else: 124 success = method(stream, option) 125 if not success: 126 return None 127 return stream.GetData() 128 129 130# ================================================= 131# Convert some enum value to its string counterpart 132# ================================================= 133 134def state_type_to_str(enum): 135 """Returns the stateType string given an enum.""" 136 if enum == lldb.eStateInvalid: 137 return "invalid" 138 elif enum == lldb.eStateUnloaded: 139 return "unloaded" 140 elif enum == lldb.eStateConnected: 141 return "connected" 142 elif enum == lldb.eStateAttaching: 143 return "attaching" 144 elif enum == lldb.eStateLaunching: 145 return "launching" 146 elif enum == lldb.eStateStopped: 147 return "stopped" 148 elif enum == lldb.eStateRunning: 149 return "running" 150 elif enum == lldb.eStateStepping: 151 return "stepping" 152 elif enum == lldb.eStateCrashed: 153 return "crashed" 154 elif enum == lldb.eStateDetached: 155 return "detached" 156 elif enum == lldb.eStateExited: 157 return "exited" 158 elif enum == lldb.eStateSuspended: 159 return "suspended" 160 else: 161 raise Exception("Unknown StateType enum") 162 163def stop_reason_to_str(enum): 164 """Returns the stopReason string given an enum.""" 165 if enum == lldb.eStopReasonInvalid: 166 return "invalid" 167 elif enum == lldb.eStopReasonNone: 168 return "none" 169 elif enum == lldb.eStopReasonTrace: 170 return "trace" 171 elif enum == lldb.eStopReasonBreakpoint: 172 return "breakpoint" 173 elif enum == lldb.eStopReasonWatchpoint: 174 return "watchpoint" 175 elif enum == lldb.eStopReasonSignal: 176 return "signal" 177 elif enum == lldb.eStopReasonException: 178 return "exception" 179 elif enum == lldb.eStopReasonPlanComplete: 180 return "plancomplete" 181 else: 182 raise Exception("Unknown StopReason enum") 183 184def value_type_to_str(enum): 185 """Returns the valueType string given an enum.""" 186 if enum == lldb.eValueTypeInvalid: 187 return "invalid" 188 elif enum == lldb.eValueTypeVariableGlobal: 189 return "global_variable" 190 elif enum == lldb.eValueTypeVariableStatic: 191 return "static_variable" 192 elif enum == lldb.eValueTypeVariableArgument: 193 return "argument_variable" 194 elif enum == lldb.eValueTypeVariableLocal: 195 return "local_variable" 196 elif enum == lldb.eValueTypeRegister: 197 return "register" 198 elif enum == lldb.eValueTypeRegisterSet: 199 return "register_set" 200 elif enum == lldb.eValueTypeConstResult: 201 return "constant_result" 202 else: 203 raise Exception("Unknown ValueType enum") 204 205 206# ================================================== 207# Utility functions related to Threads and Processes 208# ================================================== 209 210def get_stopped_threads(process, reason): 211 """Returns the thread(s) with the specified stop reason in a list.""" 212 threads = [] 213 for t in process: 214 if t.GetStopReason() == reason: 215 threads.append(t) 216 return threads 217 218def get_stopped_thread(process, reason): 219 """A convenience function which returns the first thread with the given stop 220 reason or None. 221 222 Example usages: 223 224 1. Get the stopped thread due to a breakpoint condition 225 226 ... 227 from lldbutil import get_stopped_thread 228 thread = get_stopped_thread(self.process, lldb.eStopReasonPlanComplete) 229 self.assertTrue(thread != None, "There should be a thread stopped due to breakpoint condition") 230 ... 231 232 2. Get the thread stopped due to a breakpoint 233 234 ... 235 from lldbutil import get_stopped_thread 236 thread = get_stopped_thread(self.process, lldb.eStopReasonBreakpoint) 237 self.assertTrue(thread != None, "There should be a thread stopped due to breakpoint") 238 ... 239 240 """ 241 threads = get_stopped_threads(process, reason) 242 if len(threads) == 0: 243 return None 244 return threads[0] 245 246def get_threads_stopped_at_breakpoint (process, bkpt): 247 """ For a stopped process returns the thread stopped at the breakpoint passed in bkpt""" 248 stopped_threads = [] 249 threads = [] 250 251 stopped_threads = get_stopped_threads (process, lldb.eStopReasonBreakpoint) 252 253 if len(stopped_threads) == 0: 254 return threads 255 256 for thread in stopped_threads: 257 # Make sure we've hit our breakpoint... 258 break_id = thread.GetStopReasonDataAtIndex (0) 259 if break_id == bkpt.GetID(): 260 threads.append(thread) 261 262 return threads 263 264def continue_to_breakpoint (process, bkpt): 265 """ Continues the process, if it stops, returns the threads stopped at bkpt; otherwise, returns None""" 266 process.Continue() 267 if process.GetState() != lldb.eStateStopped: 268 return None 269 else: 270 return get_threads_stopped_at_breakpoint (process, bkpt) 271 272def get_caller_symbol(thread): 273 """ 274 Returns the symbol name for the call site of the leaf function. 275 """ 276 depth = thread.GetNumFrames() 277 if depth <= 1: 278 return None 279 caller = thread.GetFrameAtIndex(1).GetSymbol() 280 if caller: 281 return caller.GetName() 282 else: 283 return None 284 285 286def get_function_names(thread): 287 """ 288 Returns a sequence of function names from the stack frames of this thread. 289 """ 290 def GetFuncName(i): 291 return thread.GetFrameAtIndex(i).GetFunction().GetName() 292 293 return map(GetFuncName, range(thread.GetNumFrames())) 294 295 296def get_symbol_names(thread): 297 """ 298 Returns a sequence of symbols for this thread. 299 """ 300 def GetSymbol(i): 301 return thread.GetFrameAtIndex(i).GetSymbol().GetName() 302 303 return map(GetSymbol, range(thread.GetNumFrames())) 304 305 306def get_pc_addresses(thread): 307 """ 308 Returns a sequence of pc addresses for this thread. 309 """ 310 def GetPCAddress(i): 311 return thread.GetFrameAtIndex(i).GetPCAddress() 312 313 return map(GetPCAddress, range(thread.GetNumFrames())) 314 315 316def get_filenames(thread): 317 """ 318 Returns a sequence of file names from the stack frames of this thread. 319 """ 320 def GetFilename(i): 321 return thread.GetFrameAtIndex(i).GetLineEntry().GetFileSpec().GetFilename() 322 323 return map(GetFilename, range(thread.GetNumFrames())) 324 325 326def get_line_numbers(thread): 327 """ 328 Returns a sequence of line numbers from the stack frames of this thread. 329 """ 330 def GetLineNumber(i): 331 return thread.GetFrameAtIndex(i).GetLineEntry().GetLine() 332 333 return map(GetLineNumber, range(thread.GetNumFrames())) 334 335 336def get_module_names(thread): 337 """ 338 Returns a sequence of module names from the stack frames of this thread. 339 """ 340 def GetModuleName(i): 341 return thread.GetFrameAtIndex(i).GetModule().GetFileSpec().GetFilename() 342 343 return map(GetModuleName, range(thread.GetNumFrames())) 344 345 346def get_stack_frames(thread): 347 """ 348 Returns a sequence of stack frames for this thread. 349 """ 350 def GetStackFrame(i): 351 return thread.GetFrameAtIndex(i) 352 353 return map(GetStackFrame, range(thread.GetNumFrames())) 354 355 356def print_stacktrace(thread, string_buffer = False): 357 """Prints a simple stack trace of this thread.""" 358 359 output = StringIO.StringIO() if string_buffer else sys.stdout 360 target = thread.GetProcess().GetTarget() 361 362 depth = thread.GetNumFrames() 363 364 mods = get_module_names(thread) 365 funcs = get_function_names(thread) 366 symbols = get_symbol_names(thread) 367 files = get_filenames(thread) 368 lines = get_line_numbers(thread) 369 addrs = get_pc_addresses(thread) 370 371 if thread.GetStopReason() != lldb.eStopReasonInvalid: 372 desc = "stop reason=" + stop_reason_to_str(thread.GetStopReason()) 373 else: 374 desc = "" 375 print >> output, "Stack trace for thread id={0:#x} name={1} queue={2} ".format( 376 thread.GetThreadID(), thread.GetName(), thread.GetQueueName()) + desc 377 378 for i in range(depth): 379 frame = thread.GetFrameAtIndex(i) 380 function = frame.GetFunction() 381 382 load_addr = addrs[i].GetLoadAddress(target) 383 if not function.IsValid(): 384 file_addr = addrs[i].GetFileAddress() 385 print >> output, " frame #{num}: {addr:#016x} {mod}`{symbol} + ????".format( 386 num=i, addr=load_addr, mod=mods[i], symbol=symbols[i]) 387 else: 388 print >> output, " frame #{num}: {addr:#016x} {mod}`{func} at {file}:{line}".format( 389 num=i, addr=load_addr, mod=mods[i], func=funcs[i], file=files[i], line=lines[i]) 390 391 if string_buffer: 392 return output.getvalue() 393 394 395def print_stacktraces(process, string_buffer = False): 396 """Prints the stack traces of all the threads.""" 397 398 output = StringIO.StringIO() if string_buffer else sys.stdout 399 400 print >> output, "Stack traces for " + repr(process) 401 402 for thread in process: 403 print >> output, print_stacktrace(thread, string_buffer=True) 404 405 if string_buffer: 406 return output.getvalue() 407 408# =================================== 409# Utility functions related to Frames 410# =================================== 411 412def print_registers(frame, string_buffer = False): 413 """Prints all the register sets of the frame.""" 414 415 output = StringIO.StringIO() if string_buffer else sys.stdout 416 417 print >> output, "Register sets for " + repr(frame) 418 419 registerSet = frame.GetRegisters() # Return type of SBValueList. 420 print >> output, "Frame registers (size of register set = %d):" % registerSet.GetSize() 421 for value in registerSet: 422 #print >> output, value 423 print >> output, "%s (number of children = %d):" % (value.GetName(), value.GetNumChildren()) 424 for child in value: 425 print >> output, "Name: %s, Value: %s" % (child.GetName(), child.GetValue(frame)) 426 427 if string_buffer: 428 return output.getvalue() 429 430def get_registers(frame, kind): 431 """Returns the registers given the frame and the kind of registers desired. 432 433 Returns None if there's no such kind. 434 """ 435 registerSet = frame.GetRegisters() # Return type of SBValueList. 436 for value in registerSet: 437 if kind.lower() in value.GetName().lower(): 438 return value 439 440 return None 441 442def get_GPRs(frame): 443 """Returns the general purpose registers of the frame as an SBValue. 444 445 The returned SBValue object is iterable. An example: 446 ... 447 from lldbutil import get_GPRs 448 regs = get_GPRs(frame) 449 for reg in regs: 450 print "%s => %s" % (reg.GetName(), reg.GetValue()) 451 ... 452 """ 453 return get_registers(frame, "general purpose") 454 455def get_FPRs(frame): 456 """Returns the floating point registers of the frame as an SBValue. 457 458 The returned SBValue object is iterable. An example: 459 ... 460 from lldbutil import get_FPRs 461 regs = get_FPRs(frame) 462 for reg in regs: 463 print "%s => %s" % (reg.GetName(), reg.GetValue()) 464 ... 465 """ 466 return get_registers(frame, "floating point") 467 468def get_ESRs(frame): 469 """Returns the exception state registers of the frame as an SBValue. 470 471 The returned SBValue object is iterable. An example: 472 ... 473 from lldbutil import get_ESRs 474 regs = get_ESRs(frame) 475 for reg in regs: 476 print "%s => %s" % (reg.GetName(), reg.GetValue()) 477 ... 478 """ 479 return get_registers(frame, "exception state") 480