• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""
2This LLDB module contains miscellaneous utilities.
3Some of the test suite takes advantage of the utility functions defined here.
4They can also be useful for general purpose lldb scripting.
5"""
6
7import lldb
8import os, sys
9import StringIO
10
11# ===================================================
12# Utilities for locating/checking executable programs
13# ===================================================
14
15def is_exe(fpath):
16    """Returns True if fpath is an executable."""
17    return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
18
19def which(program):
20    """Returns the full path to a program; None otherwise."""
21    fpath, fname = os.path.split(program)
22    if fpath:
23        if is_exe(program):
24            return program
25    else:
26        for path in os.environ["PATH"].split(os.pathsep):
27            exe_file = os.path.join(path, program)
28            if is_exe(exe_file):
29                return exe_file
30    return None
31
32# ===================================================
33# Disassembly for an SBFunction or an SBSymbol object
34# ===================================================
35
36def disassemble(target, function_or_symbol):
37    """Disassemble the function or symbol given a target.
38
39    It returns the disassembly content in a string object.
40    """
41    buf = StringIO.StringIO()
42    insts = function_or_symbol.GetInstructions(target)
43    for i in insts:
44        print >> buf, i
45    return buf.getvalue()
46
47# ==========================================================
48# Integer (byte size 1, 2, 4, and 8) to bytearray conversion
49# ==========================================================
50
51def int_to_bytearray(val, bytesize):
52    """Utility function to convert an integer into a bytearray.
53
54    It returns the bytearray in the little endian format.  It is easy to get the
55    big endian format, just do ba.reverse() on the returned object.
56    """
57    import struct
58
59    if bytesize == 1:
60        return bytearray([val])
61
62    # Little endian followed by a format character.
63    template = "<%c"
64    if bytesize == 2:
65        fmt = template % 'h'
66    elif bytesize == 4:
67        fmt = template % 'i'
68    elif bytesize == 4:
69        fmt = template % 'q'
70    else:
71        return None
72
73    packed = struct.pack(fmt, val)
74    return bytearray(map(ord, packed))
75
76def bytearray_to_int(bytes, bytesize):
77    """Utility function to convert a bytearray into an integer.
78
79    It interprets the bytearray in the little endian format. For a big endian
80    bytearray, just do ba.reverse() on the object before passing it in.
81    """
82    import struct
83
84    if bytesize == 1:
85        return bytes[0]
86
87    # Little endian followed by a format character.
88    template = "<%c"
89    if bytesize == 2:
90        fmt = template % 'h'
91    elif bytesize == 4:
92        fmt = template % 'i'
93    elif bytesize == 4:
94        fmt = template % 'q'
95    else:
96        return None
97
98    unpacked = struct.unpack(fmt, str(bytes))
99    return unpacked[0]
100
101
102# ==============================================================
103# Get the description of an lldb object or None if not available
104# ==============================================================
105def get_description(obj, option=None):
106    """Calls lldb_obj.GetDescription() and returns a string, or None.
107
108    For SBTarget, SBBreakpointLocation, and SBWatchpoint lldb objects, an extra
109    option can be passed in to describe the detailed level of description
110    desired:
111        o lldb.eDescriptionLevelBrief
112        o lldb.eDescriptionLevelFull
113        o lldb.eDescriptionLevelVerbose
114    """
115    method = getattr(obj, 'GetDescription')
116    if not method:
117        return None
118    tuple = (lldb.SBTarget, lldb.SBBreakpointLocation, lldb.SBWatchpoint)
119    if isinstance(obj, tuple):
120        if option is None:
121            option = lldb.eDescriptionLevelBrief
122
123    stream = lldb.SBStream()
124    if option is None:
125        success = method(stream)
126    else:
127        success = method(stream, option)
128    if not success:
129        return None
130    return stream.GetData()
131
132
133# =================================================
134# Convert some enum value to its string counterpart
135# =================================================
136
137def state_type_to_str(enum):
138    """Returns the stateType string given an enum."""
139    if enum == lldb.eStateInvalid:
140        return "invalid"
141    elif enum == lldb.eStateUnloaded:
142        return "unloaded"
143    elif enum == lldb.eStateConnected:
144        return "connected"
145    elif enum == lldb.eStateAttaching:
146        return "attaching"
147    elif enum == lldb.eStateLaunching:
148        return "launching"
149    elif enum == lldb.eStateStopped:
150        return "stopped"
151    elif enum == lldb.eStateRunning:
152        return "running"
153    elif enum == lldb.eStateStepping:
154        return "stepping"
155    elif enum == lldb.eStateCrashed:
156        return "crashed"
157    elif enum == lldb.eStateDetached:
158        return "detached"
159    elif enum == lldb.eStateExited:
160        return "exited"
161    elif enum == lldb.eStateSuspended:
162        return "suspended"
163    else:
164        raise Exception("Unknown StateType enum")
165
166def stop_reason_to_str(enum):
167    """Returns the stopReason string given an enum."""
168    if enum == lldb.eStopReasonInvalid:
169        return "invalid"
170    elif enum == lldb.eStopReasonNone:
171        return "none"
172    elif enum == lldb.eStopReasonTrace:
173        return "trace"
174    elif enum == lldb.eStopReasonBreakpoint:
175        return "breakpoint"
176    elif enum == lldb.eStopReasonWatchpoint:
177        return "watchpoint"
178    elif enum == lldb.eStopReasonSignal:
179        return "signal"
180    elif enum == lldb.eStopReasonException:
181        return "exception"
182    elif enum == lldb.eStopReasonPlanComplete:
183        return "plancomplete"
184    elif enum == lldb.eStopReasonThreadExiting:
185        return "threadexiting"
186    else:
187        raise Exception("Unknown StopReason enum")
188
189def symbol_type_to_str(enum):
190    """Returns the symbolType string given an enum."""
191    if enum == lldb.eSymbolTypeInvalid:
192        return "invalid"
193    elif enum == lldb.eSymbolTypeAbsolute:
194        return "absolute"
195    elif enum == lldb.eSymbolTypeCode:
196        return "code"
197    elif enum == lldb.eSymbolTypeData:
198        return "data"
199    elif enum == lldb.eSymbolTypeTrampoline:
200        return "trampoline"
201    elif enum == lldb.eSymbolTypeRuntime:
202        return "runtime"
203    elif enum == lldb.eSymbolTypeException:
204        return "exception"
205    elif enum == lldb.eSymbolTypeSourceFile:
206        return "sourcefile"
207    elif enum == lldb.eSymbolTypeHeaderFile:
208        return "headerfile"
209    elif enum == lldb.eSymbolTypeObjectFile:
210        return "objectfile"
211    elif enum == lldb.eSymbolTypeCommonBlock:
212        return "commonblock"
213    elif enum == lldb.eSymbolTypeBlock:
214        return "block"
215    elif enum == lldb.eSymbolTypeLocal:
216        return "local"
217    elif enum == lldb.eSymbolTypeParam:
218        return "param"
219    elif enum == lldb.eSymbolTypeVariable:
220        return "variable"
221    elif enum == lldb.eSymbolTypeVariableType:
222        return "variabletype"
223    elif enum == lldb.eSymbolTypeLineEntry:
224        return "lineentry"
225    elif enum == lldb.eSymbolTypeLineHeader:
226        return "lineheader"
227    elif enum == lldb.eSymbolTypeScopeBegin:
228        return "scopebegin"
229    elif enum == lldb.eSymbolTypeScopeEnd:
230        return "scopeend"
231    elif enum == lldb.eSymbolTypeAdditional:
232        return "additional"
233    elif enum == lldb.eSymbolTypeCompiler:
234        return "compiler"
235    elif enum == lldb.eSymbolTypeInstrumentation:
236        return "instrumentation"
237    elif enum == lldb.eSymbolTypeUndefined:
238        return "undefined"
239
240def value_type_to_str(enum):
241    """Returns the valueType string given an enum."""
242    if enum == lldb.eValueTypeInvalid:
243        return "invalid"
244    elif enum == lldb.eValueTypeVariableGlobal:
245        return "global_variable"
246    elif enum == lldb.eValueTypeVariableStatic:
247        return "static_variable"
248    elif enum == lldb.eValueTypeVariableArgument:
249        return "argument_variable"
250    elif enum == lldb.eValueTypeVariableLocal:
251        return "local_variable"
252    elif enum == lldb.eValueTypeRegister:
253        return "register"
254    elif enum == lldb.eValueTypeRegisterSet:
255        return "register_set"
256    elif enum == lldb.eValueTypeConstResult:
257        return "constant_result"
258    else:
259        raise Exception("Unknown ValueType enum")
260
261
262# ==================================================
263# Get stopped threads due to each stop reason.
264# ==================================================
265
266def sort_stopped_threads(process,
267                         breakpoint_threads = None,
268                         crashed_threads = None,
269                         watchpoint_threads = None,
270                         signal_threads = None,
271                         exiting_threads = None,
272                         other_threads = None):
273    """ Fills array *_threads with threads stopped for the corresponding stop
274        reason.
275    """
276    for lst in [breakpoint_threads,
277                watchpoint_threads,
278                signal_threads,
279                exiting_threads,
280                other_threads]:
281        if lst is not None:
282            lst[:] = []
283
284    for thread in process:
285        dispatched = False
286        for (reason, list) in [(lldb.eStopReasonBreakpoint, breakpoint_threads),
287                               (lldb.eStopReasonException, crashed_threads),
288                               (lldb.eStopReasonWatchpoint, watchpoint_threads),
289                               (lldb.eStopReasonSignal, signal_threads),
290                               (lldb.eStopReasonThreadExiting, exiting_threads),
291                               (None, other_threads)]:
292            if not dispatched and list is not None:
293                if thread.GetStopReason() == reason or reason is None:
294                    list.append(thread)
295                    dispatched = True
296
297# ==================================================
298# Utility functions for setting breakpoints
299# ==================================================
300
301def run_break_set_by_file_and_line (test, file_name, line_number, extra_options = None, num_expected_locations = 1, loc_exact=False, module_name=None):
302    """Set a breakpoint by file and line, returning the breakpoint number.
303
304    If extra_options is not None, then we append it to the breakpoint set command.
305
306    If num_expected_locations is -1 we check that we got AT LEAST one location, otherwise we check that num_expected_locations equals the number of locations.
307
308    If loc_exact is true, we check that there is one location, and that location must be at the input file and line number."""
309
310    if file_name == None:
311        command = 'breakpoint set -l %d'%(line_number)
312    else:
313        command = 'breakpoint set -f "%s" -l %d'%(file_name, line_number)
314
315    if module_name:
316        command += " --shlib '%s'" % (module_name)
317
318    if extra_options:
319        command += " " + extra_options
320
321    break_results = run_break_set_command (test, command)
322
323    if num_expected_locations == 1 and loc_exact:
324        check_breakpoint_result (test, break_results, num_locations=num_expected_locations, file_name = file_name, line_number = line_number, module_name=module_name)
325    else:
326        check_breakpoint_result (test, break_results, num_locations = num_expected_locations)
327
328    return get_bpno_from_match (break_results)
329
330def run_break_set_by_symbol (test, symbol, extra_options = None, num_expected_locations = -1, sym_exact = False, module_name=None):
331    """Set a breakpoint by symbol name.  Common options are the same as run_break_set_by_file_and_line.
332
333    If sym_exact is true, then the output symbol must match the input exactly, otherwise we do a substring match."""
334    command = 'breakpoint set -n "%s"'%(symbol)
335
336    if module_name:
337        command += " --shlib '%s'" % (module_name)
338
339    if extra_options:
340        command += " " + extra_options
341
342    break_results = run_break_set_command (test, command)
343
344    if num_expected_locations == 1 and sym_exact:
345        check_breakpoint_result (test, break_results, num_locations = num_expected_locations, symbol_name = symbol, module_name=module_name)
346    else:
347        check_breakpoint_result (test, break_results, num_locations = num_expected_locations)
348
349    return get_bpno_from_match (break_results)
350
351def run_break_set_by_selector (test, selector, extra_options = None, num_expected_locations = -1, module_name=None):
352    """Set a breakpoint by selector.  Common options are the same as run_break_set_by_file_and_line."""
353
354    command = 'breakpoint set -S "%s"' % (selector)
355
356    if module_name:
357        command += ' --shlib "%s"' % (module_name)
358
359    if extra_options:
360        command += " " + extra_options
361
362    break_results = run_break_set_command (test, command)
363
364    if num_expected_locations == 1:
365        check_breakpoint_result (test, break_results, num_locations = num_expected_locations, symbol_name = selector, symbol_match_exact=False, module_name=module_name)
366    else:
367        check_breakpoint_result (test, break_results, num_locations = num_expected_locations)
368
369    return get_bpno_from_match (break_results)
370
371def run_break_set_by_regexp (test, regexp, extra_options=None, num_expected_locations=-1):
372    """Set a breakpoint by regular expression match on symbol name.  Common options are the same as run_break_set_by_file_and_line."""
373
374    command = 'breakpoint set -r "%s"'%(regexp)
375    if extra_options:
376        command += " " + extra_options
377
378    break_results = run_break_set_command (test, command)
379
380    check_breakpoint_result (test, break_results, num_locations=num_expected_locations)
381
382    return get_bpno_from_match (break_results)
383
384def run_break_set_by_source_regexp (test, regexp, extra_options=None, num_expected_locations=-1):
385    """Set a breakpoint by source regular expression.  Common options are the same as run_break_set_by_file_and_line."""
386    command = 'breakpoint set -p "%s"'%(regexp)
387    if extra_options:
388        command += " " + extra_options
389
390    break_results = run_break_set_command (test, command)
391
392    check_breakpoint_result (test, break_results, num_locations=num_expected_locations)
393
394    return get_bpno_from_match (break_results)
395
396def run_break_set_command (test, command):
397    """Run the command passed in - it must be some break set variant - and analyze the result.
398    Returns a dictionary of information gleaned from the command-line results.
399    Will assert if the breakpoint setting fails altogether.
400
401    Dictionary will contain:
402        bpno          - breakpoint of the newly created breakpoint, -1 on error.
403        num_locations - number of locations set for the breakpoint.
404
405    If there is only one location, the dictionary MAY contain:
406        file          - source file name
407        line_no       - source line number
408        symbol        - symbol name
409        inline_symbol - inlined symbol name
410        offset        - offset from the original symbol
411        module        - module
412        address       - address at which the breakpoint was set."""
413
414    patterns = [r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>[0-9]+) locations\.$",
415                r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>no) locations \(pending\)\.",
416                r"^Breakpoint (?P<bpno>[0-9]+): where = (?P<module>.*)`(?P<symbol>[+\-]{0,1}[^+]+)( \+ (?P<offset>[0-9]+)){0,1}( \[inlined\] (?P<inline_symbol>.*)){0,1} at (?P<file>[^:]+):(?P<line_no>[0-9]+), address = (?P<address>0x[0-9a-fA-F]+)$",
417                r"^Breakpoint (?P<bpno>[0-9]+): where = (?P<module>.*)`(?P<symbol>.*)( \+ (?P<offset>[0-9]+)){0,1}, address = (?P<address>0x[0-9a-fA-F]+)$"]
418    match_object = test.match (command, patterns)
419    break_results = match_object.groupdict()
420
421    # We always insert the breakpoint number, setting it to -1 if we couldn't find it
422    # Also, make sure it gets stored as an integer.
423    if not 'bpno' in break_results:
424        break_results['bpno'] = -1
425    else:
426        break_results['bpno'] = int(break_results['bpno'])
427
428    # We always insert the number of locations
429    # If ONE location is set for the breakpoint, then the output doesn't mention locations, but it has to be 1...
430    # We also make sure it is an integer.
431
432    if not 'num_locations' in break_results:
433        num_locations = 1
434    else:
435        num_locations = break_results['num_locations']
436        if num_locations == 'no':
437            num_locations = 0
438        else:
439            num_locations = int(break_results['num_locations'])
440
441    break_results['num_locations'] = num_locations
442
443    if 'line_no' in break_results:
444        break_results['line_no'] = int(break_results['line_no'])
445
446    return break_results
447
448def get_bpno_from_match (break_results):
449    return int (break_results['bpno'])
450
451def check_breakpoint_result (test, break_results, file_name=None, line_number=-1, symbol_name=None, symbol_match_exact=True, module_name=None, offset=-1, num_locations=-1):
452
453    out_num_locations = break_results['num_locations']
454
455    if num_locations == -1:
456        test.assertTrue (out_num_locations > 0, "Expecting one or more locations, got none.")
457    else:
458        test.assertTrue (num_locations == out_num_locations, "Expecting %d locations, got %d."%(num_locations, out_num_locations))
459
460    if file_name:
461        out_file_name = ""
462        if 'file' in break_results:
463            out_file_name = break_results['file']
464        test.assertTrue (file_name == out_file_name, "Breakpoint file name '%s' doesn't match resultant name '%s'."%(file_name, out_file_name))
465
466    if line_number != -1:
467        out_file_line = -1
468        if 'line_no' in break_results:
469            out_line_number = break_results['line_no']
470
471        test.assertTrue (line_number == out_line_number, "Breakpoint line number %s doesn't match resultant line %s."%(line_number, out_line_number))
472
473    if symbol_name:
474        out_symbol_name = ""
475        # Look first for the inlined symbol name, otherwise use the symbol name:
476        if 'inline_symbol' in break_results and break_results['inline_symbol']:
477            out_symbol_name = break_results['inline_symbol']
478        elif 'symbol' in break_results:
479            out_symbol_name = break_results['symbol']
480
481        if symbol_match_exact:
482            test.assertTrue(symbol_name == out_symbol_name, "Symbol name '%s' doesn't match resultant symbol '%s'."%(symbol_name, out_symbol_name))
483        else:
484            test.assertTrue(out_symbol_name.find(symbol_name) != -1, "Symbol name '%s' isn't in resultant symbol '%s'."%(symbol_name, out_symbol_name))
485
486    if module_name:
487        out_nodule_name = None
488        if 'module' in break_results:
489            out_module_name = break_results['module']
490
491        test.assertTrue (module_name.find(out_module_name) != -1, "Symbol module name '%s' isn't in expected module name '%s'."%(out_module_name, module_name))
492
493# ==================================================
494# Utility functions related to Threads and Processes
495# ==================================================
496
497def get_stopped_threads(process, reason):
498    """Returns the thread(s) with the specified stop reason in a list.
499
500    The list can be empty if no such thread exists.
501    """
502    threads = []
503    for t in process:
504        if t.GetStopReason() == reason:
505            threads.append(t)
506    return threads
507
508def get_stopped_thread(process, reason):
509    """A convenience function which returns the first thread with the given stop
510    reason or None.
511
512    Example usages:
513
514    1. Get the stopped thread due to a breakpoint condition
515
516    ...
517        from lldbutil import get_stopped_thread
518        thread = get_stopped_thread(process, lldb.eStopReasonPlanComplete)
519        self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint condition")
520    ...
521
522    2. Get the thread stopped due to a breakpoint
523
524    ...
525        from lldbutil import get_stopped_thread
526        thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint)
527        self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint")
528    ...
529
530    """
531    threads = get_stopped_threads(process, reason)
532    if len(threads) == 0:
533        return None
534    return threads[0]
535
536def get_threads_stopped_at_breakpoint (process, bkpt):
537    """ For a stopped process returns the thread stopped at the breakpoint passed in bkpt"""
538    stopped_threads = []
539    threads = []
540
541    stopped_threads = get_stopped_threads (process, lldb.eStopReasonBreakpoint)
542
543    if len(stopped_threads) == 0:
544        return threads
545
546    for thread in stopped_threads:
547        # Make sure we've hit our breakpoint...
548        break_id = thread.GetStopReasonDataAtIndex (0)
549        if break_id == bkpt.GetID():
550            threads.append(thread)
551
552    return threads
553
554def continue_to_breakpoint (process, bkpt):
555    """ Continues the process, if it stops, returns the threads stopped at bkpt; otherwise, returns None"""
556    process.Continue()
557    if process.GetState() != lldb.eStateStopped:
558        return None
559    else:
560        return get_threads_stopped_at_breakpoint (process, bkpt)
561
562def get_caller_symbol(thread):
563    """
564    Returns the symbol name for the call site of the leaf function.
565    """
566    depth = thread.GetNumFrames()
567    if depth <= 1:
568        return None
569    caller = thread.GetFrameAtIndex(1).GetSymbol()
570    if caller:
571        return caller.GetName()
572    else:
573        return None
574
575
576def get_function_names(thread):
577    """
578    Returns a sequence of function names from the stack frames of this thread.
579    """
580    def GetFuncName(i):
581        return thread.GetFrameAtIndex(i).GetFunctionName()
582
583    return map(GetFuncName, range(thread.GetNumFrames()))
584
585
586def get_symbol_names(thread):
587    """
588    Returns a sequence of symbols for this thread.
589    """
590    def GetSymbol(i):
591        return thread.GetFrameAtIndex(i).GetSymbol().GetName()
592
593    return map(GetSymbol, range(thread.GetNumFrames()))
594
595
596def get_pc_addresses(thread):
597    """
598    Returns a sequence of pc addresses for this thread.
599    """
600    def GetPCAddress(i):
601        return thread.GetFrameAtIndex(i).GetPCAddress()
602
603    return map(GetPCAddress, range(thread.GetNumFrames()))
604
605
606def get_filenames(thread):
607    """
608    Returns a sequence of file names from the stack frames of this thread.
609    """
610    def GetFilename(i):
611        return thread.GetFrameAtIndex(i).GetLineEntry().GetFileSpec().GetFilename()
612
613    return map(GetFilename, range(thread.GetNumFrames()))
614
615
616def get_line_numbers(thread):
617    """
618    Returns a sequence of line numbers from the stack frames of this thread.
619    """
620    def GetLineNumber(i):
621        return thread.GetFrameAtIndex(i).GetLineEntry().GetLine()
622
623    return map(GetLineNumber, range(thread.GetNumFrames()))
624
625
626def get_module_names(thread):
627    """
628    Returns a sequence of module names from the stack frames of this thread.
629    """
630    def GetModuleName(i):
631        return thread.GetFrameAtIndex(i).GetModule().GetFileSpec().GetFilename()
632
633    return map(GetModuleName, range(thread.GetNumFrames()))
634
635
636def get_stack_frames(thread):
637    """
638    Returns a sequence of stack frames for this thread.
639    """
640    def GetStackFrame(i):
641        return thread.GetFrameAtIndex(i)
642
643    return map(GetStackFrame, range(thread.GetNumFrames()))
644
645
646def print_stacktrace(thread, string_buffer = False):
647    """Prints a simple stack trace of this thread."""
648
649    output = StringIO.StringIO() if string_buffer else sys.stdout
650    target = thread.GetProcess().GetTarget()
651
652    depth = thread.GetNumFrames()
653
654    mods = get_module_names(thread)
655    funcs = get_function_names(thread)
656    symbols = get_symbol_names(thread)
657    files = get_filenames(thread)
658    lines = get_line_numbers(thread)
659    addrs = get_pc_addresses(thread)
660
661    if thread.GetStopReason() != lldb.eStopReasonInvalid:
662        desc =  "stop reason=" + stop_reason_to_str(thread.GetStopReason())
663    else:
664        desc = ""
665    print >> output, "Stack trace for thread id={0:#x} name={1} queue={2} ".format(
666        thread.GetThreadID(), thread.GetName(), thread.GetQueueName()) + desc
667
668    for i in range(depth):
669        frame = thread.GetFrameAtIndex(i)
670        function = frame.GetFunction()
671
672        load_addr = addrs[i].GetLoadAddress(target)
673        if not function:
674            file_addr = addrs[i].GetFileAddress()
675            start_addr = frame.GetSymbol().GetStartAddress().GetFileAddress()
676            symbol_offset = file_addr - start_addr
677            print >> output, "  frame #{num}: {addr:#016x} {mod}`{symbol} + {offset}".format(
678                num=i, addr=load_addr, mod=mods[i], symbol=symbols[i], offset=symbol_offset)
679        else:
680            print >> output, "  frame #{num}: {addr:#016x} {mod}`{func} at {file}:{line} {args}".format(
681                num=i, addr=load_addr, mod=mods[i],
682                func='%s [inlined]' % funcs[i] if frame.IsInlined() else funcs[i],
683                file=files[i], line=lines[i],
684                args=get_args_as_string(frame, showFuncName=False) if not frame.IsInlined() else '()')
685
686    if string_buffer:
687        return output.getvalue()
688
689
690def print_stacktraces(process, string_buffer = False):
691    """Prints the stack traces of all the threads."""
692
693    output = StringIO.StringIO() if string_buffer else sys.stdout
694
695    print >> output, "Stack traces for " + str(process)
696
697    for thread in process:
698        print >> output, print_stacktrace(thread, string_buffer=True)
699
700    if string_buffer:
701        return output.getvalue()
702
703# ===================================
704# Utility functions related to Frames
705# ===================================
706
707def get_parent_frame(frame):
708    """
709    Returns the parent frame of the input frame object; None if not available.
710    """
711    thread = frame.GetThread()
712    parent_found = False
713    for f in thread:
714        if parent_found:
715            return f
716        if f.GetFrameID() == frame.GetFrameID():
717            parent_found = True
718
719    # If we reach here, no parent has been found, return None.
720    return None
721
722def get_args_as_string(frame, showFuncName=True):
723    """
724    Returns the args of the input frame object as a string.
725    """
726    # arguments     => True
727    # locals        => False
728    # statics       => False
729    # in_scope_only => True
730    vars = frame.GetVariables(True, False, False, True) # type of SBValueList
731    args = [] # list of strings
732    for var in vars:
733        args.append("(%s)%s=%s" % (var.GetTypeName(),
734                                   var.GetName(),
735                                   var.GetValue()))
736    if frame.GetFunction():
737        name = frame.GetFunction().GetName()
738    elif frame.GetSymbol():
739        name = frame.GetSymbol().GetName()
740    else:
741        name = ""
742    if showFuncName:
743        return "%s(%s)" % (name, ", ".join(args))
744    else:
745        return "(%s)" % (", ".join(args))
746
747def print_registers(frame, string_buffer = False):
748    """Prints all the register sets of the frame."""
749
750    output = StringIO.StringIO() if string_buffer else sys.stdout
751
752    print >> output, "Register sets for " + str(frame)
753
754    registerSet = frame.GetRegisters() # Return type of SBValueList.
755    print >> output, "Frame registers (size of register set = %d):" % registerSet.GetSize()
756    for value in registerSet:
757        #print >> output, value
758        print >> output, "%s (number of children = %d):" % (value.GetName(), value.GetNumChildren())
759        for child in value:
760            print >> output, "Name: %s, Value: %s" % (child.GetName(), child.GetValue())
761
762    if string_buffer:
763        return output.getvalue()
764
765def get_registers(frame, kind):
766    """Returns the registers given the frame and the kind of registers desired.
767
768    Returns None if there's no such kind.
769    """
770    registerSet = frame.GetRegisters() # Return type of SBValueList.
771    for value in registerSet:
772        if kind.lower() in value.GetName().lower():
773            return value
774
775    return None
776
777def get_GPRs(frame):
778    """Returns the general purpose registers of the frame as an SBValue.
779
780    The returned SBValue object is iterable.  An example:
781        ...
782        from lldbutil import get_GPRs
783        regs = get_GPRs(frame)
784        for reg in regs:
785            print "%s => %s" % (reg.GetName(), reg.GetValue())
786        ...
787    """
788    return get_registers(frame, "general purpose")
789
790def get_FPRs(frame):
791    """Returns the floating point registers of the frame as an SBValue.
792
793    The returned SBValue object is iterable.  An example:
794        ...
795        from lldbutil import get_FPRs
796        regs = get_FPRs(frame)
797        for reg in regs:
798            print "%s => %s" % (reg.GetName(), reg.GetValue())
799        ...
800    """
801    return get_registers(frame, "floating point")
802
803def get_ESRs(frame):
804    """Returns the exception state registers of the frame as an SBValue.
805
806    The returned SBValue object is iterable.  An example:
807        ...
808        from lldbutil import get_ESRs
809        regs = get_ESRs(frame)
810        for reg in regs:
811            print "%s => %s" % (reg.GetName(), reg.GetValue())
812        ...
813    """
814    return get_registers(frame, "exception state")
815
816# ======================================
817# Utility classes/functions for SBValues
818# ======================================
819
820class BasicFormatter(object):
821    """The basic formatter inspects the value object and prints the value."""
822    def format(self, value, buffer=None, indent=0):
823        if not buffer:
824            output = StringIO.StringIO()
825        else:
826            output = buffer
827        # If there is a summary, it suffices.
828        val = value.GetSummary()
829        # Otherwise, get the value.
830        if val == None:
831            val = value.GetValue()
832        if val == None and value.GetNumChildren() > 0:
833            val = "%s (location)" % value.GetLocation()
834        print >> output, "{indentation}({type}) {name} = {value}".format(
835            indentation = ' ' * indent,
836            type = value.GetTypeName(),
837            name = value.GetName(),
838            value = val)
839        return output.getvalue()
840
841class ChildVisitingFormatter(BasicFormatter):
842    """The child visiting formatter prints the value and its immediate children.
843
844    The constructor takes a keyword arg: indent_child, which defaults to 2.
845    """
846    def __init__(self, indent_child=2):
847        """Default indentation of 2 SPC's for the children."""
848        self.cindent = indent_child
849    def format(self, value, buffer=None):
850        if not buffer:
851            output = StringIO.StringIO()
852        else:
853            output = buffer
854
855        BasicFormatter.format(self, value, buffer=output)
856        for child in value:
857            BasicFormatter.format(self, child, buffer=output, indent=self.cindent)
858
859        return output.getvalue()
860
861class RecursiveDecentFormatter(BasicFormatter):
862    """The recursive decent formatter prints the value and the decendents.
863
864    The constructor takes two keyword args: indent_level, which defaults to 0,
865    and indent_child, which defaults to 2.  The current indentation level is
866    determined by indent_level, while the immediate children has an additional
867    indentation by inden_child.
868    """
869    def __init__(self, indent_level=0, indent_child=2):
870        self.lindent = indent_level
871        self.cindent = indent_child
872    def format(self, value, buffer=None):
873        if not buffer:
874            output = StringIO.StringIO()
875        else:
876            output = buffer
877
878        BasicFormatter.format(self, value, buffer=output, indent=self.lindent)
879        new_indent = self.lindent + self.cindent
880        for child in value:
881            if child.GetSummary() != None:
882                BasicFormatter.format(self, child, buffer=output, indent=new_indent)
883            else:
884                if child.GetNumChildren() > 0:
885                    rdf = RecursiveDecentFormatter(indent_level=new_indent)
886                    rdf.format(child, buffer=output)
887                else:
888                    BasicFormatter.format(self, child, buffer=output, indent=new_indent)
889
890        return output.getvalue()
891