blob: e78925fd49f5764d8b8aa704644a487ce9c45a04 [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 Chen0bfa8592011-03-23 20:28:59 +00009def is_exe(fpath):
10 return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
11
Johnny Chen0bfa8592011-03-23 20:28:59 +000012def which(program):
Johnny Chen0b4dfac2011-04-18 18:34:09 +000013 """Find the full path to a program, or return None."""
Johnny Chen0bfa8592011-03-23 20:28:59 +000014 fpath, fname = os.path.split(program)
15 if fpath:
16 if is_exe(program):
17 return program
18 else:
19 for path in os.environ["PATH"].split(os.pathsep):
20 exe_file = os.path.join(path, program)
21 if is_exe(exe_file):
22 return exe_file
23 return None
24
Johnny Chen77356a02011-03-03 01:41:57 +000025# ===========================================
26# Iterator for lldb aggregate data structures
27# ===========================================
28
29def lldb_iter(obj, getsize, getelem):
30 """A generator adaptor for lldb aggregate data structures.
31
32 API clients pass in an aggregate object or a container of it, the name of
33 the method to get the size of the aggregate, and the name of the method to
34 get the element by index.
35
36 Example usages:
37
38 1. Pass an aggregate as the first argument:
39
40 def disassemble_instructions (insts):
41 from lldbutil import lldb_iter
42 for i in lldb_iter(insts, 'GetSize', 'GetInstructionAtIndex'):
43 print i
44
45 2. Pass a container of aggregate which provides APIs to get to the size and
46 the element of the aggregate:
47
48 # Module is a container of symbol table
49 module = target.FindModule(filespec)
50 for symbol in lldb_iter(module, 'GetNumSymbols', 'GetSymbolAtIndex'):
51 name = symbol.GetName()
52 ...
53 """
54 size = getattr(obj, getsize)
55 elem = getattr(obj, getelem)
56 for i in range(size()):
57 yield elem(i)
58
59
Johnny Chen51ed1b62011-03-03 19:14:00 +000060# ===================================================
61# Disassembly for an SBFunction or an SBSymbol object
62# ===================================================
63
64def disassemble(target, function_or_symbol):
65 """Disassemble the function or symbol given a target.
66
67 It returns the disassembly content in a string object.
68 """
69 buf = StringIO.StringIO()
70 insts = function_or_symbol.GetInstructions(target)
71 for i in lldb_iter(insts, 'GetSize', 'GetInstructionAtIndex'):
72 print >> buf, i
73 return buf.getvalue()
74
75
Johnny Chen4c70f282011-03-02 01:36:45 +000076# ==========================================================
77# Integer (byte size 1, 2, 4, and 8) to bytearray conversion
78# ==========================================================
79
80def int_to_bytearray(val, bytesize):
81 """Utility function to convert an integer into a bytearray.
82
Johnny Chend2765fc2011-03-02 20:54:22 +000083 It returns the bytearray in the little endian format. It is easy to get the
84 big endian format, just do ba.reverse() on the returned object.
Johnny Chen4c70f282011-03-02 01:36:45 +000085 """
Johnny Chenf4c0d1d2011-03-30 17:54:35 +000086 import struct
Johnny Chen4c70f282011-03-02 01:36:45 +000087
88 if bytesize == 1:
89 return bytearray([val])
90
91 # Little endian followed by a format character.
92 template = "<%c"
93 if bytesize == 2:
94 fmt = template % 'h'
95 elif bytesize == 4:
96 fmt = template % 'i'
97 elif bytesize == 4:
98 fmt = template % 'q'
99 else:
100 return None
101
Johnny Chenf4c0d1d2011-03-30 17:54:35 +0000102 packed = struct.pack(fmt, val)
Johnny Chen4c70f282011-03-02 01:36:45 +0000103 return bytearray(map(ord, packed))
104
105def bytearray_to_int(bytes, bytesize):
106 """Utility function to convert a bytearray into an integer.
107
Johnny Chend2765fc2011-03-02 20:54:22 +0000108 It interprets the bytearray in the little endian format. For a big endian
109 bytearray, just do ba.reverse() on the object before passing it in.
Johnny Chen4c70f282011-03-02 01:36:45 +0000110 """
Johnny Chenf4c0d1d2011-03-30 17:54:35 +0000111 import struct
Johnny Chen4c70f282011-03-02 01:36:45 +0000112
113 if bytesize == 1:
114 return ba[0]
115
116 # Little endian followed by a format character.
117 template = "<%c"
118 if bytesize == 2:
119 fmt = template % 'h'
120 elif bytesize == 4:
121 fmt = template % 'i'
122 elif bytesize == 4:
123 fmt = template % 'q'
124 else:
125 return None
126
Johnny Chenf4c0d1d2011-03-30 17:54:35 +0000127 unpacked = struct.unpack(fmt, str(bytes))
Johnny Chen4c70f282011-03-02 01:36:45 +0000128 return unpacked[0]
129
130
Johnny Chenbc1a93e2011-04-23 00:13:34 +0000131# ==============================================================
132# Get the description of an lldb object or None if not available
133# ==============================================================
Johnny Chenbdc36bd2011-04-25 20:23:05 +0000134def get_description(obj, option=None):
135 """Calls lldb_obj.GetDescription() and returns a string, or None.
136
137 For SBTarget and SBBreakpointLocation lldb objects, an extra option can be
138 passed in to describe the detailed level of description desired:
139 o lldb.eDescriptionLevelBrief
140 o lldb.eDescriptionLevelFull
141 o lldb.eDescriptionLevelVerbose
142 """
143 method = getattr(obj, 'GetDescription')
Johnny Chenbc1a93e2011-04-23 00:13:34 +0000144 if not method:
145 return None
Johnny Chenbdc36bd2011-04-25 20:23:05 +0000146 if isinstance(obj, lldb.SBTarget) or isinstance(obj, lldb.SBBreakpointLocation):
147 if option is None:
148 option = lldb.eDescriptionLevelBrief
149
Johnny Chenbc1a93e2011-04-23 00:13:34 +0000150 stream = lldb.SBStream()
151 if option is None:
152 success = method(stream)
153 else:
154 success = method(stream, option)
155 if not success:
156 return None
157 return stream.GetData()
158
159
Johnny Chen168a61a2010-10-22 21:31:03 +0000160# =================================================
161# Convert some enum value to its string counterpart
162# =================================================
Johnny Chenbe683bc2010-10-07 22:15:58 +0000163
164def StateTypeString(enum):
165 """Returns the stateType string given an enum."""
166 if enum == lldb.eStateInvalid:
Johnny Chen59b84772010-10-18 15:46:54 +0000167 return "invalid"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000168 elif enum == lldb.eStateUnloaded:
Johnny Chen59b84772010-10-18 15:46:54 +0000169 return "unloaded"
Johnny Chen42da4da2011-03-05 01:20:11 +0000170 elif enum == lldb.eStateConnected:
171 return "connected"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000172 elif enum == lldb.eStateAttaching:
Johnny Chen59b84772010-10-18 15:46:54 +0000173 return "attaching"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000174 elif enum == lldb.eStateLaunching:
Johnny Chen59b84772010-10-18 15:46:54 +0000175 return "launching"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000176 elif enum == lldb.eStateStopped:
Johnny Chen59b84772010-10-18 15:46:54 +0000177 return "stopped"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000178 elif enum == lldb.eStateRunning:
Johnny Chen59b84772010-10-18 15:46:54 +0000179 return "running"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000180 elif enum == lldb.eStateStepping:
Johnny Chen59b84772010-10-18 15:46:54 +0000181 return "stepping"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000182 elif enum == lldb.eStateCrashed:
Johnny Chen59b84772010-10-18 15:46:54 +0000183 return "crashed"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000184 elif enum == lldb.eStateDetached:
Johnny Chen59b84772010-10-18 15:46:54 +0000185 return "detached"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000186 elif enum == lldb.eStateExited:
Johnny Chen59b84772010-10-18 15:46:54 +0000187 return "exited"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000188 elif enum == lldb.eStateSuspended:
Johnny Chen59b84772010-10-18 15:46:54 +0000189 return "suspended"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000190 else:
Johnny Chen42da4da2011-03-05 01:20:11 +0000191 raise Exception("Unknown StateType enum")
Johnny Chenbe683bc2010-10-07 22:15:58 +0000192
193def StopReasonString(enum):
194 """Returns the stopReason string given an enum."""
195 if enum == lldb.eStopReasonInvalid:
Johnny Chen59b84772010-10-18 15:46:54 +0000196 return "invalid"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000197 elif enum == lldb.eStopReasonNone:
Johnny Chen59b84772010-10-18 15:46:54 +0000198 return "none"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000199 elif enum == lldb.eStopReasonTrace:
Johnny Chen59b84772010-10-18 15:46:54 +0000200 return "trace"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000201 elif enum == lldb.eStopReasonBreakpoint:
Johnny Chen59b84772010-10-18 15:46:54 +0000202 return "breakpoint"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000203 elif enum == lldb.eStopReasonWatchpoint:
Johnny Chen59b84772010-10-18 15:46:54 +0000204 return "watchpoint"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000205 elif enum == lldb.eStopReasonSignal:
Johnny Chen59b84772010-10-18 15:46:54 +0000206 return "signal"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000207 elif enum == lldb.eStopReasonException:
Johnny Chen59b84772010-10-18 15:46:54 +0000208 return "exception"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000209 elif enum == lldb.eStopReasonPlanComplete:
Johnny Chen59b84772010-10-18 15:46:54 +0000210 return "plancomplete"
Johnny Chenbe683bc2010-10-07 22:15:58 +0000211 else:
Johnny Chen42da4da2011-03-05 01:20:11 +0000212 raise Exception("Unknown StopReason enum")
Johnny Chenbe683bc2010-10-07 22:15:58 +0000213
Johnny Chen2c8d1592010-11-03 21:37:58 +0000214def ValueTypeString(enum):
215 """Returns the valueType string given an enum."""
216 if enum == lldb.eValueTypeInvalid:
217 return "invalid"
218 elif enum == lldb.eValueTypeVariableGlobal:
219 return "global_variable"
220 elif enum == lldb.eValueTypeVariableStatic:
221 return "static_variable"
222 elif enum == lldb.eValueTypeVariableArgument:
223 return "argument_variable"
224 elif enum == lldb.eValueTypeVariableLocal:
225 return "local_variable"
226 elif enum == lldb.eValueTypeRegister:
227 return "register"
228 elif enum == lldb.eValueTypeRegisterSet:
229 return "register_set"
230 elif enum == lldb.eValueTypeConstResult:
231 return "constant_result"
232 else:
Johnny Chen42da4da2011-03-05 01:20:11 +0000233 raise Exception("Unknown ValueType enum")
Johnny Chen2c8d1592010-11-03 21:37:58 +0000234
Johnny Chenbe683bc2010-10-07 22:15:58 +0000235
Johnny Chen168a61a2010-10-22 21:31:03 +0000236# ==================================================
237# Utility functions related to Threads and Processes
238# ==================================================
Johnny Chenbe683bc2010-10-07 22:15:58 +0000239
Johnny Chene428d332011-04-25 22:04:05 +0000240def get_stopped_threads(process, reason):
241 """Returns the thread(s) with the specified stop reason in a list."""
242 threads = []
243 for t in lldb_iter(process, 'GetNumThreads', 'GetThreadAtIndex'):
244 if t.GetStopReason() == reason:
245 threads.append(t)
246 return threads
247
248def get_stopped_thread(process, reason):
249 """A convenience function which returns the first thread with the given stop
250 reason or None.
251
252 Example usages:
253
254 1. Get the stopped thread due to a breakpoint condition
255
256 ...
257 from lldbutil import get_stopped_thread
258 thread = get_stopped_thread(self.process, lldb.eStopReasonPlanComplete)
259 self.assertTrue(thread != None, "There should be a thread stopped due to breakpoint condition")
260 ...
261
262 2. Get the thread stopped due to a breakpoint
263
264 ...
265 from lldbutil import get_stopped_thread
266 thread = get_stopped_thread(self.process, lldb.eStopReasonBreakpoint)
267 self.assertTrue(thread != None, "There should be a thread stopped due to breakpoint")
268 ...
269
270 """
271 threads = get_stopped_threads(process, reason)
272 if len(threads) == 0:
273 return None
274 return threads[0]
275
Johnny Chen318aaa02011-04-25 23:38:13 +0000276def get_threads_stopped_at_breakpoint (process, bkpt):
277 """ For a stopped process returns the thread stopped at the breakpoint passed in bkpt"""
278 stopped_threads = []
279 threads = []
280
281 stopped_threads = get_stopped_threads (process, lldb.eStopReasonBreakpoint)
282
283 if len(stopped_threads) == 0:
284 return threads
285
286 for thread in stopped_threads:
287 # Make sure we've hit our breakpoint...
288 break_id = thread.GetStopReasonDataAtIndex (0)
289 if break_id == bkpt.GetID():
290 threads.append(thread)
291
292 return threads
293
294def continue_to_breakpoint (process, bkpt):
295 """ Continues the process, if it stops, returns the threads stopped at bkpt; otherwise, returns None"""
296 process.Continue()
297 if process.GetState() != lldb.eStateStopped:
298 return None
299 else:
300 return get_threads_stopped_at_breakpoint (process, bkpt)
301
Johnny Chen69af39d2011-03-09 23:45:56 +0000302def get_caller_symbol(thread):
303 """
304 Returns the symbol name for the call site of the leaf function.
305 """
306 depth = thread.GetNumFrames()
307 if depth <= 1:
308 return None
309 caller = thread.GetFrameAtIndex(1).GetSymbol()
310 if caller:
311 return caller.GetName()
312 else:
313 return None
314
315
Johnny Chen318aaa02011-04-25 23:38:13 +0000316def get_function_names(thread):
Johnny Chen1605cf62010-09-08 22:54:46 +0000317 """
318 Returns a sequence of function names from the stack frames of this thread.
319 """
320 def GetFuncName(i):
321 return thread.GetFrameAtIndex(i).GetFunction().GetName()
322
323 return map(GetFuncName, range(thread.GetNumFrames()))
324
325
Johnny Chen318aaa02011-04-25 23:38:13 +0000326def get_symbol_names(thread):
Johnny Chenb51d87d2010-10-07 21:38:28 +0000327 """
328 Returns a sequence of symbols for this thread.
329 """
330 def GetSymbol(i):
331 return thread.GetFrameAtIndex(i).GetSymbol().GetName()
332
333 return map(GetSymbol, range(thread.GetNumFrames()))
334
335
Johnny Chen318aaa02011-04-25 23:38:13 +0000336def get_pc_addresses(thread):
Johnny Chenb51d87d2010-10-07 21:38:28 +0000337 """
338 Returns a sequence of pc addresses for this thread.
339 """
340 def GetPCAddress(i):
341 return thread.GetFrameAtIndex(i).GetPCAddress()
342
343 return map(GetPCAddress, range(thread.GetNumFrames()))
344
345
Johnny Chen318aaa02011-04-25 23:38:13 +0000346def get_filenames(thread):
Johnny Chen1605cf62010-09-08 22:54:46 +0000347 """
348 Returns a sequence of file names from the stack frames of this thread.
349 """
350 def GetFilename(i):
351 return thread.GetFrameAtIndex(i).GetLineEntry().GetFileSpec().GetFilename()
352
353 return map(GetFilename, range(thread.GetNumFrames()))
354
355
Johnny Chen318aaa02011-04-25 23:38:13 +0000356def get_line_numbers(thread):
Johnny Chen1605cf62010-09-08 22:54:46 +0000357 """
358 Returns a sequence of line numbers from the stack frames of this thread.
359 """
360 def GetLineNumber(i):
361 return thread.GetFrameAtIndex(i).GetLineEntry().GetLine()
362
363 return map(GetLineNumber, range(thread.GetNumFrames()))
364
365
Johnny Chen318aaa02011-04-25 23:38:13 +0000366def get_module_names(thread):
Johnny Chen1605cf62010-09-08 22:54:46 +0000367 """
368 Returns a sequence of module names from the stack frames of this thread.
369 """
370 def GetModuleName(i):
371 return thread.GetFrameAtIndex(i).GetModule().GetFileSpec().GetFilename()
372
373 return map(GetModuleName, range(thread.GetNumFrames()))
374
375
Johnny Chen318aaa02011-04-25 23:38:13 +0000376def get_stack_frames(thread):
Johnny Chen88866ac2010-09-09 00:55:07 +0000377 """
378 Returns a sequence of stack frames for this thread.
379 """
380 def GetStackFrame(i):
381 return thread.GetFrameAtIndex(i)
382
383 return map(GetStackFrame, range(thread.GetNumFrames()))
384
385
Johnny Chen318aaa02011-04-25 23:38:13 +0000386def print_stacktrace(thread, string_buffer = False):
Johnny Chen1605cf62010-09-08 22:54:46 +0000387 """Prints a simple stack trace of this thread."""
Johnny Chen30425e92010-10-07 18:52:48 +0000388
Johnny Chened5f04e2010-10-15 23:33:18 +0000389 output = StringIO.StringIO() if string_buffer else sys.stdout
Johnny Chenb51d87d2010-10-07 21:38:28 +0000390 target = thread.GetProcess().GetTarget()
391
Johnny Chen1605cf62010-09-08 22:54:46 +0000392 depth = thread.GetNumFrames()
393
Johnny Chen318aaa02011-04-25 23:38:13 +0000394 mods = get_module_names(thread)
395 funcs = get_function_names(thread)
396 symbols = get_symbol_names(thread)
397 files = get_filenames(thread)
398 lines = get_line_numbers(thread)
399 addrs = get_pc_addresses(thread)
Johnny Chen30425e92010-10-07 18:52:48 +0000400
Johnny Chenad5fd402010-10-25 19:13:52 +0000401 if thread.GetStopReason() != lldb.eStopReasonInvalid:
402 desc = "stop reason=" + StopReasonString(thread.GetStopReason())
403 else:
404 desc = ""
405 print >> output, "Stack trace for thread id={0:#x} name={1} queue={2} ".format(
406 thread.GetThreadID(), thread.GetName(), thread.GetQueueName()) + desc
Johnny Chen1605cf62010-09-08 22:54:46 +0000407
Johnny Chenb51d87d2010-10-07 21:38:28 +0000408 for i in range(depth):
409 frame = thread.GetFrameAtIndex(i)
410 function = frame.GetFunction()
Johnny Chen1605cf62010-09-08 22:54:46 +0000411
Johnny Chenb51d87d2010-10-07 21:38:28 +0000412 load_addr = addrs[i].GetLoadAddress(target)
413 if not function.IsValid():
414 file_addr = addrs[i].GetFileAddress()
415 print >> output, " frame #{num}: {addr:#016x} {mod}`{symbol} + ????".format(
416 num=i, addr=load_addr, mod=mods[i], symbol=symbols[i])
417 else:
418 print >> output, " frame #{num}: {addr:#016x} {mod}`{func} at {file}:{line}".format(
419 num=i, addr=load_addr, mod=mods[i], func=funcs[i], file=files[i], line=lines[i])
420
421 if string_buffer:
Johnny Chened5f04e2010-10-15 23:33:18 +0000422 return output.getvalue()
Johnny Chenb51d87d2010-10-07 21:38:28 +0000423
424
Johnny Chen318aaa02011-04-25 23:38:13 +0000425def print_stacktraces(process, string_buffer = False):
Johnny Chenb51d87d2010-10-07 21:38:28 +0000426 """Prints the stack traces of all the threads."""
427
Johnny Chened5f04e2010-10-15 23:33:18 +0000428 output = StringIO.StringIO() if string_buffer else sys.stdout
Johnny Chenb51d87d2010-10-07 21:38:28 +0000429
430 print >> output, "Stack traces for " + repr(process)
431
432 for i in range(process.GetNumThreads()):
Johnny Chen318aaa02011-04-25 23:38:13 +0000433 print >> output, print_stacktrace(process.GetThreadAtIndex(i), string_buffer=True)
Johnny Chen30425e92010-10-07 18:52:48 +0000434
435 if string_buffer:
Johnny Chened5f04e2010-10-15 23:33:18 +0000436 return output.getvalue()