blob: 948fe469478c1e279f311566f29ee7388513d6fd [file] [log] [blame]
Johnny Chen1605cf62010-09-08 22:54:46 +00001"""
Johnny Chenb51d87d2010-10-07 21:38:28 +00002This LLDB module contains miscellaneous utilities.
Johnny Chen1605cf62010-09-08 22:54:46 +00003"""
4
5import lldb
Johnny Chen0bfa8592011-03-23 20:28:59 +00006import os, sys
Johnny Chened5f04e2010-10-15 23:33:18 +00007import StringIO
Johnny Chen1605cf62010-09-08 22:54:46 +00008
Johnny Chen8a3b54e2011-04-26 23:07:40 +00009# ===================================================
10# Utilities for locating/checking executable programs
11# ===================================================
Johnny Chen979cb5d2011-04-26 22:53:38 +000012
Johnny Chen0bfa8592011-03-23 20:28:59 +000013def is_exe(fpath):
Johnny Chenefdc26a2011-04-26 23:10:15 +000014 """Returns True if fpath is an executable."""
Johnny Chen0bfa8592011-03-23 20:28:59 +000015 return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
16
Johnny Chen0bfa8592011-03-23 20:28:59 +000017def which(program):
Johnny Chenefdc26a2011-04-26 23:10:15 +000018 """Returns the full path to a program; None otherwise."""
Johnny Chen0bfa8592011-03-23 20:28:59 +000019 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
Johnny Chen77356a02011-03-03 01:41:57 +000030# ===========================================
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
Johnny Chen51ed1b62011-03-03 19:14:00 +000065# ===================================================
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
Johnny Chen4c70f282011-03-02 01:36:45 +000081# ==========================================================
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
Johnny Chend2765fc2011-03-02 20:54:22 +000088 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.
Johnny Chen4c70f282011-03-02 01:36:45 +000090 """
Johnny Chenf4c0d1d2011-03-30 17:54:35 +000091 import struct
Johnny Chen4c70f282011-03-02 01:36:45 +000092
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
Johnny Chenf4c0d1d2011-03-30 17:54:35 +0000107 packed = struct.pack(fmt, val)
Johnny Chen4c70f282011-03-02 01:36:45 +0000108 return bytearray(map(ord, packed))
109
110def bytearray_to_int(bytes, bytesize):
111 """Utility function to convert a bytearray into an integer.
112
Johnny Chend2765fc2011-03-02 20:54:22 +0000113 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.
Johnny Chen4c70f282011-03-02 01:36:45 +0000115 """
Johnny Chenf4c0d1d2011-03-30 17:54:35 +0000116 import struct
Johnny Chen4c70f282011-03-02 01:36:45 +0000117
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
Johnny Chenf4c0d1d2011-03-30 17:54:35 +0000132 unpacked = struct.unpack(fmt, str(bytes))
Johnny Chen4c70f282011-03-02 01:36:45 +0000133 return unpacked[0]
134
135
Johnny Chenbc1a93e2011-04-23 00:13:34 +0000136# ==============================================================
137# Get the description of an lldb object or None if not available
138# ==============================================================
Johnny Chenbdc36bd2011-04-25 20:23:05 +0000139def 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')
Johnny Chenbc1a93e2011-04-23 00:13:34 +0000149 if not method:
150 return None
Johnny Chenbdc36bd2011-04-25 20:23:05 +0000151 if isinstance(obj, lldb.SBTarget) or isinstance(obj, lldb.SBBreakpointLocation):
152 if option is None:
153 option = lldb.eDescriptionLevelBrief
154
Johnny Chenbc1a93e2011-04-23 00:13:34 +0000155 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
Johnny Chen168a61a2010-10-22 21:31:03 +0000165# =================================================
166# Convert some enum value to its string counterpart
167# =================================================
Johnny Chenbe683bc2010-10-07 22:15:58 +0000168
Johnny Chen47342d52011-04-27 17:43:07 +0000169def state_type_to_str(enum):
Johnny Chenbe683bc2010-10-07 22:15:58 +0000170 """Returns the stateType string given an enum."""
171 if enum == lldb.eStateInvalid:
Johnny Chen59b84772010-10-18 15:46:54 +0000172 return "invalid"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000173 elif enum == lldb.eStateUnloaded:
Johnny Chen59b84772010-10-18 15:46:54 +0000174 return "unloaded"
Johnny Chen42da4da2011-03-05 01:20:11 +0000175 elif enum == lldb.eStateConnected:
176 return "connected"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000177 elif enum == lldb.eStateAttaching:
Johnny Chen59b84772010-10-18 15:46:54 +0000178 return "attaching"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000179 elif enum == lldb.eStateLaunching:
Johnny Chen59b84772010-10-18 15:46:54 +0000180 return "launching"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000181 elif enum == lldb.eStateStopped:
Johnny Chen59b84772010-10-18 15:46:54 +0000182 return "stopped"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000183 elif enum == lldb.eStateRunning:
Johnny Chen59b84772010-10-18 15:46:54 +0000184 return "running"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000185 elif enum == lldb.eStateStepping:
Johnny Chen59b84772010-10-18 15:46:54 +0000186 return "stepping"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000187 elif enum == lldb.eStateCrashed:
Johnny Chen59b84772010-10-18 15:46:54 +0000188 return "crashed"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000189 elif enum == lldb.eStateDetached:
Johnny Chen59b84772010-10-18 15:46:54 +0000190 return "detached"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000191 elif enum == lldb.eStateExited:
Johnny Chen59b84772010-10-18 15:46:54 +0000192 return "exited"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000193 elif enum == lldb.eStateSuspended:
Johnny Chen59b84772010-10-18 15:46:54 +0000194 return "suspended"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000195 else:
Johnny Chen42da4da2011-03-05 01:20:11 +0000196 raise Exception("Unknown StateType enum")
Johnny Chenbe683bc2010-10-07 22:15:58 +0000197
Johnny Chen47342d52011-04-27 17:43:07 +0000198def stop_reason_to_str(enum):
Johnny Chenbe683bc2010-10-07 22:15:58 +0000199 """Returns the stopReason string given an enum."""
200 if enum == lldb.eStopReasonInvalid:
Johnny Chen59b84772010-10-18 15:46:54 +0000201 return "invalid"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000202 elif enum == lldb.eStopReasonNone:
Johnny Chen59b84772010-10-18 15:46:54 +0000203 return "none"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000204 elif enum == lldb.eStopReasonTrace:
Johnny Chen59b84772010-10-18 15:46:54 +0000205 return "trace"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000206 elif enum == lldb.eStopReasonBreakpoint:
Johnny Chen59b84772010-10-18 15:46:54 +0000207 return "breakpoint"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000208 elif enum == lldb.eStopReasonWatchpoint:
Johnny Chen59b84772010-10-18 15:46:54 +0000209 return "watchpoint"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000210 elif enum == lldb.eStopReasonSignal:
Johnny Chen59b84772010-10-18 15:46:54 +0000211 return "signal"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000212 elif enum == lldb.eStopReasonException:
Johnny Chen59b84772010-10-18 15:46:54 +0000213 return "exception"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000214 elif enum == lldb.eStopReasonPlanComplete:
Johnny Chen59b84772010-10-18 15:46:54 +0000215 return "plancomplete"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000216 else:
Johnny Chen42da4da2011-03-05 01:20:11 +0000217 raise Exception("Unknown StopReason enum")
Johnny Chenbe683bc2010-10-07 22:15:58 +0000218
Johnny Chen47342d52011-04-27 17:43:07 +0000219def value_type_to_str(enum):
Johnny Chen2c8d1592010-11-03 21:37:58 +0000220 """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:
Johnny Chen42da4da2011-03-05 01:20:11 +0000238 raise Exception("Unknown ValueType enum")
Johnny Chen2c8d1592010-11-03 21:37:58 +0000239
Johnny Chenbe683bc2010-10-07 22:15:58 +0000240
Johnny Chen168a61a2010-10-22 21:31:03 +0000241# ==================================================
242# Utility functions related to Threads and Processes
243# ==================================================
Johnny Chenbe683bc2010-10-07 22:15:58 +0000244
Johnny Chene428d332011-04-25 22:04:05 +0000245def 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
Johnny Chen318aaa02011-04-25 23:38:13 +0000281def 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
Johnny Chen69af39d2011-03-09 23:45:56 +0000307def 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
Johnny Chen318aaa02011-04-25 23:38:13 +0000321def get_function_names(thread):
Johnny Chen1605cf62010-09-08 22:54:46 +0000322 """
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
Johnny Chen318aaa02011-04-25 23:38:13 +0000331def get_symbol_names(thread):
Johnny Chenb51d87d2010-10-07 21:38:28 +0000332 """
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
Johnny Chen318aaa02011-04-25 23:38:13 +0000341def get_pc_addresses(thread):
Johnny Chenb51d87d2010-10-07 21:38:28 +0000342 """
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
Johnny Chen318aaa02011-04-25 23:38:13 +0000351def get_filenames(thread):
Johnny Chen1605cf62010-09-08 22:54:46 +0000352 """
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
Johnny Chen318aaa02011-04-25 23:38:13 +0000361def get_line_numbers(thread):
Johnny Chen1605cf62010-09-08 22:54:46 +0000362 """
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
Johnny Chen318aaa02011-04-25 23:38:13 +0000371def get_module_names(thread):
Johnny Chen1605cf62010-09-08 22:54:46 +0000372 """
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
Johnny Chen318aaa02011-04-25 23:38:13 +0000381def get_stack_frames(thread):
Johnny Chen88866ac2010-09-09 00:55:07 +0000382 """
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
Johnny Chen318aaa02011-04-25 23:38:13 +0000391def print_stacktrace(thread, string_buffer = False):
Johnny Chen1605cf62010-09-08 22:54:46 +0000392 """Prints a simple stack trace of this thread."""
Johnny Chen30425e92010-10-07 18:52:48 +0000393
Johnny Chened5f04e2010-10-15 23:33:18 +0000394 output = StringIO.StringIO() if string_buffer else sys.stdout
Johnny Chenb51d87d2010-10-07 21:38:28 +0000395 target = thread.GetProcess().GetTarget()
396
Johnny Chen1605cf62010-09-08 22:54:46 +0000397 depth = thread.GetNumFrames()
398
Johnny Chen318aaa02011-04-25 23:38:13 +0000399 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)
Johnny Chen30425e92010-10-07 18:52:48 +0000405
Johnny Chenad5fd402010-10-25 19:13:52 +0000406 if thread.GetStopReason() != lldb.eStopReasonInvalid:
Johnny Chen47342d52011-04-27 17:43:07 +0000407 desc = "stop reason=" + stop_reason_to_str(thread.GetStopReason())
Johnny Chenad5fd402010-10-25 19:13:52 +0000408 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
Johnny Chen1605cf62010-09-08 22:54:46 +0000412
Johnny Chenb51d87d2010-10-07 21:38:28 +0000413 for i in range(depth):
414 frame = thread.GetFrameAtIndex(i)
415 function = frame.GetFunction()
Johnny Chen1605cf62010-09-08 22:54:46 +0000416
Johnny Chenb51d87d2010-10-07 21:38:28 +0000417 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:
Johnny Chened5f04e2010-10-15 23:33:18 +0000427 return output.getvalue()
Johnny Chenb51d87d2010-10-07 21:38:28 +0000428
429
Johnny Chen318aaa02011-04-25 23:38:13 +0000430def print_stacktraces(process, string_buffer = False):
Johnny Chenb51d87d2010-10-07 21:38:28 +0000431 """Prints the stack traces of all the threads."""
432
Johnny Chened5f04e2010-10-15 23:33:18 +0000433 output = StringIO.StringIO() if string_buffer else sys.stdout
Johnny Chenb51d87d2010-10-07 21:38:28 +0000434
435 print >> output, "Stack traces for " + repr(process)
436
437 for i in range(process.GetNumThreads()):
Johnny Chen318aaa02011-04-25 23:38:13 +0000438 print >> output, print_stacktrace(process.GetThreadAtIndex(i), string_buffer=True)
Johnny Chen30425e92010-10-07 18:52:48 +0000439
440 if string_buffer:
Johnny Chened5f04e2010-10-15 23:33:18 +0000441 return output.getvalue()