brintos

brintos / llvm-project-archived public Read only

0
0
Text · 104.4 KiB · 8c1eea9 Raw
2754 lines · python
1"""2LLDB module which provides the abstract base class of lldb test case.3 4The concrete subclass can override lldbtest.TestBase in order to inherit the5common behavior for unitest.TestCase.setUp/tearDown implemented in this file.6 7./dotest.py provides a test driver which sets up the environment to run the8entire of part of the test suite .  Example:9 10# Exercises the test suite in the types directory....11/Volumes/data/lldb/svn/ToT/test $ ./dotest.py -A x86_64 types12...13 14Session logs for test failures/errors/unexpected successes will go into directory '2012-05-16-13_35_42'15Command invoked: python ./dotest.py -A x86_64 types16compilers=['clang']17 18Configuration: arch=x86_64 compiler=clang19----------------------------------------------------------------------20Collected 72 tests21 22........................................................................23----------------------------------------------------------------------24Ran 72 tests in 135.468s25 26OK27$28"""29 30# System modules31import abc32from functools import wraps33import gc34import io35import json36import os.path37import re38import shutil39import shlex40import signal41from subprocess import *42import sys43import time44import traceback45 46# Third-party modules47import unittest48 49# LLDB modules50import lldb51from . import configuration52from . import cpu_feature53from . import decorators54from . import lldbplatformutil55from . import lldbtest_config56from . import lldbutil57from . import test_categories58from lldbsuite.support import encoded_file59from lldbsuite.support import funcutils60from lldbsuite.test_event import build_exception61 62# See also dotest.parseOptionsAndInitTestdirs(), where the environment variables63# LLDB_COMMAND_TRACE is set from '-t' option.64 65# By default, traceAlways is False.66if "LLDB_COMMAND_TRACE" in os.environ and os.environ["LLDB_COMMAND_TRACE"] == "YES":67    traceAlways = True68else:69    traceAlways = False70 71# By default, doCleanup is True.72if "LLDB_DO_CLEANUP" in os.environ and os.environ["LLDB_DO_CLEANUP"] == "NO":73    doCleanup = False74else:75    doCleanup = True76 77 78#79# Some commonly used assert messages.80#81 82COMMAND_FAILED_AS_EXPECTED = "Command has failed as expected"83 84CURRENT_EXECUTABLE_SET = "Current executable set successfully"85 86PROCESS_IS_VALID = "Process is valid"87 88PROCESS_KILLED = "Process is killed successfully"89 90PROCESS_EXITED = "Process exited successfully"91 92PROCESS_STOPPED = "Process status should be stopped"93 94RUN_SUCCEEDED = "Process is launched successfully"95 96RUN_COMPLETED = "Process exited successfully"97 98BACKTRACE_DISPLAYED_CORRECTLY = "Backtrace displayed correctly"99 100BREAKPOINT_CREATED = "Breakpoint created successfully"101 102BREAKPOINT_STATE_CORRECT = "Breakpoint state is correct"103 104BREAKPOINT_PENDING_CREATED = "Pending breakpoint created successfully"105 106BREAKPOINT_HIT_ONCE = "Breakpoint resolved with hit count = 1"107 108BREAKPOINT_HIT_TWICE = "Breakpoint resolved with hit count = 2"109 110BREAKPOINT_HIT_THRICE = "Breakpoint resolved with hit count = 3"111 112MISSING_EXPECTED_REGISTERS = "At least one expected register is unavailable."113 114OBJECT_PRINTED_CORRECTLY = "Object printed correctly"115 116SOURCE_DISPLAYED_CORRECTLY = "Source code displayed correctly"117 118STEP_IN_SUCCEEDED = "Thread step-in succeeded"119 120STEP_OUT_SUCCEEDED = "Thread step-out succeeded"121 122STOPPED_DUE_TO_EXC_BAD_ACCESS = "Process should be stopped due to bad access exception"123 124STOPPED_DUE_TO_ASSERT = "Process should be stopped due to an assertion"125 126STOPPED_DUE_TO_BREAKPOINT = "Process should be stopped due to breakpoint"127 128STOPPED_DUE_TO_BREAKPOINT_WITH_STOP_REASON_AS = "%s, %s" % (129    STOPPED_DUE_TO_BREAKPOINT,130    "instead, the actual stop reason is: '%s'",131)132 133STOPPED_DUE_TO_BREAKPOINT_CONDITION = "Stopped due to breakpoint condition"134 135STOPPED_DUE_TO_BREAKPOINT_IGNORE_COUNT = "Stopped due to breakpoint and ignore count"136 137STOPPED_DUE_TO_BREAKPOINT_JITTED_CONDITION = (138    "Stopped due to breakpoint jitted condition"139)140 141STOPPED_DUE_TO_SIGNAL = "Process state is stopped due to signal"142 143STOPPED_DUE_TO_STEP_IN = "Process state is stopped due to step in"144 145STOPPED_DUE_TO_WATCHPOINT = "Process should be stopped due to watchpoint"146 147STOPPED_DUE_TO_HISTORY_BOUNDARY = "Process should be stopped due to history boundary"148 149DATA_TYPES_DISPLAYED_CORRECTLY = "Data type(s) displayed correctly"150 151VALID_BREAKPOINT = "Got a valid breakpoint"152 153VALID_BREAKPOINT_LOCATION = "Got a valid breakpoint location"154 155VALID_COMMAND_INTERPRETER = "Got a valid command interpreter"156 157VALID_FILESPEC = "Got a valid filespec"158 159VALID_MODULE = "Got a valid module"160 161VALID_PROCESS = "Got a valid process"162 163VALID_SYMBOL = "Got a valid symbol"164 165VALID_TARGET = "Got a valid target"166 167VALID_PLATFORM = "Got a valid platform"168 169VALID_TYPE = "Got a valid type"170 171VALID_VARIABLE = "Got a valid variable"172 173VARIABLES_DISPLAYED_CORRECTLY = "Variable(s) displayed correctly"174 175WATCHPOINT_CREATED = "Watchpoint created successfully"176 177 178def CMD_MSG(command):179    """A generic "Command '%s' did not return successfully" message generator."""180    return f"Command '{command}' did not return successfully"181 182 183def COMPLETION_MSG(str_before, str_after, completions):184    """A generic assertion failed message generator for the completion mechanism."""185    return "'%s' successfully completes to '%s', but completions were:\n%s" % (186        str_before,187        str_after,188        "\n".join(completions),189    )190 191 192def EXP_MSG(str, actual, exe):193    """A generic "'%s' returned unexpected result" message generator if exe.194    Otherwise, it generates "'%s' does not match expected result" message."""195 196    return "'%s' %s result, got '%s'" % (197        str,198        "returned unexpected" if exe else "does not match expected",199        actual.strip(),200    )201 202 203def SETTING_MSG(setting):204    """A generic "Value of setting '%s' is not correct" message generator."""205    return "Value of setting '%s' is not correct" % setting206 207 208def line_number(filename, string_to_match):209    """Helper function to return the line number of the first matched string."""210    with io.open(filename, mode="r", encoding="utf-8") as f:211        for i, line in enumerate(f):212            if line.find(string_to_match) != -1:213                # Found our match.214                return i + 1215    raise Exception("Unable to find '%s' within file %s" % (string_to_match, filename))216 217 218def get_line(filename, line_number):219    """Return the text of the line at the 1-based line number."""220    with io.open(filename, mode="r", encoding="utf-8") as f:221        return f.readlines()[line_number - 1]222 223 224def pointer_size():225    """Return the pointer size of the host system."""226    import ctypes227 228    a_pointer = ctypes.c_void_p(0xFFFF)229    return 8 * ctypes.sizeof(a_pointer)230 231 232def is_exe(fpath):233    """Returns true if fpath is an executable."""234    if fpath is None:235        return False236    if sys.platform == "win32":237        if not fpath.endswith(".exe"):238            fpath += ".exe"239    return os.path.isfile(fpath) and os.access(fpath, os.X_OK)240 241 242def which(program):243    """Returns the full path to a program; None otherwise."""244    fpath, fname = os.path.split(program)245    if fpath:246        if is_exe(program):247            return program248    else:249        for path in os.environ["PATH"].split(os.pathsep):250            exe_file = os.path.join(path, program)251            if is_exe(exe_file):252                return exe_file253    return None254 255 256class ValueCheck:257    def __init__(258        self,259        name=None,260        value=None,261        type=None,262        summary=None,263        children=None,264        dereference=None,265    ):266        """267        :param name: The name that the SBValue should have. None if the summary268                     should not be checked.269        :param summary: The summary that the SBValue should have. None if the270                        summary should not be checked.271        :param value: The value that the SBValue should have. None if the value272                      should not be checked.273        :param type: The type that the SBValue result should have. None if the274                     type should not be checked.275        :param children: A list of ValueChecks that need to match the children276                         of this SBValue. None if children shouldn't be checked.277                         The order of checks is the order of the checks in the278                         list. The number of checks has to match the number of279                         children.280        :param dereference: A ValueCheck for the SBValue returned by the281                            `Dereference` function.282        """283        self.expect_name = name284        self.expect_value = value285        self.expect_type = type286        self.expect_summary = summary287        self.children = children288        self.dereference = dereference289 290    def check_value(self, test_base, val, error_msg=None):291        """292        Checks that the given value matches the currently set properties293        of this ValueCheck. If a match failed, the given TestBase will294        be used to emit an error. A custom error message can be specified295        that will be used to describe failed check for this SBValue (but296        not errors in the child values).297        """298 299        this_error_msg = error_msg if error_msg else ""300        this_error_msg += "\nChecking SBValue: " + str(val)301 302        test_base.assertSuccess(val.GetError())303 304        # Python 3.6 doesn't declare a `re.Pattern` type, get the dynamic type.305        pattern_type = type(re.compile(""))306 307        if self.expect_name:308            test_base.assertEqual(self.expect_name, val.GetName(), this_error_msg)309        if self.expect_value:310            if isinstance(self.expect_value, pattern_type):311                test_base.assertRegex(val.GetValue(), self.expect_value, this_error_msg)312            else:313                test_base.assertEqual(self.expect_value, val.GetValue(), this_error_msg)314        if self.expect_type:315            test_base.assertEqual(316                self.expect_type, val.GetDisplayTypeName(), this_error_msg317            )318        if self.expect_summary:319            if isinstance(self.expect_summary, pattern_type):320                test_base.assertRegex(321                    val.GetSummary(), self.expect_summary, this_error_msg322                )323            else:324                test_base.assertEqual(325                    self.expect_summary, val.GetSummary(), this_error_msg326                )327        if self.children is not None:328            self.check_value_children(test_base, val, error_msg)329 330        if self.dereference is not None:331            self.dereference.check_value(test_base, val.Dereference(), error_msg)332 333    def check_value_children(self, test_base, val, error_msg=None):334        """335        Checks that the children of a SBValue match a certain structure and336        have certain properties.337 338        :param test_base: The current test's TestBase object.339        :param val: The SBValue to check.340        """341 342        this_error_msg = error_msg if error_msg else ""343        this_error_msg += "\nChecking SBValue: " + str(val)344 345        test_base.assertEqual(len(self.children), val.GetNumChildren(), this_error_msg)346 347        for i in range(0, val.GetNumChildren()):348            expected_child = self.children[i]349            actual_child = val.GetChildAtIndex(i)350            child_error = "Checking child with index " + str(i) + ":\n" + error_msg351            expected_child.check_value(test_base, actual_child, child_error)352 353 354class recording(io.StringIO):355    """356    A nice little context manager for recording the debugger interactions into357    our session object.  If trace flag is ON, it also emits the interactions358    into the stderr.359    """360 361    def __init__(self, test, trace):362        """Create a io.StringIO instance; record the session obj and trace flag."""363        io.StringIO.__init__(self)364        # The test might not have undergone the 'setUp(self)' phase yet, so that365        # the attribute 'session' might not even exist yet.366        self.session = getattr(test, "session", None) if test else None367        self.trace = trace368 369    def __enter__(self):370        """371        Context management protocol on entry to the body of the with statement.372        Just return the io.StringIO object.373        """374        return self375 376    def __exit__(self, type, value, tb):377        """378        Context management protocol on exit from the body of the with statement.379        If trace is ON, it emits the recordings into stderr.  Always add the380        recordings to our session object.  And close the io.StringIO object, too.381        """382        if self.trace:383            print(self.getvalue(), file=sys.stderr)384        if self.session:385            print(self.getvalue(), file=self.session)386        self.close()387 388 389class _BaseProcess(object, metaclass=abc.ABCMeta):390    @abc.abstractproperty391    def pid(self):392        """Returns process PID if has been launched already."""393 394    @abc.abstractmethod395    def launch(self, executable, args, extra_env):396        """Launches new process with given executable and args."""397 398    @abc.abstractmethod399    def terminate(self):400        """Terminates previously launched process.."""401 402 403class _LocalProcess(_BaseProcess):404    def __init__(self, trace_on):405        self._proc = None406        self._trace_on = trace_on407        self._delayafterterminate = 0.1408 409    @property410    def pid(self):411        return self._proc.pid412 413    def launch(self, executable, args, extra_env):414        env = None415        if extra_env:416            env = dict(os.environ)417            env.update([kv.split("=", 1) for kv in extra_env])418 419        self._proc = Popen(420            [executable] + args,421            stdout=DEVNULL if not self._trace_on else None,422            stdin=PIPE,423            env=env,424        )425 426    def terminate(self):427        if self._proc.poll() is None:428            # Terminate _proc like it does the pexpect429            signals_to_try = [430                sig for sig in ["SIGHUP", "SIGCONT", "SIGINT"] if sig in dir(signal)431            ]432            for sig in signals_to_try:433                try:434                    self._proc.send_signal(getattr(signal, sig))435                    time.sleep(self._delayafterterminate)436                    if self._proc.poll() is not None:437                        return438                except ValueError:439                    pass  # Windows says SIGINT is not a valid signal to send440            self._proc.terminate()441            time.sleep(self._delayafterterminate)442            if self._proc.poll() is not None:443                return444            self._proc.kill()445            time.sleep(self._delayafterterminate)446 447    def poll(self):448        return self._proc.poll()449 450    def wait(self, timeout=None):451        return self._proc.wait(timeout)452 453 454class _RemoteProcess(_BaseProcess):455    def __init__(self, install_remote):456        self._pid = None457        self._install_remote = install_remote458 459    @property460    def pid(self):461        return self._pid462 463    def launch(self, executable, args, extra_env):464        if self._install_remote:465            src_path = executable466            dst_path = lldbutil.join_remote_paths(467                lldb.remote_platform.GetWorkingDirectory(), os.path.basename(executable)468            )469 470            dst_file_spec = lldb.SBFileSpec(dst_path, False)471            err = lldb.remote_platform.Install(472                lldb.SBFileSpec(src_path, True), dst_file_spec473            )474            if err.Fail():475                raise Exception(476                    "remote_platform.Install('%s', '%s') failed: %s"477                    % (src_path, dst_path, err)478                )479        else:480            dst_path = executable481            dst_file_spec = lldb.SBFileSpec(executable, False)482 483        launch_info = lldb.SBLaunchInfo(args)484        launch_info.SetExecutableFile(dst_file_spec, True)485        launch_info.SetWorkingDirectory(lldb.remote_platform.GetWorkingDirectory())486 487        # Redirect stdout and stderr to /dev/null488        launch_info.AddSuppressFileAction(1, False, True)489        launch_info.AddSuppressFileAction(2, False, True)490 491        if extra_env:492            launch_info.SetEnvironmentEntries(extra_env, True)493 494        err = lldb.remote_platform.Launch(launch_info)495        if err.Fail():496            raise Exception(497                "remote_platform.Launch('%s', '%s') failed: %s" % (dst_path, args, err)498            )499        self._pid = launch_info.GetProcessID()500 501    def terminate(self):502        lldb.remote_platform.Kill(self._pid)503 504 505def getsource_if_available(obj):506    """507    Return the text of the source code for an object if available.  Otherwise,508    a print representation is returned.509    """510    import inspect511 512    try:513        return inspect.getsource(obj)514    except:515        return repr(obj)516 517 518def builder_module():519    return lldbplatformutil.builder_module()520 521 522class Base(unittest.TestCase):523    """524    Abstract base for performing lldb (see TestBase) or other generic tests (see525    BenchBase for one example).  lldbtest.Base works with the test driver to526    accomplish things.527 528    """529 530    # The concrete subclass should override this attribute.531    mydir = None532 533    # Keep track of the old current working directory.534    oldcwd = None535 536    # Maximum allowed attempts when launching the inferior process.537    # Can be overridden by the LLDB_MAX_LAUNCH_COUNT environment variable.538    maxLaunchCount = 1539 540    # Time to wait before the next launching attempt in second(s).541    # Can be overridden by the LLDB_TIME_WAIT_NEXT_LAUNCH environment variable.542    timeWaitNextLaunch = 1.0543 544    @staticmethod545    def compute_mydir(test_file):546        """Subclasses should call this function to correctly calculate the547        required "mydir" attribute as follows:548 549         mydir = TestBase.compute_mydir(__file__)550        """551        # /abs/path/to/packages/group/subdir/mytest.py -> group/subdir552        lldb_test_src = configuration.test_src_root553        if not test_file.startswith(lldb_test_src):554            raise Exception(555                "Test file '%s' must reside within lldb_test_src "556                "(which is '%s')." % (test_file, lldb_test_src)557            )558        return os.path.dirname(os.path.relpath(test_file, start=lldb_test_src))559 560    def TraceOn(self):561        """Returns True if we are in trace mode (tracing detailed test execution)."""562        return traceAlways563 564    def trace(self, *args, **kwargs):565        with recording(self, self.TraceOn()) as sbuf:566            print(*args, file=sbuf, **kwargs)567 568    @classmethod569    def setUpClass(cls):570        """571        Python unittest framework class setup fixture.572        Do current directory manipulation.573        """574        # Fail fast if 'mydir' attribute is not overridden.575        if not cls.mydir:576            cls.mydir = Base.compute_mydir(sys.modules[cls.__module__].__file__)577        if not cls.mydir:578            raise Exception("Subclasses must override the 'mydir' attribute.")579 580        # Save old working directory.581        cls.oldcwd = os.getcwd()582 583        full_dir = os.path.join(configuration.test_src_root, cls.mydir)584        if traceAlways:585            print("Change dir to:", full_dir, file=sys.stderr)586        os.chdir(full_dir)587 588        # Set platform context.589        cls.platformContext = lldbplatformutil.createPlatformContext()590 591    @classmethod592    def tearDownClass(cls):593        """594        Python unittest framework class teardown fixture.595        Do class-wide cleanup.596        """597 598        if doCleanup:599            # First, let's do the platform-specific cleanup.600            module = builder_module()601            module.cleanup()602 603            # Subclass might have specific cleanup function defined.604            if getattr(cls, "classCleanup", None):605                if traceAlways:606                    print(607                        "Call class-specific cleanup function for class:",608                        cls,609                        file=sys.stderr,610                    )611                try:612                    cls.classCleanup()613                except:614                    exc_type, exc_value, exc_tb = sys.exc_info()615                    traceback.print_exception(exc_type, exc_value, exc_tb)616 617        # Restore old working directory.618        if traceAlways:619            print("Restore dir to:", cls.oldcwd, file=sys.stderr)620        os.chdir(cls.oldcwd)621 622    def enableLogChannelsForCurrentTest(self):623        if len(lldbtest_config.channels) == 0:624            return625 626        # if debug channels are specified in lldbtest_config.channels,627        # create a new set of log files for every test628        log_basename = self.getLogBasenameForCurrentTest()629 630        # confirm that the file is writeable631        host_log_path = "{}-host.log".format(log_basename)632        open(host_log_path, "w").close()633        self.log_files.append(host_log_path)634 635        log_enable = "log enable -Tpn -f {} ".format(host_log_path)636        for channel_with_categories in lldbtest_config.channels:637            channel_then_categories = channel_with_categories.split(" ", 1)638            channel = channel_then_categories[0]639            if len(channel_then_categories) > 1:640                categories = channel_then_categories[1]641            else:642                categories = "default"643 644            if channel == "gdb-remote" and lldb.remote_platform is None:645                # communicate gdb-remote categories to debugserver646                os.environ["LLDB_DEBUGSERVER_LOG_FLAGS"] = categories647 648            self.ci.HandleCommand(log_enable + channel_with_categories, self.res)649            if not self.res.Succeeded():650                raise Exception(651                    "log enable failed (check LLDB_LOG_OPTION env variable)"652                )653 654        # Communicate log path name to debugserver & lldb-server655        # For remote debugging, these variables need to be set when starting the platform656        # instance.657        if lldb.remote_platform is None:658            server_log_path = "{}-server.log".format(log_basename)659            open(server_log_path, "w").close()660            self.log_files.append(server_log_path)661            os.environ["LLDB_DEBUGSERVER_LOG_FILE"] = server_log_path662 663            # Communicate channels to lldb-server664            os.environ["LLDB_SERVER_LOG_CHANNELS"] = ":".join(lldbtest_config.channels)665 666        self.addTearDownHook(self.disableLogChannelsForCurrentTest)667 668    def disableLogChannelsForCurrentTest(self):669        # close all log files that we opened670        for channel_and_categories in lldbtest_config.channels:671            # channel format - <channel-name> [<category0> [<category1> ...]]672            channel = channel_and_categories.split(" ", 1)[0]673            self.ci.HandleCommand("log disable " + channel, self.res)674            if not self.res.Succeeded():675                raise Exception(676                    "log disable failed (check LLDB_LOG_OPTION env variable)"677                )678 679        # Retrieve the server log (if any) from the remote system. It is assumed the server log680        # is writing to the "server.log" file in the current test directory. This can be681        # achieved by setting LLDB_DEBUGSERVER_LOG_FILE="server.log" when starting remote682        # platform.683        if lldb.remote_platform:684            server_log_path = self.getLogBasenameForCurrentTest() + "-server.log"685            if lldb.remote_platform.Get(686                lldb.SBFileSpec("server.log"), lldb.SBFileSpec(server_log_path)687            ).Success():688                self.log_files.append(server_log_path)689 690    def setPlatformWorkingDir(self):691        if not lldb.remote_platform or not configuration.lldb_platform_working_dir:692            return693 694        components = self.mydir.split(os.path.sep) + [695            str(self.test_number),696            self.getBuildDirBasename(),697        ]698        remote_test_dir = configuration.lldb_platform_working_dir699        for c in components:700            remote_test_dir = lldbutil.join_remote_paths(remote_test_dir, c)701            error = lldb.remote_platform.MakeDirectory(702                remote_test_dir, 448703            )  # 448 = 0o700704            if error.Fail():705                raise Exception(706                    "making remote directory '%s': %s" % (remote_test_dir, error)707                )708 709        lldb.remote_platform.SetWorkingDirectory(remote_test_dir)710 711        # This function removes all files from the current working directory while leaving712        # the directories in place. The cleanup is required to reduce the disk space required713        # by the test suite while leaving the directories untouched is neccessary because714        # sub-directories might belong to an other test715        def clean_working_directory():716            # TODO: Make it working on Windows when we need it for remote debugging support717            # TODO: Replace the heuristic to remove the files with a logic what collects the718            # list of files we have to remove during test runs.719            shell_cmd = lldb.SBPlatformShellCommand("rm %s/*" % remote_test_dir)720            lldb.remote_platform.Run(shell_cmd)721 722        self.addTearDownHook(clean_working_directory)723 724    def getSourceDir(self):725        """Return the full path to the current test."""726        return os.path.join(configuration.test_src_root, self.mydir)727 728    def getBuildDirBasename(self):729        return self.__class__.__module__ + "." + self.testMethodName730 731    def getBuildDir(self):732        """Return the full path to the current test."""733        return os.path.join(734            configuration.test_build_dir, self.mydir, self.getBuildDirBasename()735        )736 737    def makeBuildDir(self):738        """Create the test-specific working directory, deleting any previous739        contents."""740        bdir = self.getBuildDir()741        if os.path.isdir(bdir):742            shutil.rmtree(bdir)743        lldbutil.mkdir_p(bdir)744 745    def getBuildArtifact(self, name="a.out"):746        """Return absolute path to an artifact in the test's build directory."""747        return os.path.join(self.getBuildDir(), name)748 749    def getSourcePath(self, name):750        """Return absolute path to a file in the test's source directory."""751        return os.path.join(self.getSourceDir(), name)752 753    def getPlatformAvailablePorts(self):754        """Return ports available for connection to a lldb server on the remote platform."""755        return configuration.lldb_platform_available_ports756 757    @classmethod758    def setUpCommands(cls):759        commands = [760            # First of all, clear all settings to have clean state of global properties.761            "settings clear --all",762            # Disable Spotlight lookup. The testsuite creates763            # different binaries with the same UUID, because they only764            # differ in the debug info, which is not being hashed.765            "settings set symbols.enable-external-lookup false",766            # Inherit the TCC permissions from the inferior's parent.767            "settings set target.inherit-tcc true",768            # Based on https://discourse.llvm.org/t/running-lldb-in-a-container/76801/4769            "settings set target.disable-aslr false",770            # Kill rather than detach from the inferior if something goes wrong.771            "settings set target.detach-on-error false",772            # Disable fix-its by default so that incorrect expressions in tests don't773            # pass just because Clang thinks it has a fix-it.774            "settings set target.auto-apply-fixits false",775            # Testsuite runs in parallel and the host can have also other load.776            "settings set plugin.process.gdb-remote.packet-timeout 60",777            'settings set symbols.clang-modules-cache-path "{}"'.format(778                configuration.lldb_module_cache_dir779            ),780            # Disable colors by default.781            "settings set use-color false",782            # Disable the statusline by default.783            "settings set show-statusline false",784        ]785 786        # Set any user-overridden settings.787        for setting, value in configuration.settings:788            commands.append("setting set %s %s" % (setting, value))789 790        # Make sure that a sanitizer LLDB's environment doesn't get passed on.791        if (792            cls.platformContext793            and cls.platformContext.shlib_environment_var in os.environ794        ):795            commands.append(796                "settings set target.env-vars {}=".format(797                    cls.platformContext.shlib_environment_var798                )799            )800 801        # Set environment variables for the inferior.802        if lldbtest_config.inferior_env:803            commands.append(804                "settings set target.env-vars {}".format(lldbtest_config.inferior_env)805            )806        return commands807 808    def setUp(self):809        """Fixture for unittest test case setup.810 811        It works with the test driver to conditionally skip tests and does other812        initializations."""813        # import traceback814        # traceback.print_stack()815 816        if "LLDB_MAX_LAUNCH_COUNT" in os.environ:817            self.maxLaunchCount = int(os.environ["LLDB_MAX_LAUNCH_COUNT"])818 819        if "LLDB_TIME_WAIT_NEXT_LAUNCH" in os.environ:820            self.timeWaitNextLaunch = float(os.environ["LLDB_TIME_WAIT_NEXT_LAUNCH"])821 822        if "LIBCXX_PATH" in os.environ:823            self.libcxxPath = os.environ["LIBCXX_PATH"]824        else:825            self.libcxxPath = None826 827        if "LLDBDAP_EXEC" in os.environ:828            self.lldbDAPExec = os.environ["LLDBDAP_EXEC"]829        else:830            self.lldbDAPExec = None831 832        self.lldbOption = " ".join("-o '" + s + "'" for s in self.setUpCommands())833 834        # If we spawn an lldb process for test (via pexpect), do not load the835        # init file unless told otherwise.836        if os.environ.get("NO_LLDBINIT") != "NO":837            self.lldbOption += " --no-lldbinit"838 839        # Assign the test method name to self.testMethodName.840        #841        # For an example of the use of this attribute, look at test/types dir.842        # There are a bunch of test cases under test/types and we don't want the843        # module cacheing subsystem to be confused with executable name "a.out"844        # used for all the test cases.845        self.testMethodName = self._testMethodName846 847        # This is for the case of directly spawning 'lldb'/'gdb' and interacting848        # with it using pexpect.849        self.child = None850        self.child_prompt = "(lldb) "851        # If the child is interacting with the embedded script interpreter,852        # there are two exits required during tear down, first to quit the853        # embedded script interpreter and second to quit the lldb command854        # interpreter.855        self.child_in_script_interpreter = False856 857        # These are for customized teardown cleanup.858        self.dict = None859        self.doTearDownCleanup = False860        # And in rare cases where there are multiple teardown cleanups.861        self.dicts = []862        self.doTearDownCleanups = False863 864        # List of spawned subproces.Popen objects865        self.subprocesses = []866 867        # List of log files produced by the current test.868        self.log_files = []869 870        # Create the build directory.871        # The logs are stored in the build directory, so we have to create it872        # before creating the first log file.873        self.makeBuildDir()874 875        session_file = self.getLogBasenameForCurrentTest() + ".log"876        self.log_files.append(session_file)877 878        # Optimistically set __errored__, __failed__, __expected__ to False879        # initially.  If the test errored/failed, the session info880        # is then dumped into a session specific file for diagnosis.881        self.__cleanup_errored__ = False882        self.__errored__ = False883        self.__failed__ = False884        self.__expected__ = False885        # We are also interested in unexpected success.886        self.__unexpected__ = False887        # And skipped tests.888        self.__skipped__ = False889 890        # See addTearDownHook(self, hook) which allows the client to add a hook891        # function to be run during tearDown() time.892        self.hooks = []893 894        # See HideStdout(self).895        self.sys_stdout_hidden = False896 897        if self.platformContext:898            # set environment variable names for finding shared libraries899            self.dylibPath = self.platformContext.shlib_environment_var900 901        # Create the debugger instance.902        self.dbg = lldb.SBDebugger.Create()903        # Copy selected platform from a global instance if it exists.904        if lldb.selected_platform is not None:905            self.dbg.SetSelectedPlatform(lldb.selected_platform)906 907        if not self.dbg:908            raise Exception("Invalid debugger instance")909 910        # Retrieve the associated command interpreter instance.911        self.ci = self.dbg.GetCommandInterpreter()912        if not self.ci:913            raise Exception("Could not get the command interpreter")914 915        # And the result object.916        self.res = lldb.SBCommandReturnObject()917 918        self.setPlatformWorkingDir()919        self.enableLogChannelsForCurrentTest()920 921        self.lib_lldb = None922        self.framework_dir = None923        self.darwinWithFramework = False924 925        if sys.platform.startswith("darwin") and configuration.lldb_framework_path:926            framework = configuration.lldb_framework_path927            lib = os.path.join(framework, "LLDB")928            if os.path.exists(lib):929                self.framework_dir = os.path.dirname(framework)930                self.lib_lldb = lib931                self.darwinWithFramework = self.platformIsDarwin()932 933    def setAsync(self, value):934        """Sets async mode to True/False and ensures it is reset after the testcase completes."""935        old_async = self.dbg.GetAsync()936        self.dbg.SetAsync(value)937        self.addTearDownHook(lambda: self.dbg.SetAsync(old_async))938 939    def cleanupSubprocesses(self):940        # Terminate subprocesses in reverse order from how they were created.941        for p in reversed(self.subprocesses):942            p.terminate()943            del p944        del self.subprocesses[:]945 946    def spawnSubprocess(self, executable, args=[], extra_env=None, install_remote=True):947        """Creates a subprocess.Popen object with the specified executable and arguments,948        saves it in self.subprocesses, and returns the object.949        """950        proc = (951            _RemoteProcess(install_remote)952            if lldb.remote_platform953            else _LocalProcess(self.TraceOn())954        )955        proc.launch(executable, args, extra_env=extra_env)956        self.subprocesses.append(proc)957        return proc958 959    def runCmd(self, cmd, msg=None, check=True, trace=False, inHistory=False):960        """961        Ask the command interpreter to handle the command and then check its962        return status.963        """964        # Fail fast if 'cmd' is not meaningful.965        if cmd is None:966            raise Exception("Bad 'cmd' parameter encountered")967 968        trace = True if traceAlways else trace969 970        if cmd.startswith("target create "):971            cmd = cmd.replace("target create ", "file ")972 973        running = cmd.startswith("run") or cmd.startswith("process launch")974 975        for i in range(self.maxLaunchCount if running else 1):976            with recording(self, trace) as sbuf:977                print("runCmd:", cmd, file=sbuf)978                if not check:979                    print("check of return status not required", file=sbuf)980 981            self.ci.HandleCommand(cmd, self.res, inHistory)982 983            with recording(self, trace) as sbuf:984                if self.res.Succeeded():985                    print("output:", self.res.GetOutput(), file=sbuf)986                else:987                    print("runCmd failed!", file=sbuf)988                    print(self.res.GetError(), file=sbuf)989 990            if self.res.Succeeded():991                break992            elif running:993                # For process launch, wait some time before possible next try.994                time.sleep(self.timeWaitNextLaunch)995                with recording(self, trace) as sbuf:996                    print("Command '" + cmd + "' failed!", file=sbuf)997 998        if check:999            if not msg:1000                msg = CMD_MSG(cmd)1001            output = ""1002            if self.res.GetOutput():1003                output += "\nCommand output:\n" + self.res.GetOutput()1004            if self.res.GetError():1005                output += "\nError output:\n" + self.res.GetError()1006            self.assertTrue(self.res.Succeeded(), msg + output)1007 1008    def HideStdout(self):1009        """Hide output to stdout from the user.1010 1011        During test execution, there might be cases where we don't want to show the1012        standard output to the user.  For example,1013 1014            self.runCmd(r'''sc print("\n\n\tHello!\n")''')1015 1016        tests whether command abbreviation for 'script' works or not.  There is no1017        need to show the 'Hello' output to the user as long as the 'script' command1018        succeeds and we are not in TraceOn() mode (see the '-t' option).1019 1020        In this case, the test method calls self.HideStdout(self) to redirect the1021        sys.stdout to a null device, and restores the sys.stdout upon teardown.1022 1023        Note that you should only call this method at most once during a test case1024        execution.  Any subsequent call has no effect at all."""1025        if self.sys_stdout_hidden:1026            return1027 1028        self.sys_stdout_hidden = True1029        old_stdout = sys.stdout1030        sys.stdout = open(os.devnull, "w")1031 1032        def restore_stdout():1033            sys.stdout = old_stdout1034 1035        self.addTearDownHook(restore_stdout)1036 1037    # =======================================================================1038    # Methods for customized teardown cleanups as well as execution of hooks.1039    # =======================================================================1040 1041    def setTearDownCleanup(self, dictionary=None):1042        """Register a cleanup action at tearDown() time with a dictionary"""1043        self.dict = dictionary1044        self.doTearDownCleanup = True1045 1046    def addTearDownCleanup(self, dictionary):1047        """Add a cleanup action at tearDown() time with a dictionary"""1048        self.dicts.append(dictionary)1049        self.doTearDownCleanups = True1050 1051    def addTearDownHook(self, hook):1052        """1053        Add a function to be run during tearDown() time.1054 1055        Hooks are executed in a first come first serve manner.1056        """1057        if callable(hook):1058            with recording(self, traceAlways) as sbuf:1059                print("Adding tearDown hook:", getsource_if_available(hook), file=sbuf)1060            self.hooks.append(hook)1061 1062        return self1063 1064    def deletePexpectChild(self):1065        # This is for the case of directly spawning 'lldb' and interacting with it1066        # using pexpect.1067        if self.child and self.child.isalive():1068            import pexpect1069 1070            with recording(self, traceAlways) as sbuf:1071                print("tearing down the child process....", file=sbuf)1072            try:1073                if self.child_in_script_interpreter:1074                    self.child.sendline("quit()")1075                    self.child.expect_exact(self.child_prompt)1076                self.child.sendline("settings set interpreter.prompt-on-quit false")1077                self.child.sendline("quit")1078                self.child.expect(pexpect.EOF)1079            except (ValueError, pexpect.ExceptionPexpect):1080                # child is already terminated1081                pass1082            except OSError as exception:1083                import errno1084 1085                if exception.errno != errno.EIO:1086                    # unexpected error1087                    raise1088                # child is already terminated1089            finally:1090                # Give it one final blow to make sure the child is terminated.1091                self.child.close()1092 1093    def tearDown(self):1094        """Fixture for unittest test case teardown."""1095        self.deletePexpectChild()1096 1097        # Check and run any hook functions.1098        for hook in reversed(self.hooks):1099            with recording(self, traceAlways) as sbuf:1100                print(1101                    "Executing tearDown hook:", getsource_if_available(hook), file=sbuf1102                )1103            if funcutils.requires_self(hook):1104                hook(self)1105            else:1106                hook()  # try the plain call and hope it works1107 1108        del self.hooks1109 1110        # Perform registered teardown cleanup.1111        if doCleanup and self.doTearDownCleanup:1112            self.cleanup(dictionary=self.dict)1113 1114        # In rare cases where there are multiple teardown cleanups added.1115        if doCleanup and self.doTearDownCleanups:1116            if self.dicts:1117                for dict in reversed(self.dicts):1118                    self.cleanup(dictionary=dict)1119 1120        # Remove subprocesses created by the test.1121        self.cleanupSubprocesses()1122 1123        # This must be the last statement, otherwise teardown hooks or other1124        # lines might depend on this still being active.1125        lldb.SBDebugger.Destroy(self.dbg)1126        del self.dbg1127 1128        # All modules should be orphaned now so that they can be cleared from1129        # the shared module cache.1130        lldb.SBModule.GarbageCollectAllocatedModules()1131 1132        # Assert that the global module cache is empty.1133        # FIXME: This assert fails on Windows.1134        if self.getPlatform() != "windows":1135            self.assertEqual(lldb.SBModule.GetNumberAllocatedModules(), 0)1136 1137    # =========================================================1138    # Various callbacks to allow introspection of test progress1139    # =========================================================1140 1141    def markError(self):1142        """Callback invoked when an error (unexpected exception) errored."""1143        self.__errored__ = True1144        with recording(self, False) as sbuf:1145            # False because there's no need to write "ERROR" to the stderr twice.1146            # Once by the Python unittest framework, and a second time by us.1147            print("ERROR", file=sbuf)1148 1149    def markCleanupError(self):1150        """Callback invoked when an error occurs while a test is cleaning up."""1151        self.__cleanup_errored__ = True1152        with recording(self, False) as sbuf:1153            # False because there's no need to write "CLEANUP_ERROR" to the stderr twice.1154            # Once by the Python unittest framework, and a second time by us.1155            print("CLEANUP_ERROR", file=sbuf)1156 1157    def markFailure(self):1158        """Callback invoked when a failure (test assertion failure) occurred."""1159        self.__failed__ = True1160        with recording(self, False) as sbuf:1161            # False because there's no need to write "FAIL" to the stderr twice.1162            # Once by the Python unittest framework, and a second time by us.1163            print("FAIL", file=sbuf)1164 1165    def markExpectedFailure(self, err):1166        """Callback invoked when an expected failure/error occurred."""1167        self.__expected__ = True1168        with recording(self, False) as sbuf:1169            # False because there's no need to write "expected failure" to the1170            # stderr twice.1171            # Once by the Python unittest framework, and a second time by us.1172            print("expected failure", file=sbuf)1173 1174    def markSkippedTest(self):1175        """Callback invoked when a test is skipped."""1176        self.__skipped__ = True1177        with recording(self, False) as sbuf:1178            # False because there's no need to write "skipped test" to the1179            # stderr twice.1180            # Once by the Python unittest framework, and a second time by us.1181            print("skipped test", file=sbuf)1182 1183    def markUnexpectedSuccess(self):1184        """Callback invoked when an unexpected success occurred."""1185        self.__unexpected__ = True1186        with recording(self, False) as sbuf:1187            # False because there's no need to write "unexpected success" to the1188            # stderr twice.1189            # Once by the Python unittest framework, and a second time by us.1190            print("unexpected success", file=sbuf)1191 1192    def getRerunArgs(self):1193        return " -f %s.%s" % (self.__class__.__name__, self._testMethodName)1194 1195    def getLogBasenameForCurrentTest(self, prefix="Incomplete"):1196        """1197        returns a partial path that can be used as the beginning of the name of multiple1198        log files pertaining to this test1199        """1200        return os.path.join(self.getBuildDir(), prefix)1201 1202    def dumpSessionInfo(self):1203        """1204        Dump the debugger interactions leading to a test error/failure.  This1205        allows for more convenient postmortem analysis.1206 1207        See also LLDBTestResult (dotest.py) which is a singlton class derived1208        from TextTestResult and overwrites addError, addFailure, and1209        addExpectedFailure methods to allow us to to mark the test instance as1210        such.1211        """1212 1213        # We are here because self.tearDown() detected that this test instance1214        # either errored or failed.  The lldb.test_result singleton contains1215        # two lists (errors and failures) which get populated by the unittest1216        # framework.  Look over there for stack trace information.1217        #1218        # The lists contain 2-tuples of TestCase instances and strings holding1219        # formatted tracebacks.1220        #1221        # See http://docs.python.org/library/unittest.html#unittest.TestResult.1222 1223        # output tracebacks into session1224        pairs = []1225        if self.__errored__:1226            pairs = configuration.test_result.errors1227            prefix = "Error"1228        elif self.__cleanup_errored__:1229            pairs = configuration.test_result.cleanup_errors1230            prefix = "CleanupError"1231        elif self.__failed__:1232            pairs = configuration.test_result.failures1233            prefix = "Failure"1234        elif self.__expected__:1235            pairs = configuration.test_result.expectedFailures1236            prefix = "ExpectedFailure"1237        elif self.__skipped__:1238            prefix = "SkippedTest"1239        elif self.__unexpected__:1240            prefix = "UnexpectedSuccess"1241        else:1242            prefix = "Success"1243 1244        session_file = self.getLogBasenameForCurrentTest() + ".log"1245 1246        # Python 3 doesn't support unbuffered I/O in text mode.  Open buffered.1247        session = encoded_file.open(session_file, "utf-8", mode="w")1248 1249        if not self.__unexpected__ and not self.__skipped__:1250            for test, traceback in pairs:1251                if test is self:1252                    print(traceback, file=session)1253 1254        import datetime1255 1256        print(1257            "Session info generated @",1258            datetime.datetime.now().ctime(),1259            file=session,1260        )1261        session.close()1262        del session1263 1264        # process the log files1265        if prefix != "Success" or lldbtest_config.log_success:1266            # keep all log files, rename them to include prefix1267            src_log_basename = self.getLogBasenameForCurrentTest()1268            dst_log_basename = self.getLogBasenameForCurrentTest(prefix)1269            for src in self.log_files:1270                if os.path.isfile(src):1271                    dst = src.replace(src_log_basename, dst_log_basename)1272                    if os.name == "nt" and os.path.isfile(dst):1273                        # On Windows, renaming a -> b will throw an exception if1274                        # b exists.  On non-Windows platforms it silently1275                        # replaces the destination.  Ultimately this means that1276                        # atomic renames are not guaranteed to be possible on1277                        # Windows, but we need this to work anyway, so just1278                        # remove the destination first if it already exists.1279                        remove_file(dst)1280 1281                    lldbutil.mkdir_p(os.path.dirname(dst))1282                    os.rename(src, dst)1283        else:1284            # success!  (and we don't want log files) delete log files1285            for log_file in self.log_files:1286                if os.path.isfile(log_file):1287                    remove_file(log_file)1288 1289    # ====================================================1290    # Config. methods supported through a plugin interface1291    # (enables reading of the current test configuration)1292    # ====================================================1293 1294    def hasXMLSupport(self):1295        """Returns True if lldb was built with XML support. Use this check to1296        enable parts of tests, if you want to skip a whole test use skipIfXmlSupportMissing1297        instead."""1298        return (1299            lldb.SBDebugger.GetBuildConfiguration()1300            .GetValueForKey("xml")1301            .GetValueForKey("value")1302            .GetBooleanValue(False)1303        )1304 1305    def isMIPS(self):1306        """Returns true if the architecture is MIPS."""1307        arch = self.getArchitecture()1308        if re.match("mips", arch):1309            return True1310        return False1311 1312    def isPPC64le(self):1313        """Returns true if the architecture is PPC64LE."""1314        arch = self.getArchitecture()1315        if re.match("powerpc64le", arch):1316            return True1317        return False1318 1319    def isAArch64(self):1320        """Returns true if the architecture is AArch64."""1321        arch = self.getArchitecture().lower()1322        return arch in ["aarch64", "arm64", "arm64e"]1323 1324    def isARM(self):1325        """Returns true if the architecture is ARM, meaning 32-bit ARM. Which could1326        be M profile, A profile Armv7-a, or the AArch32 mode of Armv8-a."""1327        return not self.isAArch64() and (1328            self.getArchitecture().lower().startswith("arm")1329        )1330 1331    def isSupported(self, cpu_feature: cpu_feature.CPUFeature):1332        triple = self.dbg.GetSelectedPlatform().GetTriple()1333        cmd_runner = self.run_platform_command1334        return cpu_feature.is_supported(triple, cmd_runner)1335 1336    def isAArch64SVE(self):1337        return self.isAArch64() and self.isSupported(cpu_feature.AArch64.SVE)1338 1339    def isAArch64SME(self):1340        return self.isAArch64() and self.isSupported(cpu_feature.AArch64.SME)1341 1342    def isAArch64SME2(self):1343        # If you have sme2, you also have sme.1344        return self.isAArch64() and self.isSupported(cpu_feature.AArch64.SME2)1345 1346    def isAArch64SMEFA64(self):1347        # smefa64 allows the use of the full A64 instruction set in streaming1348        # mode. This is required by certain test programs to setup register1349        # state.1350        return (1351            self.isAArch64()1352            and self.isSupported(cpu_feature.AArch64.SME)1353            and self.isSupported(cpu_feature.AArch64.SME_FA64)1354        )1355 1356    def isAArch64MTE(self):1357        return self.isAArch64() and self.isSupported(cpu_feature.AArch64.MTE)1358 1359    def isAArch64MTEStoreOnly(self):1360        return self.isAArch64() and self.isSupported(cpu_feature.AArch64.MTE_STORE_ONLY)1361 1362    def isAArch64GCS(self):1363        return self.isAArch64() and self.isSupported(cpu_feature.AArch64.GCS)1364 1365    def isAArch64PAuth(self):1366        if self.getArchitecture() == "arm64e":1367            return True1368        return self.isAArch64() and self.isSupported(cpu_feature.AArch64.PTR_AUTH)1369 1370    def isAArch64FPMR(self):1371        return self.isAArch64() and self.isSupported(cpu_feature.AArch64.FPMR)1372 1373    def isAArch64Windows(self):1374        """Returns true if the architecture is AArch64 and platform windows."""1375        if self.getPlatform() == "windows":1376            arch = self.getArchitecture().lower()1377            return arch in ["aarch64", "arm64", "arm64e"]1378        return False1379 1380    def isLoongArch(self):1381        """Returns true if the architecture is LoongArch."""1382        arch = self.getArchitecture().lower()1383        return arch in ["loongarch64", "loongarch32"]1384 1385    def isLoongArchLSX(self):1386        return self.isLoongArch() and self.isSupported(cpu_feature.Loong.LSX)1387 1388    def isLoongArchLASX(self):1389        return self.isLoongArch() and self.isSupported(cpu_feature.Loong.LASX)1390 1391    def isRISCV(self):1392        """Returns true if the architecture is RISCV64 or RISCV32."""1393        return self.getArchitecture() in ["riscv64", "riscv32"]1394 1395    def getArchitecture(self):1396        """Returns the architecture in effect the test suite is running with."""1397        return lldbplatformutil.getArchitecture()1398 1399    def getLldbArchitecture(self):1400        """Returns the architecture of the lldb binary."""1401        return lldbplatformutil.getLLDBArchitecture()1402 1403    def getCompiler(self):1404        """Returns the compiler in effect the test suite is running with."""1405        return lldbplatformutil.getCompiler()1406 1407    def getCompilerVersion(self):1408        """Returns a string that represents the compiler version.1409        Supports: llvm, clang.1410        """1411        return lldbplatformutil.getCompilerVersion()1412 1413    def getDwarfVersion(self):1414        """Returns the dwarf version generated by clang or '0'."""1415        return lldbplatformutil.getDwarfVersion()1416 1417    def platformIsDarwin(self):1418        """Returns true if the OS triple for the selected platform is any valid apple OS"""1419        return lldbplatformutil.platformIsDarwin()1420 1421    def hasDarwinFramework(self):1422        return self.darwinWithFramework1423 1424    def getPlatform(self):1425        """Returns the target platform the test suite is running on."""1426        return lldbplatformutil.getPlatform()1427 1428    def isIntelCompiler(self):1429        """Returns true if using an Intel (ICC) compiler, false otherwise."""1430        return any([x in self.getCompiler() for x in ["icc", "icpc", "icl"]])1431 1432    def expectedCompilerVersion(self, compiler_version):1433        """Returns True iff compiler_version[1] matches the current compiler version.1434        Use compiler_version[0] to specify the operator used to determine if a match has occurred.1435        Any operator other than the following defaults to an equality test:1436          '>', '>=', "=>", '<', '<=', '=<', '!=', "!" or 'not'1437 1438        If the current compiler version cannot be determined, we assume it is close to the top1439        of trunk, so any less-than or equal-to comparisons will return False, and any1440        greater-than or not-equal-to comparisons will return True.1441        """1442        return lldbplatformutil.expectedCompilerVersion(compiler_version)1443 1444    def expectedCompiler(self, compilers):1445        """Returns True iff any element of compilers is a sub-string of the current compiler."""1446        return lldbplatformutil.expectedCompiler(compilers)1447 1448    def expectedArch(self, archs):1449        """Returns True iff any element of archs is a sub-string of the current architecture."""1450        if archs is None:1451            return True1452 1453        for arch in archs:1454            if arch in self.getArchitecture():1455                return True1456 1457        return False1458 1459    def getRunOptions(self):1460        """Command line option for -A and -C to run this test again, called from1461        self.dumpSessionInfo()."""1462        arch = self.getArchitecture()1463        comp = self.getCompiler()1464        option_str = ""1465        if arch:1466            option_str = "-A " + arch1467        if comp:1468            option_str += " -C " + comp1469        return option_str1470 1471    def getDebugInfo(self):1472        method = getattr(self, self.testMethodName)1473        return getattr(method, "debug_info", None)1474 1475    def build(1476        self,1477        debug_info=None,1478        architecture=None,1479        compiler=None,1480        dictionary=None,1481        make_targets=None,1482    ):1483        """Platform specific way to build binaries."""1484        if not architecture and configuration.arch:1485            architecture = configuration.arch1486 1487        if debug_info is None:1488            debug_info = self.getDebugInfo()1489 1490        dictionary = lldbplatformutil.finalize_build_dictionary(dictionary)1491 1492        testdir = self.mydir1493        testname = self.getBuildDirBasename()1494 1495        module = builder_module()1496        command = module.getBuildCommand(1497            debug_info,1498            architecture,1499            compiler,1500            dictionary,1501            testdir,1502            testname,1503            make_targets,1504        )1505        if command is None:1506            raise Exception("Don't know how to build binary")1507 1508        self.runBuildCommand(command)1509 1510    def runBuildCommand(self, command):1511        self.trace(shlex.join(command))1512        try:1513            output = check_output(command, stderr=STDOUT, errors="replace")1514        except CalledProcessError as cpe:1515            raise build_exception.BuildError(cpe)1516        self.trace(output)1517 1518    # ==================================================1519    # Build methods supported through a plugin interface1520    # ==================================================1521 1522    def getstdlibFlag(self):1523        """Returns the proper -stdlib flag, or empty if not required."""1524        if (1525            self.platformIsDarwin()1526            or self.getPlatform() == "freebsd"1527            or self.getPlatform() == "openbsd"1528        ):1529            stdlibflag = "-stdlib=libc++"1530        else:  # this includes NetBSD1531            stdlibflag = ""1532        return stdlibflag1533 1534    def getstdFlag(self):1535        """Returns the proper stdflag."""1536        if "gcc" in self.getCompiler() and "4.6" in self.getCompilerVersion():1537            stdflag = "-std=c++0x"1538        else:1539            stdflag = "-std=c++11"1540        return stdflag1541 1542    def buildDriver(self, sources, exe_name, defines=None):1543        """Platform-specific way to build a program that links with LLDB (via the liblldb.so1544        or LLDB.framework).1545        """1546        if defines is None:1547            defines = []1548 1549        stdflag = self.getstdFlag()1550        stdlibflag = self.getstdlibFlag()1551        defines = " ".join(["-D{}={}".format(name, value) for name, value in defines])1552 1553        lib_dir = configuration.lldb_libs_dir1554        if self.hasDarwinFramework():1555            d = {1556                "CXX_SOURCES": sources,1557                "EXE": exe_name,1558                "CFLAGS_EXTRAS": "%s %s %s" % (stdflag, stdlibflag, defines),1559                "FRAMEWORK_INCLUDES": "-F%s" % self.framework_dir,1560                "LD_EXTRAS": "%s -Wl,-rpath,%s" % (self.lib_lldb, self.framework_dir),1561            }1562        elif sys.platform.startswith("win"):1563            d = {1564                "CXX_SOURCES": sources,1565                "EXE": exe_name,1566                "CFLAGS_EXTRAS": "%s %s -I%s -I%s %s"1567                % (1568                    stdflag,1569                    stdlibflag,1570                    os.path.join(os.environ["LLDB_SRC"], "include"),1571                    os.path.join(configuration.lldb_obj_root, "include"),1572                    defines,1573                ),1574                "LD_EXTRAS": "-L%s -lliblldb" % lib_dir,1575            }1576        else:1577            d = {1578                "CXX_SOURCES": sources,1579                "EXE": exe_name,1580                "CFLAGS_EXTRAS": "%s %s -I%s -I%s %s"1581                % (1582                    stdflag,1583                    stdlibflag,1584                    os.path.join(os.environ["LLDB_SRC"], "include"),1585                    os.path.join(configuration.lldb_obj_root, "include"),1586                    defines,1587                ),1588                "LD_EXTRAS": "-L%s -llldb -Wl,-rpath,%s" % (lib_dir, lib_dir),1589            }1590        if self.TraceOn():1591            print("Building LLDB Driver (%s) from sources %s" % (exe_name, sources))1592 1593        self.build(dictionary=d)1594 1595    def buildLibrary(self, sources, lib_name):1596        """Platform specific way to build a default library."""1597 1598        stdflag = self.getstdFlag()1599 1600        lib_dir = configuration.lldb_libs_dir1601        if self.hasDarwinFramework():1602            d = {1603                "DYLIB_CXX_SOURCES": sources,1604                "DYLIB_NAME": lib_name,1605                "CFLAGS_EXTRAS": "%s -stdlib=libc++ -I%s"1606                % (stdflag, os.path.join(configuration.lldb_obj_root, "include")),1607                "FRAMEWORK_INCLUDES": "-F%s" % self.framework_dir,1608                "LD_EXTRAS": "%s -Wl,-rpath,%s -dynamiclib"1609                % (self.lib_lldb, self.framework_dir),1610            }1611        elif self.getPlatform() == "windows":1612            d = {1613                "DYLIB_CXX_SOURCES": sources,1614                "DYLIB_NAME": lib_name,1615                "CFLAGS_EXTRAS": "%s -I%s -I%s"1616                % (1617                    stdflag,1618                    os.path.join(os.environ["LLDB_SRC"], "include"),1619                    os.path.join(configuration.lldb_obj_root, "include"),1620                ),1621                "LD_EXTRAS": "-shared -l%s\\liblldb.lib" % lib_dir,1622            }1623        else:1624            d = {1625                "DYLIB_CXX_SOURCES": sources,1626                "DYLIB_NAME": lib_name,1627                "CFLAGS_EXTRAS": "%s -I%s -I%s -fPIC"1628                % (1629                    stdflag,1630                    os.path.join(os.environ["LLDB_SRC"], "include"),1631                    os.path.join(configuration.lldb_obj_root, "include"),1632                ),1633                "LD_EXTRAS": "-shared -L%s -llldb -Wl,-rpath,%s" % (lib_dir, lib_dir),1634            }1635        if self.TraceOn():1636            print("Building LLDB Library (%s) from sources %s" % (lib_name, sources))1637 1638        self.build(dictionary=d)1639 1640    def buildProgram(self, sources, exe_name):1641        """Platform specific way to build an executable from C/C++ sources."""1642        d = {"CXX_SOURCES": sources, "EXE": exe_name}1643        self.build(dictionary=d)1644 1645    def findBuiltClang(self):1646        """Tries to find and use Clang from the build directory as the compiler (instead of the system compiler)."""1647        paths_to_try = [1648            "llvm-build/Release+Asserts/x86_64/bin/clang",1649            "llvm-build/Debug+Asserts/x86_64/bin/clang",1650            "llvm-build/Release/x86_64/bin/clang",1651            "llvm-build/Debug/x86_64/bin/clang",1652        ]1653        lldb_root_path = os.path.join(os.path.dirname(__file__), "..", "..", "..", "..")1654        for p in paths_to_try:1655            path = os.path.join(lldb_root_path, p)1656            if os.path.exists(path):1657                return path1658 1659        # Tries to find clang at the same folder as the lldb1660        lldb_dir = os.path.dirname(lldbtest_config.lldbExec)1661        path = shutil.which("clang", path=lldb_dir)1662        if path is not None:1663            return path1664 1665        return os.environ["CC"]1666 1667    def yaml2obj(self, yaml_path, obj_path, max_size=None):1668        """1669        Create an object file at the given path from a yaml file.1670 1671        Throws subprocess.CalledProcessError if the object could not be created.1672        """1673        yaml2obj_bin = configuration.get_yaml2obj_path()1674        if not yaml2obj_bin:1675            self.assertTrue(False, "No valid yaml2obj executable specified")1676        command = [yaml2obj_bin, "-o=%s" % obj_path, yaml_path]1677        if max_size is not None:1678            command += ["--max-size=%d" % max_size]1679        self.runBuildCommand(command)1680 1681    def yaml2macho_core(self, yaml_path, obj_path, uuids=None):1682        """1683        Create a Mach-O corefile at the given path from a yaml file.1684 1685        Throws subprocess.CalledProcessError if the object could not be created.1686        """1687        yaml2macho_core_bin = configuration.get_yaml2macho_core_path()1688        if not yaml2macho_core_bin:1689            self.assertTrue(False, "No valid yaml2macho-core executable specified")1690        if uuids != None:1691            command = [1692                yaml2macho_core_bin,1693                "-i",1694                yaml_path,1695                "-o",1696                obj_path,1697                "-u",1698                uuids,1699            ]1700        else:1701            command = [yaml2macho_core_bin, "-i", yaml_path, "-o", obj_path]1702        self.runBuildCommand(command)1703 1704    def cleanup(self, dictionary=None):1705        """Platform specific way to do cleanup after build."""1706        module = builder_module()1707        if not module.cleanup(dictionary):1708            raise Exception(1709                "Don't know how to do cleanup with dictionary: " + dictionary1710            )1711 1712    def invoke(self, obj, name, trace=False):1713        """Use reflection to call a method dynamically with no argument."""1714        trace = True if traceAlways else trace1715 1716        method = getattr(obj, name)1717        import inspect1718 1719        self.assertTrue(1720            inspect.ismethod(method), name + "is a method name of object: " + str(obj)1721        )1722        result = method()1723        with recording(self, trace) as sbuf:1724            print(str(method) + ":", result, file=sbuf)1725        return result1726 1727    def getLibcPlusPlusLibs(self):1728        if self.getPlatform() in ("freebsd", "linux", "netbsd", "openbsd"):1729            return ["libc++.so.1"]1730        else:1731            return ["libc++.1.dylib", "libc++abi."]1732 1733    def run_platform_command(self, cmd):1734        platform = self.dbg.GetSelectedPlatform()1735        shell_command = lldb.SBPlatformShellCommand(cmd)1736        err = platform.Run(shell_command)1737        return (err, shell_command.GetStatus(), shell_command.GetOutput())1738 1739    def get_stats(self, options=None):1740        """1741        Get the output of the "statistics dump" with optional extra options1742        and return the JSON as a python dictionary.1743        """1744        return_obj = lldb.SBCommandReturnObject()1745        command = "statistics dump "1746        if options is not None:1747            command += options1748        self.ci.HandleCommand(command, return_obj, False)1749        metrics_json = return_obj.GetOutput()1750        return json.loads(metrics_json)1751 1752 1753# Metaclass for TestBase to change the list of test metods when a new TestCase is loaded.1754# We change the test methods to create a new test method for each test for each debug info we are1755# testing. The name of the new test method will be '<original-name>_<debug-info>' and with adding1756# the new test method we remove the old method at the same time. This functionality can be1757# supressed by at test case level setting the class attribute NO_DEBUG_INFO_TESTCASE or at test1758# level by using the decorator @no_debug_info_test.1759 1760 1761class LLDBTestCaseFactory(type):1762    def __new__(cls, name, bases, attrs):1763        original_testcase = super(LLDBTestCaseFactory, cls).__new__(1764            cls, name, bases, attrs1765        )1766        if original_testcase.NO_DEBUG_INFO_TESTCASE:1767            return original_testcase1768 1769        # Default implementation for skip/xfail reason based on the debug category,1770        # where "None" means to run the test as usual.1771        def no_reason(_):1772            return None1773 1774        newattrs = {}1775        for attrname, attrvalue in attrs.items():1776            if attrname.startswith("test") and not getattr(1777                attrvalue, "__no_debug_info_test__", False1778            ):1779                # If any debug info categories were explicitly tagged, assume that list to be1780                # authoritative.  If none were specified, try with all debug info formats.1781                test_method_categories = set(getattr(attrvalue, "categories", []))1782                all_dbginfo_categories = set(1783                    test_categories.debug_info_categories.keys()1784                )1785                dbginfo_categories = test_method_categories & all_dbginfo_categories1786                other_categories = list(test_method_categories - all_dbginfo_categories)1787                if not dbginfo_categories:1788                    dbginfo_categories = [1789                        category1790                        for category, can_replicate in test_categories.debug_info_categories.items()1791                        if can_replicate1792                    ]1793 1794                    # PDB is off by default, because it has a lot of failures right now.1795                    # See llvm.org/pr1494981796                    if original_testcase.TEST_WITH_PDB_DEBUG_INFO:1797                        dbginfo_categories.append("pdb")1798 1799                xfail_for_debug_info_cat_fn = getattr(1800                    attrvalue, "__xfail_for_debug_info_cat_fn__", no_reason1801                )1802                skip_for_debug_info_cat_fn = getattr(1803                    attrvalue, "__skip_for_debug_info_cat_fn__", no_reason1804                )1805                for cat in dbginfo_categories:1806 1807                    @wraps(attrvalue)1808                    def test_method(self, attrvalue=attrvalue):1809                        return attrvalue(self)1810 1811                    method_name = attrname + "_" + cat1812                    test_method.__name__ = method_name1813                    test_method.debug_info = cat1814                    test_method.categories = other_categories + [cat]1815 1816                    xfail_reason = xfail_for_debug_info_cat_fn(cat)1817                    if xfail_reason:1818                        test_method = unittest.expectedFailure(test_method)1819 1820                    skip_reason = skip_for_debug_info_cat_fn(cat)1821                    if skip_reason:1822                        test_method = unittest.skip(skip_reason)(test_method)1823 1824                    newattrs[method_name] = test_method1825 1826            else:1827                newattrs[attrname] = attrvalue1828        return super(LLDBTestCaseFactory, cls).__new__(cls, name, bases, newattrs)1829 1830 1831# Setup the metaclass for this class to change the list of the test1832# methods when a new class is loaded1833 1834 1835class TestBase(Base, metaclass=LLDBTestCaseFactory):1836    """1837    This abstract base class is meant to be subclassed.  It provides default1838    implementations for setUpClass(), tearDownClass(), setUp(), and tearDown(),1839    among other things.1840 1841    Important things for test class writers:1842 1843        - The setUp method sets up things to facilitate subsequent interactions1844          with the debugger as part of the test.  These include:1845              - populate the test method name1846              - create/get a debugger set with synchronous mode (self.dbg)1847              - get the command interpreter from with the debugger (self.ci)1848              - create a result object for use with the command interpreter1849                (self.res)1850              - plus other stuffs1851 1852        - The tearDown method tries to perform some necessary cleanup on behalf1853          of the test to return the debugger to a good state for the next test.1854          These include:1855              - execute any tearDown hooks registered by the test method with1856                TestBase.addTearDownHook(); examples can be found in1857                settings/TestSettings.py1858              - kill the inferior process associated with each target, if any,1859                and, then delete the target from the debugger's target list1860              - perform build cleanup before running the next test method in the1861                same test class; examples of registering for this service can be1862                found in types/TestIntegerTypes.py with the call:1863                    - self.setTearDownCleanup(dictionary=d)1864 1865        - Similarly setUpClass and tearDownClass perform classwise setup and1866          teardown fixtures.  The tearDownClass method invokes a default build1867          cleanup for the entire test class;  also, subclasses can implement the1868          classmethod classCleanup(cls) to perform special class cleanup action.1869 1870        - The instance methods runCmd and expect are used heavily by existing1871          test cases to send a command to the command interpreter and to perform1872          string/pattern matching on the output of such command execution.  The1873          expect method also provides a mode to peform string/pattern matching1874          without running a command.1875 1876        - The build method is used to build the binaries used during a1877          particular test scenario.  A plugin should be provided for the1878          sys.platform running the test suite.  The Mac OS X implementation is1879          located in builders/darwin.py.1880    """1881 1882    # Subclasses can set this to true (if they don't depend on debug info) to avoid running the1883    # test multiple times with various debug info types.1884    NO_DEBUG_INFO_TESTCASE = False1885 1886    TEST_WITH_PDB_DEBUG_INFO = False1887    """1888    Subclasses can set this to True to test with PDB in addition to the other debug info1889    types. This id off by default because many tests will fail due to missing functionality in PDB.1890    See llvm.org/pr149498.1891    """1892 1893    def generateSource(self, source):1894        template = source + ".template"1895        temp = os.path.join(self.getSourceDir(), template)1896        with open(temp, "r") as f:1897            content = f.read()1898 1899        public_api_dir = os.path.join(os.environ["LLDB_SRC"], "include", "lldb", "API")1900 1901        # Look under the include/lldb/API directory and add #include statements1902        # for all the SB API headers.1903        public_headers = os.listdir(public_api_dir)1904        # For different platforms, the include statement can vary.1905        if self.hasDarwinFramework():1906            include_stmt = "'#include <%s>' % os.path.join('LLDB', header)"1907        else:1908            include_stmt = (1909                "'#include <%s>' % os.path.join(r'" + public_api_dir + "', header)"1910            )1911        list = [1912            eval(include_stmt)1913            for header in public_headers1914            if (header.startswith("SB") and header.endswith(".h"))1915        ]1916        includes = "\n".join(list)1917        new_content = content.replace("%include_SB_APIs%", includes)1918        new_content = new_content.replace("%SOURCE_DIR%", self.getSourceDir())1919        src = os.path.join(self.getBuildDir(), source)1920        with open(src, "w") as f:1921            f.write(new_content)1922 1923        self.addTearDownHook(lambda: os.remove(src))1924 1925    def setUp(self):1926        # Works with the test driver to conditionally skip tests via1927        # decorators.1928        Base.setUp(self)1929 1930        for s in self.setUpCommands():1931            self.runCmd(s)1932 1933        # We want our debugger to be synchronous.1934        self.dbg.SetAsync(False)1935 1936        # Retrieve the associated command interpreter instance.1937        self.ci = self.dbg.GetCommandInterpreter()1938        if not self.ci:1939            raise Exception("Could not get the command interpreter")1940 1941        # And the result object.1942        self.res = lldb.SBCommandReturnObject()1943 1944    def registerSharedLibrariesWithTarget(self, target, shlibs):1945        """If we are remotely running the test suite, register the shared libraries with the target so they get uploaded, otherwise do nothing1946 1947        Any modules in the target that have their remote install file specification set will1948        get uploaded to the remote host. This function registers the local copies of the1949        shared libraries with the target and sets their remote install locations so they will1950        be uploaded when the target is run.1951        """1952        if not shlibs or not self.platformContext:1953            return None1954 1955        shlib_environment_var = self.platformContext.shlib_environment_var1956        shlib_prefix = self.platformContext.shlib_prefix1957        shlib_extension = "." + self.platformContext.shlib_extension1958 1959        dirs = []1960        # Add any shared libraries to our target if remote so they get1961        # uploaded into the working directory on the remote side1962        for name in shlibs:1963            # The path can be a full path to a shared library, or a make file name like "Foo" for1964            # "libFoo.dylib" or "libFoo.so", or "Foo.so" for "Foo.so" or "libFoo.so", or just a1965            # basename like "libFoo.so". So figure out which one it is and resolve the local copy1966            # of the shared library accordingly1967            if os.path.isfile(name):1968                local_shlib_path = (1969                    name  # name is the full path to the local shared library1970                )1971            else:1972                # Check relative names1973                local_shlib_path = os.path.join(1974                    self.getBuildDir(), shlib_prefix + name + shlib_extension1975                )1976                if not os.path.exists(local_shlib_path):1977                    local_shlib_path = os.path.join(1978                        self.getBuildDir(), name + shlib_extension1979                    )1980                    if not os.path.exists(local_shlib_path):1981                        local_shlib_path = os.path.join(self.getBuildDir(), name)1982 1983                # Make sure we found the local shared library in the above code1984                self.assertTrue(os.path.exists(local_shlib_path))1985 1986            # Add the shared library to our target1987            shlib_module = target.AddModule(local_shlib_path, None, None, None)1988            if lldb.remote_platform:1989                # We must set the remote install location if we want the shared library1990                # to get uploaded to the remote target1991                remote_shlib_path = lldbutil.append_to_process_working_directory(1992                    self, os.path.basename(local_shlib_path)1993                )1994                shlib_module.SetRemoteInstallFileSpec(1995                    lldb.SBFileSpec(remote_shlib_path, False)1996                )1997                dir_to_add = self.get_process_working_directory()1998            else:1999                dir_to_add = os.path.dirname(local_shlib_path)2000 2001            if dir_to_add not in dirs:2002                dirs.append(dir_to_add)2003 2004        env_value = self.platformContext.shlib_path_separator.join(dirs)2005        return ["%s=%s" % (shlib_environment_var, env_value)]2006 2007    def registerSanitizerLibrariesWithTarget(self, target):2008        runtimes = []2009        for m in target.module_iter():2010            libspec = m.GetFileSpec()2011            if "clang_rt" in libspec.GetFilename():2012                runtimes.append(2013                    os.path.join(libspec.GetDirectory(), libspec.GetFilename())2014                )2015        return self.registerSharedLibrariesWithTarget(target, runtimes)2016 2017    # utility methods that tests can use to access the current objects2018    def target(self):2019        if not self.dbg:2020            raise Exception("Invalid debugger instance")2021        return self.dbg.GetSelectedTarget()2022 2023    def process(self):2024        if not self.dbg:2025            raise Exception("Invalid debugger instance")2026        return self.dbg.GetSelectedTarget().GetProcess()2027 2028    def thread(self):2029        if not self.dbg:2030            raise Exception("Invalid debugger instance")2031        return self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread()2032 2033    def frame(self):2034        if not self.dbg:2035            raise Exception("Invalid debugger instance")2036        return (2037            self.dbg.GetSelectedTarget()2038            .GetProcess()2039            .GetSelectedThread()2040            .GetSelectedFrame()2041        )2042 2043    def get_process_working_directory(self):2044        """Get the working directory that should be used when launching processes for local or remote processes."""2045        if lldb.remote_platform:2046            # Remote tests set the platform working directory up in2047            # Base.setUp()2048            return lldb.remote_platform.GetWorkingDirectory()2049        else:2050            # local tests change directory into each test subdirectory2051            return self.getBuildDir()2052 2053    def tearDown(self):2054        # Ensure all the references to SB objects have gone away so that we can2055        # be sure that all test-specific resources have been freed before we2056        # attempt to delete the targets.2057        gc.collect()2058 2059        # Delete the target(s) from the debugger as a general cleanup step.2060        # This includes terminating the process for each target, if any.2061        # We'd like to reuse the debugger for our next test without incurring2062        # the initialization overhead.2063        targets = []2064        for target in self.dbg:2065            if target:2066                targets.append(target)2067                process = target.GetProcess()2068                if process:2069                    rc = self.invoke(process, "Kill")2070                    assert rc.Success()2071        for target in targets:2072            self.dbg.DeleteTarget(target)2073 2074        # Assert that all targets are deleted.2075        self.assertEqual(self.dbg.GetNumTargets(), 0)2076 2077        # Do this last, to make sure it's in reverse order from how we setup.2078        Base.tearDown(self)2079 2080    def switch_to_thread_with_stop_reason(self, stop_reason):2081        """2082        Run the 'thread list' command, and select the thread with stop reason as2083        'stop_reason'.  If no such thread exists, no select action is done.2084        """2085        from .lldbutil import stop_reason_to_str2086 2087        self.runCmd("thread list")2088        output = self.res.GetOutput()2089        thread_line_pattern = re.compile(2090            "^[ *] thread #([0-9]+):.*stop reason = %s"2091            % stop_reason_to_str(stop_reason)2092        )2093        for line in output.splitlines():2094            matched = thread_line_pattern.match(line)2095            if matched:2096                self.runCmd("thread select %s" % matched.group(1))2097 2098    def match(2099        self, str, patterns, msg=None, trace=False, error=False, matching=True, exe=True2100    ):2101        """run command in str, and match the result against regexp in patterns returning the match object for the first matching pattern2102 2103        Otherwise, all the arguments have the same meanings as for the expect function2104        """2105 2106        trace = True if traceAlways else trace2107 2108        if exe:2109            # First run the command.  If we are expecting error, set check=False.2110            # Pass the assert message along since it provides more semantic2111            # info.2112            self.runCmd(str, msg=msg, trace=(True if trace else False), check=not error)2113 2114            # Then compare the output against expected strings.2115            output = self.res.GetError() if error else self.res.GetOutput()2116 2117            # If error is True, the API client expects the command to fail!2118            if error:2119                self.assertFalse(2120                    self.res.Succeeded(), "Command '" + str + "' is expected to fail!"2121                )2122        else:2123            # No execution required, just compare str against the golden input.2124            output = str2125            with recording(self, trace) as sbuf:2126                print("looking at:", output, file=sbuf)2127 2128        # The heading says either "Expecting" or "Not expecting".2129        heading = "Expecting" if matching else "Not expecting"2130 2131        for pattern in patterns:2132            # Match Objects always have a boolean value of True.2133            match_object = re.search(pattern, output)2134            matched = bool(match_object)2135            with recording(self, trace) as sbuf:2136                print("%s pattern: %s" % (heading, pattern), file=sbuf)2137                print("Matched" if matched else "Not matched", file=sbuf)2138            if matched:2139                break2140 2141        self.assertTrue(2142            matched if matching else not matched,2143            msg if msg else EXP_MSG(str, output, exe),2144        )2145 2146        return match_object2147 2148    def check_completion_with_desc(2149        self, str_input, match_desc_pairs, enforce_order=False2150    ):2151        """2152        Checks that when the given input is completed at the given list of2153        completions and descriptions is returned.2154        :param str_input: The input that should be completed. The completion happens at the end of the string.2155        :param match_desc_pairs: A list of pairs that indicate what completions have to be in the list of2156                                 completions returned by LLDB. The first element of the pair is the completion2157                                 string that LLDB should generate and the second element the description.2158        :param enforce_order: True iff the order in which the completions are returned by LLDB2159                              should match the order of the match_desc_pairs pairs.2160        """2161        interp = self.dbg.GetCommandInterpreter()2162        match_strings = lldb.SBStringList()2163        description_strings = lldb.SBStringList()2164        num_matches = interp.HandleCompletionWithDescriptions(2165            str_input, len(str_input), 0, -1, match_strings, description_strings2166        )2167        self.assertEqual(len(description_strings), len(match_strings))2168 2169        # The index of the last matched description in description_strings or2170        # -1 if no description has been matched yet.2171        last_found_index = -12172        out_of_order_errors = ""2173        missing_pairs = []2174        for pair in match_desc_pairs:2175            found_pair = False2176            for i in range(num_matches + 1):2177                match_candidate = match_strings.GetStringAtIndex(i)2178                description_candidate = description_strings.GetStringAtIndex(i)2179                if match_candidate == pair[0] and description_candidate == pair[1]:2180                    found_pair = True2181                    if enforce_order and last_found_index > i:2182                        new_err = (2183                            "Found completion "2184                            + pair[0]2185                            + " at index "2186                            + str(i)2187                            + " in returned completion list but "2188                            + "should have been after completion "2189                            + match_strings.GetStringAtIndex(last_found_index)2190                            + " (index:"2191                            + str(last_found_index)2192                            + ")\n"2193                        )2194                        out_of_order_errors += new_err2195                    last_found_index = i2196                    break2197            if not found_pair:2198                missing_pairs.append(pair)2199 2200        error_msg = ""2201        got_failure = False2202        if len(missing_pairs):2203            got_failure = True2204            error_msg += "Missing pairs:\n"2205            for pair in missing_pairs:2206                error_msg += " [" + pair[0] + ":" + pair[1] + "]\n"2207        if len(out_of_order_errors):2208            got_failure = True2209            error_msg += out_of_order_errors2210        if got_failure:2211            error_msg += (2212                "Got the following " + str(num_matches) + " completions back:\n"2213            )2214            for i in range(num_matches + 1):2215                match_candidate = match_strings.GetStringAtIndex(i)2216                description_candidate = description_strings.GetStringAtIndex(i)2217                error_msg += (2218                    "["2219                    + match_candidate2220                    + ":"2221                    + description_candidate2222                    + "] index "2223                    + str(i)2224                    + "\n"2225                )2226            self.assertFalse(got_failure, error_msg)2227 2228    def complete_from_to(self, str_input, patterns):2229        """Test that the completion mechanism completes str_input to patterns,2230        where patterns could be a single pattern-string or a list of2231        pattern-strings.2232 2233        If there is only one pattern and it is exactly equal to str_input, this2234        assumes that there should be no completions provided and that the result2235        should be the same as the input."""2236 2237        # Patterns should not be None in order to proceed.2238        self.assertFalse(patterns is None)2239        # And should be either a string or list of strings.  Check for list type2240        # below, if not, make a list out of the singleton string.  If patterns2241        # is not a string or not a list of strings, there'll be runtime errors2242        # later on.2243        if not isinstance(patterns, list):2244            patterns = [patterns]2245 2246        interp = self.dbg.GetCommandInterpreter()2247        match_strings = lldb.SBStringList()2248        num_matches = interp.HandleCompletion(2249            str_input, len(str_input), 0, -1, match_strings2250        )2251        common_match = match_strings.GetStringAtIndex(0)2252        if num_matches == 0:2253            compare_string = str_input2254        else:2255            if common_match is not None and len(common_match) > 0:2256                compare_string = str_input + common_match2257            else:2258                compare_string = ""2259                for idx in range(1, num_matches + 1):2260                    compare_string += match_strings.GetStringAtIndex(idx) + "\n"2261 2262        if len(patterns) == 1 and str_input == patterns[0] and num_matches:2263            self.fail("Expected no completions but got:\n" + compare_string)2264 2265        for p in patterns:2266            self.expect(2267                compare_string,2268                msg=COMPLETION_MSG(str_input, p, match_strings),2269                exe=False,2270                substrs=[p],2271            )2272 2273    def completions_match(self, command, completions, max_completions=-1):2274        """Checks that the completions for the given command are equal to the2275        given list of completions"""2276        interp = self.dbg.GetCommandInterpreter()2277        match_strings = lldb.SBStringList()2278        interp.HandleCompletion(2279            command, len(command), 0, max_completions, match_strings2280        )2281        # match_strings is a 1-indexed list, so we have to slice...2282        self.assertCountEqual(2283            completions, list(match_strings)[1:], "List of returned completion is wrong"2284        )2285 2286    def completions_contain(self, command, completions, match=True):2287        """Checks that the completions for the given command contain the given2288        list of completions."""2289        interp = self.dbg.GetCommandInterpreter()2290        match_strings = lldb.SBStringList()2291        interp.HandleCompletion(command, len(command), 0, -1, match_strings)2292        for completion in completions:2293            # match_strings is a 1-indexed list, so we have to slice...2294            if match:2295                self.assertIn(2296                    completion,2297                    list(match_strings)[1:],2298                    "Couldn't find expected completion",2299                )2300            else:2301                self.assertNotIn(2302                    completion, list(match_strings)[1:], "Found unexpected completion"2303                )2304 2305    def filecheck(2306        self, command, check_file, filecheck_options="", expect_cmd_failure=False2307    ):2308        # Run the command.2309        self.runCmd(2310            command,2311            check=(not expect_cmd_failure),2312            msg="FileCheck'ing result of `{0}`".format(command),2313        )2314 2315        self.assertTrue((not expect_cmd_failure) == self.res.Succeeded())2316 2317        # Get the error text if there was an error, and the regular text if not.2318        output = self.res.GetOutput() if self.res.Succeeded() else self.res.GetError()2319 2320        # Assemble the absolute path to the check file. As a convenience for2321        # LLDB inline tests, assume that the check file is a relative path to2322        # a file within the inline test directory.2323        if check_file.endswith(".pyc"):2324            check_file = check_file[:-1]2325        check_file_abs = os.path.abspath(check_file)2326 2327        # Run FileCheck.2328        filecheck_bin = configuration.get_filecheck_path()2329        if not filecheck_bin:2330            self.assertTrue(False, "No valid FileCheck executable specified")2331        filecheck_args = [filecheck_bin, check_file_abs]2332        if filecheck_options:2333            filecheck_args.append(filecheck_options)2334        subproc = Popen(2335            filecheck_args,2336            stdin=PIPE,2337            stdout=PIPE,2338            stderr=PIPE,2339            universal_newlines=True,2340        )2341        cmd_stdout, cmd_stderr = subproc.communicate(input=output)2342        cmd_status = subproc.returncode2343 2344        filecheck_cmd = " ".join(filecheck_args)2345        filecheck_trace = """2346--- FileCheck trace (code={0}) ---2347{1}2348 2349FileCheck input:2350{2}2351 2352FileCheck output:2353{3}2354{4}2355""".format(2356            cmd_status, filecheck_cmd, output, cmd_stdout, cmd_stderr2357        )2358 2359        trace = cmd_status != 0 or traceAlways2360        with recording(self, trace) as sbuf:2361            print(filecheck_trace, file=sbuf)2362 2363        self.assertTrue(cmd_status == 0)2364 2365    def expect(2366        self,2367        string,2368        msg=None,2369        patterns=None,2370        startstr=None,2371        endstr=None,2372        substrs=None,2373        trace=False,2374        error=False,2375        ordered=True,2376        matching=True,2377        exe=True,2378        inHistory=False,2379    ):2380        """2381        Similar to runCmd; with additional expect style output matching ability.2382 2383        Ask the command interpreter to handle the command and then check its2384        return status.  The 'msg' parameter specifies an informational assert2385        message.  We expect the output from running the command to start with2386        'startstr', matches the substrings contained in 'substrs', and regexp2387        matches the patterns contained in 'patterns'.2388 2389        When matching is true and ordered is true, which are both the default,2390        the strings in the substrs array, and regex in the patterns array, have2391        to appear in the command output in the order in which they appear in2392        their respective array.2393 2394        If the keyword argument error is set to True, it signifies that the API2395        client is expecting the command to fail.  In this case, the error stream2396        from running the command is retrieved and compared against the golden2397        input, instead.2398 2399        If the keyword argument matching is set to False, it signifies that the API2400        client is expecting the output of the command not to match the golden2401        input.2402 2403        Finally, the required argument 'string' represents the lldb command to be2404        sent to the command interpreter.  In case the keyword argument 'exe' is2405        set to False, the 'string' is treated as a string to be matched/not-matched2406        against the golden input.2407        """2408        # Catch cases where `expect` has been miscalled. Specifically, prevent2409        # this easy to make mistake:2410        #     self.expect("lldb command", "some substr")2411        # The `msg` parameter is used only when a failed match occurs. A failed2412        # match can only occur when one of `patterns`, `startstr`, `endstr`, or2413        # `substrs` has been given. Thus, if a `msg` is given, it's an error to2414        # not also provide one of the matcher parameters.2415        if msg and not (patterns or startstr or endstr or substrs or error):2416            assert False, "expect() missing a matcher argument"2417 2418        # Check `patterns` and `substrs` are not accidentally given as strings.2419        assert not isinstance(patterns, str), "patterns must be a collection of strings"2420        assert not isinstance(substrs, str), "substrs must be a collection of strings"2421 2422        trace = True if traceAlways else trace2423 2424        if exe:2425            # First run the command.  If we are expecting error, set check=False.2426            # Pass the assert message along since it provides more semantic2427            # info.2428            self.runCmd(2429                string,2430                msg=msg,2431                trace=(True if trace else False),2432                check=not error,2433                inHistory=inHistory,2434            )2435 2436            # Then compare the output against expected strings.2437            output = self.res.GetError() if error else self.res.GetOutput()2438 2439            # If error is True, the API client expects the command to fail!2440            if error:2441                self.assertFalse(2442                    self.res.Succeeded(),2443                    "Command '" + string + "' is expected to fail!",2444                )2445        else:2446            # No execution required, just compare string against the golden input.2447            if isinstance(string, lldb.SBCommandReturnObject):2448                output = string.GetOutput()2449            else:2450                output = string2451            with recording(self, trace) as sbuf:2452                print("looking at:", output, file=sbuf)2453 2454        expecting_str = "Expecting" if matching else "Not expecting"2455 2456        def found_str(matched):2457            return "was found" if matched else "was not found"2458 2459        # To be used as assert fail message and/or trace content2460        log_lines = [2461            "{}:".format("Ran command" if exe else "Checking string"),2462            '"{}"'.format(string),2463            # Space out command and output2464            "",2465        ]2466        if exe:2467            # Newline before output to make large strings more readable2468            log_lines.append("Got output:\n{}".format(output))2469 2470        # Assume that we start matched if we want a match2471        # Meaning if you have no conditions, matching or2472        # not matching will always pass2473        matched = matching2474 2475        # We will stop checking on first failure2476        if startstr:2477            matched = output.startswith(startstr)2478            log_lines.append(2479                '{} start string: "{}" ({})'.format(2480                    expecting_str, startstr, found_str(matched)2481                )2482            )2483 2484        if endstr and matched == matching:2485            matched = output.endswith(endstr)2486            log_lines.append(2487                '{} end string: "{}" ({})'.format(2488                    expecting_str, endstr, found_str(matched)2489                )2490            )2491 2492        if substrs and matched == matching:2493            start = 02494            for substr in substrs:2495                index = output.find(substr, start)2496                matched = index != -12497                start = index + len(substr) if ordered and matched else 02498                log_lines.append(2499                    '{} sub string: "{}" ({})'.format(2500                        expecting_str, substr, found_str(matched)2501                    )2502                )2503 2504                if matched != matching:2505                    break2506 2507        if patterns and matched == matching:2508            start = 02509            for pattern in patterns:2510                pat = re.compile(pattern)2511                match = pat.search(output, start)2512                matched = bool(match)2513                start = match.end() if ordered and matched else 02514 2515                pattern_line = '{} regex pattern: "{}" ({}'.format(2516                    expecting_str, pattern, found_str(matched)2517                )2518                if match:2519                    pattern_line += ', matched "{}"'.format(match.group(0))2520                pattern_line += ")"2521                log_lines.append(pattern_line)2522 2523                if matched != matching:2524                    break2525 2526        # If a check failed, add any extra assert message2527        if msg is not None and matched != matching:2528            log_lines.append(msg)2529 2530        log_msg = "\n".join(log_lines)2531        with recording(self, trace) as sbuf:2532            print(log_msg, file=sbuf)2533        if matched != matching:2534            self.fail(log_msg)2535 2536    def expect_expr(2537        self,2538        expr,2539        result_summary=None,2540        result_value=None,2541        result_type=None,2542        result_children=None,2543    ):2544        """2545        Evaluates the given expression and verifies the result.2546        :param expr: The expression as a string.2547        :param result_summary: The summary that the expression should have. None if the summary should not be checked.2548        :param result_value: The value that the expression should have. None if the value should not be checked.2549        :param result_type: The type that the expression result should have. None if the type should not be checked.2550        :param result_children: The expected children of the expression result2551                                as a list of ValueChecks. None if the children shouldn't be checked.2552        """2553        self.assertTrue(2554            expr.strip() == expr,2555            "Expression contains trailing/leading whitespace: '" + expr + "'",2556        )2557 2558        frame = self.frame()2559        options = lldb.SBExpressionOptions()2560 2561        # Disable fix-its that tests don't pass by accident.2562        options.SetAutoApplyFixIts(False)2563 2564        # Set the usual default options for normal expressions.2565        options.SetIgnoreBreakpoints(True)2566 2567        if self.frame().IsValid():2568            options.SetLanguage(frame.GuessLanguage())2569            eval_result = self.frame().EvaluateExpression(expr, options)2570        else:2571            target = self.target()2572            # If there is no selected target, run the expression in the dummy2573            # target.2574            if not target.IsValid():2575                target = self.dbg.GetDummyTarget()2576            eval_result = target.EvaluateExpression(expr, options)2577 2578        value_check = ValueCheck(2579            type=result_type,2580            value=result_value,2581            summary=result_summary,2582            children=result_children,2583        )2584        value_check.check_value(self, eval_result, str(eval_result))2585        return eval_result2586 2587    def expect_var_path(2588        self, var_path, summary=None, value=None, type=None, children=None2589    ):2590        """2591        Evaluates the given variable path and verifies the result.2592        See also 'frame variable' and SBFrame.GetValueForVariablePath.2593        :param var_path: The variable path as a string.2594        :param summary: The summary that the variable should have. None if the summary should not be checked.2595        :param value: The value that the variable should have. None if the value should not be checked.2596        :param type: The type that the variable result should have. None if the type should not be checked.2597        :param children: The expected children of the variable  as a list of ValueChecks.2598                         None if the children shouldn't be checked.2599        """2600        self.assertTrue(2601            var_path.strip() == var_path,2602            "Expression contains trailing/leading whitespace: '" + var_path + "'",2603        )2604 2605        frame = self.frame()2606        eval_result = frame.GetValueForVariablePath(var_path)2607 2608        value_check = ValueCheck(2609            type=type, value=value, summary=summary, children=children2610        )2611        value_check.check_value(self, eval_result, str(eval_result))2612        return eval_result2613 2614    """Assert that an lldb.SBError is in the "success" state."""2615 2616    def assertSuccess(self, obj, msg=None):2617        if not obj.Success():2618            error = obj.GetCString()2619            self.fail(self._formatMessage(msg, "'{}' is not success".format(error)))2620 2621    """Assert that an lldb.SBError is in the "failure" state."""2622 2623    def assertFailure(self, obj, error_str=None, msg=None):2624        if obj.Success():2625            self.fail(self._formatMessage(msg, "Error not in a fail state"))2626 2627        if error_str is None:2628            return2629 2630        error = obj.GetCString()2631        self.assertEqual(error, error_str, msg)2632 2633    """Assert that a command return object is successful"""2634 2635    def assertCommandReturn(self, obj, msg=None):2636        if not obj.Succeeded():2637            error = obj.GetError()2638            self.fail(self._formatMessage(msg, "'{}' is not success".format(error)))2639 2640    """Assert two states are equal"""2641 2642    def assertState(self, first, second, msg=None):2643        if first != second:2644            error = "{} ({}) != {} ({})".format(2645                lldbutil.state_type_to_str(first),2646                first,2647                lldbutil.state_type_to_str(second),2648                second,2649            )2650            self.fail(self._formatMessage(msg, error))2651 2652    """Assert two stop reasons are equal"""2653 2654    def assertStopReason(self, first, second, msg=None):2655        if first != second:2656            error = "{} ({}) != {} ({})".format(2657                lldbutil.stop_reason_to_str(first),2658                first,2659                lldbutil.stop_reason_to_str(second),2660                second,2661            )2662            self.fail(self._formatMessage(msg, error))2663 2664    def createTestTarget(self, file_path=None, msg=None, load_dependent_modules=True):2665        """2666        Creates a target from the file found at the given file path.2667        Asserts that the resulting target is valid.2668        :param file_path: The file path that should be used to create the target.2669                          The default argument opens the current default test2670                          executable in the current test directory.2671        :param msg: A custom error message.2672        """2673        if file_path is None:2674            file_path = self.getBuildArtifact("a.out")2675        error = lldb.SBError()2676        triple = ""2677        platform = ""2678        target = self.dbg.CreateTarget(2679            file_path, triple, platform, load_dependent_modules, error2680        )2681        if error.Fail():2682            err = "Couldn't create target for path '{}': {}".format(2683                file_path, str(error)2684            )2685            self.fail(self._formatMessage(msg, err))2686 2687        self.assertTrue(target.IsValid(), "Got invalid target without error")2688        return target2689 2690    # =================================================2691    # Misc. helper methods for debugging test execution2692    # =================================================2693 2694    def DebugSBValue(self, val):2695        """Debug print a SBValue object, if traceAlways is True."""2696        from .lldbutil import value_type_to_str2697 2698        if not traceAlways:2699            return2700 2701        err = sys.stderr2702        err.write(val.GetName() + ":\n")2703        err.write("\t" + "TypeName         -> " + val.GetTypeName() + "\n")2704        err.write("\t" + "ByteSize         -> " + str(val.GetByteSize()) + "\n")2705        err.write("\t" + "NumChildren      -> " + str(val.GetNumChildren()) + "\n")2706        err.write("\t" + "Value            -> " + str(val.GetValue()) + "\n")2707        err.write("\t" + "ValueAsUnsigned  -> " + str(val.GetValueAsUnsigned()) + "\n")2708        err.write(2709            "\t" + "ValueType        -> " + value_type_to_str(val.GetValueType()) + "\n"2710        )2711        err.write("\t" + "Summary          -> " + str(val.GetSummary()) + "\n")2712        err.write("\t" + "IsPointerType    -> " + str(val.TypeIsPointerType()) + "\n")2713        err.write("\t" + "Location         -> " + val.GetLocation() + "\n")2714 2715    def DebugSBType(self, type):2716        """Debug print a SBType object, if traceAlways is True."""2717        if not traceAlways:2718            return2719 2720        err = sys.stderr2721        err.write(type.GetName() + ":\n")2722        err.write("\t" + "ByteSize        -> " + str(type.GetByteSize()) + "\n")2723        err.write("\t" + "IsAggregateType   -> " + str(type.IsAggregateType()) + "\n")2724        err.write("\t" + "IsPointerType   -> " + str(type.IsPointerType()) + "\n")2725        err.write("\t" + "IsReferenceType -> " + str(type.IsReferenceType()) + "\n")2726 2727    def DebugPExpect(self, child):2728        """Debug the spwaned pexpect object."""2729        if not traceAlways:2730            return2731 2732        print(child)2733 2734    @classmethod2735    def RemoveTempFile(cls, file):2736        if os.path.exists(file):2737            remove_file(file)2738 2739 2740# On Windows, the first attempt to delete a recently-touched file can fail2741# because of a race with antimalware scanners.  This function will detect a2742# failure and retry.2743 2744 2745def remove_file(file, num_retries=1, sleep_duration=0.5):2746    for i in range(num_retries + 1):2747        try:2748            os.remove(file)2749            return True2750        except:2751            time.sleep(sleep_duration)2752            continue2753    return False2754