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