xref: /llvm-project/lldb/packages/Python/lldbsuite/test/lldbtest.py (revision b4776b8d8ea742a46039002fac4c280e619ac48d)
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 unittest
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(unittest.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            # Based on https://discourse.llvm.org/t/running-lldb-in-a-container/76801/4
755            "settings set target.disable-aslr false",
756            # Kill rather than detach from the inferior if something goes wrong.
757            "settings set target.detach-on-error false",
758            # Disable fix-its by default so that incorrect expressions in tests don't
759            # pass just because Clang thinks it has a fix-it.
760            "settings set target.auto-apply-fixits false",
761            # Testsuite runs in parallel and the host can have also other load.
762            "settings set plugin.process.gdb-remote.packet-timeout 60",
763            'settings set symbols.clang-modules-cache-path "{}"'.format(
764                configuration.lldb_module_cache_dir
765            ),
766            "settings set use-color false",
767        ]
768
769        # Set any user-overridden settings.
770        for setting, value in configuration.settings:
771            commands.append("setting set %s %s" % (setting, value))
772
773        # Make sure that a sanitizer LLDB's environment doesn't get passed on.
774        if (
775            cls.platformContext
776            and cls.platformContext.shlib_environment_var in os.environ
777        ):
778            commands.append(
779                "settings set target.env-vars {}=".format(
780                    cls.platformContext.shlib_environment_var
781                )
782            )
783
784        # Set environment variables for the inferior.
785        if lldbtest_config.inferior_env:
786            commands.append(
787                "settings set target.env-vars {}".format(lldbtest_config.inferior_env)
788            )
789        return commands
790
791    def setUp(self):
792        """Fixture for unittest test case setup.
793
794        It works with the test driver to conditionally skip tests and does other
795        initializations."""
796        # import traceback
797        # traceback.print_stack()
798
799        if "LIBCXX_PATH" in os.environ:
800            self.libcxxPath = os.environ["LIBCXX_PATH"]
801        else:
802            self.libcxxPath = None
803
804        if "LLDBDAP_EXEC" in os.environ:
805            self.lldbDAPExec = os.environ["LLDBDAP_EXEC"]
806        else:
807            self.lldbDAPExec = None
808
809        self.lldbOption = " ".join("-o '" + s + "'" for s in self.setUpCommands())
810
811        # If we spawn an lldb process for test (via pexpect), do not load the
812        # init file unless told otherwise.
813        if os.environ.get("NO_LLDBINIT") != "NO":
814            self.lldbOption += " --no-lldbinit"
815
816        # Assign the test method name to self.testMethodName.
817        #
818        # For an example of the use of this attribute, look at test/types dir.
819        # There are a bunch of test cases under test/types and we don't want the
820        # module cacheing subsystem to be confused with executable name "a.out"
821        # used for all the test cases.
822        self.testMethodName = self._testMethodName
823
824        # This is for the case of directly spawning 'lldb'/'gdb' and interacting
825        # with it using pexpect.
826        self.child = None
827        self.child_prompt = "(lldb) "
828        # If the child is interacting with the embedded script interpreter,
829        # there are two exits required during tear down, first to quit the
830        # embedded script interpreter and second to quit the lldb command
831        # interpreter.
832        self.child_in_script_interpreter = False
833
834        # These are for customized teardown cleanup.
835        self.dict = None
836        self.doTearDownCleanup = False
837        # And in rare cases where there are multiple teardown cleanups.
838        self.dicts = []
839        self.doTearDownCleanups = False
840
841        # List of spawned subproces.Popen objects
842        self.subprocesses = []
843
844        # List of log files produced by the current test.
845        self.log_files = []
846
847        # Create the build directory.
848        # The logs are stored in the build directory, so we have to create it
849        # before creating the first log file.
850        self.makeBuildDir()
851
852        session_file = self.getLogBasenameForCurrentTest() + ".log"
853        self.log_files.append(session_file)
854
855        # Python 3 doesn't support unbuffered I/O in text mode.  Open buffered.
856        self.session = encoded_file.open(session_file, "utf-8", mode="w")
857
858        # Optimistically set __errored__, __failed__, __expected__ to False
859        # initially.  If the test errored/failed, the session info
860        # (self.session) is then dumped into a session specific file for
861        # diagnosis.
862        self.__cleanup_errored__ = False
863        self.__errored__ = False
864        self.__failed__ = False
865        self.__expected__ = False
866        # We are also interested in unexpected success.
867        self.__unexpected__ = False
868        # And skipped tests.
869        self.__skipped__ = False
870
871        # See addTearDownHook(self, hook) which allows the client to add a hook
872        # function to be run during tearDown() time.
873        self.hooks = []
874
875        # See HideStdout(self).
876        self.sys_stdout_hidden = False
877
878        if self.platformContext:
879            # set environment variable names for finding shared libraries
880            self.dylibPath = self.platformContext.shlib_environment_var
881
882        # Create the debugger instance.
883        self.dbg = lldb.SBDebugger.Create()
884        # Copy selected platform from a global instance if it exists.
885        if lldb.selected_platform is not None:
886            self.dbg.SetSelectedPlatform(lldb.selected_platform)
887
888        if not self.dbg:
889            raise Exception("Invalid debugger instance")
890
891        # Retrieve the associated command interpreter instance.
892        self.ci = self.dbg.GetCommandInterpreter()
893        if not self.ci:
894            raise Exception("Could not get the command interpreter")
895
896        # And the result object.
897        self.res = lldb.SBCommandReturnObject()
898
899        self.setPlatformWorkingDir()
900        self.enableLogChannelsForCurrentTest()
901
902        self.lib_lldb = None
903        self.framework_dir = None
904        self.darwinWithFramework = False
905
906        if sys.platform.startswith("darwin") and configuration.lldb_framework_path:
907            framework = configuration.lldb_framework_path
908            lib = os.path.join(framework, "LLDB")
909            if os.path.exists(lib):
910                self.framework_dir = os.path.dirname(framework)
911                self.lib_lldb = lib
912                self.darwinWithFramework = self.platformIsDarwin()
913
914    def setAsync(self, value):
915        """Sets async mode to True/False and ensures it is reset after the testcase completes."""
916        old_async = self.dbg.GetAsync()
917        self.dbg.SetAsync(value)
918        self.addTearDownHook(lambda: self.dbg.SetAsync(old_async))
919
920    def cleanupSubprocesses(self):
921        # Terminate subprocesses in reverse order from how they were created.
922        for p in reversed(self.subprocesses):
923            p.terminate()
924            del p
925        del self.subprocesses[:]
926
927    def spawnSubprocess(self, executable, args=[], extra_env=None, install_remote=True):
928        """Creates a subprocess.Popen object with the specified executable and arguments,
929        saves it in self.subprocesses, and returns the object.
930        """
931        proc = (
932            _RemoteProcess(install_remote)
933            if lldb.remote_platform
934            else _LocalProcess(self.TraceOn())
935        )
936        proc.launch(executable, args, extra_env=extra_env)
937        self.subprocesses.append(proc)
938        return proc
939
940    def HideStdout(self):
941        """Hide output to stdout from the user.
942
943        During test execution, there might be cases where we don't want to show the
944        standard output to the user.  For example,
945
946            self.runCmd(r'''sc print("\n\n\tHello!\n")''')
947
948        tests whether command abbreviation for 'script' works or not.  There is no
949        need to show the 'Hello' output to the user as long as the 'script' command
950        succeeds and we are not in TraceOn() mode (see the '-t' option).
951
952        In this case, the test method calls self.HideStdout(self) to redirect the
953        sys.stdout to a null device, and restores the sys.stdout upon teardown.
954
955        Note that you should only call this method at most once during a test case
956        execution.  Any subsequent call has no effect at all."""
957        if self.sys_stdout_hidden:
958            return
959
960        self.sys_stdout_hidden = True
961        old_stdout = sys.stdout
962        sys.stdout = open(os.devnull, "w")
963
964        def restore_stdout():
965            sys.stdout = old_stdout
966
967        self.addTearDownHook(restore_stdout)
968
969    # =======================================================================
970    # Methods for customized teardown cleanups as well as execution of hooks.
971    # =======================================================================
972
973    def setTearDownCleanup(self, dictionary=None):
974        """Register a cleanup action at tearDown() time with a dictionary"""
975        self.dict = dictionary
976        self.doTearDownCleanup = True
977
978    def addTearDownCleanup(self, dictionary):
979        """Add a cleanup action at tearDown() time with a dictionary"""
980        self.dicts.append(dictionary)
981        self.doTearDownCleanups = True
982
983    def addTearDownHook(self, hook):
984        """
985        Add a function to be run during tearDown() time.
986
987        Hooks are executed in a first come first serve manner.
988        """
989        if callable(hook):
990            with recording(self, traceAlways) as sbuf:
991                print("Adding tearDown hook:", getsource_if_available(hook), file=sbuf)
992            self.hooks.append(hook)
993
994        return self
995
996    def deletePexpectChild(self):
997        # This is for the case of directly spawning 'lldb' and interacting with it
998        # using pexpect.
999        if self.child and self.child.isalive():
1000            import pexpect
1001
1002            with recording(self, traceAlways) as sbuf:
1003                print("tearing down the child process....", file=sbuf)
1004            try:
1005                if self.child_in_script_interpreter:
1006                    self.child.sendline("quit()")
1007                    self.child.expect_exact(self.child_prompt)
1008                self.child.sendline("settings set interpreter.prompt-on-quit false")
1009                self.child.sendline("quit")
1010                self.child.expect(pexpect.EOF)
1011            except (ValueError, pexpect.ExceptionPexpect):
1012                # child is already terminated
1013                pass
1014            except OSError as exception:
1015                import errno
1016
1017                if exception.errno != errno.EIO:
1018                    # unexpected error
1019                    raise
1020                # child is already terminated
1021            finally:
1022                # Give it one final blow to make sure the child is terminated.
1023                self.child.close()
1024
1025    def tearDown(self):
1026        """Fixture for unittest test case teardown."""
1027        self.deletePexpectChild()
1028
1029        # Check and run any hook functions.
1030        for hook in reversed(self.hooks):
1031            with recording(self, traceAlways) as sbuf:
1032                print(
1033                    "Executing tearDown hook:", getsource_if_available(hook), file=sbuf
1034                )
1035            if funcutils.requires_self(hook):
1036                hook(self)
1037            else:
1038                hook()  # try the plain call and hope it works
1039
1040        del self.hooks
1041
1042        # Perform registered teardown cleanup.
1043        if doCleanup and self.doTearDownCleanup:
1044            self.cleanup(dictionary=self.dict)
1045
1046        # In rare cases where there are multiple teardown cleanups added.
1047        if doCleanup and self.doTearDownCleanups:
1048            if self.dicts:
1049                for dict in reversed(self.dicts):
1050                    self.cleanup(dictionary=dict)
1051
1052        # Remove subprocesses created by the test.
1053        self.cleanupSubprocesses()
1054
1055        # This must be the last statement, otherwise teardown hooks or other
1056        # lines might depend on this still being active.
1057        lldb.SBDebugger.Destroy(self.dbg)
1058        del self.dbg
1059
1060        # All modules should be orphaned now so that they can be cleared from
1061        # the shared module cache.
1062        lldb.SBModule.GarbageCollectAllocatedModules()
1063
1064        # Assert that the global module cache is empty.
1065        # FIXME: This assert fails on Windows.
1066        if self.getPlatform() != "windows":
1067            self.assertEqual(lldb.SBModule.GetNumberAllocatedModules(), 0)
1068
1069    # =========================================================
1070    # Various callbacks to allow introspection of test progress
1071    # =========================================================
1072
1073    def markError(self):
1074        """Callback invoked when an error (unexpected exception) errored."""
1075        self.__errored__ = True
1076        with recording(self, False) as sbuf:
1077            # False because there's no need to write "ERROR" to the stderr twice.
1078            # Once by the Python unittest framework, and a second time by us.
1079            print("ERROR", file=sbuf)
1080
1081    def markCleanupError(self):
1082        """Callback invoked when an error occurs while a test is cleaning up."""
1083        self.__cleanup_errored__ = True
1084        with recording(self, False) as sbuf:
1085            # False because there's no need to write "CLEANUP_ERROR" to the stderr twice.
1086            # Once by the Python unittest framework, and a second time by us.
1087            print("CLEANUP_ERROR", file=sbuf)
1088
1089    def markFailure(self):
1090        """Callback invoked when a failure (test assertion failure) occurred."""
1091        self.__failed__ = True
1092        with recording(self, False) as sbuf:
1093            # False because there's no need to write "FAIL" to the stderr twice.
1094            # Once by the Python unittest framework, and a second time by us.
1095            print("FAIL", file=sbuf)
1096
1097    def markExpectedFailure(self, err):
1098        """Callback invoked when an expected failure/error occurred."""
1099        self.__expected__ = True
1100        with recording(self, False) as sbuf:
1101            # False because there's no need to write "expected failure" to the
1102            # stderr twice.
1103            # Once by the Python unittest framework, and a second time by us.
1104            print("expected failure", file=sbuf)
1105
1106    def markSkippedTest(self):
1107        """Callback invoked when a test is skipped."""
1108        self.__skipped__ = True
1109        with recording(self, False) as sbuf:
1110            # False because there's no need to write "skipped test" to the
1111            # stderr twice.
1112            # Once by the Python unittest framework, and a second time by us.
1113            print("skipped test", file=sbuf)
1114
1115    def markUnexpectedSuccess(self):
1116        """Callback invoked when an unexpected success occurred."""
1117        self.__unexpected__ = True
1118        with recording(self, False) as sbuf:
1119            # False because there's no need to write "unexpected success" to the
1120            # stderr twice.
1121            # Once by the Python unittest framework, and a second time by us.
1122            print("unexpected success", file=sbuf)
1123
1124    def getRerunArgs(self):
1125        return " -f %s.%s" % (self.__class__.__name__, self._testMethodName)
1126
1127    def getLogBasenameForCurrentTest(self, prefix="Incomplete"):
1128        """
1129        returns a partial path that can be used as the beginning of the name of multiple
1130        log files pertaining to this test
1131        """
1132        return os.path.join(self.getBuildDir(), prefix)
1133
1134    def dumpSessionInfo(self):
1135        """
1136        Dump the debugger interactions leading to a test error/failure.  This
1137        allows for more convenient postmortem analysis.
1138
1139        See also LLDBTestResult (dotest.py) which is a singlton class derived
1140        from TextTestResult and overwrites addError, addFailure, and
1141        addExpectedFailure methods to allow us to to mark the test instance as
1142        such.
1143        """
1144
1145        # We are here because self.tearDown() detected that this test instance
1146        # either errored or failed.  The lldb.test_result singleton contains
1147        # two lists (errors and failures) which get populated by the unittest
1148        # framework.  Look over there for stack trace information.
1149        #
1150        # The lists contain 2-tuples of TestCase instances and strings holding
1151        # formatted tracebacks.
1152        #
1153        # See http://docs.python.org/library/unittest.html#unittest.TestResult.
1154
1155        # output tracebacks into session
1156        pairs = []
1157        if self.__errored__:
1158            pairs = configuration.test_result.errors
1159            prefix = "Error"
1160        elif self.__cleanup_errored__:
1161            pairs = configuration.test_result.cleanup_errors
1162            prefix = "CleanupError"
1163        elif self.__failed__:
1164            pairs = configuration.test_result.failures
1165            prefix = "Failure"
1166        elif self.__expected__:
1167            pairs = configuration.test_result.expectedFailures
1168            prefix = "ExpectedFailure"
1169        elif self.__skipped__:
1170            prefix = "SkippedTest"
1171        elif self.__unexpected__:
1172            prefix = "UnexpectedSuccess"
1173        else:
1174            prefix = "Success"
1175
1176        if not self.__unexpected__ and not self.__skipped__:
1177            for test, traceback in pairs:
1178                if test is self:
1179                    print(traceback, file=self.session)
1180
1181        import datetime
1182
1183        print(
1184            "Session info generated @",
1185            datetime.datetime.now().ctime(),
1186            file=self.session,
1187        )
1188        self.session.close()
1189        del self.session
1190
1191        # process the log files
1192        if prefix != "Success" or lldbtest_config.log_success:
1193            # keep all log files, rename them to include prefix
1194            src_log_basename = self.getLogBasenameForCurrentTest()
1195            dst_log_basename = self.getLogBasenameForCurrentTest(prefix)
1196            for src in self.log_files:
1197                if os.path.isfile(src):
1198                    dst = src.replace(src_log_basename, dst_log_basename)
1199                    if os.name == "nt" and os.path.isfile(dst):
1200                        # On Windows, renaming a -> b will throw an exception if
1201                        # b exists.  On non-Windows platforms it silently
1202                        # replaces the destination.  Ultimately this means that
1203                        # atomic renames are not guaranteed to be possible on
1204                        # Windows, but we need this to work anyway, so just
1205                        # remove the destination first if it already exists.
1206                        remove_file(dst)
1207
1208                    lldbutil.mkdir_p(os.path.dirname(dst))
1209                    os.rename(src, dst)
1210        else:
1211            # success!  (and we don't want log files) delete log files
1212            for log_file in self.log_files:
1213                if os.path.isfile(log_file):
1214                    remove_file(log_file)
1215
1216    # ====================================================
1217    # Config. methods supported through a plugin interface
1218    # (enables reading of the current test configuration)
1219    # ====================================================
1220
1221    def hasXMLSupport(self):
1222        """Returns True if lldb was built with XML support. Use this check to
1223        enable parts of tests, if you want to skip a whole test use skipIfXmlSupportMissing
1224        instead."""
1225        return (
1226            lldb.SBDebugger.GetBuildConfiguration()
1227            .GetValueForKey("xml")
1228            .GetValueForKey("value")
1229            .GetBooleanValue(False)
1230        )
1231
1232    def isMIPS(self):
1233        """Returns true if the architecture is MIPS."""
1234        arch = self.getArchitecture()
1235        if re.match("mips", arch):
1236            return True
1237        return False
1238
1239    def isPPC64le(self):
1240        """Returns true if the architecture is PPC64LE."""
1241        arch = self.getArchitecture()
1242        if re.match("powerpc64le", arch):
1243            return True
1244        return False
1245
1246    def getCPUInfo(self):
1247        triple = self.dbg.GetSelectedPlatform().GetTriple()
1248
1249        # TODO other platforms, please implement this function
1250        if not re.match(".*-.*-linux", triple):
1251            return ""
1252
1253        # Need to do something different for non-Linux/Android targets
1254        cpuinfo_path = self.getBuildArtifact("cpuinfo")
1255        if configuration.lldb_platform_name:
1256            self.runCmd('platform get-file "/proc/cpuinfo" ' + cpuinfo_path)
1257        else:
1258            cpuinfo_path = "/proc/cpuinfo"
1259
1260        try:
1261            with open(cpuinfo_path, "r") as f:
1262                cpuinfo = f.read()
1263        except:
1264            return ""
1265
1266        return cpuinfo
1267
1268    def isAArch64(self):
1269        """Returns true if the architecture is AArch64."""
1270        arch = self.getArchitecture().lower()
1271        return arch in ["aarch64", "arm64", "arm64e"]
1272
1273    def isAArch64SVE(self):
1274        return self.isAArch64() and "sve" in self.getCPUInfo()
1275
1276    def isAArch64SME(self):
1277        return self.isAArch64() and "sme" in self.getCPUInfo()
1278
1279    def isAArch64SME2(self):
1280        # If you have sme2, you also have sme.
1281        return self.isAArch64() and "sme2" in self.getCPUInfo()
1282
1283    def isAArch64SMEFA64(self):
1284        # smefa64 allows the use of the full A64 instruction set in streaming
1285        # mode. This is required by certain test programs to setup register
1286        # state.
1287        cpuinfo = self.getCPUInfo()
1288        return self.isAArch64() and "sme" in cpuinfo and "smefa64" in cpuinfo
1289
1290    def isAArch64MTE(self):
1291        return self.isAArch64() and "mte" in self.getCPUInfo()
1292
1293    def isAArch64PAuth(self):
1294        if self.getArchitecture() == "arm64e":
1295            return True
1296        return self.isAArch64() and "paca" in self.getCPUInfo()
1297
1298    def isAArch64Windows(self):
1299        """Returns true if the architecture is AArch64 and platform windows."""
1300        if self.getPlatform() == "windows":
1301            arch = self.getArchitecture().lower()
1302            return arch in ["aarch64", "arm64", "arm64e"]
1303        return False
1304
1305    def getArchitecture(self):
1306        """Returns the architecture in effect the test suite is running with."""
1307        return lldbplatformutil.getArchitecture()
1308
1309    def getLldbArchitecture(self):
1310        """Returns the architecture of the lldb binary."""
1311        return lldbplatformutil.getLLDBArchitecture()
1312
1313    def getCompiler(self):
1314        """Returns the compiler in effect the test suite is running with."""
1315        return lldbplatformutil.getCompiler()
1316
1317    def getCompilerBinary(self):
1318        """Returns the compiler binary the test suite is running with."""
1319        return lldbplatformutil.getCompilerBinary()
1320
1321    def getCompilerVersion(self):
1322        """Returns a string that represents the compiler version.
1323        Supports: llvm, clang.
1324        """
1325        return lldbplatformutil.getCompilerVersion()
1326
1327    def getDwarfVersion(self):
1328        """Returns the dwarf version generated by clang or '0'."""
1329        return lldbplatformutil.getDwarfVersion()
1330
1331    def platformIsDarwin(self):
1332        """Returns true if the OS triple for the selected platform is any valid apple OS"""
1333        return lldbplatformutil.platformIsDarwin()
1334
1335    def hasDarwinFramework(self):
1336        return self.darwinWithFramework
1337
1338    def getPlatform(self):
1339        """Returns the target platform the test suite is running on."""
1340        return lldbplatformutil.getPlatform()
1341
1342    def isIntelCompiler(self):
1343        """Returns true if using an Intel (ICC) compiler, false otherwise."""
1344        return any([x in self.getCompiler() for x in ["icc", "icpc", "icl"]])
1345
1346    def expectedCompilerVersion(self, compiler_version):
1347        """Returns True iff compiler_version[1] matches the current compiler version.
1348        Use compiler_version[0] to specify the operator used to determine if a match has occurred.
1349        Any operator other than the following defaults to an equality test:
1350          '>', '>=', "=>", '<', '<=', '=<', '!=', "!" or 'not'
1351
1352        If the current compiler version cannot be determined, we assume it is close to the top
1353        of trunk, so any less-than or equal-to comparisons will return False, and any
1354        greater-than or not-equal-to comparisons will return True.
1355        """
1356        return lldbplatformutil.expectedCompilerVersion(compiler_version)
1357
1358    def expectedCompiler(self, compilers):
1359        """Returns True iff any element of compilers is a sub-string of the current compiler."""
1360        return lldbplatformutil.expectedCompiler(compilers)
1361
1362    def expectedArch(self, archs):
1363        """Returns True iff any element of archs is a sub-string of the current architecture."""
1364        if archs is None:
1365            return True
1366
1367        for arch in archs:
1368            if arch in self.getArchitecture():
1369                return True
1370
1371        return False
1372
1373    def getRunOptions(self):
1374        """Command line option for -A and -C to run this test again, called from
1375        self.dumpSessionInfo()."""
1376        arch = self.getArchitecture()
1377        comp = self.getCompiler()
1378        option_str = ""
1379        if arch:
1380            option_str = "-A " + arch
1381        if comp:
1382            option_str += " -C " + comp
1383        return option_str
1384
1385    def getDebugInfo(self):
1386        method = getattr(self, self.testMethodName)
1387        return getattr(method, "debug_info", None)
1388
1389    def build(
1390        self,
1391        debug_info=None,
1392        architecture=None,
1393        compiler=None,
1394        dictionary=None,
1395        make_targets=None,
1396    ):
1397        """Platform specific way to build binaries."""
1398        if not architecture and configuration.arch:
1399            architecture = configuration.arch
1400
1401        if debug_info is None:
1402            debug_info = self.getDebugInfo()
1403
1404        dictionary = lldbplatformutil.finalize_build_dictionary(dictionary)
1405
1406        testdir = self.mydir
1407        testname = self.getBuildDirBasename()
1408
1409        module = builder_module()
1410        command = builder_module().getBuildCommand(
1411            debug_info,
1412            architecture,
1413            compiler,
1414            dictionary,
1415            testdir,
1416            testname,
1417            make_targets,
1418        )
1419        if command is None:
1420            raise Exception("Don't know how to build binary")
1421
1422        self.runBuildCommand(command)
1423
1424    def runBuildCommand(self, command):
1425        self.trace(seven.join_for_shell(command))
1426        try:
1427            output = check_output(command, stderr=STDOUT, errors="replace")
1428        except CalledProcessError as cpe:
1429            raise build_exception.BuildError(cpe)
1430        self.trace(output)
1431
1432    # ==================================================
1433    # Build methods supported through a plugin interface
1434    # ==================================================
1435
1436    def getstdlibFlag(self):
1437        """Returns the proper -stdlib flag, or empty if not required."""
1438        if (
1439            self.platformIsDarwin()
1440            or self.getPlatform() == "freebsd"
1441            or self.getPlatform() == "openbsd"
1442        ):
1443            stdlibflag = "-stdlib=libc++"
1444        else:  # this includes NetBSD
1445            stdlibflag = ""
1446        return stdlibflag
1447
1448    def getstdFlag(self):
1449        """Returns the proper stdflag."""
1450        if "gcc" in self.getCompiler() and "4.6" in self.getCompilerVersion():
1451            stdflag = "-std=c++0x"
1452        else:
1453            stdflag = "-std=c++11"
1454        return stdflag
1455
1456    def buildDriver(self, sources, exe_name):
1457        """Platform-specific way to build a program that links with LLDB (via the liblldb.so
1458        or LLDB.framework).
1459        """
1460        stdflag = self.getstdFlag()
1461        stdlibflag = self.getstdlibFlag()
1462
1463        lib_dir = configuration.lldb_libs_dir
1464        if self.hasDarwinFramework():
1465            d = {
1466                "CXX_SOURCES": sources,
1467                "EXE": exe_name,
1468                "CFLAGS_EXTRAS": "%s %s" % (stdflag, stdlibflag),
1469                "FRAMEWORK_INCLUDES": "-F%s" % self.framework_dir,
1470                "LD_EXTRAS": "%s -Wl,-rpath,%s" % (self.lib_lldb, self.framework_dir),
1471            }
1472        elif sys.platform.startswith("win"):
1473            d = {
1474                "CXX_SOURCES": sources,
1475                "EXE": exe_name,
1476                "CFLAGS_EXTRAS": "%s %s -I%s"
1477                % (
1478                    stdflag,
1479                    stdlibflag,
1480                    os.path.join(os.environ["LLDB_SRC"], "include"),
1481                ),
1482                "LD_EXTRAS": "-L%s -lliblldb" % lib_dir,
1483            }
1484        else:
1485            d = {
1486                "CXX_SOURCES": sources,
1487                "EXE": exe_name,
1488                "CFLAGS_EXTRAS": "%s %s -I%s"
1489                % (
1490                    stdflag,
1491                    stdlibflag,
1492                    os.path.join(os.environ["LLDB_SRC"], "include"),
1493                ),
1494                "LD_EXTRAS": "-L%s -llldb -Wl,-rpath,%s" % (lib_dir, lib_dir),
1495            }
1496        if self.TraceOn():
1497            print("Building LLDB Driver (%s) from sources %s" % (exe_name, sources))
1498
1499        self.build(dictionary=d)
1500
1501    def buildLibrary(self, sources, lib_name):
1502        """Platform specific way to build a default library."""
1503
1504        stdflag = self.getstdFlag()
1505
1506        lib_dir = configuration.lldb_libs_dir
1507        if self.hasDarwinFramework():
1508            d = {
1509                "DYLIB_CXX_SOURCES": sources,
1510                "DYLIB_NAME": lib_name,
1511                "CFLAGS_EXTRAS": "%s -stdlib=libc++" % stdflag,
1512                "FRAMEWORK_INCLUDES": "-F%s" % self.framework_dir,
1513                "LD_EXTRAS": "%s -Wl,-rpath,%s -dynamiclib"
1514                % (self.lib_lldb, self.framework_dir),
1515            }
1516        elif self.getPlatform() == "windows":
1517            d = {
1518                "DYLIB_CXX_SOURCES": sources,
1519                "DYLIB_NAME": lib_name,
1520                "CFLAGS_EXTRAS": "%s -I%s "
1521                % (stdflag, os.path.join(os.environ["LLDB_SRC"], "include")),
1522                "LD_EXTRAS": "-shared -l%s\liblldb.lib" % lib_dir,
1523            }
1524        else:
1525            d = {
1526                "DYLIB_CXX_SOURCES": sources,
1527                "DYLIB_NAME": lib_name,
1528                "CFLAGS_EXTRAS": "%s -I%s -fPIC"
1529                % (stdflag, os.path.join(os.environ["LLDB_SRC"], "include")),
1530                "LD_EXTRAS": "-shared -L%s -llldb -Wl,-rpath,%s" % (lib_dir, lib_dir),
1531            }
1532        if self.TraceOn():
1533            print("Building LLDB Library (%s) from sources %s" % (lib_name, sources))
1534
1535        self.build(dictionary=d)
1536
1537    def buildProgram(self, sources, exe_name):
1538        """Platform specific way to build an executable from C/C++ sources."""
1539        d = {"CXX_SOURCES": sources, "EXE": exe_name}
1540        self.build(dictionary=d)
1541
1542    def findBuiltClang(self):
1543        """Tries to find and use Clang from the build directory as the compiler (instead of the system compiler)."""
1544        paths_to_try = [
1545            "llvm-build/Release+Asserts/x86_64/bin/clang",
1546            "llvm-build/Debug+Asserts/x86_64/bin/clang",
1547            "llvm-build/Release/x86_64/bin/clang",
1548            "llvm-build/Debug/x86_64/bin/clang",
1549        ]
1550        lldb_root_path = os.path.join(os.path.dirname(__file__), "..", "..", "..", "..")
1551        for p in paths_to_try:
1552            path = os.path.join(lldb_root_path, p)
1553            if os.path.exists(path):
1554                return path
1555
1556        # Tries to find clang at the same folder as the lldb
1557        lldb_dir = os.path.dirname(lldbtest_config.lldbExec)
1558        path = shutil.which("clang", path=lldb_dir)
1559        if path is not None:
1560            return path
1561
1562        return os.environ["CC"]
1563
1564    def yaml2obj(self, yaml_path, obj_path, max_size=None):
1565        """
1566        Create an object file at the given path from a yaml file.
1567
1568        Throws subprocess.CalledProcessError if the object could not be created.
1569        """
1570        yaml2obj_bin = configuration.get_yaml2obj_path()
1571        if not yaml2obj_bin:
1572            self.assertTrue(False, "No valid yaml2obj executable specified")
1573        command = [yaml2obj_bin, "-o=%s" % obj_path, yaml_path]
1574        if max_size is not None:
1575            command += ["--max-size=%d" % max_size]
1576        self.runBuildCommand(command)
1577
1578    def cleanup(self, dictionary=None):
1579        """Platform specific way to do cleanup after build."""
1580        module = builder_module()
1581        if not module.cleanup(dictionary):
1582            raise Exception(
1583                "Don't know how to do cleanup with dictionary: " + dictionary
1584            )
1585
1586    def invoke(self, obj, name, trace=False):
1587        """Use reflection to call a method dynamically with no argument."""
1588        trace = True if traceAlways else trace
1589
1590        method = getattr(obj, name)
1591        import inspect
1592
1593        self.assertTrue(
1594            inspect.ismethod(method), name + "is a method name of object: " + str(obj)
1595        )
1596        result = method()
1597        with recording(self, trace) as sbuf:
1598            print(str(method) + ":", result, file=sbuf)
1599        return result
1600
1601    def getLibcPlusPlusLibs(self):
1602        if self.getPlatform() in ("freebsd", "linux", "netbsd", "openbsd"):
1603            return ["libc++.so.1"]
1604        else:
1605            return ["libc++.1.dylib", "libc++abi."]
1606
1607    def run_platform_command(self, cmd):
1608        platform = self.dbg.GetSelectedPlatform()
1609        shell_command = lldb.SBPlatformShellCommand(cmd)
1610        err = platform.Run(shell_command)
1611        return (err, shell_command.GetStatus(), shell_command.GetOutput())
1612
1613    def get_stats(self, options=None):
1614        """
1615        Get the output of the "statistics dump" with optional extra options
1616        and return the JSON as a python dictionary.
1617        """
1618        return_obj = lldb.SBCommandReturnObject()
1619        command = "statistics dump "
1620        if options is not None:
1621            command += options
1622        self.ci.HandleCommand(command, return_obj, False)
1623        metrics_json = return_obj.GetOutput()
1624        return json.loads(metrics_json)
1625
1626
1627# Metaclass for TestBase to change the list of test metods when a new TestCase is loaded.
1628# We change the test methods to create a new test method for each test for each debug info we are
1629# testing. The name of the new test method will be '<original-name>_<debug-info>' and with adding
1630# the new test method we remove the old method at the same time. This functionality can be
1631# supressed by at test case level setting the class attribute NO_DEBUG_INFO_TESTCASE or at test
1632# level by using the decorator @no_debug_info_test.
1633
1634
1635class LLDBTestCaseFactory(type):
1636    def __new__(cls, name, bases, attrs):
1637        original_testcase = super(LLDBTestCaseFactory, cls).__new__(
1638            cls, name, bases, attrs
1639        )
1640        if original_testcase.NO_DEBUG_INFO_TESTCASE:
1641            return original_testcase
1642
1643        # Default implementation for skip/xfail reason based on the debug category,
1644        # where "None" means to run the test as usual.
1645        def no_reason(_):
1646            return None
1647
1648        newattrs = {}
1649        for attrname, attrvalue in attrs.items():
1650            if attrname.startswith("test") and not getattr(
1651                attrvalue, "__no_debug_info_test__", False
1652            ):
1653                # If any debug info categories were explicitly tagged, assume that list to be
1654                # authoritative.  If none were specified, try with all debug
1655                # info formats.
1656                all_dbginfo_categories = set(
1657                    test_categories.debug_info_categories.keys()
1658                )
1659                categories = (
1660                    set(getattr(attrvalue, "categories", [])) & all_dbginfo_categories
1661                )
1662                if not categories:
1663                    categories = [
1664                        category
1665                        for category, can_replicate in test_categories.debug_info_categories.items()
1666                        if can_replicate
1667                    ]
1668
1669                xfail_for_debug_info_cat_fn = getattr(
1670                    attrvalue, "__xfail_for_debug_info_cat_fn__", no_reason
1671                )
1672                skip_for_debug_info_cat_fn = getattr(
1673                    attrvalue, "__skip_for_debug_info_cat_fn__", no_reason
1674                )
1675                for cat in categories:
1676
1677                    @decorators.add_test_categories([cat])
1678                    @wraps(attrvalue)
1679                    def test_method(self, attrvalue=attrvalue):
1680                        return attrvalue(self)
1681
1682                    method_name = attrname + "_" + cat
1683                    test_method.__name__ = method_name
1684                    test_method.debug_info = cat
1685
1686                    xfail_reason = xfail_for_debug_info_cat_fn(cat)
1687                    if xfail_reason:
1688                        test_method = unittest.expectedFailure(test_method)
1689
1690                    skip_reason = skip_for_debug_info_cat_fn(cat)
1691                    if skip_reason:
1692                        test_method = unittest.skip(skip_reason)(test_method)
1693
1694                    newattrs[method_name] = test_method
1695
1696            else:
1697                newattrs[attrname] = attrvalue
1698        return super(LLDBTestCaseFactory, cls).__new__(cls, name, bases, newattrs)
1699
1700
1701# Setup the metaclass for this class to change the list of the test
1702# methods when a new class is loaded
1703
1704
1705class TestBase(Base, metaclass=LLDBTestCaseFactory):
1706    """
1707    This abstract base class is meant to be subclassed.  It provides default
1708    implementations for setUpClass(), tearDownClass(), setUp(), and tearDown(),
1709    among other things.
1710
1711    Important things for test class writers:
1712
1713        - The setUp method sets up things to facilitate subsequent interactions
1714          with the debugger as part of the test.  These include:
1715              - populate the test method name
1716              - create/get a debugger set with synchronous mode (self.dbg)
1717              - get the command interpreter from with the debugger (self.ci)
1718              - create a result object for use with the command interpreter
1719                (self.res)
1720              - plus other stuffs
1721
1722        - The tearDown method tries to perform some necessary cleanup on behalf
1723          of the test to return the debugger to a good state for the next test.
1724          These include:
1725              - execute any tearDown hooks registered by the test method with
1726                TestBase.addTearDownHook(); examples can be found in
1727                settings/TestSettings.py
1728              - kill the inferior process associated with each target, if any,
1729                and, then delete the target from the debugger's target list
1730              - perform build cleanup before running the next test method in the
1731                same test class; examples of registering for this service can be
1732                found in types/TestIntegerTypes.py with the call:
1733                    - self.setTearDownCleanup(dictionary=d)
1734
1735        - Similarly setUpClass and tearDownClass perform classwise setup and
1736          teardown fixtures.  The tearDownClass method invokes a default build
1737          cleanup for the entire test class;  also, subclasses can implement the
1738          classmethod classCleanup(cls) to perform special class cleanup action.
1739
1740        - The instance methods runCmd and expect are used heavily by existing
1741          test cases to send a command to the command interpreter and to perform
1742          string/pattern matching on the output of such command execution.  The
1743          expect method also provides a mode to peform string/pattern matching
1744          without running a command.
1745
1746        - The build method is used to build the binaries used during a
1747          particular test scenario.  A plugin should be provided for the
1748          sys.platform running the test suite.  The Mac OS X implementation is
1749          located in builders/darwin.py.
1750    """
1751
1752    # Subclasses can set this to true (if they don't depend on debug info) to avoid running the
1753    # test multiple times with various debug info types.
1754    NO_DEBUG_INFO_TESTCASE = False
1755
1756    # Maximum allowed attempts when launching the inferior process.
1757    # Can be overridden by the LLDB_MAX_LAUNCH_COUNT environment variable.
1758    maxLaunchCount = 1
1759
1760    # Time to wait before the next launching attempt in second(s).
1761    # Can be overridden by the LLDB_TIME_WAIT_NEXT_LAUNCH environment variable.
1762    timeWaitNextLaunch = 1.0
1763
1764    def generateSource(self, source):
1765        template = source + ".template"
1766        temp = os.path.join(self.getSourceDir(), template)
1767        with open(temp, "r") as f:
1768            content = f.read()
1769
1770        public_api_dir = os.path.join(os.environ["LLDB_SRC"], "include", "lldb", "API")
1771
1772        # Look under the include/lldb/API directory and add #include statements
1773        # for all the SB API headers.
1774        public_headers = os.listdir(public_api_dir)
1775        # For different platforms, the include statement can vary.
1776        if self.hasDarwinFramework():
1777            include_stmt = "'#include <%s>' % os.path.join('LLDB', header)"
1778        else:
1779            include_stmt = (
1780                "'#include <%s>' % os.path.join(r'" + public_api_dir + "', header)"
1781            )
1782        list = [
1783            eval(include_stmt)
1784            for header in public_headers
1785            if (header.startswith("SB") and header.endswith(".h"))
1786        ]
1787        includes = "\n".join(list)
1788        new_content = content.replace("%include_SB_APIs%", includes)
1789        new_content = new_content.replace("%SOURCE_DIR%", self.getSourceDir())
1790        src = os.path.join(self.getBuildDir(), source)
1791        with open(src, "w") as f:
1792            f.write(new_content)
1793
1794        self.addTearDownHook(lambda: os.remove(src))
1795
1796    def setUp(self):
1797        # Works with the test driver to conditionally skip tests via
1798        # decorators.
1799        Base.setUp(self)
1800
1801        for s in self.setUpCommands():
1802            self.runCmd(s)
1803
1804        if "LLDB_MAX_LAUNCH_COUNT" in os.environ:
1805            self.maxLaunchCount = int(os.environ["LLDB_MAX_LAUNCH_COUNT"])
1806
1807        if "LLDB_TIME_WAIT_NEXT_LAUNCH" in os.environ:
1808            self.timeWaitNextLaunch = float(os.environ["LLDB_TIME_WAIT_NEXT_LAUNCH"])
1809
1810        # We want our debugger to be synchronous.
1811        self.dbg.SetAsync(False)
1812
1813        # Retrieve the associated command interpreter instance.
1814        self.ci = self.dbg.GetCommandInterpreter()
1815        if not self.ci:
1816            raise Exception("Could not get the command interpreter")
1817
1818        # And the result object.
1819        self.res = lldb.SBCommandReturnObject()
1820
1821    def registerSharedLibrariesWithTarget(self, target, shlibs):
1822        """If we are remotely running the test suite, register the shared libraries with the target so they get uploaded, otherwise do nothing
1823
1824        Any modules in the target that have their remote install file specification set will
1825        get uploaded to the remote host. This function registers the local copies of the
1826        shared libraries with the target and sets their remote install locations so they will
1827        be uploaded when the target is run.
1828        """
1829        if not shlibs or not self.platformContext:
1830            return None
1831
1832        shlib_environment_var = self.platformContext.shlib_environment_var
1833        shlib_prefix = self.platformContext.shlib_prefix
1834        shlib_extension = "." + self.platformContext.shlib_extension
1835
1836        dirs = []
1837        # Add any shared libraries to our target if remote so they get
1838        # uploaded into the working directory on the remote side
1839        for name in shlibs:
1840            # The path can be a full path to a shared library, or a make file name like "Foo" for
1841            # "libFoo.dylib" or "libFoo.so", or "Foo.so" for "Foo.so" or "libFoo.so", or just a
1842            # basename like "libFoo.so". So figure out which one it is and resolve the local copy
1843            # of the shared library accordingly
1844            if os.path.isfile(name):
1845                local_shlib_path = (
1846                    name  # name is the full path to the local shared library
1847                )
1848            else:
1849                # Check relative names
1850                local_shlib_path = os.path.join(
1851                    self.getBuildDir(), shlib_prefix + name + shlib_extension
1852                )
1853                if not os.path.exists(local_shlib_path):
1854                    local_shlib_path = os.path.join(
1855                        self.getBuildDir(), name + shlib_extension
1856                    )
1857                    if not os.path.exists(local_shlib_path):
1858                        local_shlib_path = os.path.join(self.getBuildDir(), name)
1859
1860                # Make sure we found the local shared library in the above code
1861                self.assertTrue(os.path.exists(local_shlib_path))
1862
1863            # Add the shared library to our target
1864            shlib_module = target.AddModule(local_shlib_path, None, None, None)
1865            if lldb.remote_platform:
1866                # We must set the remote install location if we want the shared library
1867                # to get uploaded to the remote target
1868                remote_shlib_path = lldbutil.append_to_process_working_directory(
1869                    self, os.path.basename(local_shlib_path)
1870                )
1871                shlib_module.SetRemoteInstallFileSpec(
1872                    lldb.SBFileSpec(remote_shlib_path, False)
1873                )
1874                dir_to_add = self.get_process_working_directory()
1875            else:
1876                dir_to_add = os.path.dirname(local_shlib_path)
1877
1878            if dir_to_add not in dirs:
1879                dirs.append(dir_to_add)
1880
1881        env_value = self.platformContext.shlib_path_separator.join(dirs)
1882        return ["%s=%s" % (shlib_environment_var, env_value)]
1883
1884    def registerSanitizerLibrariesWithTarget(self, target):
1885        runtimes = []
1886        for m in target.module_iter():
1887            libspec = m.GetFileSpec()
1888            if "clang_rt" in libspec.GetFilename():
1889                runtimes.append(
1890                    os.path.join(libspec.GetDirectory(), libspec.GetFilename())
1891                )
1892        return self.registerSharedLibrariesWithTarget(target, runtimes)
1893
1894    # utility methods that tests can use to access the current objects
1895    def target(self):
1896        if not self.dbg:
1897            raise Exception("Invalid debugger instance")
1898        return self.dbg.GetSelectedTarget()
1899
1900    def process(self):
1901        if not self.dbg:
1902            raise Exception("Invalid debugger instance")
1903        return self.dbg.GetSelectedTarget().GetProcess()
1904
1905    def thread(self):
1906        if not self.dbg:
1907            raise Exception("Invalid debugger instance")
1908        return self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread()
1909
1910    def frame(self):
1911        if not self.dbg:
1912            raise Exception("Invalid debugger instance")
1913        return (
1914            self.dbg.GetSelectedTarget()
1915            .GetProcess()
1916            .GetSelectedThread()
1917            .GetSelectedFrame()
1918        )
1919
1920    def get_process_working_directory(self):
1921        """Get the working directory that should be used when launching processes for local or remote processes."""
1922        if lldb.remote_platform:
1923            # Remote tests set the platform working directory up in
1924            # TestBase.setUp()
1925            return lldb.remote_platform.GetWorkingDirectory()
1926        else:
1927            # local tests change directory into each test subdirectory
1928            return self.getBuildDir()
1929
1930    def tearDown(self):
1931        # Ensure all the references to SB objects have gone away so that we can
1932        # be sure that all test-specific resources have been freed before we
1933        # attempt to delete the targets.
1934        gc.collect()
1935
1936        # Delete the target(s) from the debugger as a general cleanup step.
1937        # This includes terminating the process for each target, if any.
1938        # We'd like to reuse the debugger for our next test without incurring
1939        # the initialization overhead.
1940        targets = []
1941        for target in self.dbg:
1942            if target:
1943                targets.append(target)
1944                process = target.GetProcess()
1945                if process:
1946                    rc = self.invoke(process, "Kill")
1947                    assert rc.Success()
1948        for target in targets:
1949            self.dbg.DeleteTarget(target)
1950
1951        # Assert that all targets are deleted.
1952        self.assertEqual(self.dbg.GetNumTargets(), 0)
1953
1954        # Do this last, to make sure it's in reverse order from how we setup.
1955        Base.tearDown(self)
1956
1957    def switch_to_thread_with_stop_reason(self, stop_reason):
1958        """
1959        Run the 'thread list' command, and select the thread with stop reason as
1960        'stop_reason'.  If no such thread exists, no select action is done.
1961        """
1962        from .lldbutil import stop_reason_to_str
1963
1964        self.runCmd("thread list")
1965        output = self.res.GetOutput()
1966        thread_line_pattern = re.compile(
1967            "^[ *] thread #([0-9]+):.*stop reason = %s"
1968            % stop_reason_to_str(stop_reason)
1969        )
1970        for line in output.splitlines():
1971            matched = thread_line_pattern.match(line)
1972            if matched:
1973                self.runCmd("thread select %s" % matched.group(1))
1974
1975    def runCmd(self, cmd, msg=None, check=True, trace=False, inHistory=False):
1976        """
1977        Ask the command interpreter to handle the command and then check its
1978        return status.
1979        """
1980        # Fail fast if 'cmd' is not meaningful.
1981        if cmd is None:
1982            raise Exception("Bad 'cmd' parameter encountered")
1983
1984        trace = True if traceAlways else trace
1985
1986        if cmd.startswith("target create "):
1987            cmd = cmd.replace("target create ", "file ")
1988
1989        running = cmd.startswith("run") or cmd.startswith("process launch")
1990
1991        for i in range(self.maxLaunchCount if running else 1):
1992            with recording(self, trace) as sbuf:
1993                print("runCmd:", cmd, file=sbuf)
1994                if not check:
1995                    print("check of return status not required", file=sbuf)
1996
1997            self.ci.HandleCommand(cmd, self.res, inHistory)
1998
1999            with recording(self, trace) as sbuf:
2000                if self.res.Succeeded():
2001                    print("output:", self.res.GetOutput(), file=sbuf)
2002                else:
2003                    print("runCmd failed!", file=sbuf)
2004                    print(self.res.GetError(), file=sbuf)
2005
2006            if self.res.Succeeded():
2007                break
2008            elif running:
2009                # For process launch, wait some time before possible next try.
2010                time.sleep(self.timeWaitNextLaunch)
2011                with recording(self, trace) as sbuf:
2012                    print("Command '" + cmd + "' failed!", file=sbuf)
2013
2014        if check:
2015            output = ""
2016            if self.res.GetOutput():
2017                output += "\nCommand output:\n" + self.res.GetOutput()
2018            if self.res.GetError():
2019                output += "\nError output:\n" + self.res.GetError()
2020            if msg:
2021                msg += output
2022            if cmd:
2023                cmd += output
2024            self.assertTrue(self.res.Succeeded(), msg if (msg) else CMD_MSG(cmd))
2025
2026    def match(
2027        self, str, patterns, msg=None, trace=False, error=False, matching=True, exe=True
2028    ):
2029        """run command in str, and match the result against regexp in patterns returning the match object for the first matching pattern
2030
2031        Otherwise, all the arguments have the same meanings as for the expect function
2032        """
2033
2034        trace = True if traceAlways else trace
2035
2036        if exe:
2037            # First run the command.  If we are expecting error, set check=False.
2038            # Pass the assert message along since it provides more semantic
2039            # info.
2040            self.runCmd(str, msg=msg, trace=(True if trace else False), check=not error)
2041
2042            # Then compare the output against expected strings.
2043            output = self.res.GetError() if error else self.res.GetOutput()
2044
2045            # If error is True, the API client expects the command to fail!
2046            if error:
2047                self.assertFalse(
2048                    self.res.Succeeded(), "Command '" + str + "' is expected to fail!"
2049                )
2050        else:
2051            # No execution required, just compare str against the golden input.
2052            output = str
2053            with recording(self, trace) as sbuf:
2054                print("looking at:", output, file=sbuf)
2055
2056        # The heading says either "Expecting" or "Not expecting".
2057        heading = "Expecting" if matching else "Not expecting"
2058
2059        for pattern in patterns:
2060            # Match Objects always have a boolean value of True.
2061            match_object = re.search(pattern, output)
2062            matched = bool(match_object)
2063            with recording(self, trace) as sbuf:
2064                print("%s pattern: %s" % (heading, pattern), file=sbuf)
2065                print("Matched" if matched else "Not matched", file=sbuf)
2066            if matched:
2067                break
2068
2069        self.assertTrue(
2070            matched if matching else not matched,
2071            msg if msg else EXP_MSG(str, output, exe),
2072        )
2073
2074        return match_object
2075
2076    def check_completion_with_desc(
2077        self, str_input, match_desc_pairs, enforce_order=False
2078    ):
2079        """
2080        Checks that when the given input is completed at the given list of
2081        completions and descriptions is returned.
2082        :param str_input: The input that should be completed. The completion happens at the end of the string.
2083        :param match_desc_pairs: A list of pairs that indicate what completions have to be in the list of
2084                                 completions returned by LLDB. The first element of the pair is the completion
2085                                 string that LLDB should generate and the second element the description.
2086        :param enforce_order: True iff the order in which the completions are returned by LLDB
2087                              should match the order of the match_desc_pairs pairs.
2088        """
2089        interp = self.dbg.GetCommandInterpreter()
2090        match_strings = lldb.SBStringList()
2091        description_strings = lldb.SBStringList()
2092        num_matches = interp.HandleCompletionWithDescriptions(
2093            str_input, len(str_input), 0, -1, match_strings, description_strings
2094        )
2095        self.assertEqual(len(description_strings), len(match_strings))
2096
2097        # The index of the last matched description in description_strings or
2098        # -1 if no description has been matched yet.
2099        last_found_index = -1
2100        out_of_order_errors = ""
2101        missing_pairs = []
2102        for pair in match_desc_pairs:
2103            found_pair = False
2104            for i in range(num_matches + 1):
2105                match_candidate = match_strings.GetStringAtIndex(i)
2106                description_candidate = description_strings.GetStringAtIndex(i)
2107                if match_candidate == pair[0] and description_candidate == pair[1]:
2108                    found_pair = True
2109                    if enforce_order and last_found_index > i:
2110                        new_err = (
2111                            "Found completion "
2112                            + pair[0]
2113                            + " at index "
2114                            + str(i)
2115                            + " in returned completion list but "
2116                            + "should have been after completion "
2117                            + match_strings.GetStringAtIndex(last_found_index)
2118                            + " (index:"
2119                            + str(last_found_index)
2120                            + ")\n"
2121                        )
2122                        out_of_order_errors += new_err
2123                    last_found_index = i
2124                    break
2125            if not found_pair:
2126                missing_pairs.append(pair)
2127
2128        error_msg = ""
2129        got_failure = False
2130        if len(missing_pairs):
2131            got_failure = True
2132            error_msg += "Missing pairs:\n"
2133            for pair in missing_pairs:
2134                error_msg += " [" + pair[0] + ":" + pair[1] + "]\n"
2135        if len(out_of_order_errors):
2136            got_failure = True
2137            error_msg += out_of_order_errors
2138        if got_failure:
2139            error_msg += (
2140                "Got the following " + str(num_matches) + " completions back:\n"
2141            )
2142            for i in range(num_matches + 1):
2143                match_candidate = match_strings.GetStringAtIndex(i)
2144                description_candidate = description_strings.GetStringAtIndex(i)
2145                error_msg += (
2146                    "["
2147                    + match_candidate
2148                    + ":"
2149                    + description_candidate
2150                    + "] index "
2151                    + str(i)
2152                    + "\n"
2153                )
2154            self.assertFalse(got_failure, error_msg)
2155
2156    def complete_from_to(self, str_input, patterns):
2157        """Test that the completion mechanism completes str_input to patterns,
2158        where patterns could be a single pattern-string or a list of
2159        pattern-strings.
2160
2161        If there is only one pattern and it is exactly equal to str_input, this
2162        assumes that there should be no completions provided and that the result
2163        should be the same as the input."""
2164
2165        # Patterns should not be None in order to proceed.
2166        self.assertFalse(patterns is None)
2167        # And should be either a string or list of strings.  Check for list type
2168        # below, if not, make a list out of the singleton string.  If patterns
2169        # is not a string or not a list of strings, there'll be runtime errors
2170        # later on.
2171        if not isinstance(patterns, list):
2172            patterns = [patterns]
2173
2174        interp = self.dbg.GetCommandInterpreter()
2175        match_strings = lldb.SBStringList()
2176        num_matches = interp.HandleCompletion(
2177            str_input, len(str_input), 0, -1, match_strings
2178        )
2179        common_match = match_strings.GetStringAtIndex(0)
2180        if num_matches == 0:
2181            compare_string = str_input
2182        else:
2183            if common_match != None and len(common_match) > 0:
2184                compare_string = str_input + common_match
2185            else:
2186                compare_string = ""
2187                for idx in range(1, num_matches + 1):
2188                    compare_string += match_strings.GetStringAtIndex(idx) + "\n"
2189
2190        if len(patterns) == 1 and str_input == patterns[0] and num_matches:
2191            self.fail("Expected no completions but got:\n" + compare_string)
2192
2193        for p in patterns:
2194            self.expect(
2195                compare_string,
2196                msg=COMPLETION_MSG(str_input, p, match_strings),
2197                exe=False,
2198                substrs=[p],
2199            )
2200
2201    def completions_match(self, command, completions):
2202        """Checks that the completions for the given command are equal to the
2203        given list of completions"""
2204        interp = self.dbg.GetCommandInterpreter()
2205        match_strings = lldb.SBStringList()
2206        interp.HandleCompletion(command, len(command), 0, -1, match_strings)
2207        # match_strings is a 1-indexed list, so we have to slice...
2208        self.assertCountEqual(
2209            completions, list(match_strings)[1:], "List of returned completion is wrong"
2210        )
2211
2212    def completions_contain(self, command, completions):
2213        """Checks that the completions for the given command contain the given
2214        list of completions."""
2215        interp = self.dbg.GetCommandInterpreter()
2216        match_strings = lldb.SBStringList()
2217        interp.HandleCompletion(command, len(command), 0, -1, match_strings)
2218        for completion in completions:
2219            # match_strings is a 1-indexed list, so we have to slice...
2220            self.assertIn(
2221                completion, list(match_strings)[1:], "Couldn't find expected completion"
2222            )
2223
2224    def filecheck(
2225        self, command, check_file, filecheck_options="", expect_cmd_failure=False
2226    ):
2227        # Run the command.
2228        self.runCmd(
2229            command,
2230            check=(not expect_cmd_failure),
2231            msg="FileCheck'ing result of `{0}`".format(command),
2232        )
2233
2234        self.assertTrue((not expect_cmd_failure) == self.res.Succeeded())
2235
2236        # Get the error text if there was an error, and the regular text if not.
2237        output = self.res.GetOutput() if self.res.Succeeded() else self.res.GetError()
2238
2239        # Assemble the absolute path to the check file. As a convenience for
2240        # LLDB inline tests, assume that the check file is a relative path to
2241        # a file within the inline test directory.
2242        if check_file.endswith(".pyc"):
2243            check_file = check_file[:-1]
2244        check_file_abs = os.path.abspath(check_file)
2245
2246        # Run FileCheck.
2247        filecheck_bin = configuration.get_filecheck_path()
2248        if not filecheck_bin:
2249            self.assertTrue(False, "No valid FileCheck executable specified")
2250        filecheck_args = [filecheck_bin, check_file_abs]
2251        if filecheck_options:
2252            filecheck_args.append(filecheck_options)
2253        subproc = Popen(
2254            filecheck_args,
2255            stdin=PIPE,
2256            stdout=PIPE,
2257            stderr=PIPE,
2258            universal_newlines=True,
2259        )
2260        cmd_stdout, cmd_stderr = subproc.communicate(input=output)
2261        cmd_status = subproc.returncode
2262
2263        filecheck_cmd = " ".join(filecheck_args)
2264        filecheck_trace = """
2265--- FileCheck trace (code={0}) ---
2266{1}
2267
2268FileCheck input:
2269{2}
2270
2271FileCheck output:
2272{3}
2273{4}
2274""".format(
2275            cmd_status, filecheck_cmd, output, cmd_stdout, cmd_stderr
2276        )
2277
2278        trace = cmd_status != 0 or traceAlways
2279        with recording(self, trace) as sbuf:
2280            print(filecheck_trace, file=sbuf)
2281
2282        self.assertTrue(cmd_status == 0)
2283
2284    def expect(
2285        self,
2286        string,
2287        msg=None,
2288        patterns=None,
2289        startstr=None,
2290        endstr=None,
2291        substrs=None,
2292        trace=False,
2293        error=False,
2294        ordered=True,
2295        matching=True,
2296        exe=True,
2297        inHistory=False,
2298    ):
2299        """
2300        Similar to runCmd; with additional expect style output matching ability.
2301
2302        Ask the command interpreter to handle the command and then check its
2303        return status.  The 'msg' parameter specifies an informational assert
2304        message.  We expect the output from running the command to start with
2305        'startstr', matches the substrings contained in 'substrs', and regexp
2306        matches the patterns contained in 'patterns'.
2307
2308        When matching is true and ordered is true, which are both the default,
2309        the strings in the substrs array have to appear in the command output
2310        in the order in which they appear in the array.
2311
2312        If the keyword argument error is set to True, it signifies that the API
2313        client is expecting the command to fail.  In this case, the error stream
2314        from running the command is retrieved and compared against the golden
2315        input, instead.
2316
2317        If the keyword argument matching is set to False, it signifies that the API
2318        client is expecting the output of the command not to match the golden
2319        input.
2320
2321        Finally, the required argument 'string' represents the lldb command to be
2322        sent to the command interpreter.  In case the keyword argument 'exe' is
2323        set to False, the 'string' is treated as a string to be matched/not-matched
2324        against the golden input.
2325        """
2326        # Catch cases where `expect` has been miscalled. Specifically, prevent
2327        # this easy to make mistake:
2328        #     self.expect("lldb command", "some substr")
2329        # The `msg` parameter is used only when a failed match occurs. A failed
2330        # match can only occur when one of `patterns`, `startstr`, `endstr`, or
2331        # `substrs` has been given. Thus, if a `msg` is given, it's an error to
2332        # not also provide one of the matcher parameters.
2333        if msg and not (patterns or startstr or endstr or substrs or error):
2334            assert False, "expect() missing a matcher argument"
2335
2336        # Check `patterns` and `substrs` are not accidentally given as strings.
2337        assert not isinstance(patterns, str), "patterns must be a collection of strings"
2338        assert not isinstance(substrs, str), "substrs must be a collection of strings"
2339
2340        trace = True if traceAlways else trace
2341
2342        if exe:
2343            # First run the command.  If we are expecting error, set check=False.
2344            # Pass the assert message along since it provides more semantic
2345            # info.
2346            self.runCmd(
2347                string,
2348                msg=msg,
2349                trace=(True if trace else False),
2350                check=not error,
2351                inHistory=inHistory,
2352            )
2353
2354            # Then compare the output against expected strings.
2355            output = self.res.GetError() if error else self.res.GetOutput()
2356
2357            # If error is True, the API client expects the command to fail!
2358            if error:
2359                self.assertFalse(
2360                    self.res.Succeeded(),
2361                    "Command '" + string + "' is expected to fail!",
2362                )
2363        else:
2364            # No execution required, just compare string against the golden input.
2365            if isinstance(string, lldb.SBCommandReturnObject):
2366                output = string.GetOutput()
2367            else:
2368                output = string
2369            with recording(self, trace) as sbuf:
2370                print("looking at:", output, file=sbuf)
2371
2372        expecting_str = "Expecting" if matching else "Not expecting"
2373
2374        def found_str(matched):
2375            return "was found" if matched else "was not found"
2376
2377        # To be used as assert fail message and/or trace content
2378        log_lines = [
2379            "{}:".format("Ran command" if exe else "Checking string"),
2380            '"{}"'.format(string),
2381            # Space out command and output
2382            "",
2383        ]
2384        if exe:
2385            # Newline before output to make large strings more readable
2386            log_lines.append("Got output:\n{}".format(output))
2387
2388        # Assume that we start matched if we want a match
2389        # Meaning if you have no conditions, matching or
2390        # not matching will always pass
2391        matched = matching
2392
2393        # We will stop checking on first failure
2394        if startstr:
2395            matched = output.startswith(startstr)
2396            log_lines.append(
2397                '{} start string: "{}" ({})'.format(
2398                    expecting_str, startstr, found_str(matched)
2399                )
2400            )
2401
2402        if endstr and matched == matching:
2403            matched = output.endswith(endstr)
2404            log_lines.append(
2405                '{} end string: "{}" ({})'.format(
2406                    expecting_str, endstr, found_str(matched)
2407                )
2408            )
2409
2410        if substrs and matched == matching:
2411            start = 0
2412            for substr in substrs:
2413                index = output[start:].find(substr)
2414                start = start + index + len(substr) if ordered and matching else 0
2415                matched = index != -1
2416                log_lines.append(
2417                    '{} sub string: "{}" ({})'.format(
2418                        expecting_str, substr, found_str(matched)
2419                    )
2420                )
2421
2422                if matched != matching:
2423                    break
2424
2425        if patterns and matched == matching:
2426            for pattern in patterns:
2427                matched = re.search(pattern, output)
2428
2429                pattern_line = '{} regex pattern: "{}" ({}'.format(
2430                    expecting_str, pattern, found_str(matched)
2431                )
2432                if matched:
2433                    pattern_line += ', matched "{}"'.format(matched.group(0))
2434                pattern_line += ")"
2435                log_lines.append(pattern_line)
2436
2437                # Convert to bool because match objects
2438                # are True-ish but != True itself
2439                matched = bool(matched)
2440                if matched != matching:
2441                    break
2442
2443        # If a check failed, add any extra assert message
2444        if msg is not None and matched != matching:
2445            log_lines.append(msg)
2446
2447        log_msg = "\n".join(log_lines)
2448        with recording(self, trace) as sbuf:
2449            print(log_msg, file=sbuf)
2450        if matched != matching:
2451            self.fail(log_msg)
2452
2453    def expect_expr(
2454        self,
2455        expr,
2456        result_summary=None,
2457        result_value=None,
2458        result_type=None,
2459        result_children=None,
2460    ):
2461        """
2462        Evaluates the given expression and verifies the result.
2463        :param expr: The expression as a string.
2464        :param result_summary: The summary that the expression should have. None if the summary should not be checked.
2465        :param result_value: The value that the expression should have. None if the value should not be checked.
2466        :param result_type: The type that the expression result should have. None if the type should not be checked.
2467        :param result_children: The expected children of the expression result
2468                                as a list of ValueChecks. None if the children shouldn't be checked.
2469        """
2470        self.assertTrue(
2471            expr.strip() == expr,
2472            "Expression contains trailing/leading whitespace: '" + expr + "'",
2473        )
2474
2475        frame = self.frame()
2476        options = lldb.SBExpressionOptions()
2477
2478        # Disable fix-its that tests don't pass by accident.
2479        options.SetAutoApplyFixIts(False)
2480
2481        # Set the usual default options for normal expressions.
2482        options.SetIgnoreBreakpoints(True)
2483
2484        if self.frame().IsValid():
2485            options.SetLanguage(frame.GuessLanguage())
2486            eval_result = self.frame().EvaluateExpression(expr, options)
2487        else:
2488            target = self.target()
2489            # If there is no selected target, run the expression in the dummy
2490            # target.
2491            if not target.IsValid():
2492                target = self.dbg.GetDummyTarget()
2493            eval_result = target.EvaluateExpression(expr, options)
2494
2495        value_check = ValueCheck(
2496            type=result_type,
2497            value=result_value,
2498            summary=result_summary,
2499            children=result_children,
2500        )
2501        value_check.check_value(self, eval_result, str(eval_result))
2502        return eval_result
2503
2504    def expect_var_path(
2505        self, var_path, summary=None, value=None, type=None, children=None
2506    ):
2507        """
2508        Evaluates the given variable path and verifies the result.
2509        See also 'frame variable' and SBFrame.GetValueForVariablePath.
2510        :param var_path: The variable path as a string.
2511        :param summary: The summary that the variable should have. None if the summary should not be checked.
2512        :param value: The value that the variable should have. None if the value should not be checked.
2513        :param type: The type that the variable result should have. None if the type should not be checked.
2514        :param children: The expected children of the variable  as a list of ValueChecks.
2515                         None if the children shouldn't be checked.
2516        """
2517        self.assertTrue(
2518            var_path.strip() == var_path,
2519            "Expression contains trailing/leading whitespace: '" + var_path + "'",
2520        )
2521
2522        frame = self.frame()
2523        eval_result = frame.GetValueForVariablePath(var_path)
2524
2525        value_check = ValueCheck(
2526            type=type, value=value, summary=summary, children=children
2527        )
2528        value_check.check_value(self, eval_result, str(eval_result))
2529        return eval_result
2530
2531    """Assert that an lldb.SBError is in the "success" state."""
2532
2533    def assertSuccess(self, obj, msg=None):
2534        if not obj.Success():
2535            error = obj.GetCString()
2536            self.fail(self._formatMessage(msg, "'{}' is not success".format(error)))
2537
2538    """Assert that an lldb.SBError is in the "failure" state."""
2539
2540    def assertFailure(self, obj, error_str=None, msg=None):
2541        if obj.Success():
2542            self.fail(self._formatMessage(msg, "Error not in a fail state"))
2543
2544        if error_str == None:
2545            return
2546
2547        error = obj.GetCString()
2548        self.assertEqual(error, error_str, msg)
2549
2550    """Assert that a command return object is successful"""
2551
2552    def assertCommandReturn(self, obj, msg=None):
2553        if not obj.Succeeded():
2554            error = obj.GetError()
2555            self.fail(self._formatMessage(msg, "'{}' is not success".format(error)))
2556
2557    """Assert two states are equal"""
2558
2559    def assertState(self, first, second, msg=None):
2560        if first != second:
2561            error = "{} ({}) != {} ({})".format(
2562                lldbutil.state_type_to_str(first),
2563                first,
2564                lldbutil.state_type_to_str(second),
2565                second,
2566            )
2567            self.fail(self._formatMessage(msg, error))
2568
2569    """Assert two stop reasons are equal"""
2570
2571    def assertStopReason(self, first, second, msg=None):
2572        if first != second:
2573            error = "{} ({}) != {} ({})".format(
2574                lldbutil.stop_reason_to_str(first),
2575                first,
2576                lldbutil.stop_reason_to_str(second),
2577                second,
2578            )
2579            self.fail(self._formatMessage(msg, error))
2580
2581    def createTestTarget(self, file_path=None, msg=None, load_dependent_modules=True):
2582        """
2583        Creates a target from the file found at the given file path.
2584        Asserts that the resulting target is valid.
2585        :param file_path: The file path that should be used to create the target.
2586                          The default argument opens the current default test
2587                          executable in the current test directory.
2588        :param msg: A custom error message.
2589        """
2590        if file_path is None:
2591            file_path = self.getBuildArtifact("a.out")
2592        error = lldb.SBError()
2593        triple = ""
2594        platform = ""
2595        target = self.dbg.CreateTarget(
2596            file_path, triple, platform, load_dependent_modules, error
2597        )
2598        if error.Fail():
2599            err = "Couldn't create target for path '{}': {}".format(
2600                file_path, str(error)
2601            )
2602            self.fail(self._formatMessage(msg, err))
2603
2604        self.assertTrue(target.IsValid(), "Got invalid target without error")
2605        return target
2606
2607    # =================================================
2608    # Misc. helper methods for debugging test execution
2609    # =================================================
2610
2611    def DebugSBValue(self, val):
2612        """Debug print a SBValue object, if traceAlways is True."""
2613        from .lldbutil import value_type_to_str
2614
2615        if not traceAlways:
2616            return
2617
2618        err = sys.stderr
2619        err.write(val.GetName() + ":\n")
2620        err.write("\t" + "TypeName         -> " + val.GetTypeName() + "\n")
2621        err.write("\t" + "ByteSize         -> " + str(val.GetByteSize()) + "\n")
2622        err.write("\t" + "NumChildren      -> " + str(val.GetNumChildren()) + "\n")
2623        err.write("\t" + "Value            -> " + str(val.GetValue()) + "\n")
2624        err.write("\t" + "ValueAsUnsigned  -> " + str(val.GetValueAsUnsigned()) + "\n")
2625        err.write(
2626            "\t" + "ValueType        -> " + value_type_to_str(val.GetValueType()) + "\n"
2627        )
2628        err.write("\t" + "Summary          -> " + str(val.GetSummary()) + "\n")
2629        err.write("\t" + "IsPointerType    -> " + str(val.TypeIsPointerType()) + "\n")
2630        err.write("\t" + "Location         -> " + val.GetLocation() + "\n")
2631
2632    def DebugSBType(self, type):
2633        """Debug print a SBType object, if traceAlways is True."""
2634        if not traceAlways:
2635            return
2636
2637        err = sys.stderr
2638        err.write(type.GetName() + ":\n")
2639        err.write("\t" + "ByteSize        -> " + str(type.GetByteSize()) + "\n")
2640        err.write("\t" + "IsAggregateType   -> " + str(type.IsAggregateType()) + "\n")
2641        err.write("\t" + "IsPointerType   -> " + str(type.IsPointerType()) + "\n")
2642        err.write("\t" + "IsReferenceType -> " + str(type.IsReferenceType()) + "\n")
2643
2644    def DebugPExpect(self, child):
2645        """Debug the spwaned pexpect object."""
2646        if not traceAlways:
2647            return
2648
2649        print(child)
2650
2651    @classmethod
2652    def RemoveTempFile(cls, file):
2653        if os.path.exists(file):
2654            remove_file(file)
2655
2656
2657# On Windows, the first attempt to delete a recently-touched file can fail
2658# because of a race with antimalware scanners.  This function will detect a
2659# failure and retry.
2660
2661
2662def remove_file(file, num_retries=1, sleep_duration=0.5):
2663    for i in range(num_retries + 1):
2664        try:
2665            os.remove(file)
2666            return True
2667        except:
2668            time.sleep(sleep_duration)
2669            continue
2670    return False
2671