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