lldbutil.py revision abb3b2d796da9e081cd545b710d23c514489f895
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 get_parent_frame(frame):
413    """
414    Returns the parent frame of the input frame object; None if not available.
415    """
416    thread = frame.GetThread()
417    parent_found = False
418    for f in thread:
419        if parent_found:
420            return f
421        if f.GetFrameID() == frame.GetFrameID():
422            parent_found = True
423
424    # If we reach here, no parent has been found, return None.
425    return None
426
427def get_args_as_string(frame):
428    """
429    Returns the args of the input frame object as a string.
430    """
431    # arguments     => True
432    # locals        => False
433    # statics       => False
434    # in_scope_only => True
435    vars = frame.GetVariables(True, False, False, True) # type of SBValueList
436    args = [] # list of strings
437    for var in vars:
438        args.append("(%s)%s=%s" % (var.GetTypeName(),
439                                   var.GetName(),
440                                   var.GetValue(frame)))
441    return "%s(%s)" % (frame.GetFunction().GetName(), ", ".join(args))
442
443def print_registers(frame, string_buffer = False):
444    """Prints all the register sets of the frame."""
445
446    output = StringIO.StringIO() if string_buffer else sys.stdout
447
448    print >> output, "Register sets for " + repr(frame)
449
450    registerSet = frame.GetRegisters() # Return type of SBValueList.
451    print >> output, "Frame registers (size of register set = %d):" % registerSet.GetSize()
452    for value in registerSet:
453        #print >> output, value
454        print >> output, "%s (number of children = %d):" % (value.GetName(), value.GetNumChildren())
455        for child in value:
456            print >> output, "Name: %s, Value: %s" % (child.GetName(), child.GetValue(frame))
457
458    if string_buffer:
459        return output.getvalue()
460
461def get_registers(frame, kind):
462    """Returns the registers given the frame and the kind of registers desired.
463
464    Returns None if there's no such kind.
465    """
466    registerSet = frame.GetRegisters() # Return type of SBValueList.
467    for value in registerSet:
468        if kind.lower() in value.GetName().lower():
469            return value
470
471    return None
472
473def get_GPRs(frame):
474    """Returns the general purpose registers of the frame as an SBValue.
475
476    The returned SBValue object is iterable.  An example:
477        ...
478        from lldbutil import get_GPRs
479        regs = get_GPRs(frame)
480        for reg in regs:
481            print "%s => %s" % (reg.GetName(), reg.GetValue())
482        ...
483    """
484    return get_registers(frame, "general purpose")
485
486def get_FPRs(frame):
487    """Returns the floating point registers of the frame as an SBValue.
488
489    The returned SBValue object is iterable.  An example:
490        ...
491        from lldbutil import get_FPRs
492        regs = get_FPRs(frame)
493        for reg in regs:
494            print "%s => %s" % (reg.GetName(), reg.GetValue())
495        ...
496    """
497    return get_registers(frame, "floating point")
498
499def get_ESRs(frame):
500    """Returns the exception state registers of the frame as an SBValue.
501
502    The returned SBValue object is iterable.  An example:
503        ...
504        from lldbutil import get_ESRs
505        regs = get_ESRs(frame)
506        for reg in regs:
507            print "%s => %s" % (reg.GetName(), reg.GetValue())
508        ...
509    """
510    return get_registers(frame, "exception state")
511