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