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