brintos

brintos / llvm-project-archived public Read only

0
0
Text · 32.6 KiB · 589acae Raw
1074 lines · python
1##===-- lldbutil.py ------------------------------------------*- Python -*-===##2##3# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4# See https://llvm.org/LICENSE.txt for license information.5# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6##7##===----------------------------------------------------------------------===##8 9"""10This LLDB module contains miscellaneous utilities.11Some of the test suite takes advantage of the utility functions defined here.12They can also be useful for general purpose lldb scripting.13"""14 15import lldb16import os17import sys18import io19 20# ===================================================21# Utilities for locating/checking executable programs22# ===================================================23 24 25def is_exe(fpath):26    """Returns True if fpath is an executable."""27    return os.path.isfile(fpath) and os.access(fpath, os.X_OK)28 29 30def which(program):31    """Returns the full path to a program; None otherwise."""32    fpath, fname = os.path.split(program)33    if fpath:34        if is_exe(program):35            return program36    else:37        for path in os.environ["PATH"].split(os.pathsep):38            exe_file = os.path.join(path, program)39            if is_exe(exe_file):40                return exe_file41    return None42 43 44# ===================================================45# Disassembly for an SBFunction or an SBSymbol object46# ===================================================47 48 49def disassemble(target, function_or_symbol):50    """Disassemble the function or symbol given a target.51 52    It returns the disassembly content in a string object.53    """54    buf = io.StringIO()55    insts = function_or_symbol.GetInstructions(target)56    for i in insts:57        print(i, file=buf)58    return buf.getvalue()59 60 61# ==========================================================62# Integer (byte size 1, 2, 4, and 8) to bytearray conversion63# ==========================================================64 65 66def int_to_bytearray(val, bytesize):67    """Utility function to convert an integer into a bytearray.68 69    It returns the bytearray in the little endian format.  It is easy to get the70    big endian format, just do ba.reverse() on the returned object.71    """72    import struct73 74    if bytesize == 1:75        return bytearray([val])76 77    # Little endian followed by a format character.78    template = "<%c"79    if bytesize == 2:80        fmt = template % "h"81    elif bytesize == 4:82        fmt = template % "i"83    elif bytesize == 4:84        fmt = template % "q"85    else:86        return None87 88    packed = struct.pack(fmt, val)89    return bytearray(ord(x) for x in packed)90 91 92def bytearray_to_int(bytes, bytesize):93    """Utility function to convert a bytearray into an integer.94 95    It interprets the bytearray in the little endian format. For a big endian96    bytearray, just do ba.reverse() on the object before passing it in.97    """98    import struct99 100    if bytesize == 1:101        return bytes[0]102 103    # Little endian followed by a format character.104    template = "<%c"105    if bytesize == 2:106        fmt = template % "h"107    elif bytesize == 4:108        fmt = template % "i"109    elif bytesize == 4:110        fmt = template % "q"111    else:112        return None113 114    unpacked = struct.unpack(fmt, str(bytes))115    return unpacked[0]116 117 118# ==============================================================119# Get the description of an lldb object or None if not available120# ==============================================================121def get_description(obj, option=None):122    """Calls lldb_obj.GetDescription() and returns a string, or None.123 124    For SBTarget, SBBreakpointLocation, and SBWatchpoint lldb objects, an extra125    option can be passed in to describe the detailed level of description126    desired:127        o lldb.eDescriptionLevelBrief128        o lldb.eDescriptionLevelFull129        o lldb.eDescriptionLevelVerbose130    """131    method = getattr(obj, "GetDescription")132    if not method:133        return None134    tuple = (lldb.SBTarget, lldb.SBBreakpointLocation, lldb.SBWatchpoint)135    if isinstance(obj, tuple):136        if option is None:137            option = lldb.eDescriptionLevelBrief138 139    stream = lldb.SBStream()140    if option is None:141        success = method(stream)142    else:143        success = method(stream, option)144    if not success:145        return None146    return stream.GetData()147 148 149# =================================================150# Convert some enum value to its string counterpart151# =================================================152 153 154def state_type_to_str(enum):155    """Returns the stateType string given an enum."""156    if enum == lldb.eStateInvalid:157        return "invalid"158    elif enum == lldb.eStateUnloaded:159        return "unloaded"160    elif enum == lldb.eStateConnected:161        return "connected"162    elif enum == lldb.eStateAttaching:163        return "attaching"164    elif enum == lldb.eStateLaunching:165        return "launching"166    elif enum == lldb.eStateStopped:167        return "stopped"168    elif enum == lldb.eStateRunning:169        return "running"170    elif enum == lldb.eStateStepping:171        return "stepping"172    elif enum == lldb.eStateCrashed:173        return "crashed"174    elif enum == lldb.eStateDetached:175        return "detached"176    elif enum == lldb.eStateExited:177        return "exited"178    elif enum == lldb.eStateSuspended:179        return "suspended"180    else:181        raise Exception("Unknown StateType enum")182 183 184def stop_reason_to_str(enum):185    """Returns the stopReason string given an enum."""186    if enum == lldb.eStopReasonInvalid:187        return "invalid"188    elif enum == lldb.eStopReasonNone:189        return "none"190    elif enum == lldb.eStopReasonTrace:191        return "trace"192    elif enum == lldb.eStopReasonBreakpoint:193        return "breakpoint"194    elif enum == lldb.eStopReasonWatchpoint:195        return "watchpoint"196    elif enum == lldb.eStopReasonSignal:197        return "signal"198    elif enum == lldb.eStopReasonException:199        return "exception"200    elif enum == lldb.eStopReasonPlanComplete:201        return "plancomplete"202    elif enum == lldb.eStopReasonThreadExiting:203        return "threadexiting"204    else:205        raise Exception("Unknown StopReason enum")206 207 208def symbol_type_to_str(enum):209    """Returns the symbolType string given an enum."""210    if enum == lldb.eSymbolTypeInvalid:211        return "invalid"212    elif enum == lldb.eSymbolTypeAbsolute:213        return "absolute"214    elif enum == lldb.eSymbolTypeCode:215        return "code"216    elif enum == lldb.eSymbolTypeData:217        return "data"218    elif enum == lldb.eSymbolTypeTrampoline:219        return "trampoline"220    elif enum == lldb.eSymbolTypeRuntime:221        return "runtime"222    elif enum == lldb.eSymbolTypeException:223        return "exception"224    elif enum == lldb.eSymbolTypeSourceFile:225        return "sourcefile"226    elif enum == lldb.eSymbolTypeHeaderFile:227        return "headerfile"228    elif enum == lldb.eSymbolTypeObjectFile:229        return "objectfile"230    elif enum == lldb.eSymbolTypeCommonBlock:231        return "commonblock"232    elif enum == lldb.eSymbolTypeBlock:233        return "block"234    elif enum == lldb.eSymbolTypeLocal:235        return "local"236    elif enum == lldb.eSymbolTypeParam:237        return "param"238    elif enum == lldb.eSymbolTypeVariable:239        return "variable"240    elif enum == lldb.eSymbolTypeVariableType:241        return "variabletype"242    elif enum == lldb.eSymbolTypeLineEntry:243        return "lineentry"244    elif enum == lldb.eSymbolTypeLineHeader:245        return "lineheader"246    elif enum == lldb.eSymbolTypeScopeBegin:247        return "scopebegin"248    elif enum == lldb.eSymbolTypeScopeEnd:249        return "scopeend"250    elif enum == lldb.eSymbolTypeAdditional:251        return "additional"252    elif enum == lldb.eSymbolTypeCompiler:253        return "compiler"254    elif enum == lldb.eSymbolTypeInstrumentation:255        return "instrumentation"256    elif enum == lldb.eSymbolTypeUndefined:257        return "undefined"258 259 260def value_type_to_str(enum):261    """Returns the valueType string given an enum."""262    if enum == lldb.eValueTypeInvalid:263        return "invalid"264    elif enum == lldb.eValueTypeVariableGlobal:265        return "global_variable"266    elif enum == lldb.eValueTypeVariableStatic:267        return "static_variable"268    elif enum == lldb.eValueTypeVariableArgument:269        return "argument_variable"270    elif enum == lldb.eValueTypeVariableLocal:271        return "local_variable"272    elif enum == lldb.eValueTypeRegister:273        return "register"274    elif enum == lldb.eValueTypeRegisterSet:275        return "register_set"276    elif enum == lldb.eValueTypeConstResult:277        return "constant_result"278    else:279        raise Exception("Unknown ValueType enum")280 281 282# ==================================================283# Get stopped threads due to each stop reason.284# ==================================================285 286 287def sort_stopped_threads(288    process,289    breakpoint_threads=None,290    crashed_threads=None,291    watchpoint_threads=None,292    signal_threads=None,293    exiting_threads=None,294    other_threads=None,295):296    """Fills array *_threads with threads stopped for the corresponding stop297    reason.298    """299    for lst in [300        breakpoint_threads,301        watchpoint_threads,302        signal_threads,303        exiting_threads,304        other_threads,305    ]:306        if lst is not None:307            lst[:] = []308 309    for thread in process:310        dispatched = False311        for reason, list in [312            (lldb.eStopReasonBreakpoint, breakpoint_threads),313            (lldb.eStopReasonException, crashed_threads),314            (lldb.eStopReasonWatchpoint, watchpoint_threads),315            (lldb.eStopReasonSignal, signal_threads),316            (lldb.eStopReasonThreadExiting, exiting_threads),317            (None, other_threads),318        ]:319            if not dispatched and list is not None:320                if thread.GetStopReason() == reason or reason is None:321                    list.append(thread)322                    dispatched = True323 324 325# ==================================================326# Utility functions for setting breakpoints327# ==================================================328 329 330def run_break_set_by_file_and_line(331    test,332    file_name,333    line_number,334    extra_options=None,335    num_expected_locations=1,336    loc_exact=False,337    module_name=None,338):339    """Set a breakpoint by file and line, returning the breakpoint number.340 341    If extra_options is not None, then we append it to the breakpoint set command.342 343    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.344 345    If loc_exact is true, we check that there is one location, and that location must be at the input file and line number.346    """347 348    if file_name is None:349        command = "breakpoint set -l %d" % (line_number)350    else:351        command = 'breakpoint set -f "%s" -l %d' % (file_name, line_number)352 353    if module_name:354        command += " --shlib '%s'" % (module_name)355 356    if extra_options:357        command += " " + extra_options358 359    break_results = run_break_set_command(test, command)360 361    if num_expected_locations == 1 and loc_exact:362        check_breakpoint_result(363            test,364            break_results,365            num_locations=num_expected_locations,366            file_name=file_name,367            line_number=line_number,368            module_name=module_name,369        )370    else:371        check_breakpoint_result(372            test, break_results, num_locations=num_expected_locations373        )374 375    return get_bpno_from_match(break_results)376 377 378def run_break_set_by_symbol(379    test,380    symbol,381    extra_options=None,382    num_expected_locations=-1,383    sym_exact=False,384    module_name=None,385):386    """Set a breakpoint by symbol name.  Common options are the same as run_break_set_by_file_and_line.387 388    If sym_exact is true, then the output symbol must match the input exactly, otherwise we do a substring match.389    """390    command = 'breakpoint set -n "%s"' % (symbol)391 392    if module_name:393        command += " --shlib '%s'" % (module_name)394 395    if extra_options:396        command += " " + extra_options397 398    break_results = run_break_set_command(test, command)399 400    if num_expected_locations == 1 and sym_exact:401        check_breakpoint_result(402            test,403            break_results,404            num_locations=num_expected_locations,405            symbol_name=symbol,406            module_name=module_name,407        )408    else:409        check_breakpoint_result(410            test, break_results, num_locations=num_expected_locations411        )412 413    return get_bpno_from_match(break_results)414 415 416def run_break_set_by_selector(417    test, selector, extra_options=None, num_expected_locations=-1, module_name=None418):419    """Set a breakpoint by selector.  Common options are the same as run_break_set_by_file_and_line."""420 421    command = 'breakpoint set -S "%s"' % (selector)422 423    if module_name:424        command += ' --shlib "%s"' % (module_name)425 426    if extra_options:427        command += " " + extra_options428 429    break_results = run_break_set_command(test, command)430 431    if num_expected_locations == 1:432        check_breakpoint_result(433            test,434            break_results,435            num_locations=num_expected_locations,436            symbol_name=selector,437            symbol_match_exact=False,438            module_name=module_name,439        )440    else:441        check_breakpoint_result(442            test, break_results, num_locations=num_expected_locations443        )444 445    return get_bpno_from_match(break_results)446 447 448def run_break_set_by_regexp(449    test, regexp, extra_options=None, num_expected_locations=-1450):451    """Set a breakpoint by regular expression match on symbol name.  Common options are the same as run_break_set_by_file_and_line."""452 453    command = 'breakpoint set -r "%s"' % (regexp)454    if extra_options:455        command += " " + extra_options456 457    break_results = run_break_set_command(test, command)458 459    check_breakpoint_result(test, break_results, num_locations=num_expected_locations)460 461    return get_bpno_from_match(break_results)462 463 464def run_break_set_by_source_regexp(465    test, regexp, extra_options=None, num_expected_locations=-1466):467    """Set a breakpoint by source regular expression.  Common options are the same as run_break_set_by_file_and_line."""468    command = 'breakpoint set -p "%s"' % (regexp)469    if extra_options:470        command += " " + extra_options471 472    break_results = run_break_set_command(test, command)473 474    check_breakpoint_result(test, break_results, num_locations=num_expected_locations)475 476    return get_bpno_from_match(break_results)477 478 479def run_break_set_command(test, command):480    """Run the command passed in - it must be some break set variant - and analyze the result.481    Returns a dictionary of information gleaned from the command-line results.482    Will assert if the breakpoint setting fails altogether.483 484    Dictionary will contain:485        bpno          - breakpoint of the newly created breakpoint, -1 on error.486        num_locations - number of locations set for the breakpoint.487 488    If there is only one location, the dictionary MAY contain:489        file          - source file name490        line_no       - source line number491        symbol        - symbol name492        inline_symbol - inlined symbol name493        offset        - offset from the original symbol494        module        - module495        address       - address at which the breakpoint was set."""496 497    patterns = [498        r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>[0-9]+) locations\.$",499        r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>no) locations \(pending\)\.",500        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]+)$",501        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]+)$",502    ]503    match_object = test.match(command, patterns)504    break_results = match_object.groupdict()505 506    # We always insert the breakpoint number, setting it to -1 if we couldn't find it507    # Also, make sure it gets stored as an integer.508    if not "bpno" in break_results:509        break_results["bpno"] = -1510    else:511        break_results["bpno"] = int(break_results["bpno"])512 513    # We always insert the number of locations514    # If ONE location is set for the breakpoint, then the output doesn't mention locations, but it has to be 1...515    # We also make sure it is an integer.516 517    if not "num_locations" in break_results:518        num_locations = 1519    else:520        num_locations = break_results["num_locations"]521        if num_locations == "no":522            num_locations = 0523        else:524            num_locations = int(break_results["num_locations"])525 526    break_results["num_locations"] = num_locations527 528    if "line_no" in break_results:529        break_results["line_no"] = int(break_results["line_no"])530 531    return break_results532 533 534def get_bpno_from_match(break_results):535    return int(break_results["bpno"])536 537 538def check_breakpoint_result(539    test,540    break_results,541    file_name=None,542    line_number=-1,543    symbol_name=None,544    symbol_match_exact=True,545    module_name=None,546    offset=-1,547    num_locations=-1,548):549    out_num_locations = break_results["num_locations"]550 551    if num_locations == -1:552        test.assertTrue(553            out_num_locations > 0, "Expecting one or more locations, got none."554        )555    else:556        test.assertTrue(557            num_locations == out_num_locations,558            "Expecting %d locations, got %d." % (num_locations, out_num_locations),559        )560 561    if file_name:562        out_file_name = ""563        if "file" in break_results:564            out_file_name = break_results["file"]565        test.assertTrue(566            file_name == out_file_name,567            "Breakpoint file name '%s' doesn't match resultant name '%s'."568            % (file_name, out_file_name),569        )570 571    if line_number != -1:572        out_file_line = -1573        if "line_no" in break_results:574            out_line_number = break_results["line_no"]575 576        test.assertTrue(577            line_number == out_line_number,578            "Breakpoint line number %s doesn't match resultant line %s."579            % (line_number, out_line_number),580        )581 582    if symbol_name:583        out_symbol_name = ""584        # Look first for the inlined symbol name, otherwise use the symbol585        # name:586        if "inline_symbol" in break_results and break_results["inline_symbol"]:587            out_symbol_name = break_results["inline_symbol"]588        elif "symbol" in break_results:589            out_symbol_name = break_results["symbol"]590 591        if symbol_match_exact:592            test.assertTrue(593                symbol_name == out_symbol_name,594                "Symbol name '%s' doesn't match resultant symbol '%s'."595                % (symbol_name, out_symbol_name),596            )597        else:598            test.assertTrue(599                out_symbol_name.find(symbol_name) != -1,600                "Symbol name '%s' isn't in resultant symbol '%s'."601                % (symbol_name, out_symbol_name),602            )603 604    if module_name:605        out_nodule_name = None606        if "module" in break_results:607            out_module_name = break_results["module"]608 609        test.assertTrue(610            module_name.find(out_module_name) != -1,611            "Symbol module name '%s' isn't in expected module name '%s'."612            % (out_module_name, module_name),613        )614 615 616# ==================================================617# Utility functions related to Threads and Processes618# ==================================================619 620 621def get_stopped_threads(process, reason):622    """Returns the thread(s) with the specified stop reason in a list.623 624    The list can be empty if no such thread exists.625    """626    threads = []627    for t in process:628        if t.GetStopReason() == reason:629            threads.append(t)630    return threads631 632 633def get_stopped_thread(process, reason):634    """A convenience function which returns the first thread with the given stop635    reason or None.636 637    Example usages:638 639    1. Get the stopped thread due to a breakpoint condition640 641    ...642        from lldbutil import get_stopped_thread643        thread = get_stopped_thread(process, lldb.eStopReasonPlanComplete)644        self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint condition")645    ...646 647    2. Get the thread stopped due to a breakpoint648 649    ...650        from lldbutil import get_stopped_thread651        thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint)652        self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint")653    ...654 655    """656    threads = get_stopped_threads(process, reason)657    if len(threads) == 0:658        return None659    return threads[0]660 661 662def get_threads_stopped_at_breakpoint(process, bkpt):663    """For a stopped process returns the thread stopped at the breakpoint passed in bkpt"""664    stopped_threads = []665    threads = []666 667    stopped_threads = get_stopped_threads(process, lldb.eStopReasonBreakpoint)668 669    if len(stopped_threads) == 0:670        return threads671 672    for thread in stopped_threads:673        # Make sure we've hit our breakpoint...674        break_id = thread.GetStopReasonDataAtIndex(0)675        if break_id == bkpt.GetID():676            threads.append(thread)677 678    return threads679 680 681def continue_to_breakpoint(process, bkpt):682    """Continues the process, if it stops, returns the threads stopped at bkpt; otherwise, returns None"""683    process.Continue()684    if process.GetState() != lldb.eStateStopped:685        return None686    else:687        return get_threads_stopped_at_breakpoint(process, bkpt)688 689 690def get_caller_symbol(thread):691    """692    Returns the symbol name for the call site of the leaf function.693    """694    depth = thread.GetNumFrames()695    if depth <= 1:696        return None697    caller = thread.GetFrameAtIndex(1).GetSymbol()698    if caller:699        return caller.GetName()700    else:701        return None702 703 704def get_function_names(thread):705    """706    Returns a sequence of function names from the stack frames of this thread.707    """708 709    def GetFuncName(i):710        return thread.GetFrameAtIndex(i).GetFunctionName()711 712    return [GetFuncName(i) for i in range(thread.GetNumFrames())]713 714 715def get_symbol_names(thread):716    """717    Returns a sequence of symbols for this thread.718    """719 720    def GetSymbol(i):721        return thread.GetFrameAtIndex(i).GetSymbol().GetName()722 723    return [GetSymbol(i) for i in range(thread.GetNumFrames())]724 725 726def get_pc_addresses(thread):727    """728    Returns a sequence of pc addresses for this thread.729    """730 731    def GetPCAddress(i):732        return thread.GetFrameAtIndex(i).GetPCAddress()733 734    return [GetPCAddress(i) for i in range(thread.GetNumFrames())]735 736 737def get_filenames(thread):738    """739    Returns a sequence of file names from the stack frames of this thread.740    """741 742    def GetFilename(i):743        return thread.GetFrameAtIndex(i).GetLineEntry().GetFileSpec().GetFilename()744 745    return [GetFilename(i) for i in range(thread.GetNumFrames())]746 747 748def get_line_numbers(thread):749    """750    Returns a sequence of line numbers from the stack frames of this thread.751    """752 753    def GetLineNumber(i):754        return thread.GetFrameAtIndex(i).GetLineEntry().GetLine()755 756    return [GetLineNumber(i) for i in range(thread.GetNumFrames())]757 758 759def get_module_names(thread):760    """761    Returns a sequence of module names from the stack frames of this thread.762    """763 764    def GetModuleName(i):765        return thread.GetFrameAtIndex(i).GetModule().GetFileSpec().GetFilename()766 767    return [GetModuleName(i) for i in range(thread.GetNumFrames())]768 769 770def get_stack_frames(thread):771    """772    Returns a sequence of stack frames for this thread.773    """774 775    def GetStackFrame(i):776        return thread.GetFrameAtIndex(i)777 778    return [GetStackFrame(i) for i in range(thread.GetNumFrames())]779 780 781def print_stacktrace(thread, string_buffer=False):782    """Prints a simple stack trace of this thread."""783 784    output = io.StringIO() if string_buffer else sys.stdout785    target = thread.GetProcess().GetTarget()786 787    depth = thread.GetNumFrames()788 789    mods = get_module_names(thread)790    funcs = get_function_names(thread)791    symbols = get_symbol_names(thread)792    files = get_filenames(thread)793    lines = get_line_numbers(thread)794    addrs = get_pc_addresses(thread)795 796    if thread.GetStopReason() != lldb.eStopReasonInvalid:797        desc = "stop reason=" + stop_reason_to_str(thread.GetStopReason())798    else:799        desc = ""800    print(801        "Stack trace for thread id={0:#x} name={1} queue={2} ".format(802            thread.GetThreadID(), thread.GetName(), thread.GetQueueName()803        )804        + desc,805        file=output,806    )807 808    for i in range(depth):809        frame = thread.GetFrameAtIndex(i)810        function = frame.GetFunction()811 812        load_addr = addrs[i].GetLoadAddress(target)813        if not function:814            file_addr = addrs[i].GetFileAddress()815            start_addr = frame.GetSymbol().GetStartAddress().GetFileAddress()816            symbol_offset = file_addr - start_addr817            print(818                "  frame #{num}: {addr:#016x} {mod}`{symbol} + {offset}".format(819                    num=i,820                    addr=load_addr,821                    mod=mods[i],822                    symbol=symbols[i],823                    offset=symbol_offset,824                ),825                file=output,826            )827        else:828            print(829                "  frame #{num}: {addr:#016x} {mod}`{func} at {file}:{line} {args}".format(830                    num=i,831                    addr=load_addr,832                    mod=mods[i],833                    func="%s [inlined]" % funcs[i] if frame.IsInlined() else funcs[i],834                    file=files[i],835                    line=lines[i],836                    args=get_args_as_string(frame, showFuncName=False)837                    if not frame.IsInlined()838                    else "()",839                ),840                file=output,841            )842 843    if string_buffer:844        return output.getvalue()845 846 847def print_stacktraces(process, string_buffer=False):848    """Prints the stack traces of all the threads."""849 850    output = io.StringIO() if string_buffer else sys.stdout851 852    print("Stack traces for " + str(process), file=output)853 854    for thread in process:855        print(print_stacktrace(thread, string_buffer=True), file=output)856 857    if string_buffer:858        return output.getvalue()859 860 861# ===================================862# Utility functions related to Frames863# ===================================864 865 866def get_parent_frame(frame):867    """868    Returns the parent frame of the input frame object; None if not available.869    """870    thread = frame.GetThread()871    parent_found = False872    for f in thread:873        if parent_found:874            return f875        if f.GetFrameID() == frame.GetFrameID():876            parent_found = True877 878    # If we reach here, no parent has been found, return None.879    return None880 881 882def get_args_as_string(frame, showFuncName=True):883    """884    Returns the args of the input frame object as a string.885    """886    # arguments     => True887    # locals        => False888    # statics       => False889    # in_scope_only => True890    vars = frame.GetVariables(True, False, False, True)  # type of SBValueList891    args = []  # list of strings892    for var in vars:893        args.append("(%s)%s=%s" % (var.GetTypeName(), var.GetName(), var.GetValue()))894    if frame.GetFunction():895        name = frame.GetFunction().GetName()896    elif frame.GetSymbol():897        name = frame.GetSymbol().GetName()898    else:899        name = ""900    if showFuncName:901        return "%s(%s)" % (name, ", ".join(args))902    else:903        return "(%s)" % (", ".join(args))904 905 906def print_registers(frame, string_buffer=False):907    """Prints all the register sets of the frame."""908 909    output = io.StringIO() if string_buffer else sys.stdout910 911    print("Register sets for " + str(frame), file=output)912 913    registerSet = frame.GetRegisters()  # Return type of SBValueList.914    print(915        "Frame registers (size of register set = %d):" % registerSet.GetSize(),916        file=output,917    )918    for value in registerSet:919        # print >> output, value920        print(921            "%s (number of children = %d):" % (value.GetName(), value.GetNumChildren()),922            file=output,923        )924        for child in value:925            print(926                "Name: %s, Value: %s" % (child.GetName(), child.GetValue()), file=output927            )928 929    if string_buffer:930        return output.getvalue()931 932 933def get_registers(frame, kind):934    """Returns the registers given the frame and the kind of registers desired.935 936    Returns None if there's no such kind.937    """938    registerSet = frame.GetRegisters()  # Return type of SBValueList.939    for value in registerSet:940        if kind.lower() in value.GetName().lower():941            return value942 943    return None944 945 946def get_GPRs(frame):947    """Returns the general purpose registers of the frame as an SBValue.948 949    The returned SBValue object is iterable.  An example:950        ...951        from lldbutil import get_GPRs952        regs = get_GPRs(frame)953        for reg in regs:954            print("%s => %s" % (reg.GetName(), reg.GetValue()))955        ...956    """957    return get_registers(frame, "general purpose")958 959 960def get_FPRs(frame):961    """Returns the floating point registers of the frame as an SBValue.962 963    The returned SBValue object is iterable.  An example:964        ...965        from lldbutil import get_FPRs966        regs = get_FPRs(frame)967        for reg in regs:968            print("%s => %s" % (reg.GetName(), reg.GetValue()))969        ...970    """971    return get_registers(frame, "floating point")972 973 974def get_ESRs(frame):975    """Returns the exception state registers of the frame as an SBValue.976 977    The returned SBValue object is iterable.  An example:978        ...979        from lldbutil import get_ESRs980        regs = get_ESRs(frame)981        for reg in regs:982            print "%s => %s" % (reg.GetName(), reg.GetValue())983        ...984    """985    return get_registers(frame, "exception state")986 987 988# ======================================989# Utility classes/functions for SBValues990# ======================================991 992 993class BasicFormatter(object):994    """The basic formatter inspects the value object and prints the value."""995 996    def format(self, value, buffer=None, indent=0):997        if not buffer:998            output = io.StringIO()999        else:1000            output = buffer1001        # If there is a summary, it suffices.1002        val = value.GetSummary()1003        # Otherwise, get the value.1004        if val is None:1005            val = value.GetValue()1006        if val is None and value.GetNumChildren() > 0:1007            val = "%s (location)" % value.GetLocation()1008        print(1009            "{indentation}({type}) {name} = {value}".format(1010                indentation=" " * indent,1011                type=value.GetTypeName(),1012                name=value.GetName(),1013                value=val,1014            ),1015            file=output,1016        )1017        return output.getvalue()1018 1019 1020class ChildVisitingFormatter(BasicFormatter):1021    """The child visiting formatter prints the value and its immediate children.1022 1023    The constructor takes a keyword arg: indent_child, which defaults to 2.1024    """1025 1026    def __init__(self, indent_child=2):1027        """Default indentation of 2 SPC's for the children."""1028        self.cindent = indent_child1029 1030    def format(self, value, buffer=None):1031        if not buffer:1032            output = io.StringIO()1033        else:1034            output = buffer1035 1036        BasicFormatter.format(self, value, buffer=output)1037        for child in value:1038            BasicFormatter.format(self, child, buffer=output, indent=self.cindent)1039 1040        return output.getvalue()1041 1042 1043class RecursiveDescentFormatter(BasicFormatter):1044    """The recursive descent formatter prints the value and the descendents.1045 1046    The constructor takes two keyword args: indent_level, which defaults to 0,1047    and indent_child, which defaults to 2.  The current indentation level is1048    determined by indent_level, while the immediate children has an additional1049    indentation by inden_child.1050    """1051 1052    def __init__(self, indent_level=0, indent_child=2):1053        self.lindent = indent_level1054        self.cindent = indent_child1055 1056    def format(self, value, buffer=None):1057        if not buffer:1058            output = io.StringIO()1059        else:1060            output = buffer1061        BasicFormatter.format(self, value, buffer=output, indent=self.lindent)1062        new_indent = self.lindent + self.cindent1063        for child in value:1064            if child.GetSummary() is not None:1065                BasicFormatter.format(self, child, buffer=output, indent=new_indent)1066            else:1067                if child.GetNumChildren() > 0:1068                    rdf = RecursiveDescentFormatter(indent_level=new_indent)1069                    rdf.format(child, buffer=output)1070                else:1071                    BasicFormatter.format(self, child, buffer=output, indent=new_indent)1072 1073        return output.getvalue()1074