xref: /llvm-project/lldb/packages/Python/lldbsuite/test/lldbtest.py (revision 75952873036fc9989fcf12c526d1a2deaeef596a)
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 the
5common 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 the
8entire 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 types
12...
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 types
16compilers=['clang']
17
18Configuration: arch=x86_64 compiler=clang
19----------------------------------------------------------------------
20Collected 72 tests
21
22........................................................................
23----------------------------------------------------------------------
24Ran 72 tests in 135.468s
25
26OK
27$
28"""
29
30# System modules
31import abc
32from functools import wraps
33import gc
34import glob
35import io
36import json
37import os.path
38import re
39import shutil
40import signal
41from subprocess import *
42import sys
43import time
44import traceback
45
46# Third-party modules
47import unittest2
48
49# LLDB modules
50import lldb
51from . import configuration
52from . import decorators
53from . import lldbplatformutil
54from . import lldbtest_config
55from . import lldbutil
56from . import test_categories
57from lldbsuite.support import encoded_file
58from lldbsuite.support import funcutils
59from lldbsuite.support import seven
60from lldbsuite.test_event import build_exception
61
62# See also dotest.parseOptionsAndInitTestdirs(), where the environment variables
63# 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 = True
68else:
69    traceAlways = False
70
71# By default, doCleanup is True.
72if "LLDB_DO_CLEANUP" in os.environ and os.environ["LLDB_DO_CLEANUP"] == "NO":
73    doCleanup = False
74else:
75    doCleanup = True
76
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
147DATA_TYPES_DISPLAYED_CORRECTLY = "Data type(s) displayed correctly"
148
149VALID_BREAKPOINT = "Got a valid breakpoint"
150
151VALID_BREAKPOINT_LOCATION = "Got a valid breakpoint location"
152
153VALID_COMMAND_INTERPRETER = "Got a valid command interpreter"
154
155VALID_FILESPEC = "Got a valid filespec"
156
157VALID_MODULE = "Got a valid module"
158
159VALID_PROCESS = "Got a valid process"
160
161VALID_SYMBOL = "Got a valid symbol"
162
163VALID_TARGET = "Got a valid target"
164
165VALID_PLATFORM = "Got a valid platform"
166
167VALID_TYPE = "Got a valid type"
168
169VALID_VARIABLE = "Got a valid variable"
170
171VARIABLES_DISPLAYED_CORRECTLY = "Variable(s) displayed correctly"
172
173WATCHPOINT_CREATED = "Watchpoint created successfully"
174
175
176def CMD_MSG(str):
177    """A generic "Command '%s' did not return successfully" message generator."""
178    return "Command '%s' did not return successfully" % str
179
180
181def COMPLETION_MSG(str_before, str_after, completions):
182    """A generic assertion failed message generator for the completion mechanism."""
183    return "'%s' successfully completes to '%s', but completions were:\n%s" % (
184        str_before,
185        str_after,
186        "\n".join(completions),
187    )
188
189
190def EXP_MSG(str, actual, exe):
191    """A generic "'%s' returned unexpected result" message generator if exe.
192    Otherwise, it generates "'%s' does not match expected result" message."""
193
194    return "'%s' %s result, got '%s'" % (
195        str,
196        "returned unexpected" if exe else "does not match expected",
197        actual.strip(),
198    )
199
200
201def SETTING_MSG(setting):
202    """A generic "Value of setting '%s' is not correct" message generator."""
203    return "Value of setting '%s' is not correct" % setting
204
205
206def line_number(filename, string_to_match):
207    """Helper function to return the line number of the first matched string."""
208    with io.open(filename, mode="r", encoding="utf-8") as f:
209        for i, line in enumerate(f):
210            if line.find(string_to_match) != -1:
211                # Found our match.
212                return i + 1
213    raise Exception("Unable to find '%s' within file %s" % (string_to_match, filename))
214
215
216def get_line(filename, line_number):
217    """Return the text of the line at the 1-based line number."""
218    with io.open(filename, mode="r", encoding="utf-8") as f:
219        return f.readlines()[line_number - 1]
220
221
222def pointer_size():
223    """Return the pointer size of the host system."""
224    import ctypes
225
226    a_pointer = ctypes.c_void_p(0xFFFF)
227    return 8 * ctypes.sizeof(a_pointer)
228
229
230def is_exe(fpath):
231    """Returns true if fpath is an executable."""
232    if fpath == None:
233        return False
234    if sys.platform == "win32":
235        if not fpath.endswith(".exe"):
236            fpath += ".exe"
237    return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
238
239
240def which(program):
241    """Returns the full path to a program; None otherwise."""
242    fpath, fname = os.path.split(program)
243    if fpath:
244        if is_exe(program):
245            return program
246    else:
247        for path in os.environ["PATH"].split(os.pathsep):
248            exe_file = os.path.join(path, program)
249            if is_exe(exe_file):
250                return exe_file
251    return None
252
253
254class ValueCheck:
255    def __init__(
256        self,
257        name=None,
258        value=None,
259        type=None,
260        summary=None,
261        children=None,
262        dereference=None,
263    ):
264        """
265        :param name: The name that the SBValue should have. None if the summary
266                     should not be checked.
267        :param summary: The summary that the SBValue should have. None if the
268                        summary should not be checked.
269        :param value: The value that the SBValue should have. None if the value
270                      should not be checked.
271        :param type: The type that the SBValue result should have. None if the
272                     type should not be checked.
273        :param children: A list of ValueChecks that need to match the children
274                         of this SBValue. None if children shouldn't be checked.
275                         The order of checks is the order of the checks in the
276                         list. The number of checks has to match the number of
277                         children.
278        :param dereference: A ValueCheck for the SBValue returned by the
279                            `Dereference` function.
280        """
281        self.expect_name = name
282        self.expect_value = value
283        self.expect_type = type
284        self.expect_summary = summary
285        self.children = children
286        self.dereference = dereference
287
288    def check_value(self, test_base, val, error_msg=None):
289        """
290        Checks that the given value matches the currently set properties
291        of this ValueCheck. If a match failed, the given TestBase will
292        be used to emit an error. A custom error message can be specified
293        that will be used to describe failed check for this SBValue (but
294        not errors in the child values).
295        """
296
297        this_error_msg = error_msg if error_msg else ""
298        this_error_msg += "\nChecking SBValue: " + str(val)
299
300        test_base.assertSuccess(val.GetError())
301
302        # Python 3.6 doesn't declare a `re.Pattern` type, get the dynamic type.
303        pattern_type = type(re.compile(""))
304
305        if self.expect_name:
306            test_base.assertEqual(self.expect_name, val.GetName(), this_error_msg)
307        if self.expect_value:
308            if isinstance(self.expect_value, pattern_type):
309                test_base.assertRegex(val.GetValue(), self.expect_value, this_error_msg)
310            else:
311                test_base.assertEqual(self.expect_value, val.GetValue(), this_error_msg)
312        if self.expect_type:
313            test_base.assertEqual(
314                self.expect_type, val.GetDisplayTypeName(), this_error_msg
315            )
316        if self.expect_summary:
317            if isinstance(self.expect_summary, pattern_type):
318                test_base.assertRegex(
319                    val.GetSummary(), self.expect_summary, this_error_msg
320                )
321            else:
322                test_base.assertEqual(
323                    self.expect_summary, val.GetSummary(), this_error_msg
324                )
325        if self.children is not None:
326            self.check_value_children(test_base, val, error_msg)
327
328        if self.dereference is not None:
329            self.dereference.check_value(test_base, val.Dereference(), error_msg)
330
331    def check_value_children(self, test_base, val, error_msg=None):
332        """
333        Checks that the children of a SBValue match a certain structure and
334        have certain properties.
335
336        :param test_base: The current test's TestBase object.
337        :param val: The SBValue to check.
338        """
339
340        this_error_msg = error_msg if error_msg else ""
341        this_error_msg += "\nChecking SBValue: " + str(val)
342
343        test_base.assertEqual(len(self.children), val.GetNumChildren(), this_error_msg)
344
345        for i in range(0, val.GetNumChildren()):
346            expected_child = self.children[i]
347            actual_child = val.GetChildAtIndex(i)
348            child_error = "Checking child with index " + str(i) + ":\n" + error_msg
349            expected_child.check_value(test_base, actual_child, child_error)
350
351
352class recording(io.StringIO):
353    """
354    A nice little context manager for recording the debugger interactions into
355    our session object.  If trace flag is ON, it also emits the interactions
356    into the stderr.
357    """
358
359    def __init__(self, test, trace):
360        """Create a io.StringIO instance; record the session obj and trace flag."""
361        io.StringIO.__init__(self)
362        # The test might not have undergone the 'setUp(self)' phase yet, so that
363        # the attribute 'session' might not even exist yet.
364        self.session = getattr(test, "session", None) if test else None
365        self.trace = trace
366
367    def __enter__(self):
368        """
369        Context management protocol on entry to the body of the with statement.
370        Just return the io.StringIO object.
371        """
372        return self
373
374    def __exit__(self, type, value, tb):
375        """
376        Context management protocol on exit from the body of the with statement.
377        If trace is ON, it emits the recordings into stderr.  Always add the
378        recordings to our session object.  And close the io.StringIO object, too.
379        """
380        if self.trace:
381            print(self.getvalue(), file=sys.stderr)
382        if self.session:
383            print(self.getvalue(), file=self.session)
384        self.close()
385
386
387class _BaseProcess(object, metaclass=abc.ABCMeta):
388    @abc.abstractproperty
389    def pid(self):
390        """Returns process PID if has been launched already."""
391
392    @abc.abstractmethod
393    def launch(self, executable, args, extra_env):
394        """Launches new process with given executable and args."""
395
396    @abc.abstractmethod
397    def terminate(self):
398        """Terminates previously launched process.."""
399
400
401class _LocalProcess(_BaseProcess):
402    def __init__(self, trace_on):
403        self._proc = None
404        self._trace_on = trace_on
405        self._delayafterterminate = 0.1
406
407    @property
408    def pid(self):
409        return self._proc.pid
410
411    def launch(self, executable, args, extra_env):
412        env = None
413        if extra_env:
414            env = dict(os.environ)
415            env.update([kv.split("=", 1) for kv in extra_env])
416
417        self._proc = Popen(
418            [executable] + args,
419            stdout=open(os.devnull) if not self._trace_on else None,
420            stdin=PIPE,
421            env=env,
422        )
423
424    def terminate(self):
425        if self._proc.poll() is None:
426            # Terminate _proc like it does the pexpect
427            signals_to_try = [
428                sig for sig in ["SIGHUP", "SIGCONT", "SIGINT"] if sig in dir(signal)
429            ]
430            for sig in signals_to_try:
431                try:
432                    self._proc.send_signal(getattr(signal, sig))
433                    time.sleep(self._delayafterterminate)
434                    if self._proc.poll() is not None:
435                        return
436                except ValueError:
437                    pass  # Windows says SIGINT is not a valid signal to send
438            self._proc.terminate()
439            time.sleep(self._delayafterterminate)
440            if self._proc.poll() is not None:
441                return
442            self._proc.kill()
443            time.sleep(self._delayafterterminate)
444
445    def poll(self):
446        return self._proc.poll()
447
448    def wait(self, timeout=None):
449        return self._proc.wait(timeout)
450
451
452class _RemoteProcess(_BaseProcess):
453    def __init__(self, install_remote):
454        self._pid = None
455        self._install_remote = install_remote
456
457    @property
458    def pid(self):
459        return self._pid
460
461    def launch(self, executable, args, extra_env):
462        if self._install_remote:
463            src_path = executable
464            dst_path = lldbutil.join_remote_paths(
465                lldb.remote_platform.GetWorkingDirectory(), os.path.basename(executable)
466            )
467
468            dst_file_spec = lldb.SBFileSpec(dst_path, False)
469            err = lldb.remote_platform.Install(
470                lldb.SBFileSpec(src_path, True), dst_file_spec
471            )
472            if err.Fail():
473                raise Exception(
474                    "remote_platform.Install('%s', '%s') failed: %s"
475                    % (src_path, dst_path, err)
476                )
477        else:
478            dst_path = executable
479            dst_file_spec = lldb.SBFileSpec(executable, False)
480
481        launch_info = lldb.SBLaunchInfo(args)
482        launch_info.SetExecutableFile(dst_file_spec, True)
483        launch_info.SetWorkingDirectory(lldb.remote_platform.GetWorkingDirectory())
484
485        # Redirect stdout and stderr to /dev/null
486        launch_info.AddSuppressFileAction(1, False, True)
487        launch_info.AddSuppressFileAction(2, False, True)
488
489        if extra_env:
490            launch_info.SetEnvironmentEntries(extra_env, True)
491
492        err = lldb.remote_platform.Launch(launch_info)
493        if err.Fail():
494            raise Exception(
495                "remote_platform.Launch('%s', '%s') failed: %s" % (dst_path, args, err)
496            )
497        self._pid = launch_info.GetProcessID()
498
499    def terminate(self):
500        lldb.remote_platform.Kill(self._pid)
501
502
503def getsource_if_available(obj):
504    """
505    Return the text of the source code for an object if available.  Otherwise,
506    a print representation is returned.
507    """
508    import inspect
509
510    try:
511        return inspect.getsource(obj)
512    except:
513        return repr(obj)
514
515
516def builder_module():
517    return lldbplatformutil.builder_module()
518
519
520class Base(unittest2.TestCase):
521    """
522    Abstract base for performing lldb (see TestBase) or other generic tests (see
523    BenchBase for one example).  lldbtest.Base works with the test driver to
524    accomplish things.
525
526    """
527
528    # The concrete subclass should override this attribute.
529    mydir = None
530
531    # Keep track of the old current working directory.
532    oldcwd = None
533
534    @staticmethod
535    def compute_mydir(test_file):
536        """Subclasses should call this function to correctly calculate the
537        required "mydir" attribute as follows:
538
539         mydir = TestBase.compute_mydir(__file__)
540        """
541        # /abs/path/to/packages/group/subdir/mytest.py -> group/subdir
542        lldb_test_src = configuration.test_src_root
543        if not test_file.startswith(lldb_test_src):
544            raise Exception(
545                "Test file '%s' must reside within lldb_test_src "
546                "(which is '%s')." % (test_file, lldb_test_src)
547            )
548        return os.path.dirname(os.path.relpath(test_file, start=lldb_test_src))
549
550    def TraceOn(self):
551        """Returns True if we are in trace mode (tracing detailed test execution)."""
552        return traceAlways
553
554    def trace(self, *args, **kwargs):
555        with recording(self, self.TraceOn()) as sbuf:
556            print(*args, file=sbuf, **kwargs)
557
558    @classmethod
559    def setUpClass(cls):
560        """
561        Python unittest framework class setup fixture.
562        Do current directory manipulation.
563        """
564        # Fail fast if 'mydir' attribute is not overridden.
565        if not cls.mydir:
566            cls.mydir = Base.compute_mydir(sys.modules[cls.__module__].__file__)
567        if not cls.mydir:
568            raise Exception("Subclasses must override the 'mydir' attribute.")
569
570        # Save old working directory.
571        cls.oldcwd = os.getcwd()
572
573        full_dir = os.path.join(configuration.test_src_root, cls.mydir)
574        if traceAlways:
575            print("Change dir to:", full_dir, file=sys.stderr)
576        os.chdir(full_dir)
577
578        # Set platform context.
579        cls.platformContext = lldbplatformutil.createPlatformContext()
580
581    @classmethod
582    def tearDownClass(cls):
583        """
584        Python unittest framework class teardown fixture.
585        Do class-wide cleanup.
586        """
587
588        if doCleanup:
589            # First, let's do the platform-specific cleanup.
590            module = builder_module()
591            module.cleanup()
592
593            # Subclass might have specific cleanup function defined.
594            if getattr(cls, "classCleanup", None):
595                if traceAlways:
596                    print(
597                        "Call class-specific cleanup function for class:",
598                        cls,
599                        file=sys.stderr,
600                    )
601                try:
602                    cls.classCleanup()
603                except:
604                    exc_type, exc_value, exc_tb = sys.exc_info()
605                    traceback.print_exception(exc_type, exc_value, exc_tb)
606
607        # Restore old working directory.
608        if traceAlways:
609            print("Restore dir to:", cls.oldcwd, file=sys.stderr)
610        os.chdir(cls.oldcwd)
611
612    def enableLogChannelsForCurrentTest(self):
613        if len(lldbtest_config.channels) == 0:
614            return
615
616        # if debug channels are specified in lldbtest_config.channels,
617        # create a new set of log files for every test
618        log_basename = self.getLogBasenameForCurrentTest()
619
620        # confirm that the file is writeable
621        host_log_path = "{}-host.log".format(log_basename)
622        open(host_log_path, "w").close()
623        self.log_files.append(host_log_path)
624
625        log_enable = "log enable -Tpn -f {} ".format(host_log_path)
626        for channel_with_categories in lldbtest_config.channels:
627            channel_then_categories = channel_with_categories.split(" ", 1)
628            channel = channel_then_categories[0]
629            if len(channel_then_categories) > 1:
630                categories = channel_then_categories[1]
631            else:
632                categories = "default"
633
634            if channel == "gdb-remote" and lldb.remote_platform is None:
635                # communicate gdb-remote categories to debugserver
636                os.environ["LLDB_DEBUGSERVER_LOG_FLAGS"] = categories
637
638            self.ci.HandleCommand(log_enable + channel_with_categories, self.res)
639            if not self.res.Succeeded():
640                raise Exception(
641                    "log enable failed (check LLDB_LOG_OPTION env variable)"
642                )
643
644        # Communicate log path name to debugserver & lldb-server
645        # For remote debugging, these variables need to be set when starting the platform
646        # instance.
647        if lldb.remote_platform is None:
648            server_log_path = "{}-server.log".format(log_basename)
649            open(server_log_path, "w").close()
650            self.log_files.append(server_log_path)
651            os.environ["LLDB_DEBUGSERVER_LOG_FILE"] = server_log_path
652
653            # Communicate channels to lldb-server
654            os.environ["LLDB_SERVER_LOG_CHANNELS"] = ":".join(lldbtest_config.channels)
655
656        self.addTearDownHook(self.disableLogChannelsForCurrentTest)
657
658    def disableLogChannelsForCurrentTest(self):
659        # close all log files that we opened
660        for channel_and_categories in lldbtest_config.channels:
661            # channel format - <channel-name> [<category0> [<category1> ...]]
662            channel = channel_and_categories.split(" ", 1)[0]
663            self.ci.HandleCommand("log disable " + channel, self.res)
664            if not self.res.Succeeded():
665                raise Exception(
666                    "log disable failed (check LLDB_LOG_OPTION env variable)"
667                )
668
669        # Retrieve the server log (if any) from the remote system. It is assumed the server log
670        # is writing to the "server.log" file in the current test directory. This can be
671        # achieved by setting LLDB_DEBUGSERVER_LOG_FILE="server.log" when starting remote
672        # platform.
673        if lldb.remote_platform:
674            server_log_path = self.getLogBasenameForCurrentTest() + "-server.log"
675            if lldb.remote_platform.Get(
676                lldb.SBFileSpec("server.log"), lldb.SBFileSpec(server_log_path)
677            ).Success():
678                self.log_files.append(server_log_path)
679
680    def setPlatformWorkingDir(self):
681        if not lldb.remote_platform or not configuration.lldb_platform_working_dir:
682            return
683
684        components = self.mydir.split(os.path.sep) + [
685            str(self.test_number),
686            self.getBuildDirBasename(),
687        ]
688        remote_test_dir = configuration.lldb_platform_working_dir
689        for c in components:
690            remote_test_dir = lldbutil.join_remote_paths(remote_test_dir, c)
691            error = lldb.remote_platform.MakeDirectory(
692                remote_test_dir, 448
693            )  # 448 = 0o700
694            if error.Fail():
695                raise Exception(
696                    "making remote directory '%s': %s" % (remote_test_dir, error)
697                )
698
699        lldb.remote_platform.SetWorkingDirectory(remote_test_dir)
700
701        # This function removes all files from the current working directory while leaving
702        # the directories in place. The cleanup is required to reduce the disk space required
703        # by the test suite while leaving the directories untouched is neccessary because
704        # sub-directories might belong to an other test
705        def clean_working_directory():
706            # TODO: Make it working on Windows when we need it for remote debugging support
707            # TODO: Replace the heuristic to remove the files with a logic what collects the
708            # list of files we have to remove during test runs.
709            shell_cmd = lldb.SBPlatformShellCommand("rm %s/*" % remote_test_dir)
710            lldb.remote_platform.Run(shell_cmd)
711
712        self.addTearDownHook(clean_working_directory)
713
714    def getSourceDir(self):
715        """Return the full path to the current test."""
716        return os.path.join(configuration.test_src_root, self.mydir)
717
718    def getBuildDirBasename(self):
719        return self.__class__.__module__ + "." + self.testMethodName
720
721    def getBuildDir(self):
722        """Return the full path to the current test."""
723        return os.path.join(
724            configuration.test_build_dir, self.mydir, self.getBuildDirBasename()
725        )
726
727    def makeBuildDir(self):
728        """Create the test-specific working directory, deleting any previous
729        contents."""
730        bdir = self.getBuildDir()
731        if os.path.isdir(bdir):
732            shutil.rmtree(bdir)
733        lldbutil.mkdir_p(bdir)
734
735    def getBuildArtifact(self, name="a.out"):
736        """Return absolute path to an artifact in the test's build directory."""
737        return os.path.join(self.getBuildDir(), name)
738
739    def getSourcePath(self, name):
740        """Return absolute path to a file in the test's source directory."""
741        return os.path.join(self.getSourceDir(), name)
742
743    @classmethod
744    def setUpCommands(cls):
745        commands = [
746            # First of all, clear all settings to have clean state of global properties.
747            "settings clear -all",
748            # Disable Spotlight lookup. The testsuite creates
749            # different binaries with the same UUID, because they only
750            # differ in the debug info, which is not being hashed.
751            "settings set symbols.enable-external-lookup false",
752            # Inherit the TCC permissions from the inferior's parent.
753            "settings set target.inherit-tcc true",
754            # Kill rather than detach from the inferior if something goes wrong.
755            "settings set target.detach-on-error false",
756            # Disable fix-its by default so that incorrect expressions in tests don't
757            # pass just because Clang thinks it has a fix-it.
758            "settings set target.auto-apply-fixits false",
759            # Testsuite runs in parallel and the host can have also other load.
760            "settings set plugin.process.gdb-remote.packet-timeout 60",
761            'settings set symbols.clang-modules-cache-path "{}"'.format(
762                configuration.lldb_module_cache_dir
763            ),
764            "settings set use-color false",
765        ]
766
767        # Set any user-overridden settings.
768        for setting, value in configuration.settings:
769            commands.append("setting set %s %s" % (setting, value))
770
771        # Make sure that a sanitizer LLDB's environment doesn't get passed on.
772        if (
773            cls.platformContext
774            and cls.platformContext.shlib_environment_var in os.environ
775        ):
776            commands.append(
777                "settings set target.env-vars {}=".format(
778                    cls.platformContext.shlib_environment_var
779                )
780            )
781
782        # Set environment variables for the inferior.
783        if lldbtest_config.inferior_env:
784            commands.append(
785                "settings set target.env-vars {}".format(lldbtest_config.inferior_env)
786            )
787        return commands
788
789    def setUp(self):
790        """Fixture for unittest test case setup.
791
792        It works with the test driver to conditionally skip tests and does other
793        initializations."""
794        # import traceback
795        # traceback.print_stack()
796
797        if "LIBCXX_PATH" in os.environ:
798            self.libcxxPath = os.environ["LIBCXX_PATH"]
799        else:
800            self.libcxxPath = None
801
802        if "LLDBDAP_EXEC" in os.environ:
803            self.lldbDAPExec = os.environ["LLDBDAP_EXEC"]
804        else:
805            self.lldbDAPExec = None
806
807        self.lldbOption = " ".join("-o '" + s + "'" for s in self.setUpCommands())
808
809        # If we spawn an lldb process for test (via pexpect), do not load the
810        # init file unless told otherwise.
811        if os.environ.get("NO_LLDBINIT") != "NO":
812            self.lldbOption += " --no-lldbinit"
813
814        # Assign the test method name to self.testMethodName.
815        #
816        # For an example of the use of this attribute, look at test/types dir.
817        # There are a bunch of test cases under test/types and we don't want the
818        # module cacheing subsystem to be confused with executable name "a.out"
819        # used for all the test cases.
820        self.testMethodName = self._testMethodName
821
822        # This is for the case of directly spawning 'lldb'/'gdb' and interacting
823        # with it using pexpect.
824        self.child = None
825        self.child_prompt = "(lldb) "
826        # If the child is interacting with the embedded script interpreter,
827        # there are two exits required during tear down, first to quit the
828        # embedded script interpreter and second to quit the lldb command
829        # interpreter.
830        self.child_in_script_interpreter = False
831
832        # These are for customized teardown cleanup.
833        self.dict = None
834        self.doTearDownCleanup = False
835        # And in rare cases where there are multiple teardown cleanups.
836        self.dicts = []
837        self.doTearDownCleanups = False
838
839        # List of spawned subproces.Popen objects
840        self.subprocesses = []
841
842        # List of log files produced by the current test.
843        self.log_files = []
844
845        # Create the build directory.
846        # The logs are stored in the build directory, so we have to create it
847        # before creating the first log file.
848        self.makeBuildDir()
849
850        session_file = self.getLogBasenameForCurrentTest() + ".log"
851        self.log_files.append(session_file)
852
853        # Python 3 doesn't support unbuffered I/O in text mode.  Open buffered.
854        self.session = encoded_file.open(session_file, "utf-8", mode="w")
855
856        # Optimistically set __errored__, __failed__, __expected__ to False
857        # initially.  If the test errored/failed, the session info
858        # (self.session) is then dumped into a session specific file for
859        # diagnosis.
860        self.__cleanup_errored__ = False
861        self.__errored__ = False
862        self.__failed__ = False
863        self.__expected__ = False
864        # We are also interested in unexpected success.
865        self.__unexpected__ = False
866        # And skipped tests.
867        self.__skipped__ = False
868
869        # See addTearDownHook(self, hook) which allows the client to add a hook
870        # function to be run during tearDown() time.
871        self.hooks = []
872
873        # See HideStdout(self).
874        self.sys_stdout_hidden = False
875
876        if self.platformContext:
877            # set environment variable names for finding shared libraries
878            self.dylibPath = self.platformContext.shlib_environment_var
879
880        # Create the debugger instance.
881        self.dbg = lldb.SBDebugger.Create()
882        # Copy selected platform from a global instance if it exists.
883        if lldb.selected_platform is not None:
884            self.dbg.SetSelectedPlatform(lldb.selected_platform)
885
886        if not self.dbg:
887            raise Exception("Invalid debugger instance")
888
889        # Retrieve the associated command interpreter instance.
890        self.ci = self.dbg.GetCommandInterpreter()
891        if not self.ci:
892            raise Exception("Could not get the command interpreter")
893
894        # And the result object.
895        self.res = lldb.SBCommandReturnObject()
896
897        self.setPlatformWorkingDir()
898        self.enableLogChannelsForCurrentTest()
899
900        self.lib_lldb = None
901        self.framework_dir = None
902        self.darwinWithFramework = False
903
904        if sys.platform.startswith("darwin") and configuration.lldb_framework_path:
905            framework = configuration.lldb_framework_path
906            lib = os.path.join(framework, "LLDB")
907            if os.path.exists(lib):
908                self.framework_dir = os.path.dirname(framework)
909                self.lib_lldb = lib
910                self.darwinWithFramework = self.platformIsDarwin()
911
912    def setAsync(self, value):
913        """Sets async mode to True/False and ensures it is reset after the testcase completes."""
914        old_async = self.dbg.GetAsync()
915        self.dbg.SetAsync(value)
916        self.addTearDownHook(lambda: self.dbg.SetAsync(old_async))
917
918    def cleanupSubprocesses(self):
919        # Terminate subprocesses in reverse order from how they were created.
920        for p in reversed(self.subprocesses):
921            p.terminate()
922            del p
923        del self.subprocesses[:]
924
925    def spawnSubprocess(self, executable, args=[], extra_env=None, install_remote=True):
926        """Creates a subprocess.Popen object with the specified executable and arguments,
927        saves it in self.subprocesses, and returns the object.
928        """
929        proc = (
930            _RemoteProcess(install_remote)
931            if lldb.remote_platform
932            else _LocalProcess(self.TraceOn())
933        )
934        proc.launch(executable, args, extra_env=extra_env)
935        self.subprocesses.append(proc)
936        return proc
937
938    def HideStdout(self):
939        """Hide output to stdout from the user.
940
941        During test execution, there might be cases where we don't want to show the
942        standard output to the user.  For example,
943
944            self.runCmd(r'''sc print("\n\n\tHello!\n")''')
945
946        tests whether command abbreviation for 'script' works or not.  There is no
947        need to show the 'Hello' output to the user as long as the 'script' command
948        succeeds and we are not in TraceOn() mode (see the '-t' option).
949
950        In this case, the test method calls self.HideStdout(self) to redirect the
951        sys.stdout to a null device, and restores the sys.stdout upon teardown.
952
953        Note that you should only call this method at most once during a test case
954        execution.  Any subsequent call has no effect at all."""
955        if self.sys_stdout_hidden:
956            return
957
958        self.sys_stdout_hidden = True
959        old_stdout = sys.stdout
960        sys.stdout = open(os.devnull, "w")
961
962        def restore_stdout():
963            sys.stdout = old_stdout
964
965        self.addTearDownHook(restore_stdout)
966
967    # =======================================================================
968    # Methods for customized teardown cleanups as well as execution of hooks.
969    # =======================================================================
970
971    def setTearDownCleanup(self, dictionary=None):
972        """Register a cleanup action at tearDown() time with a dictionary"""
973        self.dict = dictionary
974        self.doTearDownCleanup = True
975
976    def addTearDownCleanup(self, dictionary):
977        """Add a cleanup action at tearDown() time with a dictionary"""
978        self.dicts.append(dictionary)
979        self.doTearDownCleanups = True
980
981    def addTearDownHook(self, hook):
982        """
983        Add a function to be run during tearDown() time.
984
985        Hooks are executed in a first come first serve manner.
986        """
987        if callable(hook):
988            with recording(self, traceAlways) as sbuf:
989                print("Adding tearDown hook:", getsource_if_available(hook), file=sbuf)
990            self.hooks.append(hook)
991
992        return self
993
994    def deletePexpectChild(self):
995        # This is for the case of directly spawning 'lldb' and interacting with it
996        # using pexpect.
997        if self.child and self.child.isalive():
998            import pexpect
999
1000            with recording(self, traceAlways) as sbuf:
1001                print("tearing down the child process....", file=sbuf)
1002            try:
1003                if self.child_in_script_interpreter:
1004                    self.child.sendline("quit()")
1005                    self.child.expect_exact(self.child_prompt)
1006                self.child.sendline("settings set interpreter.prompt-on-quit false")
1007                self.child.sendline("quit")
1008                self.child.expect(pexpect.EOF)
1009            except (ValueError, pexpect.ExceptionPexpect):
1010                # child is already terminated
1011                pass
1012            except OSError as exception:
1013                import errno
1014
1015                if exception.errno != errno.EIO:
1016                    # unexpected error
1017                    raise
1018                # child is already terminated
1019            finally:
1020                # Give it one final blow to make sure the child is terminated.
1021                self.child.close()
1022
1023    def tearDown(self):
1024        """Fixture for unittest test case teardown."""
1025        self.deletePexpectChild()
1026
1027        # Check and run any hook functions.
1028        for hook in reversed(self.hooks):
1029            with recording(self, traceAlways) as sbuf:
1030                print(
1031                    "Executing tearDown hook:", getsource_if_available(hook), file=sbuf
1032                )
1033            if funcutils.requires_self(hook):
1034                hook(self)
1035            else:
1036                hook()  # try the plain call and hope it works
1037
1038        del self.hooks
1039
1040        # Perform registered teardown cleanup.
1041        if doCleanup and self.doTearDownCleanup:
1042            self.cleanup(dictionary=self.dict)
1043
1044        # In rare cases where there are multiple teardown cleanups added.
1045        if doCleanup and self.doTearDownCleanups:
1046            if self.dicts:
1047                for dict in reversed(self.dicts):
1048                    self.cleanup(dictionary=dict)
1049
1050        # Remove subprocesses created by the test.
1051        self.cleanupSubprocesses()
1052
1053        # This must be the last statement, otherwise teardown hooks or other
1054        # lines might depend on this still being active.
1055        lldb.SBDebugger.Destroy(self.dbg)
1056        del self.dbg
1057
1058        # All modules should be orphaned now so that they can be cleared from
1059        # the shared module cache.
1060        lldb.SBModule.GarbageCollectAllocatedModules()
1061
1062        # Assert that the global module cache is empty.
1063        self.assertEqual(lldb.SBModule.GetNumberAllocatedModules(), 0)
1064
1065    # =========================================================
1066    # Various callbacks to allow introspection of test progress
1067    # =========================================================
1068
1069    def markError(self):
1070        """Callback invoked when an error (unexpected exception) errored."""
1071        self.__errored__ = True
1072        with recording(self, False) as sbuf:
1073            # False because there's no need to write "ERROR" to the stderr twice.
1074            # Once by the Python unittest framework, and a second time by us.
1075            print("ERROR", file=sbuf)
1076
1077    def markCleanupError(self):
1078        """Callback invoked when an error occurs while a test is cleaning up."""
1079        self.__cleanup_errored__ = True
1080        with recording(self, False) as sbuf:
1081            # False because there's no need to write "CLEANUP_ERROR" to the stderr twice.
1082            # Once by the Python unittest framework, and a second time by us.
1083            print("CLEANUP_ERROR", file=sbuf)
1084
1085    def markFailure(self):
1086        """Callback invoked when a failure (test assertion failure) occurred."""
1087        self.__failed__ = True
1088        with recording(self, False) as sbuf:
1089            # False because there's no need to write "FAIL" to the stderr twice.
1090            # Once by the Python unittest framework, and a second time by us.
1091            print("FAIL", file=sbuf)
1092
1093    def markExpectedFailure(self, err, bugnumber):
1094        """Callback invoked when an expected failure/error occurred."""
1095        self.__expected__ = True
1096        with recording(self, False) as sbuf:
1097            # False because there's no need to write "expected failure" to the
1098            # stderr twice.
1099            # Once by the Python unittest framework, and a second time by us.
1100            if bugnumber is None:
1101                print("expected failure", file=sbuf)
1102            else:
1103                print("expected failure (problem id:" + str(bugnumber) + ")", file=sbuf)
1104
1105    def markSkippedTest(self):
1106        """Callback invoked when a test is skipped."""
1107        self.__skipped__ = True
1108        with recording(self, False) as sbuf:
1109            # False because there's no need to write "skipped test" to the
1110            # stderr twice.
1111            # Once by the Python unittest framework, and a second time by us.
1112            print("skipped test", file=sbuf)
1113
1114    def markUnexpectedSuccess(self, bugnumber):
1115        """Callback invoked when an unexpected success occurred."""
1116        self.__unexpected__ = True
1117        with recording(self, False) as sbuf:
1118            # False because there's no need to write "unexpected success" to the
1119            # stderr twice.
1120            # Once by the Python unittest framework, and a second time by us.
1121            if bugnumber is None:
1122                print("unexpected success", file=sbuf)
1123            else:
1124                print(
1125                    "unexpected success (problem id:" + str(bugnumber) + ")", file=sbuf
1126                )
1127
1128    def getRerunArgs(self):
1129        return " -f %s.%s" % (self.__class__.__name__, self._testMethodName)
1130
1131    def getLogBasenameForCurrentTest(self, prefix="Incomplete"):
1132        """
1133        returns a partial path that can be used as the beginning of the name of multiple
1134        log files pertaining to this test
1135        """
1136        return os.path.join(self.getBuildDir(), prefix)
1137
1138    def dumpSessionInfo(self):
1139        """
1140        Dump the debugger interactions leading to a test error/failure.  This
1141        allows for more convenient postmortem analysis.
1142
1143        See also LLDBTestResult (dotest.py) which is a singlton class derived
1144        from TextTestResult and overwrites addError, addFailure, and
1145        addExpectedFailure methods to allow us to to mark the test instance as
1146        such.
1147        """
1148
1149        # We are here because self.tearDown() detected that this test instance
1150        # either errored or failed.  The lldb.test_result singleton contains
1151        # two lists (errors and failures) which get populated by the unittest
1152        # framework.  Look over there for stack trace information.
1153        #
1154        # The lists contain 2-tuples of TestCase instances and strings holding
1155        # formatted tracebacks.
1156        #
1157        # See http://docs.python.org/library/unittest.html#unittest.TestResult.
1158
1159        # output tracebacks into session
1160        pairs = []
1161        if self.__errored__:
1162            pairs = configuration.test_result.errors
1163            prefix = "Error"
1164        elif self.__cleanup_errored__:
1165            pairs = configuration.test_result.cleanup_errors
1166            prefix = "CleanupError"
1167        elif self.__failed__:
1168            pairs = configuration.test_result.failures
1169            prefix = "Failure"
1170        elif self.__expected__:
1171            pairs = configuration.test_result.expectedFailures
1172            prefix = "ExpectedFailure"
1173        elif self.__skipped__:
1174            prefix = "SkippedTest"
1175        elif self.__unexpected__:
1176            prefix = "UnexpectedSuccess"
1177        else:
1178            prefix = "Success"
1179
1180        if not self.__unexpected__ and not self.__skipped__:
1181            for test, traceback in pairs:
1182                if test is self:
1183                    print(traceback, file=self.session)
1184
1185        import datetime
1186
1187        print(
1188            "Session info generated @",
1189            datetime.datetime.now().ctime(),
1190            file=self.session,
1191        )
1192        self.session.close()
1193        del self.session
1194
1195        # process the log files
1196        if prefix != "Success" or lldbtest_config.log_success:
1197            # keep all log files, rename them to include prefix
1198            src_log_basename = self.getLogBasenameForCurrentTest()
1199            dst_log_basename = self.getLogBasenameForCurrentTest(prefix)
1200            for src in self.log_files:
1201                if os.path.isfile(src):
1202                    dst = src.replace(src_log_basename, dst_log_basename)
1203                    if os.name == "nt" and os.path.isfile(dst):
1204                        # On Windows, renaming a -> b will throw an exception if
1205                        # b exists.  On non-Windows platforms it silently
1206                        # replaces the destination.  Ultimately this means that
1207                        # atomic renames are not guaranteed to be possible on
1208                        # Windows, but we need this to work anyway, so just
1209                        # remove the destination first if it already exists.
1210                        remove_file(dst)
1211
1212                    lldbutil.mkdir_p(os.path.dirname(dst))
1213                    os.rename(src, dst)
1214        else:
1215            # success!  (and we don't want log files) delete log files
1216            for log_file in self.log_files:
1217                if os.path.isfile(log_file):
1218                    remove_file(log_file)
1219
1220    # ====================================================
1221    # Config. methods supported through a plugin interface
1222    # (enables reading of the current test configuration)
1223    # ====================================================
1224
1225    def hasXMLSupport(self):
1226        """Returns True if lldb was built with XML support. Use this check to
1227        enable parts of tests, if you want to skip a whole test use skipIfXmlSupportMissing
1228        instead."""
1229        return (
1230            lldb.SBDebugger.GetBuildConfiguration()
1231            .GetValueForKey("xml")
1232            .GetValueForKey("value")
1233            .GetBooleanValue(False)
1234        )
1235
1236    def isMIPS(self):
1237        """Returns true if the architecture is MIPS."""
1238        arch = self.getArchitecture()
1239        if re.match("mips", arch):
1240            return True
1241        return False
1242
1243    def isPPC64le(self):
1244        """Returns true if the architecture is PPC64LE."""
1245        arch = self.getArchitecture()
1246        if re.match("powerpc64le", arch):
1247            return True
1248        return False
1249
1250    def getCPUInfo(self):
1251        triple = self.dbg.GetSelectedPlatform().GetTriple()
1252
1253        # TODO other platforms, please implement this function
1254        if not re.match(".*-.*-linux", triple):
1255            return ""
1256
1257        # Need to do something different for non-Linux/Android targets
1258        cpuinfo_path = self.getBuildArtifact("cpuinfo")
1259        if configuration.lldb_platform_name:
1260            self.runCmd('platform get-file "/proc/cpuinfo" ' + cpuinfo_path)
1261        else:
1262            cpuinfo_path = "/proc/cpuinfo"
1263
1264        try:
1265            with open(cpuinfo_path, "r") as f:
1266                cpuinfo = f.read()
1267        except:
1268            return ""
1269
1270        return cpuinfo
1271
1272    def isAArch64(self):
1273        """Returns true if the architecture is AArch64."""
1274        arch = self.getArchitecture().lower()
1275        return arch in ["aarch64", "arm64", "arm64e"]
1276
1277    def isAArch64SVE(self):
1278        return self.isAArch64() and "sve" in self.getCPUInfo()
1279
1280    def isAArch64SME(self):
1281        return self.isAArch64() and "sme" in self.getCPUInfo()
1282
1283    def isAArch64SME2(self):
1284        # If you have sme2, you also have sme.
1285        return self.isAArch64() and "sme2" in self.getCPUInfo()
1286
1287    def isAArch64SMEFA64(self):
1288        # smefa64 allows the use of the full A64 instruction set in streaming
1289        # mode. This is required by certain test programs to setup register
1290        # state.
1291        cpuinfo = self.getCPUInfo()
1292        return self.isAArch64() and "sme" in cpuinfo and "smefa64" in cpuinfo
1293
1294    def isAArch64MTE(self):
1295        return self.isAArch64() and "mte" in self.getCPUInfo()
1296
1297    def isAArch64PAuth(self):
1298        if self.getArchitecture() == "arm64e":
1299            return True
1300        return self.isAArch64() and "paca" in self.getCPUInfo()
1301
1302    def isAArch64Windows(self):
1303        """Returns true if the architecture is AArch64 and platform windows."""
1304        if self.getPlatform() == "windows":
1305            arch = self.getArchitecture().lower()
1306            return arch in ["aarch64", "arm64", "arm64e"]
1307        return False
1308
1309    def getArchitecture(self):
1310        """Returns the architecture in effect the test suite is running with."""
1311        return lldbplatformutil.getArchitecture()
1312
1313    def getLldbArchitecture(self):
1314        """Returns the architecture of the lldb binary."""
1315        return lldbplatformutil.getLLDBArchitecture()
1316
1317    def getCompiler(self):
1318        """Returns the compiler in effect the test suite is running with."""
1319        return lldbplatformutil.getCompiler()
1320
1321    def getCompilerBinary(self):
1322        """Returns the compiler binary the test suite is running with."""
1323        return lldbplatformutil.getCompilerBinary()
1324
1325    def getCompilerVersion(self):
1326        """Returns a string that represents the compiler version.
1327        Supports: llvm, clang.
1328        """
1329        return lldbplatformutil.getCompilerVersion()
1330
1331    def getDwarfVersion(self):
1332        """Returns the dwarf version generated by clang or '0'."""
1333        return lldbplatformutil.getDwarfVersion()
1334
1335    def platformIsDarwin(self):
1336        """Returns true if the OS triple for the selected platform is any valid apple OS"""
1337        return lldbplatformutil.platformIsDarwin()
1338
1339    def hasDarwinFramework(self):
1340        return self.darwinWithFramework
1341
1342    def getPlatform(self):
1343        """Returns the target platform the test suite is running on."""
1344        return lldbplatformutil.getPlatform()
1345
1346    def isIntelCompiler(self):
1347        """Returns true if using an Intel (ICC) compiler, false otherwise."""
1348        return any([x in self.getCompiler() for x in ["icc", "icpc", "icl"]])
1349
1350    def expectedCompilerVersion(self, compiler_version):
1351        """Returns True iff compiler_version[1] matches the current compiler version.
1352        Use compiler_version[0] to specify the operator used to determine if a match has occurred.
1353        Any operator other than the following defaults to an equality test:
1354          '>', '>=', "=>", '<', '<=', '=<', '!=', "!" or 'not'
1355
1356        If the current compiler version cannot be determined, we assume it is close to the top
1357        of trunk, so any less-than or equal-to comparisons will return False, and any
1358        greater-than or not-equal-to comparisons will return True.
1359        """
1360        return lldbplatformutil.expectedCompilerVersion(compiler_version)
1361
1362    def expectedCompiler(self, compilers):
1363        """Returns True iff any element of compilers is a sub-string of the current compiler."""
1364        return lldbplatformutil.expectedCompiler(compilers)
1365
1366    def expectedArch(self, archs):
1367        """Returns True iff any element of archs is a sub-string of the current architecture."""
1368        if archs is None:
1369            return True
1370
1371        for arch in archs:
1372            if arch in self.getArchitecture():
1373                return True
1374
1375        return False
1376
1377    def getRunOptions(self):
1378        """Command line option for -A and -C to run this test again, called from
1379        self.dumpSessionInfo()."""
1380        arch = self.getArchitecture()
1381        comp = self.getCompiler()
1382        option_str = ""
1383        if arch:
1384            option_str = "-A " + arch
1385        if comp:
1386            option_str += " -C " + comp
1387        return option_str
1388
1389    def getDebugInfo(self):
1390        method = getattr(self, self.testMethodName)
1391        return getattr(method, "debug_info", None)
1392
1393    def build(
1394        self,
1395        debug_info=None,
1396        architecture=None,
1397        compiler=None,
1398        dictionary=None,
1399        make_targets=None,
1400    ):
1401        """Platform specific way to build binaries."""
1402        if not architecture and configuration.arch:
1403            architecture = configuration.arch
1404
1405        if debug_info is None:
1406            debug_info = self.getDebugInfo()
1407
1408        dictionary = lldbplatformutil.finalize_build_dictionary(dictionary)
1409
1410        testdir = self.mydir
1411        testname = self.getBuildDirBasename()
1412
1413        module = builder_module()
1414        command = builder_module().getBuildCommand(
1415            debug_info,
1416            architecture,
1417            compiler,
1418            dictionary,
1419            testdir,
1420            testname,
1421            make_targets,
1422        )
1423        if command is None:
1424            raise Exception("Don't know how to build binary")
1425
1426        self.runBuildCommand(command)
1427
1428    def runBuildCommand(self, command):
1429        self.trace(seven.join_for_shell(command))
1430        try:
1431            output = check_output(command, stderr=STDOUT, errors="replace")
1432        except CalledProcessError as cpe:
1433            raise build_exception.BuildError(cpe)
1434        self.trace(output)
1435
1436    # ==================================================
1437    # Build methods supported through a plugin interface
1438    # ==================================================
1439
1440    def getstdlibFlag(self):
1441        """Returns the proper -stdlib flag, or empty if not required."""
1442        if (
1443            self.platformIsDarwin()
1444            or self.getPlatform() == "freebsd"
1445            or self.getPlatform() == "openbsd"
1446        ):
1447            stdlibflag = "-stdlib=libc++"
1448        else:  # this includes NetBSD
1449            stdlibflag = ""
1450        return stdlibflag
1451
1452    def getstdFlag(self):
1453        """Returns the proper stdflag."""
1454        if "gcc" in self.getCompiler() and "4.6" in self.getCompilerVersion():
1455            stdflag = "-std=c++0x"
1456        else:
1457            stdflag = "-std=c++11"
1458        return stdflag
1459
1460    def buildDriver(self, sources, exe_name):
1461        """Platform-specific way to build a program that links with LLDB (via the liblldb.so
1462        or LLDB.framework).
1463        """
1464        stdflag = self.getstdFlag()
1465        stdlibflag = self.getstdlibFlag()
1466
1467        lib_dir = configuration.lldb_libs_dir
1468        if self.hasDarwinFramework():
1469            d = {
1470                "CXX_SOURCES": sources,
1471                "EXE": exe_name,
1472                "CFLAGS_EXTRAS": "%s %s" % (stdflag, stdlibflag),
1473                "FRAMEWORK_INCLUDES": "-F%s" % self.framework_dir,
1474                "LD_EXTRAS": "%s -Wl,-rpath,%s" % (self.lib_lldb, self.framework_dir),
1475            }
1476        elif sys.platform.startswith("win"):
1477            d = {
1478                "CXX_SOURCES": sources,
1479                "EXE": exe_name,
1480                "CFLAGS_EXTRAS": "%s %s -I%s"
1481                % (
1482                    stdflag,
1483                    stdlibflag,
1484                    os.path.join(os.environ["LLDB_SRC"], "include"),
1485                ),
1486                "LD_EXTRAS": "-L%s -lliblldb" % lib_dir,
1487            }
1488        else:
1489            d = {
1490                "CXX_SOURCES": sources,
1491                "EXE": exe_name,
1492                "CFLAGS_EXTRAS": "%s %s -I%s"
1493                % (
1494                    stdflag,
1495                    stdlibflag,
1496                    os.path.join(os.environ["LLDB_SRC"], "include"),
1497                ),
1498                "LD_EXTRAS": "-L%s -llldb -Wl,-rpath,%s" % (lib_dir, lib_dir),
1499            }
1500        if self.TraceOn():
1501            print("Building LLDB Driver (%s) from sources %s" % (exe_name, sources))
1502
1503        self.build(dictionary=d)
1504
1505    def buildLibrary(self, sources, lib_name):
1506        """Platform specific way to build a default library."""
1507
1508        stdflag = self.getstdFlag()
1509
1510        lib_dir = configuration.lldb_libs_dir
1511        if self.hasDarwinFramework():
1512            d = {
1513                "DYLIB_CXX_SOURCES": sources,
1514                "DYLIB_NAME": lib_name,
1515                "CFLAGS_EXTRAS": "%s -stdlib=libc++" % stdflag,
1516                "FRAMEWORK_INCLUDES": "-F%s" % self.framework_dir,
1517                "LD_EXTRAS": "%s -Wl,-rpath,%s -dynamiclib"
1518                % (self.lib_lldb, self.framework_dir),
1519            }
1520        elif self.getPlatform() == "windows":
1521            d = {
1522                "DYLIB_CXX_SOURCES": sources,
1523                "DYLIB_NAME": lib_name,
1524                "CFLAGS_EXTRAS": "%s -I%s "
1525                % (stdflag, os.path.join(os.environ["LLDB_SRC"], "include")),
1526                "LD_EXTRAS": "-shared -l%s\liblldb.lib" % lib_dir,
1527            }
1528        else:
1529            d = {
1530                "DYLIB_CXX_SOURCES": sources,
1531                "DYLIB_NAME": lib_name,
1532                "CFLAGS_EXTRAS": "%s -I%s -fPIC"
1533                % (stdflag, os.path.join(os.environ["LLDB_SRC"], "include")),
1534                "LD_EXTRAS": "-shared -L%s -llldb -Wl,-rpath,%s" % (lib_dir, lib_dir),
1535            }
1536        if self.TraceOn():
1537            print("Building LLDB Library (%s) from sources %s" % (lib_name, sources))
1538
1539        self.build(dictionary=d)
1540
1541    def buildProgram(self, sources, exe_name):
1542        """Platform specific way to build an executable from C/C++ sources."""
1543        d = {"CXX_SOURCES": sources, "EXE": exe_name}
1544        self.build(dictionary=d)
1545
1546    def findBuiltClang(self):
1547        """Tries to find and use Clang from the build directory as the compiler (instead of the system compiler)."""
1548        paths_to_try = [
1549            "llvm-build/Release+Asserts/x86_64/bin/clang",
1550            "llvm-build/Debug+Asserts/x86_64/bin/clang",
1551            "llvm-build/Release/x86_64/bin/clang",
1552            "llvm-build/Debug/x86_64/bin/clang",
1553        ]
1554        lldb_root_path = os.path.join(os.path.dirname(__file__), "..", "..", "..", "..")
1555        for p in paths_to_try:
1556            path = os.path.join(lldb_root_path, p)
1557            if os.path.exists(path):
1558                return path
1559
1560        # Tries to find clang at the same folder as the lldb
1561        lldb_dir = os.path.dirname(lldbtest_config.lldbExec)
1562        path = shutil.which("clang", path=lldb_dir)
1563        if path is not None:
1564            return path
1565
1566        return os.environ["CC"]
1567
1568    def yaml2obj(self, yaml_path, obj_path, max_size=None):
1569        """
1570        Create an object file at the given path from a yaml file.
1571
1572        Throws subprocess.CalledProcessError if the object could not be created.
1573        """
1574        yaml2obj_bin = configuration.get_yaml2obj_path()
1575        if not yaml2obj_bin:
1576            self.assertTrue(False, "No valid yaml2obj executable specified")
1577        command = [yaml2obj_bin, "-o=%s" % obj_path, yaml_path]
1578        if max_size is not None:
1579            command += ["--max-size=%d" % max_size]
1580        self.runBuildCommand(command)
1581
1582    def cleanup(self, dictionary=None):
1583        """Platform specific way to do cleanup after build."""
1584        module = builder_module()
1585        if not module.cleanup(dictionary):
1586            raise Exception(
1587                "Don't know how to do cleanup with dictionary: " + dictionary
1588            )
1589
1590    def invoke(self, obj, name, trace=False):
1591        """Use reflection to call a method dynamically with no argument."""
1592        trace = True if traceAlways else trace
1593
1594        method = getattr(obj, name)
1595        import inspect
1596
1597        self.assertTrue(
1598            inspect.ismethod(method), name + "is a method name of object: " + str(obj)
1599        )
1600        result = method()
1601        with recording(self, trace) as sbuf:
1602            print(str(method) + ":", result, file=sbuf)
1603        return result
1604
1605    def getLLDBLibraryEnvVal(self):
1606        """Returns the path that the OS-specific library search environment variable
1607        (self.dylibPath) should be set to in order for a program to find the LLDB
1608        library. If an environment variable named self.dylibPath is already set,
1609        the new path is appended to it and returned.
1610        """
1611        existing_library_path = (
1612            os.environ[self.dylibPath] if self.dylibPath in os.environ else None
1613        )
1614        if existing_library_path:
1615            return "%s:%s" % (existing_library_path, configuration.lldb_libs_dir)
1616        if sys.platform.startswith("darwin") and configuration.lldb_framework_path:
1617            return configuration.lldb_framework_path
1618        return configuration.lldb_libs_dir
1619
1620    def getLibcPlusPlusLibs(self):
1621        if self.getPlatform() in ("freebsd", "linux", "netbsd", "openbsd"):
1622            return ["libc++.so.1"]
1623        else:
1624            return ["libc++.1.dylib", "libc++abi."]
1625
1626    def run_platform_command(self, cmd):
1627        platform = self.dbg.GetSelectedPlatform()
1628        shell_command = lldb.SBPlatformShellCommand(cmd)
1629        err = platform.Run(shell_command)
1630        return (err, shell_command.GetStatus(), shell_command.GetOutput())
1631
1632    def get_stats(self, options=None):
1633        """
1634        Get the output of the "statistics dump" with optional extra options
1635        and return the JSON as a python dictionary.
1636        """
1637        return_obj = lldb.SBCommandReturnObject()
1638        command = "statistics dump "
1639        if options is not None:
1640            command += options
1641        self.ci.HandleCommand(command, return_obj, False)
1642        metrics_json = return_obj.GetOutput()
1643        return json.loads(metrics_json)
1644
1645
1646# Metaclass for TestBase to change the list of test metods when a new TestCase is loaded.
1647# We change the test methods to create a new test method for each test for each debug info we are
1648# testing. The name of the new test method will be '<original-name>_<debug-info>' and with adding
1649# the new test method we remove the old method at the same time. This functionality can be
1650# supressed by at test case level setting the class attribute NO_DEBUG_INFO_TESTCASE or at test
1651# level by using the decorator @no_debug_info_test.
1652
1653
1654class LLDBTestCaseFactory(type):
1655    def __new__(cls, name, bases, attrs):
1656        original_testcase = super(LLDBTestCaseFactory, cls).__new__(
1657            cls, name, bases, attrs
1658        )
1659        if original_testcase.NO_DEBUG_INFO_TESTCASE:
1660            return original_testcase
1661
1662        # Default implementation for skip/xfail reason based on the debug category,
1663        # where "None" means to run the test as usual.
1664        def no_reason(_):
1665            return None
1666
1667        newattrs = {}
1668        for attrname, attrvalue in attrs.items():
1669            if attrname.startswith("test") and not getattr(
1670                attrvalue, "__no_debug_info_test__", False
1671            ):
1672                # If any debug info categories were explicitly tagged, assume that list to be
1673                # authoritative.  If none were specified, try with all debug
1674                # info formats.
1675                all_dbginfo_categories = set(
1676                    test_categories.debug_info_categories.keys()
1677                )
1678                categories = (
1679                    set(getattr(attrvalue, "categories", [])) & all_dbginfo_categories
1680                )
1681                if not categories:
1682                    categories = [
1683                        category
1684                        for category, can_replicate in test_categories.debug_info_categories.items()
1685                        if can_replicate
1686                    ]
1687
1688                xfail_for_debug_info_cat_fn = getattr(
1689                    attrvalue, "__xfail_for_debug_info_cat_fn__", no_reason
1690                )
1691                skip_for_debug_info_cat_fn = getattr(
1692                    attrvalue, "__skip_for_debug_info_cat_fn__", no_reason
1693                )
1694                for cat in categories:
1695
1696                    @decorators.add_test_categories([cat])
1697                    @wraps(attrvalue)
1698                    def test_method(self, attrvalue=attrvalue):
1699                        return attrvalue(self)
1700
1701                    method_name = attrname + "_" + cat
1702                    test_method.__name__ = method_name
1703                    test_method.debug_info = cat
1704
1705                    xfail_reason = xfail_for_debug_info_cat_fn(cat)
1706                    if xfail_reason:
1707                        test_method = unittest2.expectedFailure(xfail_reason)(
1708                            test_method
1709                        )
1710
1711                    skip_reason = skip_for_debug_info_cat_fn(cat)
1712                    if skip_reason:
1713                        test_method = unittest2.skip(skip_reason)(test_method)
1714
1715                    newattrs[method_name] = test_method
1716
1717            else:
1718                newattrs[attrname] = attrvalue
1719        return super(LLDBTestCaseFactory, cls).__new__(cls, name, bases, newattrs)
1720
1721
1722# Setup the metaclass for this class to change the list of the test
1723# methods when a new class is loaded
1724
1725
1726class TestBase(Base, metaclass=LLDBTestCaseFactory):
1727    """
1728    This abstract base class is meant to be subclassed.  It provides default
1729    implementations for setUpClass(), tearDownClass(), setUp(), and tearDown(),
1730    among other things.
1731
1732    Important things for test class writers:
1733
1734        - The setUp method sets up things to facilitate subsequent interactions
1735          with the debugger as part of the test.  These include:
1736              - populate the test method name
1737              - create/get a debugger set with synchronous mode (self.dbg)
1738              - get the command interpreter from with the debugger (self.ci)
1739              - create a result object for use with the command interpreter
1740                (self.res)
1741              - plus other stuffs
1742
1743        - The tearDown method tries to perform some necessary cleanup on behalf
1744          of the test to return the debugger to a good state for the next test.
1745          These include:
1746              - execute any tearDown hooks registered by the test method with
1747                TestBase.addTearDownHook(); examples can be found in
1748                settings/TestSettings.py
1749              - kill the inferior process associated with each target, if any,
1750                and, then delete the target from the debugger's target list
1751              - perform build cleanup before running the next test method in the
1752                same test class; examples of registering for this service can be
1753                found in types/TestIntegerTypes.py with the call:
1754                    - self.setTearDownCleanup(dictionary=d)
1755
1756        - Similarly setUpClass and tearDownClass perform classwise setup and
1757          teardown fixtures.  The tearDownClass method invokes a default build
1758          cleanup for the entire test class;  also, subclasses can implement the
1759          classmethod classCleanup(cls) to perform special class cleanup action.
1760
1761        - The instance methods runCmd and expect are used heavily by existing
1762          test cases to send a command to the command interpreter and to perform
1763          string/pattern matching on the output of such command execution.  The
1764          expect method also provides a mode to peform string/pattern matching
1765          without running a command.
1766
1767        - The build method is used to build the binaries used during a
1768          particular test scenario.  A plugin should be provided for the
1769          sys.platform running the test suite.  The Mac OS X implementation is
1770          located in builders/darwin.py.
1771    """
1772
1773    # Subclasses can set this to true (if they don't depend on debug info) to avoid running the
1774    # test multiple times with various debug info types.
1775    NO_DEBUG_INFO_TESTCASE = False
1776
1777    # Maximum allowed attempts when launching the inferior process.
1778    # Can be overridden by the LLDB_MAX_LAUNCH_COUNT environment variable.
1779    maxLaunchCount = 1
1780
1781    # Time to wait before the next launching attempt in second(s).
1782    # Can be overridden by the LLDB_TIME_WAIT_NEXT_LAUNCH environment variable.
1783    timeWaitNextLaunch = 1.0
1784
1785    def generateSource(self, source):
1786        template = source + ".template"
1787        temp = os.path.join(self.getSourceDir(), template)
1788        with open(temp, "r") as f:
1789            content = f.read()
1790
1791        public_api_dir = os.path.join(os.environ["LLDB_SRC"], "include", "lldb", "API")
1792
1793        # Look under the include/lldb/API directory and add #include statements
1794        # for all the SB API headers.
1795        public_headers = os.listdir(public_api_dir)
1796        # For different platforms, the include statement can vary.
1797        if self.hasDarwinFramework():
1798            include_stmt = "'#include <%s>' % os.path.join('LLDB', header)"
1799        else:
1800            include_stmt = (
1801                "'#include <%s>' % os.path.join(r'" + public_api_dir + "', header)"
1802            )
1803        list = [
1804            eval(include_stmt)
1805            for header in public_headers
1806            if (header.startswith("SB") and header.endswith(".h"))
1807        ]
1808        includes = "\n".join(list)
1809        new_content = content.replace("%include_SB_APIs%", includes)
1810        new_content = new_content.replace("%SOURCE_DIR%", self.getSourceDir())
1811        src = os.path.join(self.getBuildDir(), source)
1812        with open(src, "w") as f:
1813            f.write(new_content)
1814
1815        self.addTearDownHook(lambda: os.remove(src))
1816
1817    def setUp(self):
1818        # Works with the test driver to conditionally skip tests via
1819        # decorators.
1820        Base.setUp(self)
1821
1822        for s in self.setUpCommands():
1823            self.runCmd(s)
1824
1825        if "LLDB_MAX_LAUNCH_COUNT" in os.environ:
1826            self.maxLaunchCount = int(os.environ["LLDB_MAX_LAUNCH_COUNT"])
1827
1828        if "LLDB_TIME_WAIT_NEXT_LAUNCH" in os.environ:
1829            self.timeWaitNextLaunch = float(os.environ["LLDB_TIME_WAIT_NEXT_LAUNCH"])
1830
1831        # We want our debugger to be synchronous.
1832        self.dbg.SetAsync(False)
1833
1834        # Retrieve the associated command interpreter instance.
1835        self.ci = self.dbg.GetCommandInterpreter()
1836        if not self.ci:
1837            raise Exception("Could not get the command interpreter")
1838
1839        # And the result object.
1840        self.res = lldb.SBCommandReturnObject()
1841
1842    def registerSharedLibrariesWithTarget(self, target, shlibs):
1843        """If we are remotely running the test suite, register the shared libraries with the target so they get uploaded, otherwise do nothing
1844
1845        Any modules in the target that have their remote install file specification set will
1846        get uploaded to the remote host. This function registers the local copies of the
1847        shared libraries with the target and sets their remote install locations so they will
1848        be uploaded when the target is run.
1849        """
1850        if not shlibs or not self.platformContext:
1851            return None
1852
1853        shlib_environment_var = self.platformContext.shlib_environment_var
1854        shlib_prefix = self.platformContext.shlib_prefix
1855        shlib_extension = "." + self.platformContext.shlib_extension
1856
1857        dirs = []
1858        # Add any shared libraries to our target if remote so they get
1859        # uploaded into the working directory on the remote side
1860        for name in shlibs:
1861            # The path can be a full path to a shared library, or a make file name like "Foo" for
1862            # "libFoo.dylib" or "libFoo.so", or "Foo.so" for "Foo.so" or "libFoo.so", or just a
1863            # basename like "libFoo.so". So figure out which one it is and resolve the local copy
1864            # of the shared library accordingly
1865            if os.path.isfile(name):
1866                local_shlib_path = (
1867                    name  # name is the full path to the local shared library
1868                )
1869            else:
1870                # Check relative names
1871                local_shlib_path = os.path.join(
1872                    self.getBuildDir(), shlib_prefix + name + shlib_extension
1873                )
1874                if not os.path.exists(local_shlib_path):
1875                    local_shlib_path = os.path.join(
1876                        self.getBuildDir(), name + shlib_extension
1877                    )
1878                    if not os.path.exists(local_shlib_path):
1879                        local_shlib_path = os.path.join(self.getBuildDir(), name)
1880
1881                # Make sure we found the local shared library in the above code
1882                self.assertTrue(os.path.exists(local_shlib_path))
1883
1884            # Add the shared library to our target
1885            shlib_module = target.AddModule(local_shlib_path, None, None, None)
1886            if lldb.remote_platform:
1887                # We must set the remote install location if we want the shared library
1888                # to get uploaded to the remote target
1889                remote_shlib_path = lldbutil.append_to_process_working_directory(
1890                    self, os.path.basename(local_shlib_path)
1891                )
1892                shlib_module.SetRemoteInstallFileSpec(
1893                    lldb.SBFileSpec(remote_shlib_path, False)
1894                )
1895                dir_to_add = self.get_process_working_directory()
1896            else:
1897                dir_to_add = os.path.dirname(local_shlib_path)
1898
1899            if dir_to_add not in dirs:
1900                dirs.append(dir_to_add)
1901
1902        env_value = self.platformContext.shlib_path_separator.join(dirs)
1903        return ["%s=%s" % (shlib_environment_var, env_value)]
1904
1905    def registerSanitizerLibrariesWithTarget(self, target):
1906        runtimes = []
1907        for m in target.module_iter():
1908            libspec = m.GetFileSpec()
1909            if "clang_rt" in libspec.GetFilename():
1910                runtimes.append(
1911                    os.path.join(libspec.GetDirectory(), libspec.GetFilename())
1912                )
1913        return self.registerSharedLibrariesWithTarget(target, runtimes)
1914
1915    # utility methods that tests can use to access the current objects
1916    def target(self):
1917        if not self.dbg:
1918            raise Exception("Invalid debugger instance")
1919        return self.dbg.GetSelectedTarget()
1920
1921    def process(self):
1922        if not self.dbg:
1923            raise Exception("Invalid debugger instance")
1924        return self.dbg.GetSelectedTarget().GetProcess()
1925
1926    def thread(self):
1927        if not self.dbg:
1928            raise Exception("Invalid debugger instance")
1929        return self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread()
1930
1931    def frame(self):
1932        if not self.dbg:
1933            raise Exception("Invalid debugger instance")
1934        return (
1935            self.dbg.GetSelectedTarget()
1936            .GetProcess()
1937            .GetSelectedThread()
1938            .GetSelectedFrame()
1939        )
1940
1941    def get_process_working_directory(self):
1942        """Get the working directory that should be used when launching processes for local or remote processes."""
1943        if lldb.remote_platform:
1944            # Remote tests set the platform working directory up in
1945            # TestBase.setUp()
1946            return lldb.remote_platform.GetWorkingDirectory()
1947        else:
1948            # local tests change directory into each test subdirectory
1949            return self.getBuildDir()
1950
1951    def tearDown(self):
1952        # Ensure all the references to SB objects have gone away so that we can
1953        # be sure that all test-specific resources have been freed before we
1954        # attempt to delete the targets.
1955        gc.collect()
1956
1957        # Delete the target(s) from the debugger as a general cleanup step.
1958        # This includes terminating the process for each target, if any.
1959        # We'd like to reuse the debugger for our next test without incurring
1960        # the initialization overhead.
1961        targets = []
1962        for target in self.dbg:
1963            if target:
1964                targets.append(target)
1965                process = target.GetProcess()
1966                if process:
1967                    rc = self.invoke(process, "Kill")
1968                    assert rc.Success()
1969        for target in targets:
1970            self.dbg.DeleteTarget(target)
1971
1972        # Assert that all targets are deleted.
1973        self.assertEqual(self.dbg.GetNumTargets(), 0)
1974
1975        # Do this last, to make sure it's in reverse order from how we setup.
1976        Base.tearDown(self)
1977
1978    def switch_to_thread_with_stop_reason(self, stop_reason):
1979        """
1980        Run the 'thread list' command, and select the thread with stop reason as
1981        'stop_reason'.  If no such thread exists, no select action is done.
1982        """
1983        from .lldbutil import stop_reason_to_str
1984
1985        self.runCmd("thread list")
1986        output = self.res.GetOutput()
1987        thread_line_pattern = re.compile(
1988            "^[ *] thread #([0-9]+):.*stop reason = %s"
1989            % stop_reason_to_str(stop_reason)
1990        )
1991        for line in output.splitlines():
1992            matched = thread_line_pattern.match(line)
1993            if matched:
1994                self.runCmd("thread select %s" % matched.group(1))
1995
1996    def runCmd(self, cmd, msg=None, check=True, trace=False, inHistory=False):
1997        """
1998        Ask the command interpreter to handle the command and then check its
1999        return status.
2000        """
2001        # Fail fast if 'cmd' is not meaningful.
2002        if cmd is None:
2003            raise Exception("Bad 'cmd' parameter encountered")
2004
2005        trace = True if traceAlways else trace
2006
2007        if cmd.startswith("target create "):
2008            cmd = cmd.replace("target create ", "file ")
2009
2010        running = cmd.startswith("run") or cmd.startswith("process launch")
2011
2012        for i in range(self.maxLaunchCount if running else 1):
2013            with recording(self, trace) as sbuf:
2014                print("runCmd:", cmd, file=sbuf)
2015                if not check:
2016                    print("check of return status not required", file=sbuf)
2017
2018            self.ci.HandleCommand(cmd, self.res, inHistory)
2019
2020            with recording(self, trace) as sbuf:
2021                if self.res.Succeeded():
2022                    print("output:", self.res.GetOutput(), file=sbuf)
2023                else:
2024                    print("runCmd failed!", file=sbuf)
2025                    print(self.res.GetError(), file=sbuf)
2026
2027            if self.res.Succeeded():
2028                break
2029            elif running:
2030                # For process launch, wait some time before possible next try.
2031                time.sleep(self.timeWaitNextLaunch)
2032                with recording(self, trace) as sbuf:
2033                    print("Command '" + cmd + "' failed!", file=sbuf)
2034
2035        if check:
2036            output = ""
2037            if self.res.GetOutput():
2038                output += "\nCommand output:\n" + self.res.GetOutput()
2039            if self.res.GetError():
2040                output += "\nError output:\n" + self.res.GetError()
2041            if msg:
2042                msg += output
2043            if cmd:
2044                cmd += output
2045            self.assertTrue(self.res.Succeeded(), msg if (msg) else CMD_MSG(cmd))
2046
2047    def match(
2048        self, str, patterns, msg=None, trace=False, error=False, matching=True, exe=True
2049    ):
2050        """run command in str, and match the result against regexp in patterns returning the match object for the first matching pattern
2051
2052        Otherwise, all the arguments have the same meanings as for the expect function
2053        """
2054
2055        trace = True if traceAlways else trace
2056
2057        if exe:
2058            # First run the command.  If we are expecting error, set check=False.
2059            # Pass the assert message along since it provides more semantic
2060            # info.
2061            self.runCmd(str, msg=msg, trace=(True if trace else False), check=not error)
2062
2063            # Then compare the output against expected strings.
2064            output = self.res.GetError() if error else self.res.GetOutput()
2065
2066            # If error is True, the API client expects the command to fail!
2067            if error:
2068                self.assertFalse(
2069                    self.res.Succeeded(), "Command '" + str + "' is expected to fail!"
2070                )
2071        else:
2072            # No execution required, just compare str against the golden input.
2073            output = str
2074            with recording(self, trace) as sbuf:
2075                print("looking at:", output, file=sbuf)
2076
2077        # The heading says either "Expecting" or "Not expecting".
2078        heading = "Expecting" if matching else "Not expecting"
2079
2080        for pattern in patterns:
2081            # Match Objects always have a boolean value of True.
2082            match_object = re.search(pattern, output)
2083            matched = bool(match_object)
2084            with recording(self, trace) as sbuf:
2085                print("%s pattern: %s" % (heading, pattern), file=sbuf)
2086                print("Matched" if matched else "Not matched", file=sbuf)
2087            if matched:
2088                break
2089
2090        self.assertTrue(
2091            matched if matching else not matched,
2092            msg if msg else EXP_MSG(str, output, exe),
2093        )
2094
2095        return match_object
2096
2097    def check_completion_with_desc(
2098        self, str_input, match_desc_pairs, enforce_order=False
2099    ):
2100        """
2101        Checks that when the given input is completed at the given list of
2102        completions and descriptions is returned.
2103        :param str_input: The input that should be completed. The completion happens at the end of the string.
2104        :param match_desc_pairs: A list of pairs that indicate what completions have to be in the list of
2105                                 completions returned by LLDB. The first element of the pair is the completion
2106                                 string that LLDB should generate and the second element the description.
2107        :param enforce_order: True iff the order in which the completions are returned by LLDB
2108                              should match the order of the match_desc_pairs pairs.
2109        """
2110        interp = self.dbg.GetCommandInterpreter()
2111        match_strings = lldb.SBStringList()
2112        description_strings = lldb.SBStringList()
2113        num_matches = interp.HandleCompletionWithDescriptions(
2114            str_input, len(str_input), 0, -1, match_strings, description_strings
2115        )
2116        self.assertEqual(len(description_strings), len(match_strings))
2117
2118        # The index of the last matched description in description_strings or
2119        # -1 if no description has been matched yet.
2120        last_found_index = -1
2121        out_of_order_errors = ""
2122        missing_pairs = []
2123        for pair in match_desc_pairs:
2124            found_pair = False
2125            for i in range(num_matches + 1):
2126                match_candidate = match_strings.GetStringAtIndex(i)
2127                description_candidate = description_strings.GetStringAtIndex(i)
2128                if match_candidate == pair[0] and description_candidate == pair[1]:
2129                    found_pair = True
2130                    if enforce_order and last_found_index > i:
2131                        new_err = (
2132                            "Found completion "
2133                            + pair[0]
2134                            + " at index "
2135                            + str(i)
2136                            + " in returned completion list but "
2137                            + "should have been after completion "
2138                            + match_strings.GetStringAtIndex(last_found_index)
2139                            + " (index:"
2140                            + str(last_found_index)
2141                            + ")\n"
2142                        )
2143                        out_of_order_errors += new_err
2144                    last_found_index = i
2145                    break
2146            if not found_pair:
2147                missing_pairs.append(pair)
2148
2149        error_msg = ""
2150        got_failure = False
2151        if len(missing_pairs):
2152            got_failure = True
2153            error_msg += "Missing pairs:\n"
2154            for pair in missing_pairs:
2155                error_msg += " [" + pair[0] + ":" + pair[1] + "]\n"
2156        if len(out_of_order_errors):
2157            got_failure = True
2158            error_msg += out_of_order_errors
2159        if got_failure:
2160            error_msg += (
2161                "Got the following " + str(num_matches) + " completions back:\n"
2162            )
2163            for i in range(num_matches + 1):
2164                match_candidate = match_strings.GetStringAtIndex(i)
2165                description_candidate = description_strings.GetStringAtIndex(i)
2166                error_msg += (
2167                    "["
2168                    + match_candidate
2169                    + ":"
2170                    + description_candidate
2171                    + "] index "
2172                    + str(i)
2173                    + "\n"
2174                )
2175            self.assertFalse(got_failure, error_msg)
2176
2177    def complete_from_to(self, str_input, patterns):
2178        """Test that the completion mechanism completes str_input to patterns,
2179        where patterns could be a single pattern-string or a list of
2180        pattern-strings.
2181
2182        If there is only one pattern and it is exactly equal to str_input, this
2183        assumes that there should be no completions provided and that the result
2184        should be the same as the input."""
2185
2186        # Patterns should not be None in order to proceed.
2187        self.assertFalse(patterns is None)
2188        # And should be either a string or list of strings.  Check for list type
2189        # below, if not, make a list out of the singleton string.  If patterns
2190        # is not a string or not a list of strings, there'll be runtime errors
2191        # later on.
2192        if not isinstance(patterns, list):
2193            patterns = [patterns]
2194
2195        interp = self.dbg.GetCommandInterpreter()
2196        match_strings = lldb.SBStringList()
2197        num_matches = interp.HandleCompletion(
2198            str_input, len(str_input), 0, -1, match_strings
2199        )
2200        common_match = match_strings.GetStringAtIndex(0)
2201        if num_matches == 0:
2202            compare_string = str_input
2203        else:
2204            if common_match != None and len(common_match) > 0:
2205                compare_string = str_input + common_match
2206            else:
2207                compare_string = ""
2208                for idx in range(1, num_matches + 1):
2209                    compare_string += match_strings.GetStringAtIndex(idx) + "\n"
2210
2211        if len(patterns) == 1 and str_input == patterns[0] and num_matches:
2212            self.fail("Expected no completions but got:\n" + compare_string)
2213
2214        for p in patterns:
2215            self.expect(
2216                compare_string,
2217                msg=COMPLETION_MSG(str_input, p, match_strings),
2218                exe=False,
2219                substrs=[p],
2220            )
2221
2222    def completions_match(self, command, completions):
2223        """Checks that the completions for the given command are equal to the
2224        given list of completions"""
2225        interp = self.dbg.GetCommandInterpreter()
2226        match_strings = lldb.SBStringList()
2227        interp.HandleCompletion(command, len(command), 0, -1, match_strings)
2228        # match_strings is a 1-indexed list, so we have to slice...
2229        self.assertItemsEqual(
2230            completions, list(match_strings)[1:], "List of returned completion is wrong"
2231        )
2232
2233    def completions_contain(self, command, completions):
2234        """Checks that the completions for the given command contain the given
2235        list of completions."""
2236        interp = self.dbg.GetCommandInterpreter()
2237        match_strings = lldb.SBStringList()
2238        interp.HandleCompletion(command, len(command), 0, -1, match_strings)
2239        for completion in completions:
2240            # match_strings is a 1-indexed list, so we have to slice...
2241            self.assertIn(
2242                completion, list(match_strings)[1:], "Couldn't find expected completion"
2243            )
2244
2245    def filecheck(
2246        self, command, check_file, filecheck_options="", expect_cmd_failure=False
2247    ):
2248        # Run the command.
2249        self.runCmd(
2250            command,
2251            check=(not expect_cmd_failure),
2252            msg="FileCheck'ing result of `{0}`".format(command),
2253        )
2254
2255        self.assertTrue((not expect_cmd_failure) == self.res.Succeeded())
2256
2257        # Get the error text if there was an error, and the regular text if not.
2258        output = self.res.GetOutput() if self.res.Succeeded() else self.res.GetError()
2259
2260        # Assemble the absolute path to the check file. As a convenience for
2261        # LLDB inline tests, assume that the check file is a relative path to
2262        # a file within the inline test directory.
2263        if check_file.endswith(".pyc"):
2264            check_file = check_file[:-1]
2265        check_file_abs = os.path.abspath(check_file)
2266
2267        # Run FileCheck.
2268        filecheck_bin = configuration.get_filecheck_path()
2269        if not filecheck_bin:
2270            self.assertTrue(False, "No valid FileCheck executable specified")
2271        filecheck_args = [filecheck_bin, check_file_abs]
2272        if filecheck_options:
2273            filecheck_args.append(filecheck_options)
2274        subproc = Popen(
2275            filecheck_args,
2276            stdin=PIPE,
2277            stdout=PIPE,
2278            stderr=PIPE,
2279            universal_newlines=True,
2280        )
2281        cmd_stdout, cmd_stderr = subproc.communicate(input=output)
2282        cmd_status = subproc.returncode
2283
2284        filecheck_cmd = " ".join(filecheck_args)
2285        filecheck_trace = """
2286--- FileCheck trace (code={0}) ---
2287{1}
2288
2289FileCheck input:
2290{2}
2291
2292FileCheck output:
2293{3}
2294{4}
2295""".format(
2296            cmd_status, filecheck_cmd, output, cmd_stdout, cmd_stderr
2297        )
2298
2299        trace = cmd_status != 0 or traceAlways
2300        with recording(self, trace) as sbuf:
2301            print(filecheck_trace, file=sbuf)
2302
2303        self.assertTrue(cmd_status == 0)
2304
2305    def expect(
2306        self,
2307        string,
2308        msg=None,
2309        patterns=None,
2310        startstr=None,
2311        endstr=None,
2312        substrs=None,
2313        trace=False,
2314        error=False,
2315        ordered=True,
2316        matching=True,
2317        exe=True,
2318        inHistory=False,
2319    ):
2320        """
2321        Similar to runCmd; with additional expect style output matching ability.
2322
2323        Ask the command interpreter to handle the command and then check its
2324        return status.  The 'msg' parameter specifies an informational assert
2325        message.  We expect the output from running the command to start with
2326        'startstr', matches the substrings contained in 'substrs', and regexp
2327        matches the patterns contained in 'patterns'.
2328
2329        When matching is true and ordered is true, which are both the default,
2330        the strings in the substrs array have to appear in the command output
2331        in the order in which they appear in the array.
2332
2333        If the keyword argument error is set to True, it signifies that the API
2334        client is expecting the command to fail.  In this case, the error stream
2335        from running the command is retrieved and compared against the golden
2336        input, instead.
2337
2338        If the keyword argument matching is set to False, it signifies that the API
2339        client is expecting the output of the command not to match the golden
2340        input.
2341
2342        Finally, the required argument 'string' represents the lldb command to be
2343        sent to the command interpreter.  In case the keyword argument 'exe' is
2344        set to False, the 'string' is treated as a string to be matched/not-matched
2345        against the golden input.
2346        """
2347        # Catch cases where `expect` has been miscalled. Specifically, prevent
2348        # this easy to make mistake:
2349        #     self.expect("lldb command", "some substr")
2350        # The `msg` parameter is used only when a failed match occurs. A failed
2351        # match can only occur when one of `patterns`, `startstr`, `endstr`, or
2352        # `substrs` has been given. Thus, if a `msg` is given, it's an error to
2353        # not also provide one of the matcher parameters.
2354        if msg and not (patterns or startstr or endstr or substrs or error):
2355            assert False, "expect() missing a matcher argument"
2356
2357        # Check `patterns` and `substrs` are not accidentally given as strings.
2358        assert not isinstance(patterns, str), "patterns must be a collection of strings"
2359        assert not isinstance(substrs, str), "substrs must be a collection of strings"
2360
2361        trace = True if traceAlways else trace
2362
2363        if exe:
2364            # First run the command.  If we are expecting error, set check=False.
2365            # Pass the assert message along since it provides more semantic
2366            # info.
2367            self.runCmd(
2368                string,
2369                msg=msg,
2370                trace=(True if trace else False),
2371                check=not error,
2372                inHistory=inHistory,
2373            )
2374
2375            # Then compare the output against expected strings.
2376            output = self.res.GetError() if error else self.res.GetOutput()
2377
2378            # If error is True, the API client expects the command to fail!
2379            if error:
2380                self.assertFalse(
2381                    self.res.Succeeded(),
2382                    "Command '" + string + "' is expected to fail!",
2383                )
2384        else:
2385            # No execution required, just compare string against the golden input.
2386            if isinstance(string, lldb.SBCommandReturnObject):
2387                output = string.GetOutput()
2388            else:
2389                output = string
2390            with recording(self, trace) as sbuf:
2391                print("looking at:", output, file=sbuf)
2392
2393        expecting_str = "Expecting" if matching else "Not expecting"
2394
2395        def found_str(matched):
2396            return "was found" if matched else "was not found"
2397
2398        # To be used as assert fail message and/or trace content
2399        log_lines = [
2400            "{}:".format("Ran command" if exe else "Checking string"),
2401            '"{}"'.format(string),
2402            # Space out command and output
2403            "",
2404        ]
2405        if exe:
2406            # Newline before output to make large strings more readable
2407            log_lines.append("Got output:\n{}".format(output))
2408
2409        # Assume that we start matched if we want a match
2410        # Meaning if you have no conditions, matching or
2411        # not matching will always pass
2412        matched = matching
2413
2414        # We will stop checking on first failure
2415        if startstr:
2416            matched = output.startswith(startstr)
2417            log_lines.append(
2418                '{} start string: "{}" ({})'.format(
2419                    expecting_str, startstr, found_str(matched)
2420                )
2421            )
2422
2423        if endstr and matched == matching:
2424            matched = output.endswith(endstr)
2425            log_lines.append(
2426                '{} end string: "{}" ({})'.format(
2427                    expecting_str, endstr, found_str(matched)
2428                )
2429            )
2430
2431        if substrs and matched == matching:
2432            start = 0
2433            for substr in substrs:
2434                index = output[start:].find(substr)
2435                start = start + index + len(substr) if ordered and matching else 0
2436                matched = index != -1
2437                log_lines.append(
2438                    '{} sub string: "{}" ({})'.format(
2439                        expecting_str, substr, found_str(matched)
2440                    )
2441                )
2442
2443                if matched != matching:
2444                    break
2445
2446        if patterns and matched == matching:
2447            for pattern in patterns:
2448                matched = re.search(pattern, output)
2449
2450                pattern_line = '{} regex pattern: "{}" ({}'.format(
2451                    expecting_str, pattern, found_str(matched)
2452                )
2453                if matched:
2454                    pattern_line += ', matched "{}"'.format(matched.group(0))
2455                pattern_line += ")"
2456                log_lines.append(pattern_line)
2457
2458                # Convert to bool because match objects
2459                # are True-ish but != True itself
2460                matched = bool(matched)
2461                if matched != matching:
2462                    break
2463
2464        # If a check failed, add any extra assert message
2465        if msg is not None and matched != matching:
2466            log_lines.append(msg)
2467
2468        log_msg = "\n".join(log_lines)
2469        with recording(self, trace) as sbuf:
2470            print(log_msg, file=sbuf)
2471        if matched != matching:
2472            self.fail(log_msg)
2473
2474    def expect_expr(
2475        self,
2476        expr,
2477        result_summary=None,
2478        result_value=None,
2479        result_type=None,
2480        result_children=None,
2481    ):
2482        """
2483        Evaluates the given expression and verifies the result.
2484        :param expr: The expression as a string.
2485        :param result_summary: The summary that the expression should have. None if the summary should not be checked.
2486        :param result_value: The value that the expression should have. None if the value should not be checked.
2487        :param result_type: The type that the expression result should have. None if the type should not be checked.
2488        :param result_children: The expected children of the expression result
2489                                as a list of ValueChecks. None if the children shouldn't be checked.
2490        """
2491        self.assertTrue(
2492            expr.strip() == expr,
2493            "Expression contains trailing/leading whitespace: '" + expr + "'",
2494        )
2495
2496        frame = self.frame()
2497        options = lldb.SBExpressionOptions()
2498
2499        # Disable fix-its that tests don't pass by accident.
2500        options.SetAutoApplyFixIts(False)
2501
2502        # Set the usual default options for normal expressions.
2503        options.SetIgnoreBreakpoints(True)
2504
2505        if self.frame().IsValid():
2506            options.SetLanguage(frame.GuessLanguage())
2507            eval_result = self.frame().EvaluateExpression(expr, options)
2508        else:
2509            target = self.target()
2510            # If there is no selected target, run the expression in the dummy
2511            # target.
2512            if not target.IsValid():
2513                target = self.dbg.GetDummyTarget()
2514            eval_result = target.EvaluateExpression(expr, options)
2515
2516        value_check = ValueCheck(
2517            type=result_type,
2518            value=result_value,
2519            summary=result_summary,
2520            children=result_children,
2521        )
2522        value_check.check_value(self, eval_result, str(eval_result))
2523        return eval_result
2524
2525    def expect_var_path(
2526        self, var_path, summary=None, value=None, type=None, children=None
2527    ):
2528        """
2529        Evaluates the given variable path and verifies the result.
2530        See also 'frame variable' and SBFrame.GetValueForVariablePath.
2531        :param var_path: The variable path as a string.
2532        :param summary: The summary that the variable should have. None if the summary should not be checked.
2533        :param value: The value that the variable should have. None if the value should not be checked.
2534        :param type: The type that the variable result should have. None if the type should not be checked.
2535        :param children: The expected children of the variable  as a list of ValueChecks.
2536                         None if the children shouldn't be checked.
2537        """
2538        self.assertTrue(
2539            var_path.strip() == var_path,
2540            "Expression contains trailing/leading whitespace: '" + var_path + "'",
2541        )
2542
2543        frame = self.frame()
2544        eval_result = frame.GetValueForVariablePath(var_path)
2545
2546        value_check = ValueCheck(
2547            type=type, value=value, summary=summary, children=children
2548        )
2549        value_check.check_value(self, eval_result, str(eval_result))
2550        return eval_result
2551
2552    """Assert that an lldb.SBError is in the "success" state."""
2553
2554    def assertSuccess(self, obj, msg=None):
2555        if not obj.Success():
2556            error = obj.GetCString()
2557            self.fail(self._formatMessage(msg, "'{}' is not success".format(error)))
2558
2559    """Assert that an lldb.SBError is in the "failure" state."""
2560
2561    def assertFailure(self, obj, error_str=None, msg=None):
2562        if obj.Success():
2563            self.fail(self._formatMessage(msg, "Error not in a fail state"))
2564
2565        if error_str == None:
2566            return
2567
2568        error = obj.GetCString()
2569        self.assertEqual(error, error_str, msg)
2570
2571    """Assert that a command return object is successful"""
2572
2573    def assertCommandReturn(self, obj, msg=None):
2574        if not obj.Succeeded():
2575            error = obj.GetError()
2576            self.fail(self._formatMessage(msg, "'{}' is not success".format(error)))
2577
2578    """Assert two states are equal"""
2579
2580    def assertState(self, first, second, msg=None):
2581        if first != second:
2582            error = "{} ({}) != {} ({})".format(
2583                lldbutil.state_type_to_str(first),
2584                first,
2585                lldbutil.state_type_to_str(second),
2586                second,
2587            )
2588            self.fail(self._formatMessage(msg, error))
2589
2590    """Assert two stop reasons are equal"""
2591
2592    def assertStopReason(self, first, second, msg=None):
2593        if first != second:
2594            error = "{} ({}) != {} ({})".format(
2595                lldbutil.stop_reason_to_str(first),
2596                first,
2597                lldbutil.stop_reason_to_str(second),
2598                second,
2599            )
2600            self.fail(self._formatMessage(msg, error))
2601
2602    def createTestTarget(self, file_path=None, msg=None, load_dependent_modules=True):
2603        """
2604        Creates a target from the file found at the given file path.
2605        Asserts that the resulting target is valid.
2606        :param file_path: The file path that should be used to create the target.
2607                          The default argument opens the current default test
2608                          executable in the current test directory.
2609        :param msg: A custom error message.
2610        """
2611        if file_path is None:
2612            file_path = self.getBuildArtifact("a.out")
2613        error = lldb.SBError()
2614        triple = ""
2615        platform = ""
2616        target = self.dbg.CreateTarget(
2617            file_path, triple, platform, load_dependent_modules, error
2618        )
2619        if error.Fail():
2620            err = "Couldn't create target for path '{}': {}".format(
2621                file_path, str(error)
2622            )
2623            self.fail(self._formatMessage(msg, err))
2624
2625        self.assertTrue(target.IsValid(), "Got invalid target without error")
2626        return target
2627
2628    # =================================================
2629    # Misc. helper methods for debugging test execution
2630    # =================================================
2631
2632    def DebugSBValue(self, val):
2633        """Debug print a SBValue object, if traceAlways is True."""
2634        from .lldbutil import value_type_to_str
2635
2636        if not traceAlways:
2637            return
2638
2639        err = sys.stderr
2640        err.write(val.GetName() + ":\n")
2641        err.write("\t" + "TypeName         -> " + val.GetTypeName() + "\n")
2642        err.write("\t" + "ByteSize         -> " + str(val.GetByteSize()) + "\n")
2643        err.write("\t" + "NumChildren      -> " + str(val.GetNumChildren()) + "\n")
2644        err.write("\t" + "Value            -> " + str(val.GetValue()) + "\n")
2645        err.write("\t" + "ValueAsUnsigned  -> " + str(val.GetValueAsUnsigned()) + "\n")
2646        err.write(
2647            "\t" + "ValueType        -> " + value_type_to_str(val.GetValueType()) + "\n"
2648        )
2649        err.write("\t" + "Summary          -> " + str(val.GetSummary()) + "\n")
2650        err.write("\t" + "IsPointerType    -> " + str(val.TypeIsPointerType()) + "\n")
2651        err.write("\t" + "Location         -> " + val.GetLocation() + "\n")
2652
2653    def DebugSBType(self, type):
2654        """Debug print a SBType object, if traceAlways is True."""
2655        if not traceAlways:
2656            return
2657
2658        err = sys.stderr
2659        err.write(type.GetName() + ":\n")
2660        err.write("\t" + "ByteSize        -> " + str(type.GetByteSize()) + "\n")
2661        err.write("\t" + "IsAggregateType   -> " + str(type.IsAggregateType()) + "\n")
2662        err.write("\t" + "IsPointerType   -> " + str(type.IsPointerType()) + "\n")
2663        err.write("\t" + "IsReferenceType -> " + str(type.IsReferenceType()) + "\n")
2664
2665    def DebugPExpect(self, child):
2666        """Debug the spwaned pexpect object."""
2667        if not traceAlways:
2668            return
2669
2670        print(child)
2671
2672    @classmethod
2673    def RemoveTempFile(cls, file):
2674        if os.path.exists(file):
2675            remove_file(file)
2676
2677
2678# On Windows, the first attempt to delete a recently-touched file can fail
2679# because of a race with antimalware scanners.  This function will detect a
2680# failure and retry.
2681
2682
2683def remove_file(file, num_retries=1, sleep_duration=0.5):
2684    for i in range(num_retries + 1):
2685        try:
2686            os.remove(file)
2687            return True
2688        except:
2689            time.sleep(sleep_duration)
2690            continue
2691    return False
2692