lldbutil.py revision 4c70f287ea336c4a0c599431bfc2b5a9a618ab5e
1"""
2This LLDB module contains miscellaneous utilities.
3"""
4
5import lldb
6import sys
7import StringIO
8
9# ==========================================================
10# Integer (byte size 1, 2, 4, and 8) to bytearray conversion
11# ==========================================================
12
13def int_to_bytearray(val, bytesize):
14    """Utility function to convert an integer into a bytearray.
15
16    It returns the bytearray in the little endian format.
17    It is easy to get the big endian representation, just do
18    ba.reverse() on the returned bytearray object.
19    """
20    from struct import *
21
22    if bytesize == 1:
23        return bytearray([val])
24
25    # Little endian followed by a format character.
26    template = "<%c"
27    if bytesize == 2:
28        fmt = template % 'h'
29    elif bytesize == 4:
30        fmt = template % 'i'
31    elif bytesize == 4:
32        fmt = template % 'q'
33    else:
34        return None
35
36    packed = pack(fmt, val)
37    return bytearray(map(ord, packed))
38
39def bytearray_to_int(bytes, bytesize):
40    """Utility function to convert a bytearray into an integer.
41
42    It interprets the bytearray in the little endian format.
43    It is easy to get the big endian representation, just do
44    ba.reverse() on the bytearray object before passing it in.
45    """
46    from struct import *
47
48    if bytesize == 1:
49        return ba[0]
50
51    # Little endian followed by a format character.
52    template = "<%c"
53    if bytesize == 2:
54        fmt = template % 'h'
55    elif bytesize == 4:
56        fmt = template % 'i'
57    elif bytesize == 4:
58        fmt = template % 'q'
59    else:
60        return None
61
62    unpacked = unpack(fmt, str(bytes))
63    return unpacked[0]
64
65
66# ===========================================
67# Iterator for lldb aggregate data structures
68# ===========================================
69
70def lldb_iter(obj, getsize, getelem):
71    """A generator adaptor for lldb aggregate data structures.
72
73    API clients pass in an aggregate object or a container of it, the name of
74    the method to get the size of the aggregate, and the name of the method to
75    get the element by index.
76
77    Example usages:
78
79    1. Pass an aggregate as the first argument:
80
81    def disassemble_instructions (insts):
82        from lldbutil import lldb_iter
83        for i in lldb_iter(insts, 'GetSize', 'GetInstructionAtIndex'):
84            print i
85
86    2. Pass a container of aggregate which provides APIs to get to the size and
87       the element of the aggregate:
88
89    # Module is a container of symbol table
90    module = target.FindModule(filespec)
91    for symbol in lldb_iter(module, 'GetNumSymbols', 'GetSymbolAtIndex'):
92        name = symbol.GetName()
93        ...
94    """
95    size = getattr(obj, getsize)
96    elem = getattr(obj, getelem)
97    for i in range(size()):
98        yield elem(i)
99
100
101# =================================================
102# Convert some enum value to its string counterpart
103# =================================================
104
105def StateTypeString(enum):
106    """Returns the stateType string given an enum."""
107    if enum == lldb.eStateInvalid:
108        return "invalid"
109    elif enum == lldb.eStateUnloaded:
110        return "unloaded"
111    elif enum == lldb.eStateAttaching:
112        return "attaching"
113    elif enum == lldb.eStateLaunching:
114        return "launching"
115    elif enum == lldb.eStateStopped:
116        return "stopped"
117    elif enum == lldb.eStateRunning:
118        return "running"
119    elif enum == lldb.eStateStepping:
120        return "stepping"
121    elif enum == lldb.eStateCrashed:
122        return "crashed"
123    elif enum == lldb.eStateDetached:
124        return "detached"
125    elif enum == lldb.eStateExited:
126        return "exited"
127    elif enum == lldb.eStateSuspended:
128        return "suspended"
129    else:
130        raise Exception("Unknown stopReason enum")
131
132def StopReasonString(enum):
133    """Returns the stopReason string given an enum."""
134    if enum == lldb.eStopReasonInvalid:
135        return "invalid"
136    elif enum == lldb.eStopReasonNone:
137        return "none"
138    elif enum == lldb.eStopReasonTrace:
139        return "trace"
140    elif enum == lldb.eStopReasonBreakpoint:
141        return "breakpoint"
142    elif enum == lldb.eStopReasonWatchpoint:
143        return "watchpoint"
144    elif enum == lldb.eStopReasonSignal:
145        return "signal"
146    elif enum == lldb.eStopReasonException:
147        return "exception"
148    elif enum == lldb.eStopReasonPlanComplete:
149        return "plancomplete"
150    else:
151        raise Exception("Unknown stopReason enum")
152
153def ValueTypeString(enum):
154    """Returns the valueType string given an enum."""
155    if enum == lldb.eValueTypeInvalid:
156        return "invalid"
157    elif enum == lldb.eValueTypeVariableGlobal:
158        return "global_variable"
159    elif enum == lldb.eValueTypeVariableStatic:
160        return "static_variable"
161    elif enum == lldb.eValueTypeVariableArgument:
162        return "argument_variable"
163    elif enum == lldb.eValueTypeVariableLocal:
164        return "local_variable"
165    elif enum == lldb.eValueTypeRegister:
166        return "register"
167    elif enum == lldb.eValueTypeRegisterSet:
168        return "register_set"
169    elif enum == lldb.eValueTypeConstResult:
170        return "constant_result"
171    else:
172        raise Exception("Unknown valueType enum")
173
174
175# ==================================================
176# Utility functions related to Threads and Processes
177# ==================================================
178
179def GetFunctionNames(thread):
180    """
181    Returns a sequence of function names from the stack frames of this thread.
182    """
183    def GetFuncName(i):
184        return thread.GetFrameAtIndex(i).GetFunction().GetName()
185
186    return map(GetFuncName, range(thread.GetNumFrames()))
187
188
189def GetSymbolNames(thread):
190    """
191    Returns a sequence of symbols for this thread.
192    """
193    def GetSymbol(i):
194        return thread.GetFrameAtIndex(i).GetSymbol().GetName()
195
196    return map(GetSymbol, range(thread.GetNumFrames()))
197
198
199def GetPCAddresses(thread):
200    """
201    Returns a sequence of pc addresses for this thread.
202    """
203    def GetPCAddress(i):
204        return thread.GetFrameAtIndex(i).GetPCAddress()
205
206    return map(GetPCAddress, range(thread.GetNumFrames()))
207
208
209def GetFilenames(thread):
210    """
211    Returns a sequence of file names from the stack frames of this thread.
212    """
213    def GetFilename(i):
214        return thread.GetFrameAtIndex(i).GetLineEntry().GetFileSpec().GetFilename()
215
216    return map(GetFilename, range(thread.GetNumFrames()))
217
218
219def GetLineNumbers(thread):
220    """
221    Returns a sequence of line numbers from the stack frames of this thread.
222    """
223    def GetLineNumber(i):
224        return thread.GetFrameAtIndex(i).GetLineEntry().GetLine()
225
226    return map(GetLineNumber, range(thread.GetNumFrames()))
227
228
229def GetModuleNames(thread):
230    """
231    Returns a sequence of module names from the stack frames of this thread.
232    """
233    def GetModuleName(i):
234        return thread.GetFrameAtIndex(i).GetModule().GetFileSpec().GetFilename()
235
236    return map(GetModuleName, range(thread.GetNumFrames()))
237
238
239def GetStackFrames(thread):
240    """
241    Returns a sequence of stack frames for this thread.
242    """
243    def GetStackFrame(i):
244        return thread.GetFrameAtIndex(i)
245
246    return map(GetStackFrame, range(thread.GetNumFrames()))
247
248
249def PrintStackTrace(thread, string_buffer = False):
250    """Prints a simple stack trace of this thread."""
251
252    output = StringIO.StringIO() if string_buffer else sys.stdout
253    target = thread.GetProcess().GetTarget()
254
255    depth = thread.GetNumFrames()
256
257    mods = GetModuleNames(thread)
258    funcs = GetFunctionNames(thread)
259    symbols = GetSymbolNames(thread)
260    files = GetFilenames(thread)
261    lines = GetLineNumbers(thread)
262    addrs = GetPCAddresses(thread)
263
264    if thread.GetStopReason() != lldb.eStopReasonInvalid:
265        desc =  "stop reason=" + StopReasonString(thread.GetStopReason())
266    else:
267        desc = ""
268    print >> output, "Stack trace for thread id={0:#x} name={1} queue={2} ".format(
269        thread.GetThreadID(), thread.GetName(), thread.GetQueueName()) + desc
270
271    for i in range(depth):
272        frame = thread.GetFrameAtIndex(i)
273        function = frame.GetFunction()
274
275        load_addr = addrs[i].GetLoadAddress(target)
276        if not function.IsValid():
277            file_addr = addrs[i].GetFileAddress()
278            print >> output, "  frame #{num}: {addr:#016x} {mod}`{symbol} + ????".format(
279                num=i, addr=load_addr, mod=mods[i], symbol=symbols[i])
280        else:
281            print >> output, "  frame #{num}: {addr:#016x} {mod}`{func} at {file}:{line}".format(
282                num=i, addr=load_addr, mod=mods[i], func=funcs[i], file=files[i], line=lines[i])
283
284    if string_buffer:
285        return output.getvalue()
286
287
288def PrintStackTraces(process, string_buffer = False):
289    """Prints the stack traces of all the threads."""
290
291    output = StringIO.StringIO() if string_buffer else sys.stdout
292
293    print >> output, "Stack traces for " + repr(process)
294
295    for i in range(process.GetNumThreads()):
296        print >> output, PrintStackTrace(process.GetThreadAtIndex(i), string_buffer=True)
297
298    if string_buffer:
299        return output.getvalue()
300