brintos

brintos / llvm-project-archived public Read only

0
0
Text · 56.0 KiB · b8a78b7 Raw
1793 lines · python
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 7# System modules8import errno9import io10import json11import os12import re13import sys14import subprocess15from typing import Dict16 17# LLDB modules18import lldb19from . import lldbtest_config20from . import configuration21 22# How often failed simulator process launches are retried.23SIMULATOR_RETRY = 324 25# ===================================================26# Utilities for locating/checking executable programs27# ===================================================28 29 30def is_exe(fpath):31    """Returns True if fpath is an executable."""32    return os.path.isfile(fpath) and os.access(fpath, os.X_OK)33 34 35def which(program):36    """Returns the full path to a program; None otherwise."""37    fpath, fname = os.path.split(program)38    if fpath:39        if is_exe(program):40            return program41    else:42        for path in os.environ["PATH"].split(os.pathsep):43            exe_file = os.path.join(path, program)44            if is_exe(exe_file):45                return exe_file46    return None47 48 49def mkdir_p(path):50    try:51        os.makedirs(path)52    except OSError as e:53        if e.errno != errno.EEXIST:54            raise55    if not os.path.isdir(path):56        raise OSError(errno.ENOTDIR, "%s is not a directory" % path)57 58 59# ============================60# Dealing with SDK and triples61# ============================62 63 64def get_xcode_sdk(os, env):65    # Respect --apple-sdk <path> if it's specified. If the SDK is simply66    # mounted from some disk image, and not actually installed, this is the67    # only way to use it.68    if configuration.apple_sdk:69        return configuration.apple_sdk70    if os == "ios":71        if env == "simulator":72            return "iphonesimulator"73        if env == "macabi":74            return "macosx"75        return "iphoneos"76    elif os == "tvos":77        if env == "simulator":78            return "appletvsimulator"79        return "appletvos"80    elif os == "watchos":81        if env == "simulator":82            return "watchsimulator"83        return "watchos"84    return os85 86 87def get_xcode_sdk_version(sdk):88    return (89        subprocess.check_output(["xcrun", "--sdk", sdk, "--show-sdk-version"])90        .rstrip()91        .decode("utf-8")92    )93 94 95def get_xcode_sdk_root(sdk):96    return (97        subprocess.check_output(["xcrun", "--sdk", sdk, "--show-sdk-path"])98        .rstrip()99        .decode("utf-8")100    )101 102 103def get_xcode_clang(sdk):104    return (105        subprocess.check_output(["xcrun", "-sdk", sdk, "-f", "clang"])106        .rstrip()107        .decode("utf-8")108    )109 110 111# ===================================================112# Disassembly for an SBFunction or an SBSymbol object113# ===================================================114 115 116def disassemble(target, function_or_symbol):117    """Disassemble the function or symbol given a target.118 119    It returns the disassembly content in a string object.120    """121    buf = io.StringIO()122    insts = function_or_symbol.GetInstructions(target)123    for i in insts:124        print(i, file=buf)125    return buf.getvalue()126 127 128# ==========================================================129# Integer (byte size 1, 2, 4, and 8) to bytearray conversion130# ==========================================================131 132 133def int_to_bytearray(val, bytesize):134    """Utility function to convert an integer into a bytearray.135 136    It returns the bytearray in the little endian format.  It is easy to get the137    big endian format, just do ba.reverse() on the returned object.138    """139    import struct140 141    if bytesize == 1:142        return bytearray([val])143 144    # Little endian followed by a format character.145    template = "<%c"146    if bytesize == 2:147        fmt = template % "h"148    elif bytesize == 4:149        fmt = template % "i"150    elif bytesize == 4:151        fmt = template % "q"152    else:153        return None154 155    packed = struct.pack(fmt, val)156    return bytearray(packed)157 158 159def bytearray_to_int(bytes, bytesize):160    """Utility function to convert a bytearray into an integer.161 162    It interprets the bytearray in the little endian format. For a big endian163    bytearray, just do ba.reverse() on the object before passing it in.164    """165    import struct166 167    if bytesize == 1:168        return bytes[0]169 170    # Little endian followed by a format character.171    template = "<%c"172    if bytesize == 2:173        fmt = template % "h"174    elif bytesize == 4:175        fmt = template % "i"176    elif bytesize == 4:177        fmt = template % "q"178    else:179        return None180 181    unpacked = struct.unpack_from(fmt, bytes)182    return unpacked[0]183 184 185# ==============================================================186# Get the description of an lldb object or None if not available187# ==============================================================188def get_description(obj, option=None):189    """Calls lldb_obj.GetDescription() and returns a string, or None.190 191    For SBTarget, SBBreakpointLocation, and SBWatchpoint lldb objects, an extra192    option can be passed in to describe the detailed level of description193    desired:194        o lldb.eDescriptionLevelBrief195        o lldb.eDescriptionLevelFull196        o lldb.eDescriptionLevelVerbose197    """198    method = getattr(obj, "GetDescription")199    if not method:200        return None201    tuple = (lldb.SBTarget, lldb.SBBreakpointLocation, lldb.SBWatchpoint)202    if isinstance(obj, tuple):203        if option is None:204            option = lldb.eDescriptionLevelBrief205 206    stream = lldb.SBStream()207    if option is None:208        success = method(stream)209    else:210        success = method(stream, option)211    if not success:212        return None213    return stream.GetData()214 215 216# =================================================217# Convert some enum value to its string counterpart218# =================================================219 220 221def _enum_names(prefix: str) -> Dict[int, str]:222    """Generate a mapping of enum value to name, for the enum prefix."""223    suffix_start = len(prefix)224    return {225        getattr(lldb, attr): attr[suffix_start:].lower()226        for attr in dir(lldb)227        if attr.startswith(prefix)228    }229 230 231_STATE_NAMES = _enum_names(prefix="eState")232 233 234def state_type_to_str(enum: int) -> str:235    """Returns the stateType string given an enum."""236    name = _STATE_NAMES.get(enum)237    if name:238        return name239    raise Exception(f"Unknown StateType enum: {enum}")240 241 242_STOP_REASON_NAMES = _enum_names(prefix="eStopReason")243 244 245def stop_reason_to_str(enum: int) -> str:246    """Returns the stopReason string given an enum."""247    name = _STOP_REASON_NAMES.get(enum)248    if name:249        return name250    raise Exception(f"Unknown StopReason enum: {enum}")251 252 253_SYMBOL_TYPE_NAMES = _enum_names(prefix="eSymbolType")254 255 256def symbol_type_to_str(enum: int) -> str:257    """Returns the symbolType string given an enum."""258    name = _SYMBOL_TYPE_NAMES.get(enum)259    if name:260        return name261    raise Exception(f"Unknown SymbolType enum: {enum}")262 263 264_VALUE_TYPE_NAMES = _enum_names(prefix="eValueType")265 266 267def value_type_to_str(enum: int) -> str:268    """Returns the valueType string given an enum."""269    name = _VALUE_TYPE_NAMES.get(enum)270    if name:271        return name272    raise Exception(f"Unknown ValueType enum: {enum}")273 274 275# ==================================================276# Get stopped threads due to each stop reason.277# ==================================================278 279 280def sort_stopped_threads(281    process,282    breakpoint_threads=None,283    crashed_threads=None,284    watchpoint_threads=None,285    signal_threads=None,286    exiting_threads=None,287    other_threads=None,288):289    """Fills array *_threads with threads stopped for the corresponding stop290    reason.291    """292    for lst in [293        breakpoint_threads,294        watchpoint_threads,295        signal_threads,296        exiting_threads,297        other_threads,298    ]:299        if lst is not None:300            lst[:] = []301 302    for thread in process:303        dispatched = False304        for reason, list in [305            (lldb.eStopReasonBreakpoint, breakpoint_threads),306            (lldb.eStopReasonException, crashed_threads),307            (lldb.eStopReasonWatchpoint, watchpoint_threads),308            (lldb.eStopReasonSignal, signal_threads),309            (lldb.eStopReasonThreadExiting, exiting_threads),310            (None, other_threads),311        ]:312            if not dispatched and list is not None:313                if thread.GetStopReason() == reason or reason is None:314                    list.append(thread)315                    dispatched = True316 317 318# ==================================================319# Utility functions for setting breakpoints320# ==================================================321 322 323def run_break_set_by_script(324    test, class_name, extra_options=None, num_expected_locations=1325):326    """Set a scripted breakpoint.  Check that it got the right number of locations."""327    test.assertTrue(class_name is not None, "Must pass in a class name.")328    command = "breakpoint set -P " + class_name329    if extra_options is not None:330        command += " " + extra_options331 332    break_results = run_break_set_command(test, command)333    check_breakpoint_result(test, break_results, num_locations=num_expected_locations)334    return get_bpno_from_match(break_results)335 336 337def run_break_set_by_file_and_line(338    test,339    file_name,340    line_number,341    extra_options=None,342    num_expected_locations=1,343    loc_exact=False,344    module_name=None,345):346    """Set a breakpoint by file and line, returning the breakpoint number.347 348    If extra_options is not None, then we append it to the breakpoint set command.349 350    If num_expected_locations is -1, we check that we got AT LEAST one location. If num_expected_locations is -2, we don't351    check the actual number at all. Otherwise, we check that num_expected_locations equals the number of locations.352 353    If loc_exact is true, we check that there is one location, and that location must be at the input file and line number.354    """355 356    if file_name is None:357        command = "breakpoint set -l %d" % (line_number)358    else:359        command = 'breakpoint set -f "%s" -l %d' % (file_name, line_number)360 361    if module_name:362        command += " --shlib '%s'" % (module_name)363 364    if extra_options:365        command += " " + extra_options366 367    break_results = run_break_set_command(test, command)368 369    if num_expected_locations == 1 and loc_exact:370        check_breakpoint_result(371            test,372            break_results,373            num_locations=num_expected_locations,374            file_name=file_name,375            line_number=line_number,376            module_name=module_name,377        )378    else:379        check_breakpoint_result(380            test, break_results, num_locations=num_expected_locations381        )382 383    return get_bpno_from_match(break_results)384 385 386def run_break_set_by_symbol(387    test,388    symbol,389    extra_options=None,390    num_expected_locations=-1,391    sym_exact=False,392    module_name=None,393):394    """Set a breakpoint by symbol name.  Common options are the same as run_break_set_by_file_and_line.395 396    If sym_exact is true, then the output symbol must match the input exactly, otherwise we do a substring match.397    """398    command = 'breakpoint set -n "%s"' % (symbol)399 400    if module_name:401        command += " --shlib '%s'" % (module_name)402 403    if extra_options:404        command += " " + extra_options405 406    break_results = run_break_set_command(test, command)407 408    if num_expected_locations == 1 and sym_exact:409        check_breakpoint_result(410            test,411            break_results,412            num_locations=num_expected_locations,413            symbol_name=symbol,414            module_name=module_name,415        )416    else:417        check_breakpoint_result(418            test, break_results, num_locations=num_expected_locations419        )420 421    return get_bpno_from_match(break_results)422 423 424def run_break_set_by_selector(425    test, selector, extra_options=None, num_expected_locations=-1, module_name=None426):427    """Set a breakpoint by selector.  Common options are the same as run_break_set_by_file_and_line."""428 429    command = 'breakpoint set -S "%s"' % (selector)430 431    if module_name:432        command += ' --shlib "%s"' % (module_name)433 434    if extra_options:435        command += " " + extra_options436 437    break_results = run_break_set_command(test, command)438 439    if num_expected_locations == 1:440        check_breakpoint_result(441            test,442            break_results,443            num_locations=num_expected_locations,444            symbol_name=selector,445            symbol_match_exact=False,446            module_name=module_name,447        )448    else:449        check_breakpoint_result(450            test, break_results, num_locations=num_expected_locations451        )452 453    return get_bpno_from_match(break_results)454 455 456def run_break_set_by_regexp(457    test, regexp, extra_options=None, num_expected_locations=-1458):459    """Set a breakpoint by regular expression match on symbol name.  Common options are the same as run_break_set_by_file_and_line."""460 461    command = 'breakpoint set -r "%s"' % (regexp)462    if extra_options:463        command += " " + extra_options464 465    break_results = run_break_set_command(test, command)466 467    check_breakpoint_result(test, break_results, num_locations=num_expected_locations)468 469    return get_bpno_from_match(break_results)470 471 472def run_break_set_by_source_regexp(473    test, regexp, extra_options=None, num_expected_locations=-1474):475    """Set a breakpoint by source regular expression.  Common options are the same as run_break_set_by_file_and_line."""476    command = 'breakpoint set -p "%s"' % (regexp)477    if extra_options:478        command += " " + extra_options479 480    break_results = run_break_set_command(test, command)481 482    check_breakpoint_result(test, break_results, num_locations=num_expected_locations)483 484    return get_bpno_from_match(break_results)485 486 487def run_break_set_by_file_colon_line(488    test,489    specifier,490    path,491    line_number,492    column_number=0,493    extra_options=None,494    num_expected_locations=-1,495):496    command = 'breakpoint set -y "%s"' % (specifier)497    if extra_options:498        command += " " + extra_options499 500    print("About to run: '%s'", command)501    break_results = run_break_set_command(test, command)502    check_breakpoint_result(503        test,504        break_results,505        num_locations=num_expected_locations,506        file_name=path,507        line_number=line_number,508        column_number=column_number,509    )510 511    return get_bpno_from_match(break_results)512 513 514def run_break_set_command(test, command):515    """Run the command passed in - it must be some break set variant - and analyze the result.516    Returns a dictionary of information gleaned from the command-line results.517    Will assert if the breakpoint setting fails altogether.518 519    Dictionary will contain:520        bpno          - breakpoint of the newly created breakpoint, -1 on error.521        num_locations - number of locations set for the breakpoint.522 523    If there is only one location, the dictionary MAY contain:524        file          - source file name525        line_no       - source line number526        column        - source column number527        symbol        - symbol name528        inline_symbol - inlined symbol name529        offset        - offset from the original symbol530        module        - module531        address       - address at which the breakpoint was set."""532 533    patterns = [534        r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>[0-9]+) locations\.$",535        r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>no) locations \(pending\)\.",536        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]+)(?P<column>(:[0-9]+)?), address = (?P<address>0x[0-9a-fA-F]+)$",537        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]+)$",538    ]539    match_object = test.match(command, patterns)540    break_results = match_object.groupdict()541 542    # We always insert the breakpoint number, setting it to -1 if we couldn't find it543    # Also, make sure it gets stored as an integer.544    if not "bpno" in break_results:545        break_results["bpno"] = -1546    else:547        break_results["bpno"] = int(break_results["bpno"])548 549    # We always insert the number of locations550    # If ONE location is set for the breakpoint, then the output doesn't mention locations, but it has to be 1...551    # We also make sure it is an integer.552 553    if not "num_locations" in break_results:554        num_locations = 1555    else:556        num_locations = break_results["num_locations"]557        if num_locations == "no":558            num_locations = 0559        else:560            num_locations = int(break_results["num_locations"])561 562    break_results["num_locations"] = num_locations563 564    if "line_no" in break_results:565        break_results["line_no"] = int(break_results["line_no"])566 567    return break_results568 569 570def get_bpno_from_match(break_results):571    return int(break_results["bpno"])572 573 574def check_breakpoint_result(575    test,576    break_results,577    file_name=None,578    line_number=-1,579    column_number=0,580    symbol_name=None,581    symbol_match_exact=True,582    module_name=None,583    offset=-1,584    num_locations=-1,585):586    out_num_locations = break_results["num_locations"]587 588    if num_locations == -1:589        test.assertTrue(590            out_num_locations > 0, "Expecting one or more locations, got none."591        )592    elif num_locations != -2:593        test.assertTrue(594            num_locations == out_num_locations,595            "Expecting %d locations, got %d." % (num_locations, out_num_locations),596        )597 598    if file_name:599        out_file_name = ""600        if "file" in break_results:601            out_file_name = break_results["file"]602        test.assertTrue(603            file_name.endswith(out_file_name),604            "Breakpoint file name '%s' doesn't match resultant name '%s'."605            % (file_name, out_file_name),606        )607 608    if line_number != -1:609        out_line_number = -1610        if "line_no" in break_results:611            out_line_number = break_results["line_no"]612 613        test.assertTrue(614            line_number == out_line_number,615            "Breakpoint line number %s doesn't match resultant line %s."616            % (line_number, out_line_number),617        )618 619    if column_number != 0:620        out_column_number = 0621        if "column" in break_results:622            out_column_number = break_results["column"]623 624        test.assertTrue(625            column_number == out_column_number,626            "Breakpoint column number %s doesn't match resultant column %s."627            % (column_number, out_column_number),628        )629 630    if symbol_name:631        out_symbol_name = ""632        # Look first for the inlined symbol name, otherwise use the symbol633        # name:634        if "inline_symbol" in break_results and break_results["inline_symbol"]:635            out_symbol_name = break_results["inline_symbol"]636        elif "symbol" in break_results:637            out_symbol_name = break_results["symbol"]638 639        if symbol_match_exact:640            test.assertTrue(641                symbol_name == out_symbol_name,642                "Symbol name '%s' doesn't match resultant symbol '%s'."643                % (symbol_name, out_symbol_name),644            )645        else:646            test.assertTrue(647                out_symbol_name.find(symbol_name) != -1,648                "Symbol name '%s' isn't in resultant symbol '%s'."649                % (symbol_name, out_symbol_name),650            )651 652    if module_name:653        out_module_name = None654        if "module" in break_results:655            out_module_name = break_results["module"]656 657        test.assertTrue(658            module_name.find(out_module_name) != -1,659            "Symbol module name '%s' isn't in expected module name '%s'."660            % (out_module_name, module_name),661        )662 663 664def check_breakpoint(665    test,666    bpno,667    expected_locations=None,668    expected_resolved_count=None,669    expected_hit_count=None,670    location_id=None,671    expected_location_resolved=True,672    expected_location_hit_count=None,673):674    """675    Test breakpoint or breakpoint location.676    Breakpoint resolved count is always checked. If not specified the assumption is that all locations677    should be resolved.678    To test a breakpoint location, breakpoint number (bpno) and location_id must be set. In this case679    the resolved count for a breakpoint is not tested by default. The location is expected to be resolved,680    unless expected_location_resolved is set to False.681    test - test context682    bpno - breakpoint number to test683    expected_locations - expected number of locations for this breakpoint. If 'None' this parameter is not tested.684    expected_resolved_count - expected resolved locations number for the breakpoint.  If 'None' - all locations should be resolved.685    expected_hit_count - expected hit count for this breakpoint. If 'None' this parameter is not tested.686    location_id - If not 'None' sets the location ID for the breakpoint to test.687    expected_location_resolved - Extected resolved status for the location_id (True/False). Default - True.688    expected_location_hit_count - Expected hit count for the breakpoint at location_id. Must be set if the location_id parameter is set.689    """690 691    if isinstance(test.target, lldb.SBTarget):692        target = test.target693    else:694        target = test.target()695    bkpt = target.FindBreakpointByID(bpno)696 697    test.assertTrue(bkpt.IsValid(), "Breakpoint is not valid.")698 699    if expected_locations is not None:700        test.assertEqual(expected_locations, bkpt.GetNumLocations())701 702    if expected_resolved_count is not None:703        test.assertEqual(expected_resolved_count, bkpt.GetNumResolvedLocations())704    else:705        expected_resolved_count = bkpt.GetNumLocations()706        if location_id is None:707            test.assertEqual(expected_resolved_count, bkpt.GetNumResolvedLocations())708 709    if expected_hit_count is not None:710        test.assertEqual(expected_hit_count, bkpt.GetHitCount())711 712    if location_id is not None:713        loc_bkpt = bkpt.FindLocationByID(location_id)714        test.assertTrue(loc_bkpt.IsValid(), "Breakpoint location is not valid.")715        test.assertEqual(loc_bkpt.IsResolved(), expected_location_resolved)716        if expected_location_hit_count is not None:717            test.assertEqual(expected_location_hit_count, loc_bkpt.GetHitCount())718 719 720# ==================================================721# Utility functions related to Threads and Processes722# ==================================================723 724 725def get_stopped_threads(process, reason):726    """Returns the thread(s) with the specified stop reason in a list.727 728    The list can be empty if no such thread exists.729    """730    threads = []731    for t in process:732        if t.GetStopReason() == reason:733            threads.append(t)734    return threads735 736 737def get_stopped_thread(process, reason):738    """A convenience function which returns the first thread with the given stop739    reason or None.740 741    Example usages:742 743    1. Get the stopped thread due to a breakpoint condition744 745    ...746        from lldbutil import get_stopped_thread747        thread = get_stopped_thread(process, lldb.eStopReasonPlanComplete)748        self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint condition")749    ...750 751    2. Get the thread stopped due to a breakpoint752 753    ...754        from lldbutil import get_stopped_thread755        thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint)756        self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint")757    ...758 759    """760    threads = get_stopped_threads(process, reason)761    if len(threads) == 0:762        return None763    return threads[0]764 765 766def get_threads_stopped_at_breakpoint_id(process, bpid):767    """For a stopped process returns the thread stopped at the breakpoint passed in bkpt"""768    stopped_threads = []769    threads = []770 771    stopped_threads = get_stopped_threads(process, lldb.eStopReasonBreakpoint)772 773    if len(stopped_threads) == 0:774        return threads775 776    for thread in stopped_threads:777        # Make sure we've hit our breakpoint.778        # From the docs of GetStopReasonDataAtIndex: "Breakpoint stop reasons779        # will have data that consists of pairs of breakpoint IDs followed by780        # the breakpoint location IDs".781        # Iterate over all such pairs looking for `bpid`.782        break_ids = [783            thread.GetStopReasonDataAtIndex(idx)784            for idx in range(0, thread.GetStopReasonDataCount(), 2)785        ]786        if bpid in break_ids:787            threads.append(thread)788 789    return threads790 791 792def get_threads_stopped_at_breakpoint(process, bkpt):793    return get_threads_stopped_at_breakpoint_id(process, bkpt.GetID())794 795 796def get_one_thread_stopped_at_breakpoint_id(process, bpid, require_exactly_one=True):797    threads = get_threads_stopped_at_breakpoint_id(process, bpid)798    if len(threads) == 0:799        return None800    if require_exactly_one and len(threads) != 1:801        return None802 803    return threads[0]804 805 806def get_one_thread_stopped_at_breakpoint(process, bkpt, require_exactly_one=True):807    return get_one_thread_stopped_at_breakpoint_id(808        process, bkpt.GetID(), require_exactly_one809    )810 811 812def is_thread_crashed(test, thread):813    """In the test suite we dereference a null pointer to simulate a crash. The way this is814    reported depends on the platform."""815    if test.platformIsDarwin():816        return (817            thread.GetStopReason() == lldb.eStopReasonException818            and "EXC_BAD_ACCESS" in thread.GetStopDescription(100)819        )820    elif test.getPlatform() in ["linux", "freebsd"]:821        return (822            thread.GetStopReason() == lldb.eStopReasonSignal823            and thread.GetStopReasonDataAtIndex(0)824            == thread.GetProcess().GetUnixSignals().GetSignalNumberFromName("SIGSEGV")825        )826    elif test.getPlatform() == "windows":827        return "Exception 0xc0000005" in thread.GetStopDescription(200)828    else:829        return "invalid address" in thread.GetStopDescription(100)830 831 832def get_crashed_threads(test, process):833    threads = []834    if process.GetState() != lldb.eStateStopped:835        return threads836    for thread in process:837        if is_thread_crashed(test, thread):838            threads.append(thread)839    return threads840 841 842# Helper functions for run_to_{source,name}_breakpoint:843 844 845def run_to_breakpoint_make_target(test, exe_name="a.out", in_cwd=True):846    exe = test.getBuildArtifact(exe_name) if in_cwd else exe_name847 848    # Create the target849    target = test.dbg.CreateTarget(exe)850    test.assertTrue(target, "Target: %s is not valid." % (exe_name))851 852    # Set environment variables for the inferior.853    if lldbtest_config.inferior_env:854        test.runCmd(855            "settings set target.env-vars {}".format(lldbtest_config.inferior_env)856        )857 858    return target859 860 861def run_to_breakpoint_do_run(862    test, target, bkpt, launch_info=None, only_one_thread=True, extra_images=None863):864    # Launch the process, and do not stop at the entry point.865    if not launch_info:866        launch_info = target.GetLaunchInfo()867        launch_info.SetWorkingDirectory(test.get_process_working_directory())868 869    if extra_images:870        environ = test.registerSharedLibrariesWithTarget(target, extra_images)871        launch_info.SetEnvironmentEntries(environ, True)872 873    error = lldb.SBError()874    process = target.Launch(launch_info, error)875 876    # Unfortunate workaround for the iPhone simulator.877    retry = SIMULATOR_RETRY878    while (879        retry880        and error.Fail()881        and error.GetCString()882        and "Unable to boot the Simulator" in error.GetCString()883    ):884        retry -= 1885        print("** Simulator is unresponsive. Retrying %d more time(s)" % retry)886        import time887 888        time.sleep(60)889        error = lldb.SBError()890        process = target.Launch(launch_info, error)891 892    test.assertTrue(893        process,894        "Could not create a valid process for %s: %s"895        % (target.GetExecutable().GetFilename(), error.GetCString()),896    )897    test.assertFalse(error.Fail(), "Process launch failed: %s" % (error.GetCString()))898 899    def processStateInfo(process):900        info = "state: {}".format(state_type_to_str(process.state))901        if process.state == lldb.eStateExited:902            info += ", exit code: {}".format(process.GetExitStatus())903            if process.exit_description:904                info += ", exit description: '{}'".format(process.exit_description)905        stdout = process.GetSTDOUT(999)906        if stdout:907            info += ", stdout: '{}'".format(stdout)908        stderr = process.GetSTDERR(999)909        if stderr:910            info += ", stderr: '{}'".format(stderr)911        return info912 913    if process.state != lldb.eStateStopped:914        test.fail(915            "Test process is not stopped at breakpoint: {}".format(916                processStateInfo(process)917            )918        )919 920    # Frame #0 should be at our breakpoint.921    threads = get_threads_stopped_at_breakpoint(process, bkpt)922 923    num_threads = len(threads)924    if only_one_thread:925        test.assertEqual(926            num_threads,927            1,928            "Expected 1 thread to stop at breakpoint, %d did." % (num_threads),929        )930    else:931        test.assertGreater(num_threads, 0, "No threads stopped at breakpoint")932 933    thread = threads[0]934    return (target, process, thread, bkpt)935 936 937def run_to_name_breakpoint(938    test,939    bkpt_name,940    launch_info=None,941    exe_name="a.out",942    bkpt_module=None,943    in_cwd=True,944    only_one_thread=True,945    extra_images=None,946):947    """Start up a target, using exe_name as the executable, and run it to948    a breakpoint set by name on bkpt_name restricted to bkpt_module.949 950    If you want to pass in launch arguments or environment951    variables, you can optionally pass in an SBLaunchInfo.  If you952    do that, remember to set the working directory as well.953 954    If your executable isn't called a.out, you can pass that in.955    And if your executable isn't in the CWD, pass in the absolute956    path to the executable in exe_name, and set in_cwd to False.957 958    If you need to restrict the breakpoint to a particular module,959    pass the module name (a string not a FileSpec) in bkpt_module.  If960    nothing is passed in setting will be unrestricted.961 962    If the target isn't valid, the breakpoint isn't found, or hit, the963    function will cause a testsuite failure.964 965    If successful it returns a tuple with the target process and966    thread that hit the breakpoint, and the breakpoint that we set967    for you.968 969    If only_one_thread is true, we require that there be only one970    thread stopped at the breakpoint.  Otherwise we only require one971    or more threads stop there.  If there are more than one, we return972    the first thread that stopped.973    """974 975    target = run_to_breakpoint_make_target(test, exe_name, in_cwd)976 977    breakpoint = target.BreakpointCreateByName(bkpt_name, bkpt_module)978 979    test.assertTrue(980        breakpoint.GetNumLocations() > 0,981        "No locations found for name breakpoint: '%s'." % (bkpt_name),982    )983    return run_to_breakpoint_do_run(984        test, target, breakpoint, launch_info, only_one_thread, extra_images985    )986 987 988def run_to_source_breakpoint(989    test,990    bkpt_pattern,991    source_spec,992    launch_info=None,993    exe_name="a.out",994    bkpt_module=None,995    in_cwd=True,996    only_one_thread=True,997    extra_images=None,998    has_locations_before_run=True,999):1000    """Start up a target, using exe_name as the executable, and run it to1001    a breakpoint set by source regex bkpt_pattern.1002 1003    The rest of the behavior is the same as run_to_name_breakpoint.1004    """1005 1006    target = run_to_breakpoint_make_target(test, exe_name, in_cwd)1007    # Set the breakpoints1008    breakpoint = target.BreakpointCreateBySourceRegex(1009        bkpt_pattern, source_spec, bkpt_module1010    )1011    if has_locations_before_run:1012        test.assertTrue(1013            breakpoint.GetNumLocations() > 0,1014            'No locations found for source breakpoint: "%s", file: "%s", dir: "%s"'1015            % (bkpt_pattern, source_spec.GetFilename(), source_spec.GetDirectory()),1016        )1017    return run_to_breakpoint_do_run(1018        test, target, breakpoint, launch_info, only_one_thread, extra_images1019    )1020 1021 1022def run_to_line_breakpoint(1023    test,1024    source_spec,1025    line_number,1026    column=0,1027    launch_info=None,1028    exe_name="a.out",1029    bkpt_module=None,1030    in_cwd=True,1031    only_one_thread=True,1032    extra_images=None,1033):1034    """Start up a target, using exe_name as the executable, and run it to1035    a breakpoint set by (source_spec, line_number(, column)).1036 1037    The rest of the behavior is the same as run_to_name_breakpoint.1038    """1039 1040    target = run_to_breakpoint_make_target(test, exe_name, in_cwd)1041    # Set the breakpoints1042    breakpoint = target.BreakpointCreateByLocation(1043        source_spec, line_number, column, 0, lldb.SBFileSpecList()1044    )1045    test.assertTrue(1046        breakpoint.GetNumLocations() > 0,1047        'No locations found for line breakpoint: "%s:%d(:%d)", dir: "%s"'1048        % (source_spec.GetFilename(), line_number, column, source_spec.GetDirectory()),1049    )1050    return run_to_breakpoint_do_run(1051        test, target, breakpoint, launch_info, only_one_thread, extra_images1052    )1053 1054 1055def continue_to_breakpoint(process, bkpt):1056    """Continues the process, if it stops, returns the threads stopped at bkpt; otherwise, returns None"""1057    process.Continue()1058    if process.GetState() != lldb.eStateStopped:1059        return None1060    else:1061        return get_threads_stopped_at_breakpoint(process, bkpt)1062 1063 1064def continue_to_source_breakpoint(test, process, bkpt_pattern, source_spec):1065    """1066    Sets a breakpoint set by source regex bkpt_pattern, continues the process, and deletes the breakpoint again.1067    Otherwise the same as `continue_to_breakpoint`1068    """1069    breakpoint = process.target.BreakpointCreateBySourceRegex(1070        bkpt_pattern, source_spec, None1071    )1072    test.assertTrue(1073        breakpoint.GetNumLocations() > 0,1074        'No locations found for source breakpoint: "%s", file: "%s", dir: "%s"'1075        % (bkpt_pattern, source_spec.GetFilename(), source_spec.GetDirectory()),1076    )1077    stopped_threads = continue_to_breakpoint(process, breakpoint)1078    process.target.BreakpointDelete(breakpoint.GetID())1079    return stopped_threads1080 1081 1082def get_caller_symbol(thread):1083    """1084    Returns the symbol name for the call site of the leaf function.1085    """1086    depth = thread.GetNumFrames()1087    if depth <= 1:1088        return None1089    caller = thread.GetFrameAtIndex(1).GetSymbol()1090    if caller:1091        return caller.GetName()1092    else:1093        return None1094 1095 1096def get_function_names(thread):1097    """1098    Returns a sequence of function names from the stack frames of this thread.1099    """1100 1101    def GetFuncName(i):1102        return thread.GetFrameAtIndex(i).GetFunctionName()1103 1104    return list(map(GetFuncName, list(range(thread.GetNumFrames()))))1105 1106 1107def get_symbol_names(thread):1108    """1109    Returns a sequence of symbols for this thread.1110    """1111 1112    def GetSymbol(i):1113        return thread.GetFrameAtIndex(i).GetSymbol().GetName()1114 1115    return list(map(GetSymbol, list(range(thread.GetNumFrames()))))1116 1117 1118def get_pc_addresses(thread):1119    """1120    Returns a sequence of pc addresses for this thread.1121    """1122 1123    def GetPCAddress(i):1124        return thread.GetFrameAtIndex(i).GetPCAddress()1125 1126    return list(map(GetPCAddress, list(range(thread.GetNumFrames()))))1127 1128 1129def get_filenames(thread):1130    """1131    Returns a sequence of file names from the stack frames of this thread.1132    """1133 1134    def GetFilename(i):1135        return thread.GetFrameAtIndex(i).GetLineEntry().GetFileSpec().GetFilename()1136 1137    return list(map(GetFilename, list(range(thread.GetNumFrames()))))1138 1139 1140def get_line_numbers(thread):1141    """1142    Returns a sequence of line numbers from the stack frames of this thread.1143    """1144 1145    def GetLineNumber(i):1146        return thread.GetFrameAtIndex(i).GetLineEntry().GetLine()1147 1148    return list(map(GetLineNumber, list(range(thread.GetNumFrames()))))1149 1150 1151def get_module_names(thread):1152    """1153    Returns a sequence of module names from the stack frames of this thread.1154    """1155 1156    def GetModuleName(i):1157        return thread.GetFrameAtIndex(i).GetModule().GetFileSpec().GetFilename()1158 1159    return list(map(GetModuleName, list(range(thread.GetNumFrames()))))1160 1161 1162def print_stacktrace(thread, string_buffer=False):1163    """Prints a simple stack trace of this thread."""1164 1165    output = io.StringIO() if string_buffer else sys.stdout1166    target = thread.GetProcess().GetTarget()1167 1168    depth = thread.GetNumFrames()1169 1170    mods = get_module_names(thread)1171    funcs = get_function_names(thread)1172    symbols = get_symbol_names(thread)1173    files = get_filenames(thread)1174    lines = get_line_numbers(thread)1175    addrs = get_pc_addresses(thread)1176 1177    if thread.GetStopReason() != lldb.eStopReasonInvalid:1178        desc = "stop reason=" + stop_reason_to_str(thread.GetStopReason())1179    else:1180        desc = ""1181    print(1182        "Stack trace for thread id={0:#x} name={1} queue={2} ".format(1183            thread.GetThreadID(), thread.GetName(), thread.GetQueueName()1184        )1185        + desc,1186        file=output,1187    )1188 1189    for i in range(depth):1190        frame = thread.GetFrameAtIndex(i)1191        function = frame.GetFunction()1192 1193        load_addr = addrs[i].GetLoadAddress(target)1194        if not function:1195            file_addr = addrs[i].GetFileAddress()1196            start_addr = frame.GetSymbol().GetStartAddress().GetFileAddress()1197            symbol_offset = file_addr - start_addr1198            print(1199                "  frame #{num}: {addr:#016x} {mod}`{symbol} + {offset}".format(1200                    num=i,1201                    addr=load_addr,1202                    mod=mods[i],1203                    symbol=symbols[i],1204                    offset=symbol_offset,1205                ),1206                file=output,1207            )1208        else:1209            print(1210                "  frame #{num}: {addr:#016x} {mod}`{func} at {file}:{line} {args}".format(1211                    num=i,1212                    addr=load_addr,1213                    mod=mods[i],1214                    func="%s [inlined]" % funcs[i] if frame.IsInlined() else funcs[i],1215                    file=files[i],1216                    line=lines[i],1217                    args=get_args_as_string(frame, showFuncName=False)1218                    if not frame.IsInlined()1219                    else "()",1220                ),1221                file=output,1222            )1223 1224    if string_buffer:1225        return output.getvalue()1226 1227 1228def print_stacktraces(process, string_buffer=False):1229    """Prints the stack traces of all the threads."""1230 1231    output = io.StringIO() if string_buffer else sys.stdout1232 1233    print("Stack traces for " + str(process), file=output)1234 1235    for thread in process:1236        print(print_stacktrace(thread, string_buffer=True), file=output)1237 1238    if string_buffer:1239        return output.getvalue()1240 1241 1242def expect_state_changes(test, listener, process, states, timeout=30):1243    """Listens for state changed events on the listener and makes sure they match what we1244    expect. Stop-and-restart events (where GetRestartedFromEvent() returns true) are ignored.1245    """1246 1247    for expected_state in states:1248 1249        def get_next_event():1250            event = lldb.SBEvent()1251            if not listener.WaitForEventForBroadcasterWithType(1252                timeout,1253                process.GetBroadcaster(),1254                lldb.SBProcess.eBroadcastBitStateChanged,1255                event,1256            ):1257                test.fail(1258                    "Timed out while waiting for a transition to state %s"1259                    % lldb.SBDebugger.StateAsCString(expected_state)1260                )1261            return event1262 1263        event = get_next_event()1264        while lldb.SBProcess.GetStateFromEvent(1265            event1266        ) == lldb.eStateStopped and lldb.SBProcess.GetRestartedFromEvent(event):1267            # Ignore restarted event and the subsequent running event.1268            event = get_next_event()1269            test.assertEqual(1270                lldb.SBProcess.GetStateFromEvent(event),1271                lldb.eStateRunning,1272                "Restarted event followed by a running event",1273            )1274            event = get_next_event()1275 1276        test.assertEqual(lldb.SBProcess.GetStateFromEvent(event), expected_state)1277 1278 1279def start_listening_from(broadcaster, event_mask):1280    """Creates a listener for a specific event mask and add it to the source broadcaster."""1281 1282    listener = lldb.SBListener("lldb.test.listener")1283    broadcaster.AddListener(listener, event_mask)1284    return listener1285 1286 1287def fetch_next_event(test, listener, broadcaster, match_class=False, timeout=10):1288    """Fetch one event from the listener and return it if it matches the provided broadcaster.1289    If `match_class` is set to True, this will match an event with an entire broadcaster class.1290    Fails otherwise."""1291 1292    event = lldb.SBEvent()1293 1294    if listener.WaitForEvent(timeout, event):1295        if match_class:1296            if event.GetBroadcasterClass() == broadcaster:1297                return event1298        else:1299            if event.BroadcasterMatchesRef(broadcaster):1300                return event1301 1302        stream = lldb.SBStream()1303        event.GetDescription(stream)1304        test.fail(1305            "received event '%s' from unexpected broadcaster '%s'."1306            % (stream.GetData(), event.GetBroadcaster().GetName())1307        )1308 1309    test.fail("couldn't fetch an event before reaching the timeout.")1310 1311 1312# ===================================1313# Utility functions related to Frames1314# ===================================1315 1316 1317def get_parent_frame(frame):1318    """1319    Returns the parent frame of the input frame object; None if not available.1320    """1321    thread = frame.GetThread()1322    parent_found = False1323    for f in thread:1324        if parent_found:1325            return f1326        if f.GetFrameID() == frame.GetFrameID():1327            parent_found = True1328 1329    # If we reach here, no parent has been found, return None.1330    return None1331 1332 1333def get_args_as_string(frame, showFuncName=True):1334    """1335    Returns the args of the input frame object as a string.1336    """1337    # arguments     => True1338    # locals        => False1339    # statics       => False1340    # in_scope_only => True1341    vars = frame.GetVariables(True, False, False, True)  # type of SBValueList1342    args = []  # list of strings1343    for var in vars:1344        args.append("(%s)%s=%s" % (var.GetTypeName(), var.GetName(), var.GetValue()))1345    if frame.GetFunction():1346        name = frame.GetFunction().GetName()1347    elif frame.GetSymbol():1348        name = frame.GetSymbol().GetName()1349    else:1350        name = ""1351    if showFuncName:1352        return "%s(%s)" % (name, ", ".join(args))1353    else:1354        return "(%s)" % (", ".join(args))1355 1356 1357def get_registers(frame, kind):1358    """Returns the registers given the frame and the kind of registers desired.1359 1360    Returns None if there's no such kind.1361    """1362    registerSet = frame.GetRegisters()  # Return type of SBValueList.1363    for value in registerSet:1364        if kind.lower() in value.GetName().lower():1365            return value1366 1367    return None1368 1369 1370def get_GPRs(frame):1371    """Returns the general purpose registers of the frame as an SBValue.1372 1373    The returned SBValue object is iterable.  An example:1374        ...1375        from lldbutil import get_GPRs1376        regs = get_GPRs(frame)1377        for reg in regs:1378            print("%s => %s" % (reg.GetName(), reg.GetValue()))1379        ...1380    """1381    return get_registers(frame, "general purpose")1382 1383 1384def get_FPRs(frame):1385    """Returns the floating point registers of the frame as an SBValue.1386 1387    The returned SBValue object is iterable.  An example:1388        ...1389        from lldbutil import get_FPRs1390        regs = get_FPRs(frame)1391        for reg in regs:1392            print("%s => %s" % (reg.GetName(), reg.GetValue()))1393        ...1394    """1395    return get_registers(frame, "floating point")1396 1397 1398def get_ESRs(frame):1399    """Returns the exception state registers of the frame as an SBValue.1400 1401    The returned SBValue object is iterable.  An example:1402        ...1403        from lldbutil import get_ESRs1404        regs = get_ESRs(frame)1405        for reg in regs:1406            print("%s => %s" % (reg.GetName(), reg.GetValue()))1407        ...1408    """1409    return get_registers(frame, "exception state")1410 1411 1412# ======================================1413# Utility classes/functions for SBValues1414# ======================================1415 1416 1417class BasicFormatter(object):1418    """The basic formatter inspects the value object and prints the value."""1419 1420    def format(self, value, buffer=None, indent=0):1421        if not buffer:1422            output = io.StringIO()1423        else:1424            output = buffer1425        # If there is a summary, it suffices.1426        val = value.GetSummary()1427        # Otherwise, get the value.1428        if val is None:1429            val = value.GetValue()1430        if val is None and value.GetNumChildren() > 0:1431            val = "%s (location)" % value.GetLocation()1432        print(1433            "{indentation}({type}) {name} = {value}".format(1434                indentation=" " * indent,1435                type=value.GetTypeName(),1436                name=value.GetName(),1437                value=val,1438            ),1439            file=output,1440        )1441        return output.getvalue()1442 1443 1444class ChildVisitingFormatter(BasicFormatter):1445    """The child visiting formatter prints the value and its immediate children.1446 1447    The constructor takes a keyword arg: indent_child, which defaults to 2.1448    """1449 1450    def __init__(self, indent_child=2):1451        """Default indentation of 2 SPC's for the children."""1452        self.cindent = indent_child1453 1454    def format(self, value, buffer=None):1455        if not buffer:1456            output = io.StringIO()1457        else:1458            output = buffer1459 1460        BasicFormatter.format(self, value, buffer=output)1461        for child in value:1462            BasicFormatter.format(self, child, buffer=output, indent=self.cindent)1463 1464        return output.getvalue()1465 1466 1467class RecursiveDescentFormatter(BasicFormatter):1468    """The recursive descent formatter prints the value and the descendents.1469 1470    The constructor takes two keyword args: indent_level, which defaults to 0,1471    and indent_child, which defaults to 2.  The current indentation level is1472    determined by indent_level, while the immediate children has an additional1473    indentation by inden_child.1474    """1475 1476    def __init__(self, indent_level=0, indent_child=2):1477        self.lindent = indent_level1478        self.cindent = indent_child1479 1480    def format(self, value, buffer=None):1481        if not buffer:1482            output = io.StringIO()1483        else:1484            output = buffer1485        BasicFormatter.format(self, value, buffer=output, indent=self.lindent)1486        new_indent = self.lindent + self.cindent1487        for child in value:1488            if child.GetSummary() is not None:1489                BasicFormatter.format(self, child, buffer=output, indent=new_indent)1490            else:1491                if child.GetNumChildren() > 0:1492                    rdf = RecursiveDescentFormatter(indent_level=new_indent)1493                    rdf.format(child, buffer=output)1494                else:1495                    BasicFormatter.format(self, child, buffer=output, indent=new_indent)1496 1497        return output.getvalue()1498 1499 1500# ===========================================================1501# Utility functions for path manipulation on remote platforms1502# ===========================================================1503 1504 1505def join_remote_paths(*paths):1506    # TODO: update with actual platform name for remote windows once it exists1507    if lldb.remote_platform.GetName() == "remote-windows":1508        return os.path.join(*paths).replace(os.path.sep, "\\")1509    return os.path.join(*paths).replace(os.path.sep, "/")1510 1511 1512def append_to_process_working_directory(test, *paths):1513    remote = lldb.remote_platform1514    if remote:1515        return join_remote_paths(remote.GetWorkingDirectory(), *paths)1516    return os.path.join(test.getBuildDir(), *paths)1517 1518 1519# ==================================================1520# Utility functions to get the correct signal number1521# ==================================================1522 1523import signal1524 1525 1526def get_signal_number(signal_name):1527    platform = lldb.remote_platform1528    if platform and platform.IsValid():1529        signals = platform.GetUnixSignals()1530        if signals.IsValid():1531            signal_number = signals.GetSignalNumberFromName(signal_name)1532            if signal_number > 0:1533                return signal_number1534    # No remote platform; fall back to using local python signals.1535    return getattr(signal, signal_name)1536 1537 1538def get_actions_for_signal(1539    testcase, signal_name, from_target=False, expected_absent=False1540):1541    """Returns a triple of (pass, stop, notify)"""1542    return_obj = lldb.SBCommandReturnObject()1543    command = "process handle {0}".format(signal_name)1544    if from_target:1545        command += " -t"1546    testcase.dbg.GetCommandInterpreter().HandleCommand(command, return_obj)1547    match = re.match(1548        "NAME *PASS *STOP *NOTIFY.*(false|true|not set) *(false|true|not set) *(false|true|not set)",1549        return_obj.GetOutput(),1550        re.IGNORECASE | re.DOTALL,1551    )1552    if match and expected_absent:1553        testcase.fail('Signal "{0}" was supposed to be absent'.format(signal_name))1554    if not match:1555        if expected_absent:1556            return (None, None, None)1557        testcase.fail("Unable to retrieve default signal disposition.")1558    return (match.group(1), match.group(2), match.group(3))1559 1560 1561def set_actions_for_signal(1562    testcase, signal_name, pass_action, stop_action, notify_action, expect_success=True1563):1564    return_obj = lldb.SBCommandReturnObject()1565    command = "process handle {0}".format(signal_name)1566    if pass_action is not None:1567        command += " -p {0}".format(pass_action)1568    if stop_action is not None:1569        command += " -s {0}".format(stop_action)1570    if notify_action is not None:1571        command += " -n {0}".format(notify_action)1572 1573    testcase.dbg.GetCommandInterpreter().HandleCommand(command, return_obj)1574    testcase.assertEqual(1575        expect_success,1576        return_obj.Succeeded(),1577        "Setting signal handling for {0} worked as expected".format(signal_name),1578    )1579 1580 1581def skip_if_callable(test, mycallable, reason):1582    if callable(mycallable):1583        if mycallable(test):1584            test.skipTest(reason)1585            return True1586    return False1587 1588 1589def skip_if_library_missing(test, target, library):1590    def find_library(target, library):1591        for module in target.modules:1592            filename = module.file.GetFilename()1593            if isinstance(library, str):1594                if library == filename:1595                    return False1596            elif hasattr(library, "match"):1597                if library.match(filename):1598                    return False1599        return True1600 1601    def find_library_callable(test):1602        return find_library(target, library)1603 1604    return skip_if_callable(1605        test,1606        find_library_callable,1607        "could not find library matching '%s' in target %s" % (library, target),1608    )1609 1610 1611def install_to_target(test, path):1612    if lldb.remote_platform:1613        filename = os.path.basename(path)1614        remote_path = append_to_process_working_directory(test, filename)1615        err = lldb.remote_platform.Install(1616            lldb.SBFileSpec(path, True), lldb.SBFileSpec(remote_path, False)1617        )1618        if err.Fail():1619            raise Exception(1620                "remote_platform.Install('%s', '%s') failed: %s"1621                % (path, remote_path, err)1622            )1623        path = remote_path1624    return path1625 1626 1627def read_file_on_target(test, remote):1628    if lldb.remote_platform:1629        local = test.getBuildArtifact("file_from_target")1630        error = lldb.remote_platform.Get(1631            lldb.SBFileSpec(remote, False), lldb.SBFileSpec(local, True)1632        )1633        test.assertTrue(1634            error.Success(), "Reading file {0} failed: {1}".format(remote, error)1635        )1636    else:1637        local = remote1638    with open(local, "r") as f:1639        return f.read()1640 1641 1642def read_file_from_process_wd(test, name):1643    path = append_to_process_working_directory(test, name)1644    return read_file_on_target(test, path)1645 1646 1647def wait_for_file_on_target(testcase, file_path, max_attempts=6):1648    for i in range(max_attempts):1649        err, retcode, msg = testcase.run_platform_command("ls %s" % file_path)1650        if err.Success() and retcode == 0:1651            break1652        if i < max_attempts:1653            # Exponential backoff!1654            import time1655 1656            time.sleep(pow(2, i) * 0.25)1657    else:1658        testcase.fail(1659            "File %s not found even after %d attempts." % (file_path, max_attempts)1660        )1661 1662    return read_file_on_target(testcase, file_path)1663 1664 1665def packetlog_get_process_info(log):1666    """parse a gdb-remote packet log file and extract the response to qProcessInfo"""1667    process_info = dict()1668    with open(log, "r") as logfile:1669        process_info_ostype = None1670        expect_process_info_response = False1671        for line in logfile:1672            if expect_process_info_response:1673                for pair in line.split(";"):1674                    keyval = pair.split(":")1675                    if len(keyval) == 2:1676                        process_info[keyval[0]] = keyval[1]1677                break1678            if "send packet: $qProcessInfo#" in line:1679                expect_process_info_response = True1680    return process_info1681 1682 1683def packetlog_get_dylib_info(log):1684    """parse a gdb-remote packet log file and extract the *last* complete1685    (=> fetch_all_solibs=true) response to jGetLoadedDynamicLibrariesInfos"""1686    import json1687 1688    dylib_info = None1689    with open(log, "r") as logfile:1690        dylib_info = None1691        expect_dylib_info_response = False1692        for line in logfile:1693            if expect_dylib_info_response:1694                while line[0] != "$":1695                    line = line[1:]1696                line = line[1:]1697                # Unescape '}'.1698                dylib_info = json.loads(line.replace("}]", "}")[:-4])1699                expect_dylib_info_response = False1700            if (1701                'send packet: $jGetLoadedDynamicLibrariesInfos:{"fetch_all_solibs":true}'1702                in line1703            ):1704                expect_dylib_info_response = True1705 1706    return dylib_info1707 1708 1709# ========================1710# Utilities for simulators1711# ========================1712 1713 1714def get_latest_apple_simulator(platform_name, log=None):1715    # Run simctl to list all simulators1716    cmd = ["xcrun", "simctl", "list", "-j", "devices"]1717    cmd_str = " ".join(cmd)1718    if log:1719        log(cmd_str)1720    sim_devices_str = subprocess.check_output(cmd).decode("utf-8")1721    sim_devices = json.loads(sim_devices_str)["devices"]1722 1723    # Find an available simulator for the requested platform1724    device_uuid = None1725    device_runtime = None1726    for simulator in sim_devices:1727        if isinstance(simulator, dict):1728            runtime = simulator["name"]1729            devices = simulator["devices"]1730        else:1731            runtime = simulator1732            devices = sim_devices[simulator]1733        if not platform_name in runtime.lower():1734            continue1735        for device in devices:1736            if "availability" in device and device["availability"] != "(available)":1737                continue1738            if "isAvailable" in device and not device["isAvailable"]:1739                continue1740            if device_runtime and runtime < device_runtime:1741                continue1742            device_uuid = device["udid"]1743            device_runtime = runtime1744            # Stop searching in this runtime1745            break1746 1747    return device_uuid1748 1749 1750def launch_exe_in_apple_simulator(1751    device_uuid,1752    exe_path,1753    exe_args=[],1754    stderr_lines_to_read=0,1755    stderr_patterns=[],1756    log=None,1757):1758    exe_path = os.path.realpath(exe_path)1759    cmd = [1760        "xcrun",1761        "simctl",1762        "spawn",1763        "-s",1764        device_uuid,1765        exe_path,1766    ] + exe_args1767    if log:1768        log(" ".join(cmd))1769    sim_launcher = subprocess.Popen(cmd, stderr=subprocess.PIPE)1770 1771    # Read stderr to try to find matches.1772    # Each pattern will return the value of group[1] of the first match in the stderr.1773    # Will read at most stderr_lines_to_read lines.1774    # Will early terminate when all matches have been found.1775    total_patterns = len(stderr_patterns)1776    matches_found = 01777    matched_strings = [None] * total_patterns1778    for _ in range(0, stderr_lines_to_read):1779        stderr = sim_launcher.stderr.readline().decode("utf-8")1780        if not stderr:1781            continue1782        for i, pattern in enumerate(stderr_patterns):1783            if matched_strings[i] is not None:1784                continue1785            match = re.match(pattern, stderr)1786            if match:1787                matched_strings[i] = str(match.group(1))1788                matches_found += 11789        if matches_found == total_patterns:1790            break1791 1792    return exe_path, matched_strings1793