xref: /openbsd-src/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbtest.py (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1061da546Spatrick"""
2061da546SpatrickLLDB module which provides the abstract base class of lldb test case.
3061da546Spatrick
4dda28197SpatrickThe concrete subclass can override lldbtest.TestBase in order to inherit the
5061da546Spatrickcommon behavior for unitest.TestCase.setUp/tearDown implemented in this file.
6061da546Spatrick
7061da546Spatrick./dotest.py provides a test driver which sets up the environment to run the
8061da546Spatrickentire of part of the test suite .  Example:
9061da546Spatrick
10061da546Spatrick# Exercises the test suite in the types directory....
11061da546Spatrick/Volumes/data/lldb/svn/ToT/test $ ./dotest.py -A x86_64 types
12061da546Spatrick...
13061da546Spatrick
14061da546SpatrickSession logs for test failures/errors/unexpected successes will go into directory '2012-05-16-13_35_42'
15061da546SpatrickCommand invoked: python ./dotest.py -A x86_64 types
16061da546Spatrickcompilers=['clang']
17061da546Spatrick
18061da546SpatrickConfiguration: arch=x86_64 compiler=clang
19061da546Spatrick----------------------------------------------------------------------
20061da546SpatrickCollected 72 tests
21061da546Spatrick
22061da546Spatrick........................................................................
23061da546Spatrick----------------------------------------------------------------------
24061da546SpatrickRan 72 tests in 135.468s
25061da546Spatrick
26061da546SpatrickOK
27061da546Spatrick$
28061da546Spatrick"""
29061da546Spatrick
30061da546Spatrickfrom __future__ import absolute_import
31061da546Spatrickfrom __future__ import print_function
32061da546Spatrick
33061da546Spatrick# System modules
34061da546Spatrickimport abc
35061da546Spatrickfrom distutils.version import LooseVersion
36061da546Spatrickfrom functools import wraps
37061da546Spatrickimport gc
38061da546Spatrickimport glob
39061da546Spatrickimport io
40*f6aab3d8Srobertimport json
41061da546Spatrickimport os.path
42061da546Spatrickimport re
43061da546Spatrickimport shutil
44061da546Spatrickimport signal
45061da546Spatrickfrom subprocess import *
46061da546Spatrickimport sys
47061da546Spatrickimport time
48061da546Spatrickimport traceback
49061da546Spatrick
50061da546Spatrick# Third-party modules
51061da546Spatrickimport unittest2
52061da546Spatrick
53061da546Spatrick# LLDB modules
54061da546Spatrickimport lldb
55061da546Spatrickfrom . import configuration
56061da546Spatrickfrom . import decorators
57061da546Spatrickfrom . import lldbplatformutil
58061da546Spatrickfrom . import lldbtest_config
59061da546Spatrickfrom . import lldbutil
60061da546Spatrickfrom . import test_categories
61061da546Spatrickfrom lldbsuite.support import encoded_file
62061da546Spatrickfrom lldbsuite.support import funcutils
63*f6aab3d8Srobertfrom lldbsuite.support import seven
64be691f3bSpatrickfrom lldbsuite.test.builders import get_builder
65*f6aab3d8Srobertfrom lldbsuite.test_event import build_exception
66061da546Spatrick
67061da546Spatrick# See also dotest.parseOptionsAndInitTestdirs(), where the environment variables
68061da546Spatrick# LLDB_COMMAND_TRACE is set from '-t' option.
69061da546Spatrick
70061da546Spatrick# By default, traceAlways is False.
71061da546Spatrickif "LLDB_COMMAND_TRACE" in os.environ and os.environ[
72061da546Spatrick        "LLDB_COMMAND_TRACE"] == "YES":
73061da546Spatrick    traceAlways = True
74061da546Spatrickelse:
75061da546Spatrick    traceAlways = False
76061da546Spatrick
77061da546Spatrick# By default, doCleanup is True.
78061da546Spatrickif "LLDB_DO_CLEANUP" in os.environ and os.environ["LLDB_DO_CLEANUP"] == "NO":
79061da546Spatrick    doCleanup = False
80061da546Spatrickelse:
81061da546Spatrick    doCleanup = True
82061da546Spatrick
83061da546Spatrick
84061da546Spatrick#
85061da546Spatrick# Some commonly used assert messages.
86061da546Spatrick#
87061da546Spatrick
88061da546SpatrickCOMMAND_FAILED_AS_EXPECTED = "Command has failed as expected"
89061da546Spatrick
90061da546SpatrickCURRENT_EXECUTABLE_SET = "Current executable set successfully"
91061da546Spatrick
92061da546SpatrickPROCESS_IS_VALID = "Process is valid"
93061da546Spatrick
94061da546SpatrickPROCESS_KILLED = "Process is killed successfully"
95061da546Spatrick
96061da546SpatrickPROCESS_EXITED = "Process exited successfully"
97061da546Spatrick
98061da546SpatrickPROCESS_STOPPED = "Process status should be stopped"
99061da546Spatrick
100061da546SpatrickRUN_SUCCEEDED = "Process is launched successfully"
101061da546Spatrick
102061da546SpatrickRUN_COMPLETED = "Process exited successfully"
103061da546Spatrick
104061da546SpatrickBACKTRACE_DISPLAYED_CORRECTLY = "Backtrace displayed correctly"
105061da546Spatrick
106061da546SpatrickBREAKPOINT_CREATED = "Breakpoint created successfully"
107061da546Spatrick
108061da546SpatrickBREAKPOINT_STATE_CORRECT = "Breakpoint state is correct"
109061da546Spatrick
110061da546SpatrickBREAKPOINT_PENDING_CREATED = "Pending breakpoint created successfully"
111061da546Spatrick
112061da546SpatrickBREAKPOINT_HIT_ONCE = "Breakpoint resolved with hit count = 1"
113061da546Spatrick
114061da546SpatrickBREAKPOINT_HIT_TWICE = "Breakpoint resolved with hit count = 2"
115061da546Spatrick
116061da546SpatrickBREAKPOINT_HIT_THRICE = "Breakpoint resolved with hit count = 3"
117061da546Spatrick
118061da546SpatrickMISSING_EXPECTED_REGISTERS = "At least one expected register is unavailable."
119061da546Spatrick
120061da546SpatrickOBJECT_PRINTED_CORRECTLY = "Object printed correctly"
121061da546Spatrick
122061da546SpatrickSOURCE_DISPLAYED_CORRECTLY = "Source code displayed correctly"
123061da546Spatrick
124be691f3bSpatrickSTEP_IN_SUCCEEDED = "Thread step-in succeeded"
125be691f3bSpatrick
126061da546SpatrickSTEP_OUT_SUCCEEDED = "Thread step-out succeeded"
127061da546Spatrick
128061da546SpatrickSTOPPED_DUE_TO_EXC_BAD_ACCESS = "Process should be stopped due to bad access exception"
129061da546Spatrick
130061da546SpatrickSTOPPED_DUE_TO_ASSERT = "Process should be stopped due to an assertion"
131061da546Spatrick
132061da546SpatrickSTOPPED_DUE_TO_BREAKPOINT = "Process should be stopped due to breakpoint"
133061da546Spatrick
134061da546SpatrickSTOPPED_DUE_TO_BREAKPOINT_WITH_STOP_REASON_AS = "%s, %s" % (
135061da546Spatrick    STOPPED_DUE_TO_BREAKPOINT, "instead, the actual stop reason is: '%s'")
136061da546Spatrick
137061da546SpatrickSTOPPED_DUE_TO_BREAKPOINT_CONDITION = "Stopped due to breakpoint condition"
138061da546Spatrick
139061da546SpatrickSTOPPED_DUE_TO_BREAKPOINT_IGNORE_COUNT = "Stopped due to breakpoint and ignore count"
140061da546Spatrick
141061da546SpatrickSTOPPED_DUE_TO_BREAKPOINT_JITTED_CONDITION = "Stopped due to breakpoint jitted condition"
142061da546Spatrick
143061da546SpatrickSTOPPED_DUE_TO_SIGNAL = "Process state is stopped due to signal"
144061da546Spatrick
145061da546SpatrickSTOPPED_DUE_TO_STEP_IN = "Process state is stopped due to step in"
146061da546Spatrick
147061da546SpatrickSTOPPED_DUE_TO_WATCHPOINT = "Process should be stopped due to watchpoint"
148061da546Spatrick
149061da546SpatrickDATA_TYPES_DISPLAYED_CORRECTLY = "Data type(s) displayed correctly"
150061da546Spatrick
151061da546SpatrickVALID_BREAKPOINT = "Got a valid breakpoint"
152061da546Spatrick
153061da546SpatrickVALID_BREAKPOINT_LOCATION = "Got a valid breakpoint location"
154061da546Spatrick
155061da546SpatrickVALID_COMMAND_INTERPRETER = "Got a valid command interpreter"
156061da546Spatrick
157061da546SpatrickVALID_FILESPEC = "Got a valid filespec"
158061da546Spatrick
159061da546SpatrickVALID_MODULE = "Got a valid module"
160061da546Spatrick
161061da546SpatrickVALID_PROCESS = "Got a valid process"
162061da546Spatrick
163061da546SpatrickVALID_SYMBOL = "Got a valid symbol"
164061da546Spatrick
165061da546SpatrickVALID_TARGET = "Got a valid target"
166061da546Spatrick
167061da546SpatrickVALID_PLATFORM = "Got a valid platform"
168061da546Spatrick
169061da546SpatrickVALID_TYPE = "Got a valid type"
170061da546Spatrick
171061da546SpatrickVALID_VARIABLE = "Got a valid variable"
172061da546Spatrick
173061da546SpatrickVARIABLES_DISPLAYED_CORRECTLY = "Variable(s) displayed correctly"
174061da546Spatrick
175061da546SpatrickWATCHPOINT_CREATED = "Watchpoint created successfully"
176061da546Spatrick
177061da546Spatrick
178061da546Spatrickdef CMD_MSG(str):
179be691f3bSpatrick    '''A generic "Command '%s' did not return successfully" message generator.'''
180be691f3bSpatrick    return "Command '%s' did not return successfully" % str
181061da546Spatrick
182061da546Spatrick
183061da546Spatrickdef COMPLETION_MSG(str_before, str_after, completions):
184be691f3bSpatrick    '''A generic assertion failed message generator for the completion mechanism.'''
185061da546Spatrick    return ("'%s' successfully completes to '%s', but completions were:\n%s"
186061da546Spatrick           % (str_before, str_after, "\n".join(completions)))
187061da546Spatrick
188061da546Spatrick
189061da546Spatrickdef EXP_MSG(str, actual, exe):
190be691f3bSpatrick    '''A generic "'%s' returned unexpected result" message generator if exe.
191be691f3bSpatrick    Otherwise, it generates "'%s' does not match expected result" message.'''
192061da546Spatrick
193be691f3bSpatrick    return "'%s' %s result, got '%s'" % (
194be691f3bSpatrick        str, 'returned unexpected' if exe else 'does not match expected', actual.strip())
195061da546Spatrick
196061da546Spatrick
197061da546Spatrickdef SETTING_MSG(setting):
198be691f3bSpatrick    '''A generic "Value of setting '%s' is not correct" message generator.'''
199be691f3bSpatrick    return "Value of setting '%s' is not correct" % setting
200061da546Spatrick
201061da546Spatrick
202061da546Spatrickdef line_number(filename, string_to_match):
203061da546Spatrick    """Helper function to return the line number of the first matched string."""
204061da546Spatrick    with io.open(filename, mode='r', encoding="utf-8") as f:
205061da546Spatrick        for i, line in enumerate(f):
206061da546Spatrick            if line.find(string_to_match) != -1:
207061da546Spatrick                # Found our match.
208061da546Spatrick                return i + 1
209061da546Spatrick    raise Exception(
210061da546Spatrick        "Unable to find '%s' within file %s" %
211061da546Spatrick        (string_to_match, filename))
212061da546Spatrick
213061da546Spatrickdef get_line(filename, line_number):
214061da546Spatrick    """Return the text of the line at the 1-based line number."""
215061da546Spatrick    with io.open(filename, mode='r', encoding="utf-8") as f:
216061da546Spatrick        return f.readlines()[line_number - 1]
217061da546Spatrick
218061da546Spatrickdef pointer_size():
219061da546Spatrick    """Return the pointer size of the host system."""
220061da546Spatrick    import ctypes
221061da546Spatrick    a_pointer = ctypes.c_void_p(0xffff)
222061da546Spatrick    return 8 * ctypes.sizeof(a_pointer)
223061da546Spatrick
224061da546Spatrick
225061da546Spatrickdef is_exe(fpath):
226061da546Spatrick    """Returns true if fpath is an executable."""
227*f6aab3d8Srobert    if fpath == None:
228*f6aab3d8Srobert        return False
229*f6aab3d8Srobert    if sys.platform == 'win32':
230*f6aab3d8Srobert        if not fpath.endswith(".exe"):
231*f6aab3d8Srobert            fpath += ".exe"
232061da546Spatrick    return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
233061da546Spatrick
234061da546Spatrick
235061da546Spatrickdef which(program):
236061da546Spatrick    """Returns the full path to a program; None otherwise."""
237061da546Spatrick    fpath, fname = os.path.split(program)
238061da546Spatrick    if fpath:
239061da546Spatrick        if is_exe(program):
240061da546Spatrick            return program
241061da546Spatrick    else:
242061da546Spatrick        for path in os.environ["PATH"].split(os.pathsep):
243061da546Spatrick            exe_file = os.path.join(path, program)
244061da546Spatrick            if is_exe(exe_file):
245061da546Spatrick                return exe_file
246061da546Spatrick    return None
247061da546Spatrick
248be691f3bSpatrickclass ValueCheck:
249be691f3bSpatrick    def __init__(self, name=None, value=None, type=None, summary=None,
250*f6aab3d8Srobert                 children=None, dereference=None):
251be691f3bSpatrick        """
252be691f3bSpatrick        :param name: The name that the SBValue should have. None if the summary
253be691f3bSpatrick                     should not be checked.
254be691f3bSpatrick        :param summary: The summary that the SBValue should have. None if the
255be691f3bSpatrick                        summary should not be checked.
256be691f3bSpatrick        :param value: The value that the SBValue should have. None if the value
257be691f3bSpatrick                      should not be checked.
258be691f3bSpatrick        :param type: The type that the SBValue result should have. None if the
259be691f3bSpatrick                     type should not be checked.
260be691f3bSpatrick        :param children: A list of ValueChecks that need to match the children
261be691f3bSpatrick                         of this SBValue. None if children shouldn't be checked.
262be691f3bSpatrick                         The order of checks is the order of the checks in the
263be691f3bSpatrick                         list. The number of checks has to match the number of
264be691f3bSpatrick                         children.
265*f6aab3d8Srobert        :param dereference: A ValueCheck for the SBValue returned by the
266*f6aab3d8Srobert                            `Dereference` function.
267be691f3bSpatrick        """
268be691f3bSpatrick        self.expect_name = name
269be691f3bSpatrick        self.expect_value = value
270be691f3bSpatrick        self.expect_type = type
271be691f3bSpatrick        self.expect_summary = summary
272be691f3bSpatrick        self.children = children
273*f6aab3d8Srobert        self.dereference = dereference
274be691f3bSpatrick
275be691f3bSpatrick    def check_value(self, test_base, val, error_msg=None):
276be691f3bSpatrick        """
277be691f3bSpatrick        Checks that the given value matches the currently set properties
278be691f3bSpatrick        of this ValueCheck. If a match failed, the given TestBase will
279be691f3bSpatrick        be used to emit an error. A custom error message can be specified
280be691f3bSpatrick        that will be used to describe failed check for this SBValue (but
281be691f3bSpatrick        not errors in the child values).
282be691f3bSpatrick        """
283be691f3bSpatrick
284be691f3bSpatrick        this_error_msg = error_msg if error_msg else ""
285be691f3bSpatrick        this_error_msg += "\nChecking SBValue: " + str(val)
286be691f3bSpatrick
287be691f3bSpatrick        test_base.assertSuccess(val.GetError())
288be691f3bSpatrick
289*f6aab3d8Srobert        # Python 3.6 doesn't declare a `re.Pattern` type, get the dynamic type.
290*f6aab3d8Srobert        pattern_type = type(re.compile(''))
291*f6aab3d8Srobert
292be691f3bSpatrick        if self.expect_name:
293be691f3bSpatrick            test_base.assertEqual(self.expect_name, val.GetName(),
294be691f3bSpatrick                                  this_error_msg)
295be691f3bSpatrick        if self.expect_value:
296*f6aab3d8Srobert            if isinstance(self.expect_value, pattern_type):
297*f6aab3d8Srobert                test_base.assertRegex(val.GetValue(), self.expect_value,
298*f6aab3d8Srobert                                      this_error_msg)
299*f6aab3d8Srobert            else:
300be691f3bSpatrick                test_base.assertEqual(self.expect_value, val.GetValue(),
301be691f3bSpatrick                                      this_error_msg)
302be691f3bSpatrick        if self.expect_type:
303be691f3bSpatrick            test_base.assertEqual(self.expect_type, val.GetDisplayTypeName(),
304be691f3bSpatrick                                  this_error_msg)
305be691f3bSpatrick        if self.expect_summary:
306*f6aab3d8Srobert            if isinstance(self.expect_summary, pattern_type):
307*f6aab3d8Srobert                test_base.assertRegex(val.GetSummary(), self.expect_summary,
308*f6aab3d8Srobert                                      this_error_msg)
309*f6aab3d8Srobert            else:
310be691f3bSpatrick                test_base.assertEqual(self.expect_summary, val.GetSummary(),
311be691f3bSpatrick                                      this_error_msg)
312be691f3bSpatrick        if self.children is not None:
313be691f3bSpatrick            self.check_value_children(test_base, val, error_msg)
314be691f3bSpatrick
315*f6aab3d8Srobert        if self.dereference is not None:
316*f6aab3d8Srobert            self.dereference.check_value(test_base, val.Dereference(), error_msg)
317*f6aab3d8Srobert
318be691f3bSpatrick    def check_value_children(self, test_base, val, error_msg=None):
319be691f3bSpatrick        """
320be691f3bSpatrick        Checks that the children of a SBValue match a certain structure and
321be691f3bSpatrick        have certain properties.
322be691f3bSpatrick
323be691f3bSpatrick        :param test_base: The current test's TestBase object.
324be691f3bSpatrick        :param val: The SBValue to check.
325be691f3bSpatrick        """
326be691f3bSpatrick
327be691f3bSpatrick        this_error_msg = error_msg if error_msg else ""
328be691f3bSpatrick        this_error_msg += "\nChecking SBValue: " + str(val)
329be691f3bSpatrick
330be691f3bSpatrick        test_base.assertEqual(len(self.children), val.GetNumChildren(), this_error_msg)
331be691f3bSpatrick
332be691f3bSpatrick        for i in range(0, val.GetNumChildren()):
333be691f3bSpatrick            expected_child = self.children[i]
334be691f3bSpatrick            actual_child = val.GetChildAtIndex(i)
335*f6aab3d8Srobert            child_error = "Checking child with index " + str(i) + ":\n" + error_msg
336*f6aab3d8Srobert            expected_child.check_value(test_base, actual_child, child_error)
337061da546Spatrick
338*f6aab3d8Srobertclass recording(io.StringIO):
339061da546Spatrick    """
340061da546Spatrick    A nice little context manager for recording the debugger interactions into
341061da546Spatrick    our session object.  If trace flag is ON, it also emits the interactions
342061da546Spatrick    into the stderr.
343061da546Spatrick    """
344061da546Spatrick
345061da546Spatrick    def __init__(self, test, trace):
346*f6aab3d8Srobert        """Create a io.StringIO instance; record the session obj and trace flag."""
347*f6aab3d8Srobert        io.StringIO.__init__(self)
348061da546Spatrick        # The test might not have undergone the 'setUp(self)' phase yet, so that
349061da546Spatrick        # the attribute 'session' might not even exist yet.
350061da546Spatrick        self.session = getattr(test, "session", None) if test else None
351061da546Spatrick        self.trace = trace
352061da546Spatrick
353061da546Spatrick    def __enter__(self):
354061da546Spatrick        """
355061da546Spatrick        Context management protocol on entry to the body of the with statement.
356*f6aab3d8Srobert        Just return the io.StringIO object.
357061da546Spatrick        """
358061da546Spatrick        return self
359061da546Spatrick
360061da546Spatrick    def __exit__(self, type, value, tb):
361061da546Spatrick        """
362061da546Spatrick        Context management protocol on exit from the body of the with statement.
363061da546Spatrick        If trace is ON, it emits the recordings into stderr.  Always add the
364*f6aab3d8Srobert        recordings to our session object.  And close the io.StringIO object, too.
365061da546Spatrick        """
366061da546Spatrick        if self.trace:
367061da546Spatrick            print(self.getvalue(), file=sys.stderr)
368061da546Spatrick        if self.session:
369061da546Spatrick            print(self.getvalue(), file=self.session)
370061da546Spatrick        self.close()
371061da546Spatrick
372061da546Spatrick
373*f6aab3d8Srobertclass _BaseProcess(object, metaclass=abc.ABCMeta):
374061da546Spatrick
375061da546Spatrick    @abc.abstractproperty
376061da546Spatrick    def pid(self):
377061da546Spatrick        """Returns process PID if has been launched already."""
378061da546Spatrick
379061da546Spatrick    @abc.abstractmethod
380*f6aab3d8Srobert    def launch(self, executable, args, extra_env):
381061da546Spatrick        """Launches new process with given executable and args."""
382061da546Spatrick
383061da546Spatrick    @abc.abstractmethod
384061da546Spatrick    def terminate(self):
385061da546Spatrick        """Terminates previously launched process.."""
386061da546Spatrick
387061da546Spatrick
388061da546Spatrickclass _LocalProcess(_BaseProcess):
389061da546Spatrick
390061da546Spatrick    def __init__(self, trace_on):
391061da546Spatrick        self._proc = None
392061da546Spatrick        self._trace_on = trace_on
393061da546Spatrick        self._delayafterterminate = 0.1
394061da546Spatrick
395061da546Spatrick    @property
396061da546Spatrick    def pid(self):
397061da546Spatrick        return self._proc.pid
398061da546Spatrick
399*f6aab3d8Srobert    def launch(self, executable, args, extra_env):
400*f6aab3d8Srobert        env=None
401*f6aab3d8Srobert        if extra_env:
402*f6aab3d8Srobert            env = dict(os.environ)
403*f6aab3d8Srobert            env.update([kv.split("=", 1) for kv in extra_env])
404*f6aab3d8Srobert
405061da546Spatrick        self._proc = Popen(
406061da546Spatrick            [executable] + args,
407061da546Spatrick            stdout=open(
408061da546Spatrick                os.devnull) if not self._trace_on else None,
409be691f3bSpatrick            stdin=PIPE,
410*f6aab3d8Srobert            env=env)
411061da546Spatrick
412061da546Spatrick    def terminate(self):
413061da546Spatrick        if self._proc.poll() is None:
414061da546Spatrick            # Terminate _proc like it does the pexpect
415061da546Spatrick            signals_to_try = [
416061da546Spatrick                sig for sig in [
417061da546Spatrick                    'SIGHUP',
418061da546Spatrick                    'SIGCONT',
419061da546Spatrick                    'SIGINT'] if sig in dir(signal)]
420061da546Spatrick            for sig in signals_to_try:
421061da546Spatrick                try:
422061da546Spatrick                    self._proc.send_signal(getattr(signal, sig))
423061da546Spatrick                    time.sleep(self._delayafterterminate)
424061da546Spatrick                    if self._proc.poll() is not None:
425061da546Spatrick                        return
426061da546Spatrick                except ValueError:
427061da546Spatrick                    pass  # Windows says SIGINT is not a valid signal to send
428061da546Spatrick            self._proc.terminate()
429061da546Spatrick            time.sleep(self._delayafterterminate)
430061da546Spatrick            if self._proc.poll() is not None:
431061da546Spatrick                return
432061da546Spatrick            self._proc.kill()
433061da546Spatrick            time.sleep(self._delayafterterminate)
434061da546Spatrick
435061da546Spatrick    def poll(self):
436061da546Spatrick        return self._proc.poll()
437061da546Spatrick
438*f6aab3d8Srobert    def wait(self, timeout=None):
439*f6aab3d8Srobert        return self._proc.wait(timeout)
440*f6aab3d8Srobert
441061da546Spatrick
442061da546Spatrickclass _RemoteProcess(_BaseProcess):
443061da546Spatrick
444061da546Spatrick    def __init__(self, install_remote):
445061da546Spatrick        self._pid = None
446061da546Spatrick        self._install_remote = install_remote
447061da546Spatrick
448061da546Spatrick    @property
449061da546Spatrick    def pid(self):
450061da546Spatrick        return self._pid
451061da546Spatrick
452*f6aab3d8Srobert    def launch(self, executable, args, extra_env):
453061da546Spatrick        if self._install_remote:
454061da546Spatrick            src_path = executable
455061da546Spatrick            dst_path = lldbutil.join_remote_paths(
456061da546Spatrick                    lldb.remote_platform.GetWorkingDirectory(), os.path.basename(executable))
457061da546Spatrick
458061da546Spatrick            dst_file_spec = lldb.SBFileSpec(dst_path, False)
459061da546Spatrick            err = lldb.remote_platform.Install(
460061da546Spatrick                lldb.SBFileSpec(src_path, True), dst_file_spec)
461061da546Spatrick            if err.Fail():
462061da546Spatrick                raise Exception(
463061da546Spatrick                    "remote_platform.Install('%s', '%s') failed: %s" %
464061da546Spatrick                    (src_path, dst_path, err))
465061da546Spatrick        else:
466061da546Spatrick            dst_path = executable
467061da546Spatrick            dst_file_spec = lldb.SBFileSpec(executable, False)
468061da546Spatrick
469061da546Spatrick        launch_info = lldb.SBLaunchInfo(args)
470061da546Spatrick        launch_info.SetExecutableFile(dst_file_spec, True)
471061da546Spatrick        launch_info.SetWorkingDirectory(
472061da546Spatrick            lldb.remote_platform.GetWorkingDirectory())
473061da546Spatrick
474061da546Spatrick        # Redirect stdout and stderr to /dev/null
475061da546Spatrick        launch_info.AddSuppressFileAction(1, False, True)
476061da546Spatrick        launch_info.AddSuppressFileAction(2, False, True)
477061da546Spatrick
478*f6aab3d8Srobert        if extra_env:
479*f6aab3d8Srobert            launch_info.SetEnvironmentEntries(extra_env, True)
480*f6aab3d8Srobert
481061da546Spatrick        err = lldb.remote_platform.Launch(launch_info)
482061da546Spatrick        if err.Fail():
483061da546Spatrick            raise Exception(
484061da546Spatrick                "remote_platform.Launch('%s', '%s') failed: %s" %
485061da546Spatrick                (dst_path, args, err))
486061da546Spatrick        self._pid = launch_info.GetProcessID()
487061da546Spatrick
488061da546Spatrick    def terminate(self):
489061da546Spatrick        lldb.remote_platform.Kill(self._pid)
490061da546Spatrick
491061da546Spatrickdef getsource_if_available(obj):
492061da546Spatrick    """
493061da546Spatrick    Return the text of the source code for an object if available.  Otherwise,
494061da546Spatrick    a print representation is returned.
495061da546Spatrick    """
496061da546Spatrick    import inspect
497061da546Spatrick    try:
498061da546Spatrick        return inspect.getsource(obj)
499061da546Spatrick    except:
500061da546Spatrick        return repr(obj)
501061da546Spatrick
502061da546Spatrick
503061da546Spatrickdef builder_module():
504be691f3bSpatrick    return get_builder(sys.platform)
505061da546Spatrick
506061da546Spatrick
507061da546Spatrickclass Base(unittest2.TestCase):
508061da546Spatrick    """
509061da546Spatrick    Abstract base for performing lldb (see TestBase) or other generic tests (see
510061da546Spatrick    BenchBase for one example).  lldbtest.Base works with the test driver to
511061da546Spatrick    accomplish things.
512061da546Spatrick
513061da546Spatrick    """
514061da546Spatrick
515061da546Spatrick    # The concrete subclass should override this attribute.
516061da546Spatrick    mydir = None
517061da546Spatrick
518061da546Spatrick    # Keep track of the old current working directory.
519061da546Spatrick    oldcwd = None
520061da546Spatrick
521061da546Spatrick    @staticmethod
522061da546Spatrick    def compute_mydir(test_file):
523061da546Spatrick        '''Subclasses should call this function to correctly calculate the
524061da546Spatrick           required "mydir" attribute as follows:
525061da546Spatrick
526061da546Spatrick            mydir = TestBase.compute_mydir(__file__)
527061da546Spatrick        '''
528061da546Spatrick        # /abs/path/to/packages/group/subdir/mytest.py -> group/subdir
529be691f3bSpatrick        lldb_test_src = configuration.test_src_root
530be691f3bSpatrick        if not test_file.startswith(lldb_test_src):
531be691f3bSpatrick            raise Exception(
532be691f3bSpatrick                "Test file '%s' must reside within lldb_test_src "
533be691f3bSpatrick                "(which is '%s')." % (test_file, lldb_test_src))
534be691f3bSpatrick        return os.path.dirname(os.path.relpath(test_file, start=lldb_test_src))
535061da546Spatrick
536061da546Spatrick    def TraceOn(self):
537061da546Spatrick        """Returns True if we are in trace mode (tracing detailed test execution)."""
538061da546Spatrick        return traceAlways
539061da546Spatrick
540dda28197Spatrick    def trace(self, *args,**kwargs):
541dda28197Spatrick        with recording(self, self.TraceOn()) as sbuf:
542dda28197Spatrick            print(*args, file=sbuf, **kwargs)
543dda28197Spatrick
544061da546Spatrick    @classmethod
545061da546Spatrick    def setUpClass(cls):
546061da546Spatrick        """
547061da546Spatrick        Python unittest framework class setup fixture.
548061da546Spatrick        Do current directory manipulation.
549061da546Spatrick        """
550061da546Spatrick        # Fail fast if 'mydir' attribute is not overridden.
551*f6aab3d8Srobert        if not cls.mydir:
552*f6aab3d8Srobert            cls.mydir = Base.compute_mydir(sys.modules[cls.__module__].__file__)
553*f6aab3d8Srobert        if not cls.mydir:
554061da546Spatrick            raise Exception("Subclasses must override the 'mydir' attribute.")
555061da546Spatrick
556061da546Spatrick        # Save old working directory.
557061da546Spatrick        cls.oldcwd = os.getcwd()
558061da546Spatrick
559be691f3bSpatrick        full_dir = os.path.join(configuration.test_src_root, cls.mydir)
560061da546Spatrick        if traceAlways:
561061da546Spatrick            print("Change dir to:", full_dir, file=sys.stderr)
562061da546Spatrick        os.chdir(full_dir)
563dda28197Spatrick        lldb.SBReproducer.SetWorkingDirectory(full_dir)
564061da546Spatrick
565061da546Spatrick        # Set platform context.
566061da546Spatrick        cls.platformContext = lldbplatformutil.createPlatformContext()
567061da546Spatrick
568061da546Spatrick    @classmethod
569061da546Spatrick    def tearDownClass(cls):
570061da546Spatrick        """
571061da546Spatrick        Python unittest framework class teardown fixture.
572061da546Spatrick        Do class-wide cleanup.
573061da546Spatrick        """
574061da546Spatrick
575061da546Spatrick        if doCleanup:
576061da546Spatrick            # First, let's do the platform-specific cleanup.
577061da546Spatrick            module = builder_module()
578061da546Spatrick            module.cleanup()
579061da546Spatrick
580061da546Spatrick            # Subclass might have specific cleanup function defined.
581061da546Spatrick            if getattr(cls, "classCleanup", None):
582061da546Spatrick                if traceAlways:
583061da546Spatrick                    print(
584061da546Spatrick                        "Call class-specific cleanup function for class:",
585061da546Spatrick                        cls,
586061da546Spatrick                        file=sys.stderr)
587061da546Spatrick                try:
588061da546Spatrick                    cls.classCleanup()
589061da546Spatrick                except:
590061da546Spatrick                    exc_type, exc_value, exc_tb = sys.exc_info()
591061da546Spatrick                    traceback.print_exception(exc_type, exc_value, exc_tb)
592061da546Spatrick
593061da546Spatrick        # Restore old working directory.
594061da546Spatrick        if traceAlways:
595061da546Spatrick            print("Restore dir to:", cls.oldcwd, file=sys.stderr)
596061da546Spatrick        os.chdir(cls.oldcwd)
597061da546Spatrick
598061da546Spatrick    def enableLogChannelsForCurrentTest(self):
599061da546Spatrick        if len(lldbtest_config.channels) == 0:
600061da546Spatrick            return
601061da546Spatrick
602061da546Spatrick        # if debug channels are specified in lldbtest_config.channels,
603061da546Spatrick        # create a new set of log files for every test
604061da546Spatrick        log_basename = self.getLogBasenameForCurrentTest()
605061da546Spatrick
606061da546Spatrick        # confirm that the file is writeable
607061da546Spatrick        host_log_path = "{}-host.log".format(log_basename)
608061da546Spatrick        open(host_log_path, 'w').close()
609dda28197Spatrick        self.log_files.append(host_log_path)
610061da546Spatrick
611061da546Spatrick        log_enable = "log enable -Tpn -f {} ".format(host_log_path)
612061da546Spatrick        for channel_with_categories in lldbtest_config.channels:
613061da546Spatrick            channel_then_categories = channel_with_categories.split(' ', 1)
614061da546Spatrick            channel = channel_then_categories[0]
615061da546Spatrick            if len(channel_then_categories) > 1:
616061da546Spatrick                categories = channel_then_categories[1]
617061da546Spatrick            else:
618061da546Spatrick                categories = "default"
619061da546Spatrick
620061da546Spatrick            if channel == "gdb-remote" and lldb.remote_platform is None:
621061da546Spatrick                # communicate gdb-remote categories to debugserver
622061da546Spatrick                os.environ["LLDB_DEBUGSERVER_LOG_FLAGS"] = categories
623061da546Spatrick
624061da546Spatrick            self.ci.HandleCommand(
625061da546Spatrick                log_enable + channel_with_categories, self.res)
626061da546Spatrick            if not self.res.Succeeded():
627061da546Spatrick                raise Exception(
628061da546Spatrick                    'log enable failed (check LLDB_LOG_OPTION env variable)')
629061da546Spatrick
630061da546Spatrick        # Communicate log path name to debugserver & lldb-server
631061da546Spatrick        # For remote debugging, these variables need to be set when starting the platform
632061da546Spatrick        # instance.
633061da546Spatrick        if lldb.remote_platform is None:
634061da546Spatrick            server_log_path = "{}-server.log".format(log_basename)
635061da546Spatrick            open(server_log_path, 'w').close()
636dda28197Spatrick            self.log_files.append(server_log_path)
637061da546Spatrick            os.environ["LLDB_DEBUGSERVER_LOG_FILE"] = server_log_path
638061da546Spatrick
639061da546Spatrick            # Communicate channels to lldb-server
640061da546Spatrick            os.environ["LLDB_SERVER_LOG_CHANNELS"] = ":".join(
641061da546Spatrick                lldbtest_config.channels)
642061da546Spatrick
643061da546Spatrick        self.addTearDownHook(self.disableLogChannelsForCurrentTest)
644061da546Spatrick
645061da546Spatrick    def disableLogChannelsForCurrentTest(self):
646061da546Spatrick        # close all log files that we opened
647061da546Spatrick        for channel_and_categories in lldbtest_config.channels:
648061da546Spatrick            # channel format - <channel-name> [<category0> [<category1> ...]]
649061da546Spatrick            channel = channel_and_categories.split(' ', 1)[0]
650061da546Spatrick            self.ci.HandleCommand("log disable " + channel, self.res)
651061da546Spatrick            if not self.res.Succeeded():
652061da546Spatrick                raise Exception(
653061da546Spatrick                    'log disable failed (check LLDB_LOG_OPTION env variable)')
654061da546Spatrick
655061da546Spatrick        # Retrieve the server log (if any) from the remote system. It is assumed the server log
656061da546Spatrick        # is writing to the "server.log" file in the current test directory. This can be
657061da546Spatrick        # achieved by setting LLDB_DEBUGSERVER_LOG_FILE="server.log" when starting remote
658dda28197Spatrick        # platform.
659061da546Spatrick        if lldb.remote_platform:
660dda28197Spatrick            server_log_path = self.getLogBasenameForCurrentTest() + "-server.log"
661dda28197Spatrick            if lldb.remote_platform.Get(
662dda28197Spatrick                lldb.SBFileSpec("server.log"),
663dda28197Spatrick                lldb.SBFileSpec(server_log_path)).Success():
664dda28197Spatrick                self.log_files.append(server_log_path)
665061da546Spatrick
666061da546Spatrick    def setPlatformWorkingDir(self):
667061da546Spatrick        if not lldb.remote_platform or not configuration.lldb_platform_working_dir:
668061da546Spatrick            return
669061da546Spatrick
670061da546Spatrick        components = self.mydir.split(os.path.sep) + [str(self.test_number), self.getBuildDirBasename()]
671061da546Spatrick        remote_test_dir = configuration.lldb_platform_working_dir
672061da546Spatrick        for c in components:
673061da546Spatrick            remote_test_dir = lldbutil.join_remote_paths(remote_test_dir, c)
674061da546Spatrick            error = lldb.remote_platform.MakeDirectory(
675061da546Spatrick                remote_test_dir, 448)  # 448 = 0o700
676061da546Spatrick            if error.Fail():
677061da546Spatrick                raise Exception("making remote directory '%s': %s" % (
678061da546Spatrick                    remote_test_dir, error))
679061da546Spatrick
680061da546Spatrick        lldb.remote_platform.SetWorkingDirectory(remote_test_dir)
681061da546Spatrick
682061da546Spatrick        # This function removes all files from the current working directory while leaving
683dda28197Spatrick        # the directories in place. The cleanup is required to reduce the disk space required
684061da546Spatrick        # by the test suite while leaving the directories untouched is neccessary because
685061da546Spatrick        # sub-directories might belong to an other test
686061da546Spatrick        def clean_working_directory():
687061da546Spatrick            # TODO: Make it working on Windows when we need it for remote debugging support
688061da546Spatrick            # TODO: Replace the heuristic to remove the files with a logic what collects the
689061da546Spatrick            # list of files we have to remove during test runs.
690061da546Spatrick            shell_cmd = lldb.SBPlatformShellCommand(
691061da546Spatrick                "rm %s/*" % remote_test_dir)
692061da546Spatrick            lldb.remote_platform.Run(shell_cmd)
693061da546Spatrick        self.addTearDownHook(clean_working_directory)
694061da546Spatrick
695061da546Spatrick    def getSourceDir(self):
696061da546Spatrick        """Return the full path to the current test."""
697be691f3bSpatrick        return os.path.join(configuration.test_src_root, self.mydir)
698061da546Spatrick
699061da546Spatrick    def getBuildDirBasename(self):
700061da546Spatrick        return self.__class__.__module__ + "." + self.testMethodName
701061da546Spatrick
702061da546Spatrick    def getBuildDir(self):
703061da546Spatrick        """Return the full path to the current test."""
704dda28197Spatrick        return os.path.join(configuration.test_build_dir, self.mydir,
705061da546Spatrick                            self.getBuildDirBasename())
706061da546Spatrick
707061da546Spatrick    def makeBuildDir(self):
708061da546Spatrick        """Create the test-specific working directory, deleting any previous
709061da546Spatrick        contents."""
710061da546Spatrick        bdir = self.getBuildDir()
711061da546Spatrick        if os.path.isdir(bdir):
712061da546Spatrick            shutil.rmtree(bdir)
713061da546Spatrick        lldbutil.mkdir_p(bdir)
714061da546Spatrick
715061da546Spatrick    def getBuildArtifact(self, name="a.out"):
716061da546Spatrick        """Return absolute path to an artifact in the test's build directory."""
717061da546Spatrick        return os.path.join(self.getBuildDir(), name)
718061da546Spatrick
719061da546Spatrick    def getSourcePath(self, name):
720061da546Spatrick        """Return absolute path to a file in the test's source directory."""
721061da546Spatrick        return os.path.join(self.getSourceDir(), name)
722061da546Spatrick
723061da546Spatrick    @classmethod
724061da546Spatrick    def setUpCommands(cls):
725061da546Spatrick        commands = [
726dda28197Spatrick            # First of all, clear all settings to have clean state of global properties.
727dda28197Spatrick            "settings clear -all",
728dda28197Spatrick
729061da546Spatrick            # Disable Spotlight lookup. The testsuite creates
730061da546Spatrick            # different binaries with the same UUID, because they only
731061da546Spatrick            # differ in the debug info, which is not being hashed.
732061da546Spatrick            "settings set symbols.enable-external-lookup false",
733061da546Spatrick
734be691f3bSpatrick            # Inherit the TCC permissions from the inferior's parent.
735be691f3bSpatrick            "settings set target.inherit-tcc true",
736be691f3bSpatrick
737be691f3bSpatrick            # Kill rather than detach from the inferior if something goes wrong.
738be691f3bSpatrick            "settings set target.detach-on-error false",
739be691f3bSpatrick
740dda28197Spatrick            # Disable fix-its by default so that incorrect expressions in tests don't
741dda28197Spatrick            # pass just because Clang thinks it has a fix-it.
742dda28197Spatrick            "settings set target.auto-apply-fixits false",
743dda28197Spatrick
744061da546Spatrick            # Testsuite runs in parallel and the host can have also other load.
745061da546Spatrick            "settings set plugin.process.gdb-remote.packet-timeout 60",
746061da546Spatrick
747061da546Spatrick            'settings set symbols.clang-modules-cache-path "{}"'.format(
748061da546Spatrick                configuration.lldb_module_cache_dir),
749061da546Spatrick            "settings set use-color false",
750061da546Spatrick        ]
751dda28197Spatrick
752dda28197Spatrick        # Set any user-overridden settings.
753dda28197Spatrick        for setting, value in configuration.settings:
754dda28197Spatrick            commands.append('setting set %s %s'%(setting, value))
755dda28197Spatrick
756061da546Spatrick        # Make sure that a sanitizer LLDB's environment doesn't get passed on.
757061da546Spatrick        if cls.platformContext and cls.platformContext.shlib_environment_var in os.environ:
758061da546Spatrick            commands.append('settings set target.env-vars {}='.format(
759061da546Spatrick                cls.platformContext.shlib_environment_var))
760061da546Spatrick
761061da546Spatrick        # Set environment variables for the inferior.
762061da546Spatrick        if lldbtest_config.inferior_env:
763061da546Spatrick            commands.append('settings set target.env-vars {}'.format(
764061da546Spatrick                lldbtest_config.inferior_env))
765061da546Spatrick        return commands
766061da546Spatrick
767061da546Spatrick    def setUp(self):
768061da546Spatrick        """Fixture for unittest test case setup.
769061da546Spatrick
770061da546Spatrick        It works with the test driver to conditionally skip tests and does other
771061da546Spatrick        initializations."""
772061da546Spatrick        #import traceback
773061da546Spatrick        # traceback.print_stack()
774061da546Spatrick
775061da546Spatrick        if "LIBCXX_PATH" in os.environ:
776061da546Spatrick            self.libcxxPath = os.environ["LIBCXX_PATH"]
777061da546Spatrick        else:
778061da546Spatrick            self.libcxxPath = None
779061da546Spatrick
780061da546Spatrick        if "LLDBVSCODE_EXEC" in os.environ:
781061da546Spatrick            self.lldbVSCodeExec = os.environ["LLDBVSCODE_EXEC"]
782061da546Spatrick        else:
783061da546Spatrick            self.lldbVSCodeExec = None
784061da546Spatrick
785061da546Spatrick        self.lldbOption = " ".join(
786061da546Spatrick            "-o '" + s + "'" for s in self.setUpCommands())
787061da546Spatrick
788061da546Spatrick        # If we spawn an lldb process for test (via pexpect), do not load the
789061da546Spatrick        # init file unless told otherwise.
790061da546Spatrick        if os.environ.get("NO_LLDBINIT") != "NO":
791061da546Spatrick            self.lldbOption += " --no-lldbinit"
792061da546Spatrick
793061da546Spatrick        # Assign the test method name to self.testMethodName.
794061da546Spatrick        #
795061da546Spatrick        # For an example of the use of this attribute, look at test/types dir.
796061da546Spatrick        # There are a bunch of test cases under test/types and we don't want the
797061da546Spatrick        # module cacheing subsystem to be confused with executable name "a.out"
798061da546Spatrick        # used for all the test cases.
799061da546Spatrick        self.testMethodName = self._testMethodName
800061da546Spatrick
801061da546Spatrick        # This is for the case of directly spawning 'lldb'/'gdb' and interacting
802061da546Spatrick        # with it using pexpect.
803061da546Spatrick        self.child = None
804061da546Spatrick        self.child_prompt = "(lldb) "
805061da546Spatrick        # If the child is interacting with the embedded script interpreter,
806061da546Spatrick        # there are two exits required during tear down, first to quit the
807061da546Spatrick        # embedded script interpreter and second to quit the lldb command
808061da546Spatrick        # interpreter.
809061da546Spatrick        self.child_in_script_interpreter = False
810061da546Spatrick
811061da546Spatrick        # These are for customized teardown cleanup.
812061da546Spatrick        self.dict = None
813061da546Spatrick        self.doTearDownCleanup = False
814061da546Spatrick        # And in rare cases where there are multiple teardown cleanups.
815061da546Spatrick        self.dicts = []
816061da546Spatrick        self.doTearDownCleanups = False
817061da546Spatrick
818061da546Spatrick        # List of spawned subproces.Popen objects
819061da546Spatrick        self.subprocesses = []
820061da546Spatrick
821dda28197Spatrick        # List of log files produced by the current test.
822dda28197Spatrick        self.log_files = []
823061da546Spatrick
824be691f3bSpatrick        # Create the build directory.
825be691f3bSpatrick        # The logs are stored in the build directory, so we have to create it
826be691f3bSpatrick        # before creating the first log file.
827be691f3bSpatrick        self.makeBuildDir()
828be691f3bSpatrick
829dda28197Spatrick        session_file = self.getLogBasenameForCurrentTest()+".log"
830dda28197Spatrick        self.log_files.append(session_file)
831dda28197Spatrick
832061da546Spatrick        # Python 3 doesn't support unbuffered I/O in text mode.  Open buffered.
833061da546Spatrick        self.session = encoded_file.open(session_file, "utf-8", mode="w")
834061da546Spatrick
835061da546Spatrick        # Optimistically set __errored__, __failed__, __expected__ to False
836061da546Spatrick        # initially.  If the test errored/failed, the session info
837061da546Spatrick        # (self.session) is then dumped into a session specific file for
838061da546Spatrick        # diagnosis.
839061da546Spatrick        self.__cleanup_errored__ = False
840061da546Spatrick        self.__errored__ = False
841061da546Spatrick        self.__failed__ = False
842061da546Spatrick        self.__expected__ = False
843061da546Spatrick        # We are also interested in unexpected success.
844061da546Spatrick        self.__unexpected__ = False
845061da546Spatrick        # And skipped tests.
846061da546Spatrick        self.__skipped__ = False
847061da546Spatrick
848061da546Spatrick        # See addTearDownHook(self, hook) which allows the client to add a hook
849061da546Spatrick        # function to be run during tearDown() time.
850061da546Spatrick        self.hooks = []
851061da546Spatrick
852061da546Spatrick        # See HideStdout(self).
853061da546Spatrick        self.sys_stdout_hidden = False
854061da546Spatrick
855061da546Spatrick        if self.platformContext:
856061da546Spatrick            # set environment variable names for finding shared libraries
857061da546Spatrick            self.dylibPath = self.platformContext.shlib_environment_var
858061da546Spatrick
859dda28197Spatrick        # Create the debugger instance.
860061da546Spatrick        self.dbg = lldb.SBDebugger.Create()
861dda28197Spatrick        # Copy selected platform from a global instance if it exists.
862dda28197Spatrick        if lldb.selected_platform is not None:
863dda28197Spatrick            self.dbg.SetSelectedPlatform(lldb.selected_platform)
864061da546Spatrick
865061da546Spatrick        if not self.dbg:
866061da546Spatrick            raise Exception('Invalid debugger instance')
867061da546Spatrick
868061da546Spatrick        # Retrieve the associated command interpreter instance.
869061da546Spatrick        self.ci = self.dbg.GetCommandInterpreter()
870061da546Spatrick        if not self.ci:
871061da546Spatrick            raise Exception('Could not get the command interpreter')
872061da546Spatrick
873061da546Spatrick        # And the result object.
874061da546Spatrick        self.res = lldb.SBCommandReturnObject()
875061da546Spatrick
876061da546Spatrick        self.setPlatformWorkingDir()
877061da546Spatrick        self.enableLogChannelsForCurrentTest()
878061da546Spatrick
879be691f3bSpatrick        self.lib_lldb = None
880061da546Spatrick        self.framework_dir = None
881061da546Spatrick        self.darwinWithFramework = False
882be691f3bSpatrick
883be691f3bSpatrick        if sys.platform.startswith("darwin") and configuration.lldb_framework_path:
884be691f3bSpatrick            framework = configuration.lldb_framework_path
885be691f3bSpatrick            lib = os.path.join(framework, 'LLDB')
886be691f3bSpatrick            if os.path.exists(lib):
887be691f3bSpatrick                self.framework_dir = os.path.dirname(framework)
888be691f3bSpatrick                self.lib_lldb = lib
889be691f3bSpatrick                self.darwinWithFramework = self.platformIsDarwin()
890061da546Spatrick
891061da546Spatrick    def setAsync(self, value):
892061da546Spatrick        """ Sets async mode to True/False and ensures it is reset after the testcase completes."""
893061da546Spatrick        old_async = self.dbg.GetAsync()
894061da546Spatrick        self.dbg.SetAsync(value)
895061da546Spatrick        self.addTearDownHook(lambda: self.dbg.SetAsync(old_async))
896061da546Spatrick
897061da546Spatrick    def cleanupSubprocesses(self):
898be691f3bSpatrick        # Terminate subprocesses in reverse order from how they were created.
899be691f3bSpatrick        for p in reversed(self.subprocesses):
900061da546Spatrick            p.terminate()
901061da546Spatrick            del p
902061da546Spatrick        del self.subprocesses[:]
903061da546Spatrick
904*f6aab3d8Srobert    def spawnSubprocess(self, executable, args=[], extra_env=None, install_remote=True):
905061da546Spatrick        """ Creates a subprocess.Popen object with the specified executable and arguments,
906061da546Spatrick            saves it in self.subprocesses, and returns the object.
907061da546Spatrick        """
908061da546Spatrick        proc = _RemoteProcess(
909061da546Spatrick            install_remote) if lldb.remote_platform else _LocalProcess(self.TraceOn())
910*f6aab3d8Srobert        proc.launch(executable, args, extra_env=extra_env)
911061da546Spatrick        self.subprocesses.append(proc)
912061da546Spatrick        return proc
913061da546Spatrick
914061da546Spatrick    def HideStdout(self):
915061da546Spatrick        """Hide output to stdout from the user.
916061da546Spatrick
917061da546Spatrick        During test execution, there might be cases where we don't want to show the
918061da546Spatrick        standard output to the user.  For example,
919061da546Spatrick
920061da546Spatrick            self.runCmd(r'''sc print("\n\n\tHello!\n")''')
921061da546Spatrick
922061da546Spatrick        tests whether command abbreviation for 'script' works or not.  There is no
923061da546Spatrick        need to show the 'Hello' output to the user as long as the 'script' command
924061da546Spatrick        succeeds and we are not in TraceOn() mode (see the '-t' option).
925061da546Spatrick
926061da546Spatrick        In this case, the test method calls self.HideStdout(self) to redirect the
927061da546Spatrick        sys.stdout to a null device, and restores the sys.stdout upon teardown.
928061da546Spatrick
929061da546Spatrick        Note that you should only call this method at most once during a test case
930061da546Spatrick        execution.  Any subsequent call has no effect at all."""
931061da546Spatrick        if self.sys_stdout_hidden:
932061da546Spatrick            return
933061da546Spatrick
934061da546Spatrick        self.sys_stdout_hidden = True
935061da546Spatrick        old_stdout = sys.stdout
936061da546Spatrick        sys.stdout = open(os.devnull, 'w')
937061da546Spatrick
938061da546Spatrick        def restore_stdout():
939061da546Spatrick            sys.stdout = old_stdout
940061da546Spatrick        self.addTearDownHook(restore_stdout)
941061da546Spatrick
942061da546Spatrick    # =======================================================================
943061da546Spatrick    # Methods for customized teardown cleanups as well as execution of hooks.
944061da546Spatrick    # =======================================================================
945061da546Spatrick
946061da546Spatrick    def setTearDownCleanup(self, dictionary=None):
947dda28197Spatrick        """Register a cleanup action at tearDown() time with a dictionary"""
948061da546Spatrick        self.dict = dictionary
949061da546Spatrick        self.doTearDownCleanup = True
950061da546Spatrick
951061da546Spatrick    def addTearDownCleanup(self, dictionary):
952dda28197Spatrick        """Add a cleanup action at tearDown() time with a dictionary"""
953061da546Spatrick        self.dicts.append(dictionary)
954061da546Spatrick        self.doTearDownCleanups = True
955061da546Spatrick
956061da546Spatrick    def addTearDownHook(self, hook):
957061da546Spatrick        """
958061da546Spatrick        Add a function to be run during tearDown() time.
959061da546Spatrick
960061da546Spatrick        Hooks are executed in a first come first serve manner.
961061da546Spatrick        """
962*f6aab3d8Srobert        if callable(hook):
963061da546Spatrick            with recording(self, traceAlways) as sbuf:
964061da546Spatrick                print(
965061da546Spatrick                    "Adding tearDown hook:",
966061da546Spatrick                    getsource_if_available(hook),
967061da546Spatrick                    file=sbuf)
968061da546Spatrick            self.hooks.append(hook)
969061da546Spatrick
970061da546Spatrick        return self
971061da546Spatrick
972061da546Spatrick    def deletePexpectChild(self):
973061da546Spatrick        # This is for the case of directly spawning 'lldb' and interacting with it
974061da546Spatrick        # using pexpect.
975061da546Spatrick        if self.child and self.child.isalive():
976061da546Spatrick            import pexpect
977061da546Spatrick            with recording(self, traceAlways) as sbuf:
978061da546Spatrick                print("tearing down the child process....", file=sbuf)
979061da546Spatrick            try:
980061da546Spatrick                if self.child_in_script_interpreter:
981061da546Spatrick                    self.child.sendline('quit()')
982061da546Spatrick                    self.child.expect_exact(self.child_prompt)
983061da546Spatrick                self.child.sendline(
984061da546Spatrick                    'settings set interpreter.prompt-on-quit false')
985061da546Spatrick                self.child.sendline('quit')
986061da546Spatrick                self.child.expect(pexpect.EOF)
987061da546Spatrick            except (ValueError, pexpect.ExceptionPexpect):
988061da546Spatrick                # child is already terminated
989061da546Spatrick                pass
990061da546Spatrick            except OSError as exception:
991061da546Spatrick                import errno
992061da546Spatrick                if exception.errno != errno.EIO:
993061da546Spatrick                    # unexpected error
994061da546Spatrick                    raise
995061da546Spatrick                # child is already terminated
996061da546Spatrick            finally:
997061da546Spatrick                # Give it one final blow to make sure the child is terminated.
998061da546Spatrick                self.child.close()
999061da546Spatrick
1000061da546Spatrick    def tearDown(self):
1001061da546Spatrick        """Fixture for unittest test case teardown."""
1002061da546Spatrick        self.deletePexpectChild()
1003061da546Spatrick
1004061da546Spatrick        # Check and run any hook functions.
1005061da546Spatrick        for hook in reversed(self.hooks):
1006061da546Spatrick            with recording(self, traceAlways) as sbuf:
1007061da546Spatrick                print(
1008061da546Spatrick                    "Executing tearDown hook:",
1009061da546Spatrick                    getsource_if_available(hook),
1010061da546Spatrick                    file=sbuf)
1011061da546Spatrick            if funcutils.requires_self(hook):
1012061da546Spatrick                hook(self)
1013061da546Spatrick            else:
1014061da546Spatrick                hook()  # try the plain call and hope it works
1015061da546Spatrick
1016061da546Spatrick        del self.hooks
1017061da546Spatrick
1018061da546Spatrick        # Perform registered teardown cleanup.
1019061da546Spatrick        if doCleanup and self.doTearDownCleanup:
1020061da546Spatrick            self.cleanup(dictionary=self.dict)
1021061da546Spatrick
1022061da546Spatrick        # In rare cases where there are multiple teardown cleanups added.
1023061da546Spatrick        if doCleanup and self.doTearDownCleanups:
1024061da546Spatrick            if self.dicts:
1025061da546Spatrick                for dict in reversed(self.dicts):
1026061da546Spatrick                    self.cleanup(dictionary=dict)
1027061da546Spatrick
1028dda28197Spatrick        # Remove subprocesses created by the test.
1029dda28197Spatrick        self.cleanupSubprocesses()
1030dda28197Spatrick
1031dda28197Spatrick        # This must be the last statement, otherwise teardown hooks or other
1032dda28197Spatrick        # lines might depend on this still being active.
1033dda28197Spatrick        lldb.SBDebugger.Destroy(self.dbg)
1034dda28197Spatrick        del self.dbg
1035dda28197Spatrick
1036be691f3bSpatrick        # All modules should be orphaned now so that they can be cleared from
1037be691f3bSpatrick        # the shared module cache.
1038be691f3bSpatrick        lldb.SBModule.GarbageCollectAllocatedModules()
1039be691f3bSpatrick
1040be691f3bSpatrick        # Assert that the global module cache is empty.
1041be691f3bSpatrick        self.assertEqual(lldb.SBModule.GetNumberAllocatedModules(), 0)
1042be691f3bSpatrick
1043be691f3bSpatrick
1044061da546Spatrick    # =========================================================
1045061da546Spatrick    # Various callbacks to allow introspection of test progress
1046061da546Spatrick    # =========================================================
1047061da546Spatrick
1048061da546Spatrick    def markError(self):
1049061da546Spatrick        """Callback invoked when an error (unexpected exception) errored."""
1050061da546Spatrick        self.__errored__ = True
1051061da546Spatrick        with recording(self, False) as sbuf:
1052061da546Spatrick            # False because there's no need to write "ERROR" to the stderr twice.
1053061da546Spatrick            # Once by the Python unittest framework, and a second time by us.
1054061da546Spatrick            print("ERROR", file=sbuf)
1055061da546Spatrick
1056061da546Spatrick    def markCleanupError(self):
1057061da546Spatrick        """Callback invoked when an error occurs while a test is cleaning up."""
1058061da546Spatrick        self.__cleanup_errored__ = True
1059061da546Spatrick        with recording(self, False) as sbuf:
1060061da546Spatrick            # False because there's no need to write "CLEANUP_ERROR" to the stderr twice.
1061061da546Spatrick            # Once by the Python unittest framework, and a second time by us.
1062061da546Spatrick            print("CLEANUP_ERROR", file=sbuf)
1063061da546Spatrick
1064061da546Spatrick    def markFailure(self):
1065061da546Spatrick        """Callback invoked when a failure (test assertion failure) occurred."""
1066061da546Spatrick        self.__failed__ = True
1067061da546Spatrick        with recording(self, False) as sbuf:
1068061da546Spatrick            # False because there's no need to write "FAIL" to the stderr twice.
1069061da546Spatrick            # Once by the Python unittest framework, and a second time by us.
1070061da546Spatrick            print("FAIL", file=sbuf)
1071061da546Spatrick
1072061da546Spatrick    def markExpectedFailure(self, err, bugnumber):
1073061da546Spatrick        """Callback invoked when an expected failure/error occurred."""
1074061da546Spatrick        self.__expected__ = True
1075061da546Spatrick        with recording(self, False) as sbuf:
1076061da546Spatrick            # False because there's no need to write "expected failure" to the
1077061da546Spatrick            # stderr twice.
1078061da546Spatrick            # Once by the Python unittest framework, and a second time by us.
1079061da546Spatrick            if bugnumber is None:
1080061da546Spatrick                print("expected failure", file=sbuf)
1081061da546Spatrick            else:
1082061da546Spatrick                print(
1083061da546Spatrick                    "expected failure (problem id:" + str(bugnumber) + ")",
1084061da546Spatrick                    file=sbuf)
1085061da546Spatrick
1086061da546Spatrick    def markSkippedTest(self):
1087061da546Spatrick        """Callback invoked when a test is skipped."""
1088061da546Spatrick        self.__skipped__ = True
1089061da546Spatrick        with recording(self, False) as sbuf:
1090061da546Spatrick            # False because there's no need to write "skipped test" to the
1091061da546Spatrick            # stderr twice.
1092061da546Spatrick            # Once by the Python unittest framework, and a second time by us.
1093061da546Spatrick            print("skipped test", file=sbuf)
1094061da546Spatrick
1095061da546Spatrick    def markUnexpectedSuccess(self, bugnumber):
1096061da546Spatrick        """Callback invoked when an unexpected success occurred."""
1097061da546Spatrick        self.__unexpected__ = True
1098061da546Spatrick        with recording(self, False) as sbuf:
1099061da546Spatrick            # False because there's no need to write "unexpected success" to the
1100061da546Spatrick            # stderr twice.
1101061da546Spatrick            # Once by the Python unittest framework, and a second time by us.
1102061da546Spatrick            if bugnumber is None:
1103061da546Spatrick                print("unexpected success", file=sbuf)
1104061da546Spatrick            else:
1105061da546Spatrick                print(
1106061da546Spatrick                    "unexpected success (problem id:" + str(bugnumber) + ")",
1107061da546Spatrick                    file=sbuf)
1108061da546Spatrick
1109061da546Spatrick    def getRerunArgs(self):
1110061da546Spatrick        return " -f %s.%s" % (self.__class__.__name__, self._testMethodName)
1111061da546Spatrick
1112be691f3bSpatrick    def getLogBasenameForCurrentTest(self, prefix="Incomplete"):
1113061da546Spatrick        """
1114061da546Spatrick        returns a partial path that can be used as the beginning of the name of multiple
1115061da546Spatrick        log files pertaining to this test
1116061da546Spatrick        """
1117be691f3bSpatrick        return os.path.join(self.getBuildDir(), prefix)
1118061da546Spatrick
1119061da546Spatrick    def dumpSessionInfo(self):
1120061da546Spatrick        """
1121061da546Spatrick        Dump the debugger interactions leading to a test error/failure.  This
1122061da546Spatrick        allows for more convenient postmortem analysis.
1123061da546Spatrick
1124061da546Spatrick        See also LLDBTestResult (dotest.py) which is a singlton class derived
1125061da546Spatrick        from TextTestResult and overwrites addError, addFailure, and
1126061da546Spatrick        addExpectedFailure methods to allow us to to mark the test instance as
1127061da546Spatrick        such.
1128061da546Spatrick        """
1129061da546Spatrick
1130061da546Spatrick        # We are here because self.tearDown() detected that this test instance
1131061da546Spatrick        # either errored or failed.  The lldb.test_result singleton contains
1132dda28197Spatrick        # two lists (errors and failures) which get populated by the unittest
1133061da546Spatrick        # framework.  Look over there for stack trace information.
1134061da546Spatrick        #
1135061da546Spatrick        # The lists contain 2-tuples of TestCase instances and strings holding
1136061da546Spatrick        # formatted tracebacks.
1137061da546Spatrick        #
1138061da546Spatrick        # See http://docs.python.org/library/unittest.html#unittest.TestResult.
1139061da546Spatrick
1140061da546Spatrick        # output tracebacks into session
1141061da546Spatrick        pairs = []
1142061da546Spatrick        if self.__errored__:
1143061da546Spatrick            pairs = configuration.test_result.errors
1144061da546Spatrick            prefix = 'Error'
1145061da546Spatrick        elif self.__cleanup_errored__:
1146061da546Spatrick            pairs = configuration.test_result.cleanup_errors
1147061da546Spatrick            prefix = 'CleanupError'
1148061da546Spatrick        elif self.__failed__:
1149061da546Spatrick            pairs = configuration.test_result.failures
1150061da546Spatrick            prefix = 'Failure'
1151061da546Spatrick        elif self.__expected__:
1152061da546Spatrick            pairs = configuration.test_result.expectedFailures
1153061da546Spatrick            prefix = 'ExpectedFailure'
1154061da546Spatrick        elif self.__skipped__:
1155061da546Spatrick            prefix = 'SkippedTest'
1156061da546Spatrick        elif self.__unexpected__:
1157061da546Spatrick            prefix = 'UnexpectedSuccess'
1158061da546Spatrick        else:
1159061da546Spatrick            prefix = 'Success'
1160061da546Spatrick
1161061da546Spatrick        if not self.__unexpected__ and not self.__skipped__:
1162061da546Spatrick            for test, traceback in pairs:
1163061da546Spatrick                if test is self:
1164061da546Spatrick                    print(traceback, file=self.session)
1165061da546Spatrick
1166061da546Spatrick        import datetime
1167061da546Spatrick        print(
1168061da546Spatrick            "Session info generated @",
1169061da546Spatrick            datetime.datetime.now().ctime(),
1170061da546Spatrick            file=self.session)
1171061da546Spatrick        self.session.close()
1172061da546Spatrick        del self.session
1173061da546Spatrick
1174061da546Spatrick        # process the log files
1175061da546Spatrick        if prefix != 'Success' or lldbtest_config.log_success:
1176061da546Spatrick            # keep all log files, rename them to include prefix
1177be691f3bSpatrick            src_log_basename = self.getLogBasenameForCurrentTest()
1178061da546Spatrick            dst_log_basename = self.getLogBasenameForCurrentTest(prefix)
1179dda28197Spatrick            for src in self.log_files:
1180061da546Spatrick                if os.path.isfile(src):
1181dda28197Spatrick                    dst = src.replace(src_log_basename, dst_log_basename)
1182061da546Spatrick                    if os.name == "nt" and os.path.isfile(dst):
1183061da546Spatrick                        # On Windows, renaming a -> b will throw an exception if
1184061da546Spatrick                        # b exists.  On non-Windows platforms it silently
1185061da546Spatrick                        # replaces the destination.  Ultimately this means that
1186061da546Spatrick                        # atomic renames are not guaranteed to be possible on
1187061da546Spatrick                        # Windows, but we need this to work anyway, so just
1188061da546Spatrick                        # remove the destination first if it already exists.
1189061da546Spatrick                        remove_file(dst)
1190061da546Spatrick
1191061da546Spatrick                    lldbutil.mkdir_p(os.path.dirname(dst))
1192061da546Spatrick                    os.rename(src, dst)
1193061da546Spatrick        else:
1194061da546Spatrick            # success!  (and we don't want log files) delete log files
1195dda28197Spatrick            for log_file in self.log_files:
1196dda28197Spatrick                if os.path.isfile(log_file):
1197061da546Spatrick                    remove_file(log_file)
1198061da546Spatrick
1199061da546Spatrick    # ====================================================
1200061da546Spatrick    # Config. methods supported through a plugin interface
1201061da546Spatrick    # (enables reading of the current test configuration)
1202061da546Spatrick    # ====================================================
1203061da546Spatrick
1204061da546Spatrick    def isMIPS(self):
1205061da546Spatrick        """Returns true if the architecture is MIPS."""
1206061da546Spatrick        arch = self.getArchitecture()
1207061da546Spatrick        if re.match("mips", arch):
1208061da546Spatrick            return True
1209061da546Spatrick        return False
1210061da546Spatrick
1211061da546Spatrick    def isPPC64le(self):
1212061da546Spatrick        """Returns true if the architecture is PPC64LE."""
1213061da546Spatrick        arch = self.getArchitecture()
1214061da546Spatrick        if re.match("powerpc64le", arch):
1215061da546Spatrick            return True
1216061da546Spatrick        return False
1217061da546Spatrick
1218be691f3bSpatrick    def getCPUInfo(self):
1219be691f3bSpatrick        triple = self.dbg.GetSelectedPlatform().GetTriple()
1220be691f3bSpatrick
1221be691f3bSpatrick        # TODO other platforms, please implement this function
1222be691f3bSpatrick        if not re.match(".*-.*-linux", triple):
1223be691f3bSpatrick            return ""
1224be691f3bSpatrick
1225be691f3bSpatrick        # Need to do something different for non-Linux/Android targets
1226be691f3bSpatrick        cpuinfo_path = self.getBuildArtifact("cpuinfo")
1227be691f3bSpatrick        if configuration.lldb_platform_name:
1228be691f3bSpatrick            self.runCmd('platform get-file "/proc/cpuinfo" ' + cpuinfo_path)
1229be691f3bSpatrick        else:
1230be691f3bSpatrick            cpuinfo_path = "/proc/cpuinfo"
1231be691f3bSpatrick
1232be691f3bSpatrick        try:
1233be691f3bSpatrick            with open(cpuinfo_path, 'r') as f:
1234be691f3bSpatrick                cpuinfo = f.read()
1235be691f3bSpatrick        except:
1236be691f3bSpatrick            return ""
1237be691f3bSpatrick
1238be691f3bSpatrick        return cpuinfo
1239be691f3bSpatrick
1240be691f3bSpatrick    def isAArch64(self):
1241be691f3bSpatrick        """Returns true if the architecture is AArch64."""
1242*f6aab3d8Srobert        arch = self.getArchitecture().lower()
1243*f6aab3d8Srobert        return arch in ["aarch64", "arm64", "arm64e"]
1244be691f3bSpatrick
1245be691f3bSpatrick    def isAArch64SVE(self):
1246be691f3bSpatrick        return self.isAArch64() and "sve" in self.getCPUInfo()
1247be691f3bSpatrick
1248be691f3bSpatrick    def isAArch64MTE(self):
1249be691f3bSpatrick        return self.isAArch64() and "mte" in self.getCPUInfo()
1250be691f3bSpatrick
1251be691f3bSpatrick    def isAArch64PAuth(self):
1252*f6aab3d8Srobert        if self.getArchitecture() == "arm64e":
1253*f6aab3d8Srobert            return True
1254be691f3bSpatrick        return self.isAArch64() and "paca" in self.getCPUInfo()
1255be691f3bSpatrick
1256061da546Spatrick    def getArchitecture(self):
1257061da546Spatrick        """Returns the architecture in effect the test suite is running with."""
1258061da546Spatrick        module = builder_module()
1259061da546Spatrick        arch = module.getArchitecture()
1260061da546Spatrick        if arch == 'amd64':
1261061da546Spatrick            arch = 'x86_64'
1262dda28197Spatrick        if arch in ['armv7l', 'armv8l'] :
1263dda28197Spatrick            arch = 'arm'
1264061da546Spatrick        return arch
1265061da546Spatrick
1266061da546Spatrick    def getLldbArchitecture(self):
1267061da546Spatrick        """Returns the architecture of the lldb binary."""
1268061da546Spatrick        if not hasattr(self, 'lldbArchitecture'):
1269061da546Spatrick
1270*f6aab3d8Srobert            # These two target settings prevent lldb from doing setup that does
1271*f6aab3d8Srobert            # nothing but slow down the end goal of printing the architecture.
1272061da546Spatrick            command = [
1273061da546Spatrick                lldbtest_config.lldbExec,
1274*f6aab3d8Srobert                "-x",
1275*f6aab3d8Srobert                "-b",
1276*f6aab3d8Srobert                "-o", "settings set target.preload-symbols false",
1277*f6aab3d8Srobert                "-o", "settings set target.load-script-from-symbol-file false",
1278*f6aab3d8Srobert                "-o", "file " + lldbtest_config.lldbExec,
1279061da546Spatrick            ]
1280061da546Spatrick
1281061da546Spatrick            output = check_output(command)
1282*f6aab3d8Srobert            str = output.decode()
1283061da546Spatrick
1284061da546Spatrick            for line in str.splitlines():
1285061da546Spatrick                m = re.search(
1286*f6aab3d8Srobert                    r"Current executable set to '.*' \((.*)\)\.", line)
1287061da546Spatrick                if m:
1288061da546Spatrick                    self.lldbArchitecture = m.group(1)
1289061da546Spatrick                    break
1290061da546Spatrick
1291061da546Spatrick        return self.lldbArchitecture
1292061da546Spatrick
1293061da546Spatrick    def getCompiler(self):
1294061da546Spatrick        """Returns the compiler in effect the test suite is running with."""
1295061da546Spatrick        module = builder_module()
1296061da546Spatrick        return module.getCompiler()
1297061da546Spatrick
1298061da546Spatrick    def getCompilerBinary(self):
1299061da546Spatrick        """Returns the compiler binary the test suite is running with."""
1300061da546Spatrick        return self.getCompiler().split()[0]
1301061da546Spatrick
1302061da546Spatrick    def getCompilerVersion(self):
1303061da546Spatrick        """ Returns a string that represents the compiler version.
1304061da546Spatrick            Supports: llvm, clang.
1305061da546Spatrick        """
1306061da546Spatrick        compiler = self.getCompilerBinary()
1307*f6aab3d8Srobert        version_output = check_output([compiler, "--version"], errors="replace")
1308*f6aab3d8Srobert        m = re.search('version ([0-9.]+)', version_output)
1309061da546Spatrick        if m:
1310be691f3bSpatrick            return m.group(1)
1311be691f3bSpatrick        return 'unknown'
1312061da546Spatrick
1313061da546Spatrick    def getDwarfVersion(self):
1314061da546Spatrick        """ Returns the dwarf version generated by clang or '0'. """
1315061da546Spatrick        if configuration.dwarf_version:
1316061da546Spatrick            return str(configuration.dwarf_version)
1317061da546Spatrick        if 'clang' in self.getCompiler():
1318061da546Spatrick            try:
1319*f6aab3d8Srobert                triple = builder_module().getTriple(self.getArchitecture())
1320*f6aab3d8Srobert                target = ['-target', triple] if triple else []
1321061da546Spatrick                driver_output = check_output(
1322*f6aab3d8Srobert                    [self.getCompiler()] + target + '-g -c -x c - -o - -###'.split(),
1323061da546Spatrick                    stderr=STDOUT)
1324061da546Spatrick                driver_output = driver_output.decode("utf-8")
1325061da546Spatrick                for line in driver_output.split(os.linesep):
1326061da546Spatrick                    m = re.search('dwarf-version=([0-9])', line)
1327061da546Spatrick                    if m:
1328061da546Spatrick                        return m.group(1)
1329*f6aab3d8Srobert            except CalledProcessError:
1330*f6aab3d8Srobert                pass
1331061da546Spatrick        return '0'
1332061da546Spatrick
1333061da546Spatrick    def platformIsDarwin(self):
1334061da546Spatrick        """Returns true if the OS triple for the selected platform is any valid apple OS"""
1335061da546Spatrick        return lldbplatformutil.platformIsDarwin()
1336061da546Spatrick
1337061da546Spatrick    def hasDarwinFramework(self):
1338061da546Spatrick        return self.darwinWithFramework
1339061da546Spatrick
1340061da546Spatrick    def getPlatform(self):
1341061da546Spatrick        """Returns the target platform the test suite is running on."""
1342061da546Spatrick        return lldbplatformutil.getPlatform()
1343061da546Spatrick
1344061da546Spatrick    def isIntelCompiler(self):
1345061da546Spatrick        """ Returns true if using an Intel (ICC) compiler, false otherwise. """
1346061da546Spatrick        return any([x in self.getCompiler() for x in ["icc", "icpc", "icl"]])
1347061da546Spatrick
1348061da546Spatrick    def expectedCompilerVersion(self, compiler_version):
1349061da546Spatrick        """Returns True iff compiler_version[1] matches the current compiler version.
1350061da546Spatrick           Use compiler_version[0] to specify the operator used to determine if a match has occurred.
1351061da546Spatrick           Any operator other than the following defaults to an equality test:
1352061da546Spatrick             '>', '>=', "=>", '<', '<=', '=<', '!=', "!" or 'not'
1353be691f3bSpatrick
1354be691f3bSpatrick           If the current compiler version cannot be determined, we assume it is close to the top
1355be691f3bSpatrick           of trunk, so any less-than or equal-to comparisons will return False, and any
1356be691f3bSpatrick           greater-than or not-equal-to comparisons will return True.
1357061da546Spatrick        """
1358be691f3bSpatrick        if compiler_version is None:
1359061da546Spatrick            return True
1360061da546Spatrick        operator = str(compiler_version[0])
1361061da546Spatrick        version = compiler_version[1]
1362061da546Spatrick
1363be691f3bSpatrick        if version is None:
1364061da546Spatrick            return True
1365be691f3bSpatrick
1366be691f3bSpatrick        test_compiler_version = self.getCompilerVersion()
1367be691f3bSpatrick        if test_compiler_version == 'unknown':
1368be691f3bSpatrick            # Assume the compiler version is at or near the top of trunk.
1369be691f3bSpatrick            return operator in ['>', '>=', '!', '!=', 'not']
1370be691f3bSpatrick
1371be691f3bSpatrick        if operator == '>':
1372be691f3bSpatrick            return LooseVersion(test_compiler_version) > LooseVersion(version)
1373be691f3bSpatrick        if operator == '>=' or operator == '=>':
1374be691f3bSpatrick            return LooseVersion(test_compiler_version) >= LooseVersion(version)
1375be691f3bSpatrick        if operator == '<':
1376be691f3bSpatrick            return LooseVersion(test_compiler_version) < LooseVersion(version)
1377be691f3bSpatrick        if operator == '<=' or operator == '=<':
1378be691f3bSpatrick            return LooseVersion(test_compiler_version) <= LooseVersion(version)
1379be691f3bSpatrick        if operator == '!=' or operator == '!' or operator == 'not':
1380be691f3bSpatrick            return str(version) not in str(test_compiler_version)
1381be691f3bSpatrick        return str(version) in str(test_compiler_version)
1382061da546Spatrick
1383061da546Spatrick    def expectedCompiler(self, compilers):
1384061da546Spatrick        """Returns True iff any element of compilers is a sub-string of the current compiler."""
1385061da546Spatrick        if (compilers is None):
1386061da546Spatrick            return True
1387061da546Spatrick
1388061da546Spatrick        for compiler in compilers:
1389061da546Spatrick            if compiler in self.getCompiler():
1390061da546Spatrick                return True
1391061da546Spatrick
1392061da546Spatrick        return False
1393061da546Spatrick
1394061da546Spatrick    def expectedArch(self, archs):
1395061da546Spatrick        """Returns True iff any element of archs is a sub-string of the current architecture."""
1396061da546Spatrick        if (archs is None):
1397061da546Spatrick            return True
1398061da546Spatrick
1399061da546Spatrick        for arch in archs:
1400061da546Spatrick            if arch in self.getArchitecture():
1401061da546Spatrick                return True
1402061da546Spatrick
1403061da546Spatrick        return False
1404061da546Spatrick
1405061da546Spatrick    def getRunOptions(self):
1406061da546Spatrick        """Command line option for -A and -C to run this test again, called from
1407061da546Spatrick        self.dumpSessionInfo()."""
1408061da546Spatrick        arch = self.getArchitecture()
1409061da546Spatrick        comp = self.getCompiler()
1410061da546Spatrick        option_str = ""
1411061da546Spatrick        if arch:
1412061da546Spatrick            option_str = "-A " + arch
1413061da546Spatrick        if comp:
1414061da546Spatrick            option_str += " -C " + comp
1415061da546Spatrick        return option_str
1416061da546Spatrick
1417061da546Spatrick    def getDebugInfo(self):
1418061da546Spatrick        method = getattr(self, self.testMethodName)
1419061da546Spatrick        return getattr(method, "debug_info", None)
1420061da546Spatrick
1421*f6aab3d8Srobert    def build(
1422*f6aab3d8Srobert            self,
1423*f6aab3d8Srobert            debug_info=None,
1424*f6aab3d8Srobert            architecture=None,
1425*f6aab3d8Srobert            compiler=None,
1426*f6aab3d8Srobert            dictionary=None,
1427*f6aab3d8Srobert            make_targets=None):
1428*f6aab3d8Srobert        """Platform specific way to build binaries."""
1429*f6aab3d8Srobert        if not architecture and configuration.arch:
1430*f6aab3d8Srobert            architecture = configuration.arch
1431*f6aab3d8Srobert
1432*f6aab3d8Srobert        if debug_info is None:
1433*f6aab3d8Srobert            debug_info = self.getDebugInfo()
1434*f6aab3d8Srobert
1435*f6aab3d8Srobert        dictionary = lldbplatformutil.finalize_build_dictionary(dictionary)
1436*f6aab3d8Srobert
1437*f6aab3d8Srobert        testdir = self.mydir
1438*f6aab3d8Srobert        testname = self.getBuildDirBasename()
1439*f6aab3d8Srobert
1440*f6aab3d8Srobert        module = builder_module()
1441*f6aab3d8Srobert        command = builder_module().getBuildCommand(debug_info, architecture,
1442*f6aab3d8Srobert                compiler, dictionary, testdir, testname, make_targets)
1443*f6aab3d8Srobert        if command is None:
1444*f6aab3d8Srobert            raise Exception("Don't know how to build binary")
1445*f6aab3d8Srobert
1446*f6aab3d8Srobert        self.runBuildCommand(command)
1447*f6aab3d8Srobert
1448*f6aab3d8Srobert    def runBuildCommand(self, command):
1449*f6aab3d8Srobert        self.trace(seven.join_for_shell(command))
1450*f6aab3d8Srobert        try:
1451*f6aab3d8Srobert            output = check_output(command, stderr=STDOUT, errors="replace")
1452*f6aab3d8Srobert        except CalledProcessError as cpe:
1453*f6aab3d8Srobert            raise build_exception.BuildError(cpe)
1454*f6aab3d8Srobert        self.trace(output)
1455*f6aab3d8Srobert
1456*f6aab3d8Srobert
1457061da546Spatrick    # ==================================================
1458061da546Spatrick    # Build methods supported through a plugin interface
1459061da546Spatrick    # ==================================================
1460061da546Spatrick
1461061da546Spatrick    def getstdlibFlag(self):
1462061da546Spatrick        """ Returns the proper -stdlib flag, or empty if not required."""
1463061da546Spatrick        if self.platformIsDarwin() or self.getPlatform() == "freebsd" or self.getPlatform() == "openbsd":
1464061da546Spatrick            stdlibflag = "-stdlib=libc++"
1465061da546Spatrick        else:  # this includes NetBSD
1466061da546Spatrick            stdlibflag = ""
1467061da546Spatrick        return stdlibflag
1468061da546Spatrick
1469061da546Spatrick    def getstdFlag(self):
1470061da546Spatrick        """ Returns the proper stdflag. """
1471061da546Spatrick        if "gcc" in self.getCompiler() and "4.6" in self.getCompilerVersion():
1472061da546Spatrick            stdflag = "-std=c++0x"
1473061da546Spatrick        else:
1474061da546Spatrick            stdflag = "-std=c++11"
1475061da546Spatrick        return stdflag
1476061da546Spatrick
1477061da546Spatrick    def buildDriver(self, sources, exe_name):
1478061da546Spatrick        """ Platform-specific way to build a program that links with LLDB (via the liblldb.so
1479061da546Spatrick            or LLDB.framework).
1480061da546Spatrick        """
1481061da546Spatrick        stdflag = self.getstdFlag()
1482061da546Spatrick        stdlibflag = self.getstdlibFlag()
1483061da546Spatrick
1484dda28197Spatrick        lib_dir = configuration.lldb_libs_dir
1485061da546Spatrick        if self.hasDarwinFramework():
1486061da546Spatrick            d = {'CXX_SOURCES': sources,
1487061da546Spatrick                 'EXE': exe_name,
1488061da546Spatrick                 'CFLAGS_EXTRAS': "%s %s" % (stdflag, stdlibflag),
1489061da546Spatrick                 'FRAMEWORK_INCLUDES': "-F%s" % self.framework_dir,
1490be691f3bSpatrick                 'LD_EXTRAS': "%s -Wl,-rpath,%s" % (self.lib_lldb, self.framework_dir),
1491061da546Spatrick                 }
1492061da546Spatrick        elif sys.platform.startswith('win'):
1493061da546Spatrick            d = {
1494061da546Spatrick                'CXX_SOURCES': sources,
1495061da546Spatrick                'EXE': exe_name,
1496061da546Spatrick                'CFLAGS_EXTRAS': "%s %s -I%s" % (stdflag,
1497061da546Spatrick                                                 stdlibflag,
1498061da546Spatrick                                                 os.path.join(
1499061da546Spatrick                                                     os.environ["LLDB_SRC"],
1500061da546Spatrick                                                     "include")),
1501be691f3bSpatrick                'LD_EXTRAS': "-L%s -lliblldb" % lib_dir}
1502061da546Spatrick        else:
1503061da546Spatrick            d = {
1504061da546Spatrick                'CXX_SOURCES': sources,
1505061da546Spatrick                'EXE': exe_name,
1506061da546Spatrick                'CFLAGS_EXTRAS': "%s %s -I%s" % (stdflag,
1507061da546Spatrick                                                 stdlibflag,
1508061da546Spatrick                                                 os.path.join(
1509061da546Spatrick                                                     os.environ["LLDB_SRC"],
1510061da546Spatrick                                                     "include")),
1511dda28197Spatrick                'LD_EXTRAS': "-L%s -llldb -Wl,-rpath,%s" % (lib_dir, lib_dir)}
1512061da546Spatrick        if self.TraceOn():
1513061da546Spatrick            print(
1514061da546Spatrick                "Building LLDB Driver (%s) from sources %s" %
1515061da546Spatrick                (exe_name, sources))
1516061da546Spatrick
1517*f6aab3d8Srobert        self.build(dictionary=d)
1518061da546Spatrick
1519061da546Spatrick    def buildLibrary(self, sources, lib_name):
1520061da546Spatrick        """Platform specific way to build a default library. """
1521061da546Spatrick
1522061da546Spatrick        stdflag = self.getstdFlag()
1523061da546Spatrick
1524dda28197Spatrick        lib_dir = configuration.lldb_libs_dir
1525061da546Spatrick        if self.hasDarwinFramework():
1526061da546Spatrick            d = {'DYLIB_CXX_SOURCES': sources,
1527061da546Spatrick                 'DYLIB_NAME': lib_name,
1528061da546Spatrick                 'CFLAGS_EXTRAS': "%s -stdlib=libc++" % stdflag,
1529061da546Spatrick                 'FRAMEWORK_INCLUDES': "-F%s" % self.framework_dir,
1530be691f3bSpatrick                 'LD_EXTRAS': "%s -Wl,-rpath,%s -dynamiclib" % (self.lib_lldb, self.framework_dir),
1531061da546Spatrick                 }
1532061da546Spatrick        elif self.getPlatform() == 'windows':
1533061da546Spatrick            d = {
1534061da546Spatrick                'DYLIB_CXX_SOURCES': sources,
1535061da546Spatrick                'DYLIB_NAME': lib_name,
1536061da546Spatrick                'CFLAGS_EXTRAS': "%s -I%s " % (stdflag,
1537061da546Spatrick                                               os.path.join(
1538061da546Spatrick                                                   os.environ["LLDB_SRC"],
1539061da546Spatrick                                                   "include")),
1540be691f3bSpatrick                'LD_EXTRAS': "-shared -l%s\liblldb.lib" % lib_dir}
1541061da546Spatrick        else:
1542061da546Spatrick            d = {
1543061da546Spatrick                'DYLIB_CXX_SOURCES': sources,
1544061da546Spatrick                'DYLIB_NAME': lib_name,
1545061da546Spatrick                'CFLAGS_EXTRAS': "%s -I%s -fPIC" % (stdflag,
1546061da546Spatrick                                                    os.path.join(
1547061da546Spatrick                                                        os.environ["LLDB_SRC"],
1548061da546Spatrick                                                        "include")),
1549dda28197Spatrick                'LD_EXTRAS': "-shared -L%s -llldb -Wl,-rpath,%s" % (lib_dir, lib_dir)}
1550061da546Spatrick        if self.TraceOn():
1551061da546Spatrick            print(
1552061da546Spatrick                "Building LLDB Library (%s) from sources %s" %
1553061da546Spatrick                (lib_name, sources))
1554061da546Spatrick
1555*f6aab3d8Srobert        self.build(dictionary=d)
1556061da546Spatrick
1557061da546Spatrick    def buildProgram(self, sources, exe_name):
1558061da546Spatrick        """ Platform specific way to build an executable from C/C++ sources. """
1559061da546Spatrick        d = {'CXX_SOURCES': sources,
1560061da546Spatrick             'EXE': exe_name}
1561*f6aab3d8Srobert        self.build(dictionary=d)
1562061da546Spatrick
1563061da546Spatrick    def signBinary(self, binary_path):
1564061da546Spatrick        if sys.platform.startswith("darwin"):
1565061da546Spatrick            codesign_cmd = "codesign --force --sign \"%s\" %s" % (
1566061da546Spatrick                lldbtest_config.codesign_identity, binary_path)
1567061da546Spatrick            call(codesign_cmd, shell=True)
1568061da546Spatrick
1569061da546Spatrick    def findBuiltClang(self):
1570061da546Spatrick        """Tries to find and use Clang from the build directory as the compiler (instead of the system compiler)."""
1571061da546Spatrick        paths_to_try = [
1572061da546Spatrick            "llvm-build/Release+Asserts/x86_64/bin/clang",
1573061da546Spatrick            "llvm-build/Debug+Asserts/x86_64/bin/clang",
1574061da546Spatrick            "llvm-build/Release/x86_64/bin/clang",
1575061da546Spatrick            "llvm-build/Debug/x86_64/bin/clang",
1576061da546Spatrick        ]
1577061da546Spatrick        lldb_root_path = os.path.join(
1578061da546Spatrick            os.path.dirname(__file__), "..", "..", "..", "..")
1579061da546Spatrick        for p in paths_to_try:
1580061da546Spatrick            path = os.path.join(lldb_root_path, p)
1581061da546Spatrick            if os.path.exists(path):
1582061da546Spatrick                return path
1583061da546Spatrick
1584061da546Spatrick        # Tries to find clang at the same folder as the lldb
1585061da546Spatrick        lldb_dir = os.path.dirname(lldbtest_config.lldbExec)
1586*f6aab3d8Srobert        path = shutil.which("clang", path=lldb_dir)
1587061da546Spatrick        if path is not None:
1588061da546Spatrick            return path
1589061da546Spatrick
1590061da546Spatrick        return os.environ["CC"]
1591061da546Spatrick
1592061da546Spatrick
1593*f6aab3d8Srobert    def yaml2obj(self, yaml_path, obj_path, max_size=None):
1594061da546Spatrick        """
1595061da546Spatrick        Create an object file at the given path from a yaml file.
1596061da546Spatrick
1597061da546Spatrick        Throws subprocess.CalledProcessError if the object could not be created.
1598061da546Spatrick        """
1599dda28197Spatrick        yaml2obj_bin = configuration.get_yaml2obj_path()
1600dda28197Spatrick        if not yaml2obj_bin:
1601be691f3bSpatrick            self.assertTrue(False, "No valid yaml2obj executable specified")
1602dda28197Spatrick        command = [yaml2obj_bin, "-o=%s" % obj_path, yaml_path]
1603*f6aab3d8Srobert        if max_size is not None:
1604*f6aab3d8Srobert            command += ["--max-size=%d" % max_size]
1605*f6aab3d8Srobert        self.runBuildCommand(command)
1606061da546Spatrick
1607061da546Spatrick    def cleanup(self, dictionary=None):
1608061da546Spatrick        """Platform specific way to do cleanup after build."""
1609061da546Spatrick        module = builder_module()
1610*f6aab3d8Srobert        if not module.cleanup(dictionary):
1611061da546Spatrick            raise Exception(
1612061da546Spatrick                "Don't know how to do cleanup with dictionary: " +
1613061da546Spatrick                dictionary)
1614061da546Spatrick
1615be691f3bSpatrick    def invoke(self, obj, name, trace=False):
1616be691f3bSpatrick        """Use reflection to call a method dynamically with no argument."""
1617be691f3bSpatrick        trace = (True if traceAlways else trace)
1618be691f3bSpatrick
1619be691f3bSpatrick        method = getattr(obj, name)
1620be691f3bSpatrick        import inspect
1621be691f3bSpatrick        self.assertTrue(inspect.ismethod(method),
1622be691f3bSpatrick                        name + "is a method name of object: " + str(obj))
1623be691f3bSpatrick        result = method()
1624be691f3bSpatrick        with recording(self, trace) as sbuf:
1625be691f3bSpatrick            print(str(method) + ":", result, file=sbuf)
1626be691f3bSpatrick        return result
1627be691f3bSpatrick
1628061da546Spatrick    def getLLDBLibraryEnvVal(self):
1629061da546Spatrick        """ Returns the path that the OS-specific library search environment variable
1630061da546Spatrick            (self.dylibPath) should be set to in order for a program to find the LLDB
1631061da546Spatrick            library. If an environment variable named self.dylibPath is already set,
1632061da546Spatrick            the new path is appended to it and returned.
1633061da546Spatrick        """
1634061da546Spatrick        existing_library_path = os.environ[
1635061da546Spatrick            self.dylibPath] if self.dylibPath in os.environ else None
1636061da546Spatrick        if existing_library_path:
1637be691f3bSpatrick            return "%s:%s" % (existing_library_path, configuration.lldb_libs_dir)
1638be691f3bSpatrick        if sys.platform.startswith("darwin") and configuration.lldb_framework_path:
1639be691f3bSpatrick            return configuration.lldb_framework_path
1640be691f3bSpatrick        return configuration.lldb_libs_dir
1641061da546Spatrick
1642061da546Spatrick    def getLibcPlusPlusLibs(self):
1643061da546Spatrick        if self.getPlatform() in ('freebsd', 'linux', 'netbsd', 'openbsd'):
1644061da546Spatrick            return ['libc++.so.1']
1645061da546Spatrick        else:
1646061da546Spatrick            return ['libc++.1.dylib', 'libc++abi.']
1647061da546Spatrick
1648be691f3bSpatrick    def run_platform_command(self, cmd):
1649be691f3bSpatrick        platform = self.dbg.GetSelectedPlatform()
1650be691f3bSpatrick        shell_command = lldb.SBPlatformShellCommand(cmd)
1651be691f3bSpatrick        err = platform.Run(shell_command)
1652be691f3bSpatrick        return (err, shell_command.GetStatus(), shell_command.GetOutput())
1653be691f3bSpatrick
1654*f6aab3d8Srobert    def get_stats(self, options=None):
1655*f6aab3d8Srobert        """
1656*f6aab3d8Srobert            Get the output of the "statistics dump" with optional extra options
1657*f6aab3d8Srobert            and return the JSON as a python dictionary.
1658*f6aab3d8Srobert        """
1659*f6aab3d8Srobert        return_obj = lldb.SBCommandReturnObject()
1660*f6aab3d8Srobert        command = "statistics dump "
1661*f6aab3d8Srobert        if options is not None:
1662*f6aab3d8Srobert            command += options
1663*f6aab3d8Srobert        self.ci.HandleCommand(command, return_obj, False)
1664*f6aab3d8Srobert        metrics_json = return_obj.GetOutput()
1665*f6aab3d8Srobert        return json.loads(metrics_json)
1666*f6aab3d8Srobert
1667061da546Spatrick# Metaclass for TestBase to change the list of test metods when a new TestCase is loaded.
1668061da546Spatrick# We change the test methods to create a new test method for each test for each debug info we are
1669061da546Spatrick# testing. The name of the new test method will be '<original-name>_<debug-info>' and with adding
1670061da546Spatrick# the new test method we remove the old method at the same time. This functionality can be
1671061da546Spatrick# supressed by at test case level setting the class attribute NO_DEBUG_INFO_TESTCASE or at test
1672061da546Spatrick# level by using the decorator @no_debug_info_test.
1673061da546Spatrick
1674061da546Spatrick
1675061da546Spatrickclass LLDBTestCaseFactory(type):
1676061da546Spatrick
1677061da546Spatrick    def __new__(cls, name, bases, attrs):
1678061da546Spatrick        original_testcase = super(
1679061da546Spatrick            LLDBTestCaseFactory, cls).__new__(
1680061da546Spatrick            cls, name, bases, attrs)
1681061da546Spatrick        if original_testcase.NO_DEBUG_INFO_TESTCASE:
1682061da546Spatrick            return original_testcase
1683061da546Spatrick
1684061da546Spatrick        newattrs = {}
1685061da546Spatrick        for attrname, attrvalue in attrs.items():
1686061da546Spatrick            if attrname.startswith("test") and not getattr(
1687061da546Spatrick                    attrvalue, "__no_debug_info_test__", False):
1688061da546Spatrick
1689061da546Spatrick                # If any debug info categories were explicitly tagged, assume that list to be
1690061da546Spatrick                # authoritative.  If none were specified, try with all debug
1691061da546Spatrick                # info formats.
1692*f6aab3d8Srobert                all_dbginfo_categories = set(test_categories.debug_info_categories.keys())
1693061da546Spatrick                categories = set(
1694061da546Spatrick                    getattr(
1695061da546Spatrick                        attrvalue,
1696061da546Spatrick                        "categories",
1697061da546Spatrick                        [])) & all_dbginfo_categories
1698061da546Spatrick                if not categories:
1699*f6aab3d8Srobert                    categories = [category for category, can_replicate \
1700*f6aab3d8Srobert                                  in test_categories.debug_info_categories.items() \
1701*f6aab3d8Srobert                                  if can_replicate]
1702061da546Spatrick
1703061da546Spatrick                for cat in categories:
1704061da546Spatrick                    @decorators.add_test_categories([cat])
1705061da546Spatrick                    @wraps(attrvalue)
1706061da546Spatrick                    def test_method(self, attrvalue=attrvalue):
1707061da546Spatrick                        return attrvalue(self)
1708061da546Spatrick
1709061da546Spatrick                    method_name = attrname + "_" + cat
1710061da546Spatrick                    test_method.__name__ = method_name
1711061da546Spatrick                    test_method.debug_info = cat
1712061da546Spatrick                    newattrs[method_name] = test_method
1713061da546Spatrick
1714061da546Spatrick            else:
1715061da546Spatrick                newattrs[attrname] = attrvalue
1716061da546Spatrick        return super(
1717061da546Spatrick            LLDBTestCaseFactory,
1718061da546Spatrick            cls).__new__(
1719061da546Spatrick            cls,
1720061da546Spatrick            name,
1721061da546Spatrick            bases,
1722061da546Spatrick            newattrs)
1723061da546Spatrick
1724061da546Spatrick# Setup the metaclass for this class to change the list of the test
1725061da546Spatrick# methods when a new class is loaded
1726061da546Spatrick
1727061da546Spatrick
1728*f6aab3d8Srobertclass TestBase(Base, metaclass=LLDBTestCaseFactory):
1729061da546Spatrick    """
1730061da546Spatrick    This abstract base class is meant to be subclassed.  It provides default
1731061da546Spatrick    implementations for setUpClass(), tearDownClass(), setUp(), and tearDown(),
1732061da546Spatrick    among other things.
1733061da546Spatrick
1734061da546Spatrick    Important things for test class writers:
1735061da546Spatrick
1736061da546Spatrick        - The setUp method sets up things to facilitate subsequent interactions
1737061da546Spatrick          with the debugger as part of the test.  These include:
1738061da546Spatrick              - populate the test method name
1739061da546Spatrick              - create/get a debugger set with synchronous mode (self.dbg)
1740061da546Spatrick              - get the command interpreter from with the debugger (self.ci)
1741061da546Spatrick              - create a result object for use with the command interpreter
1742061da546Spatrick                (self.res)
1743061da546Spatrick              - plus other stuffs
1744061da546Spatrick
1745061da546Spatrick        - The tearDown method tries to perform some necessary cleanup on behalf
1746061da546Spatrick          of the test to return the debugger to a good state for the next test.
1747061da546Spatrick          These include:
1748061da546Spatrick              - execute any tearDown hooks registered by the test method with
1749061da546Spatrick                TestBase.addTearDownHook(); examples can be found in
1750061da546Spatrick                settings/TestSettings.py
1751061da546Spatrick              - kill the inferior process associated with each target, if any,
1752061da546Spatrick                and, then delete the target from the debugger's target list
1753061da546Spatrick              - perform build cleanup before running the next test method in the
1754061da546Spatrick                same test class; examples of registering for this service can be
1755061da546Spatrick                found in types/TestIntegerTypes.py with the call:
1756061da546Spatrick                    - self.setTearDownCleanup(dictionary=d)
1757061da546Spatrick
1758061da546Spatrick        - Similarly setUpClass and tearDownClass perform classwise setup and
1759061da546Spatrick          teardown fixtures.  The tearDownClass method invokes a default build
1760061da546Spatrick          cleanup for the entire test class;  also, subclasses can implement the
1761061da546Spatrick          classmethod classCleanup(cls) to perform special class cleanup action.
1762061da546Spatrick
1763061da546Spatrick        - The instance methods runCmd and expect are used heavily by existing
1764061da546Spatrick          test cases to send a command to the command interpreter and to perform
1765061da546Spatrick          string/pattern matching on the output of such command execution.  The
1766061da546Spatrick          expect method also provides a mode to peform string/pattern matching
1767061da546Spatrick          without running a command.
1768061da546Spatrick
1769*f6aab3d8Srobert        - The build method is used to build the binaries used during a
1770*f6aab3d8Srobert          particular test scenario.  A plugin should be provided for the
1771*f6aab3d8Srobert          sys.platform running the test suite.  The Mac OS X implementation is
1772*f6aab3d8Srobert          located in builders/darwin.py.
1773061da546Spatrick    """
1774061da546Spatrick
1775061da546Spatrick    # Subclasses can set this to true (if they don't depend on debug info) to avoid running the
1776061da546Spatrick    # test multiple times with various debug info types.
1777061da546Spatrick    NO_DEBUG_INFO_TESTCASE = False
1778061da546Spatrick
1779061da546Spatrick    # Maximum allowed attempts when launching the inferior process.
1780061da546Spatrick    # Can be overridden by the LLDB_MAX_LAUNCH_COUNT environment variable.
1781061da546Spatrick    maxLaunchCount = 1
1782061da546Spatrick
1783061da546Spatrick    # Time to wait before the next launching attempt in second(s).
1784061da546Spatrick    # Can be overridden by the LLDB_TIME_WAIT_NEXT_LAUNCH environment variable.
1785061da546Spatrick    timeWaitNextLaunch = 1.0
1786061da546Spatrick
1787061da546Spatrick    def generateSource(self, source):
1788061da546Spatrick        template = source + '.template'
1789061da546Spatrick        temp = os.path.join(self.getSourceDir(), template)
1790061da546Spatrick        with open(temp, 'r') as f:
1791061da546Spatrick            content = f.read()
1792061da546Spatrick
1793061da546Spatrick        public_api_dir = os.path.join(
1794061da546Spatrick            os.environ["LLDB_SRC"], "include", "lldb", "API")
1795061da546Spatrick
1796061da546Spatrick        # Look under the include/lldb/API directory and add #include statements
1797061da546Spatrick        # for all the SB API headers.
1798061da546Spatrick        public_headers = os.listdir(public_api_dir)
1799061da546Spatrick        # For different platforms, the include statement can vary.
1800061da546Spatrick        if self.hasDarwinFramework():
1801061da546Spatrick            include_stmt = "'#include <%s>' % os.path.join('LLDB', header)"
1802061da546Spatrick        else:
1803*f6aab3d8Srobert            include_stmt = "'#include <%s>' % os.path.join(r'" + public_api_dir + "', header)"
1804061da546Spatrick        list = [eval(include_stmt) for header in public_headers if (
1805061da546Spatrick            header.startswith("SB") and header.endswith(".h"))]
1806061da546Spatrick        includes = '\n'.join(list)
1807061da546Spatrick        new_content = content.replace('%include_SB_APIs%', includes)
1808be691f3bSpatrick        new_content = new_content.replace('%SOURCE_DIR%', self.getSourceDir())
1809061da546Spatrick        src = os.path.join(self.getBuildDir(), source)
1810061da546Spatrick        with open(src, 'w') as f:
1811061da546Spatrick            f.write(new_content)
1812061da546Spatrick
1813061da546Spatrick        self.addTearDownHook(lambda: os.remove(src))
1814061da546Spatrick
1815061da546Spatrick    def setUp(self):
1816061da546Spatrick        # Works with the test driver to conditionally skip tests via
1817061da546Spatrick        # decorators.
1818061da546Spatrick        Base.setUp(self)
1819061da546Spatrick
1820061da546Spatrick        for s in self.setUpCommands():
1821061da546Spatrick            self.runCmd(s)
1822061da546Spatrick
1823061da546Spatrick        if "LLDB_MAX_LAUNCH_COUNT" in os.environ:
1824061da546Spatrick            self.maxLaunchCount = int(os.environ["LLDB_MAX_LAUNCH_COUNT"])
1825061da546Spatrick
1826061da546Spatrick        if "LLDB_TIME_WAIT_NEXT_LAUNCH" in os.environ:
1827061da546Spatrick            self.timeWaitNextLaunch = float(
1828061da546Spatrick                os.environ["LLDB_TIME_WAIT_NEXT_LAUNCH"])
1829061da546Spatrick
1830061da546Spatrick        # We want our debugger to be synchronous.
1831061da546Spatrick        self.dbg.SetAsync(False)
1832061da546Spatrick
1833061da546Spatrick        # Retrieve the associated command interpreter instance.
1834061da546Spatrick        self.ci = self.dbg.GetCommandInterpreter()
1835061da546Spatrick        if not self.ci:
1836061da546Spatrick            raise Exception('Could not get the command interpreter')
1837061da546Spatrick
1838061da546Spatrick        # And the result object.
1839061da546Spatrick        self.res = lldb.SBCommandReturnObject()
1840061da546Spatrick
1841061da546Spatrick    def registerSharedLibrariesWithTarget(self, target, shlibs):
1842061da546Spatrick        '''If we are remotely running the test suite, register the shared libraries with the target so they get uploaded, otherwise do nothing
1843061da546Spatrick
1844061da546Spatrick        Any modules in the target that have their remote install file specification set will
1845061da546Spatrick        get uploaded to the remote host. This function registers the local copies of the
1846061da546Spatrick        shared libraries with the target and sets their remote install locations so they will
1847061da546Spatrick        be uploaded when the target is run.
1848061da546Spatrick        '''
1849061da546Spatrick        if not shlibs or not self.platformContext:
1850061da546Spatrick            return None
1851061da546Spatrick
1852061da546Spatrick        shlib_environment_var = self.platformContext.shlib_environment_var
1853061da546Spatrick        shlib_prefix = self.platformContext.shlib_prefix
1854061da546Spatrick        shlib_extension = '.' + self.platformContext.shlib_extension
1855061da546Spatrick
1856be691f3bSpatrick        dirs = []
1857061da546Spatrick        # Add any shared libraries to our target if remote so they get
1858061da546Spatrick        # uploaded into the working directory on the remote side
1859061da546Spatrick        for name in shlibs:
1860061da546Spatrick            # The path can be a full path to a shared library, or a make file name like "Foo" for
1861061da546Spatrick            # "libFoo.dylib" or "libFoo.so", or "Foo.so" for "Foo.so" or "libFoo.so", or just a
1862061da546Spatrick            # basename like "libFoo.so". So figure out which one it is and resolve the local copy
1863061da546Spatrick            # of the shared library accordingly
1864061da546Spatrick            if os.path.isfile(name):
1865061da546Spatrick                local_shlib_path = name  # name is the full path to the local shared library
1866061da546Spatrick            else:
1867061da546Spatrick                # Check relative names
1868061da546Spatrick                local_shlib_path = os.path.join(
1869061da546Spatrick                    self.getBuildDir(), shlib_prefix + name + shlib_extension)
1870061da546Spatrick                if not os.path.exists(local_shlib_path):
1871061da546Spatrick                    local_shlib_path = os.path.join(
1872061da546Spatrick                        self.getBuildDir(), name + shlib_extension)
1873061da546Spatrick                    if not os.path.exists(local_shlib_path):
1874061da546Spatrick                        local_shlib_path = os.path.join(self.getBuildDir(), name)
1875061da546Spatrick
1876061da546Spatrick                # Make sure we found the local shared library in the above code
1877061da546Spatrick                self.assertTrue(os.path.exists(local_shlib_path))
1878061da546Spatrick
1879be691f3bSpatrick
1880061da546Spatrick            # Add the shared library to our target
1881061da546Spatrick            shlib_module = target.AddModule(local_shlib_path, None, None, None)
1882061da546Spatrick            if lldb.remote_platform:
1883061da546Spatrick                # We must set the remote install location if we want the shared library
1884061da546Spatrick                # to get uploaded to the remote target
1885061da546Spatrick                remote_shlib_path = lldbutil.append_to_process_working_directory(self,
1886061da546Spatrick                    os.path.basename(local_shlib_path))
1887061da546Spatrick                shlib_module.SetRemoteInstallFileSpec(
1888061da546Spatrick                    lldb.SBFileSpec(remote_shlib_path, False))
1889be691f3bSpatrick                dir_to_add = self.get_process_working_directory()
1890be691f3bSpatrick            else:
1891be691f3bSpatrick                dir_to_add = os.path.dirname(local_shlib_path)
1892061da546Spatrick
1893be691f3bSpatrick            if dir_to_add not in dirs:
1894be691f3bSpatrick                dirs.append(dir_to_add)
1895be691f3bSpatrick
1896be691f3bSpatrick        env_value = self.platformContext.shlib_path_separator.join(dirs)
1897be691f3bSpatrick        return ['%s=%s' % (shlib_environment_var, env_value)]
1898061da546Spatrick
1899061da546Spatrick    def registerSanitizerLibrariesWithTarget(self, target):
1900061da546Spatrick        runtimes = []
1901061da546Spatrick        for m in target.module_iter():
1902061da546Spatrick            libspec = m.GetFileSpec()
1903061da546Spatrick            if "clang_rt" in libspec.GetFilename():
1904061da546Spatrick                runtimes.append(os.path.join(libspec.GetDirectory(),
1905061da546Spatrick                                             libspec.GetFilename()))
1906061da546Spatrick        return self.registerSharedLibrariesWithTarget(target, runtimes)
1907061da546Spatrick
1908061da546Spatrick    # utility methods that tests can use to access the current objects
1909061da546Spatrick    def target(self):
1910061da546Spatrick        if not self.dbg:
1911061da546Spatrick            raise Exception('Invalid debugger instance')
1912061da546Spatrick        return self.dbg.GetSelectedTarget()
1913061da546Spatrick
1914061da546Spatrick    def process(self):
1915061da546Spatrick        if not self.dbg:
1916061da546Spatrick            raise Exception('Invalid debugger instance')
1917061da546Spatrick        return self.dbg.GetSelectedTarget().GetProcess()
1918061da546Spatrick
1919061da546Spatrick    def thread(self):
1920061da546Spatrick        if not self.dbg:
1921061da546Spatrick            raise Exception('Invalid debugger instance')
1922061da546Spatrick        return self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread()
1923061da546Spatrick
1924061da546Spatrick    def frame(self):
1925061da546Spatrick        if not self.dbg:
1926061da546Spatrick            raise Exception('Invalid debugger instance')
1927061da546Spatrick        return self.dbg.GetSelectedTarget().GetProcess(
1928061da546Spatrick        ).GetSelectedThread().GetSelectedFrame()
1929061da546Spatrick
1930061da546Spatrick    def get_process_working_directory(self):
1931061da546Spatrick        '''Get the working directory that should be used when launching processes for local or remote processes.'''
1932061da546Spatrick        if lldb.remote_platform:
1933061da546Spatrick            # Remote tests set the platform working directory up in
1934061da546Spatrick            # TestBase.setUp()
1935061da546Spatrick            return lldb.remote_platform.GetWorkingDirectory()
1936061da546Spatrick        else:
1937061da546Spatrick            # local tests change directory into each test subdirectory
1938061da546Spatrick            return self.getBuildDir()
1939061da546Spatrick
1940061da546Spatrick    def tearDown(self):
1941061da546Spatrick        # Ensure all the references to SB objects have gone away so that we can
1942061da546Spatrick        # be sure that all test-specific resources have been freed before we
1943061da546Spatrick        # attempt to delete the targets.
1944061da546Spatrick        gc.collect()
1945061da546Spatrick
1946061da546Spatrick        # Delete the target(s) from the debugger as a general cleanup step.
1947061da546Spatrick        # This includes terminating the process for each target, if any.
1948061da546Spatrick        # We'd like to reuse the debugger for our next test without incurring
1949061da546Spatrick        # the initialization overhead.
1950061da546Spatrick        targets = []
1951061da546Spatrick        for target in self.dbg:
1952061da546Spatrick            if target:
1953061da546Spatrick                targets.append(target)
1954061da546Spatrick                process = target.GetProcess()
1955061da546Spatrick                if process:
1956061da546Spatrick                    rc = self.invoke(process, "Kill")
1957dda28197Spatrick                    assert rc.Success()
1958061da546Spatrick        for target in targets:
1959061da546Spatrick            self.dbg.DeleteTarget(target)
1960061da546Spatrick
1961dda28197Spatrick        # Assert that all targets are deleted.
1962be691f3bSpatrick        self.assertEqual(self.dbg.GetNumTargets(), 0)
1963dda28197Spatrick
1964061da546Spatrick        # Do this last, to make sure it's in reverse order from how we setup.
1965061da546Spatrick        Base.tearDown(self)
1966061da546Spatrick
1967061da546Spatrick    def switch_to_thread_with_stop_reason(self, stop_reason):
1968061da546Spatrick        """
1969061da546Spatrick        Run the 'thread list' command, and select the thread with stop reason as
1970061da546Spatrick        'stop_reason'.  If no such thread exists, no select action is done.
1971061da546Spatrick        """
1972061da546Spatrick        from .lldbutil import stop_reason_to_str
1973061da546Spatrick        self.runCmd('thread list')
1974061da546Spatrick        output = self.res.GetOutput()
1975061da546Spatrick        thread_line_pattern = re.compile(
1976061da546Spatrick            "^[ *] thread #([0-9]+):.*stop reason = %s" %
1977061da546Spatrick            stop_reason_to_str(stop_reason))
1978061da546Spatrick        for line in output.splitlines():
1979061da546Spatrick            matched = thread_line_pattern.match(line)
1980061da546Spatrick            if matched:
1981061da546Spatrick                self.runCmd('thread select %s' % matched.group(1))
1982061da546Spatrick
1983061da546Spatrick    def runCmd(self, cmd, msg=None, check=True, trace=False, inHistory=False):
1984061da546Spatrick        """
1985061da546Spatrick        Ask the command interpreter to handle the command and then check its
1986061da546Spatrick        return status.
1987061da546Spatrick        """
1988061da546Spatrick        # Fail fast if 'cmd' is not meaningful.
1989be691f3bSpatrick        if cmd is None:
1990061da546Spatrick            raise Exception("Bad 'cmd' parameter encountered")
1991061da546Spatrick
1992061da546Spatrick        trace = (True if traceAlways else trace)
1993061da546Spatrick
1994061da546Spatrick        if cmd.startswith("target create "):
1995061da546Spatrick            cmd = cmd.replace("target create ", "file ")
1996061da546Spatrick
1997061da546Spatrick        running = (cmd.startswith("run") or cmd.startswith("process launch"))
1998061da546Spatrick
1999061da546Spatrick        for i in range(self.maxLaunchCount if running else 1):
2000061da546Spatrick            self.ci.HandleCommand(cmd, self.res, inHistory)
2001061da546Spatrick
2002061da546Spatrick            with recording(self, trace) as sbuf:
2003061da546Spatrick                print("runCmd:", cmd, file=sbuf)
2004061da546Spatrick                if not check:
2005061da546Spatrick                    print("check of return status not required", file=sbuf)
2006061da546Spatrick                if self.res.Succeeded():
2007061da546Spatrick                    print("output:", self.res.GetOutput(), file=sbuf)
2008061da546Spatrick                else:
2009061da546Spatrick                    print("runCmd failed!", file=sbuf)
2010061da546Spatrick                    print(self.res.GetError(), file=sbuf)
2011061da546Spatrick
2012061da546Spatrick            if self.res.Succeeded():
2013061da546Spatrick                break
2014061da546Spatrick            elif running:
2015061da546Spatrick                # For process launch, wait some time before possible next try.
2016061da546Spatrick                time.sleep(self.timeWaitNextLaunch)
2017061da546Spatrick                with recording(self, trace) as sbuf:
2018061da546Spatrick                    print("Command '" + cmd + "' failed!", file=sbuf)
2019061da546Spatrick
2020061da546Spatrick        if check:
2021061da546Spatrick            output = ""
2022061da546Spatrick            if self.res.GetOutput():
2023061da546Spatrick                output += "\nCommand output:\n" + self.res.GetOutput()
2024061da546Spatrick            if self.res.GetError():
2025061da546Spatrick                output += "\nError output:\n" + self.res.GetError()
2026061da546Spatrick            if msg:
2027061da546Spatrick                msg += output
2028061da546Spatrick            if cmd:
2029061da546Spatrick                cmd += output
2030061da546Spatrick            self.assertTrue(self.res.Succeeded(),
2031061da546Spatrick                            msg if (msg) else CMD_MSG(cmd))
2032061da546Spatrick
2033061da546Spatrick    def match(
2034061da546Spatrick            self,
2035061da546Spatrick            str,
2036061da546Spatrick            patterns,
2037061da546Spatrick            msg=None,
2038061da546Spatrick            trace=False,
2039061da546Spatrick            error=False,
2040061da546Spatrick            matching=True,
2041061da546Spatrick            exe=True):
2042061da546Spatrick        """run command in str, and match the result against regexp in patterns returning the match object for the first matching pattern
2043061da546Spatrick
2044061da546Spatrick        Otherwise, all the arguments have the same meanings as for the expect function"""
2045061da546Spatrick
2046061da546Spatrick        trace = (True if traceAlways else trace)
2047061da546Spatrick
2048061da546Spatrick        if exe:
2049061da546Spatrick            # First run the command.  If we are expecting error, set check=False.
2050061da546Spatrick            # Pass the assert message along since it provides more semantic
2051061da546Spatrick            # info.
2052061da546Spatrick            self.runCmd(
2053061da546Spatrick                str,
2054061da546Spatrick                msg=msg,
2055061da546Spatrick                trace=(
2056061da546Spatrick                    True if trace else False),
2057061da546Spatrick                check=not error)
2058061da546Spatrick
2059061da546Spatrick            # Then compare the output against expected strings.
2060061da546Spatrick            output = self.res.GetError() if error else self.res.GetOutput()
2061061da546Spatrick
2062061da546Spatrick            # If error is True, the API client expects the command to fail!
2063061da546Spatrick            if error:
2064061da546Spatrick                self.assertFalse(self.res.Succeeded(),
2065061da546Spatrick                                 "Command '" + str + "' is expected to fail!")
2066061da546Spatrick        else:
2067061da546Spatrick            # No execution required, just compare str against the golden input.
2068061da546Spatrick            output = str
2069061da546Spatrick            with recording(self, trace) as sbuf:
2070061da546Spatrick                print("looking at:", output, file=sbuf)
2071061da546Spatrick
2072061da546Spatrick        # The heading says either "Expecting" or "Not expecting".
2073061da546Spatrick        heading = "Expecting" if matching else "Not expecting"
2074061da546Spatrick
2075061da546Spatrick        for pattern in patterns:
2076061da546Spatrick            # Match Objects always have a boolean value of True.
2077061da546Spatrick            match_object = re.search(pattern, output)
2078061da546Spatrick            matched = bool(match_object)
2079061da546Spatrick            with recording(self, trace) as sbuf:
2080061da546Spatrick                print("%s pattern: %s" % (heading, pattern), file=sbuf)
2081061da546Spatrick                print("Matched" if matched else "Not matched", file=sbuf)
2082061da546Spatrick            if matched:
2083061da546Spatrick                break
2084061da546Spatrick
2085061da546Spatrick        self.assertTrue(matched if matching else not matched,
2086061da546Spatrick                        msg if msg else EXP_MSG(str, output, exe))
2087061da546Spatrick
2088061da546Spatrick        return match_object
2089061da546Spatrick
2090dda28197Spatrick    def check_completion_with_desc(self, str_input, match_desc_pairs, enforce_order=False):
2091dda28197Spatrick        """
2092dda28197Spatrick        Checks that when the given input is completed at the given list of
2093dda28197Spatrick        completions and descriptions is returned.
2094dda28197Spatrick        :param str_input: The input that should be completed. The completion happens at the end of the string.
2095dda28197Spatrick        :param match_desc_pairs: A list of pairs that indicate what completions have to be in the list of
2096dda28197Spatrick                                 completions returned by LLDB. The first element of the pair is the completion
2097dda28197Spatrick                                 string that LLDB should generate and the second element the description.
2098dda28197Spatrick        :param enforce_order: True iff the order in which the completions are returned by LLDB
2099dda28197Spatrick                              should match the order of the match_desc_pairs pairs.
2100dda28197Spatrick        """
2101061da546Spatrick        interp = self.dbg.GetCommandInterpreter()
2102061da546Spatrick        match_strings = lldb.SBStringList()
2103061da546Spatrick        description_strings = lldb.SBStringList()
2104061da546Spatrick        num_matches = interp.HandleCompletionWithDescriptions(str_input, len(str_input), 0, -1, match_strings, description_strings)
2105061da546Spatrick        self.assertEqual(len(description_strings), len(match_strings))
2106061da546Spatrick
2107dda28197Spatrick        # The index of the last matched description in description_strings or
2108dda28197Spatrick        # -1 if no description has been matched yet.
2109dda28197Spatrick        last_found_index = -1
2110dda28197Spatrick        out_of_order_errors = ""
2111061da546Spatrick        missing_pairs = []
2112061da546Spatrick        for pair in match_desc_pairs:
2113061da546Spatrick            found_pair = False
2114061da546Spatrick            for i in range(num_matches + 1):
2115061da546Spatrick                match_candidate = match_strings.GetStringAtIndex(i)
2116061da546Spatrick                description_candidate = description_strings.GetStringAtIndex(i)
2117061da546Spatrick                if match_candidate == pair[0] and description_candidate == pair[1]:
2118061da546Spatrick                    found_pair = True
2119dda28197Spatrick                    if enforce_order and last_found_index > i:
2120dda28197Spatrick                        new_err = ("Found completion " + pair[0] + " at index " +
2121dda28197Spatrick                                  str(i) + " in returned completion list but " +
2122dda28197Spatrick                                  "should have been after completion " +
2123dda28197Spatrick                                  match_strings.GetStringAtIndex(last_found_index) +
2124dda28197Spatrick                                  " (index:" + str(last_found_index) + ")\n")
2125dda28197Spatrick                        out_of_order_errors += new_err
2126dda28197Spatrick                    last_found_index = i
2127061da546Spatrick                    break
2128061da546Spatrick            if not found_pair:
2129061da546Spatrick                missing_pairs.append(pair)
2130061da546Spatrick
2131dda28197Spatrick        error_msg = ""
2132dda28197Spatrick        got_failure = False
2133061da546Spatrick        if len(missing_pairs):
2134dda28197Spatrick            got_failure = True
2135dda28197Spatrick            error_msg += "Missing pairs:\n"
2136061da546Spatrick            for pair in missing_pairs:
2137061da546Spatrick                error_msg += " [" + pair[0] + ":" + pair[1] + "]\n"
2138dda28197Spatrick        if len(out_of_order_errors):
2139dda28197Spatrick            got_failure = True
2140dda28197Spatrick            error_msg += out_of_order_errors
2141dda28197Spatrick        if got_failure:
2142061da546Spatrick            error_msg += "Got the following " + str(num_matches) + " completions back:\n"
2143061da546Spatrick            for i in range(num_matches + 1):
2144061da546Spatrick                match_candidate = match_strings.GetStringAtIndex(i)
2145061da546Spatrick                description_candidate = description_strings.GetStringAtIndex(i)
2146dda28197Spatrick                error_msg += "[" + match_candidate + ":" + description_candidate + "] index " + str(i) + "\n"
2147dda28197Spatrick            self.assertFalse(got_failure, error_msg)
2148061da546Spatrick
2149061da546Spatrick    def complete_exactly(self, str_input, patterns):
2150061da546Spatrick        self.complete_from_to(str_input, patterns, True)
2151061da546Spatrick
2152061da546Spatrick    def complete_from_to(self, str_input, patterns, turn_off_re_match=False):
2153061da546Spatrick        """Test that the completion mechanism completes str_input to patterns,
2154061da546Spatrick        where patterns could be a pattern-string or a list of pattern-strings"""
2155061da546Spatrick        # Patterns should not be None in order to proceed.
2156061da546Spatrick        self.assertFalse(patterns is None)
2157061da546Spatrick        # And should be either a string or list of strings.  Check for list type
2158061da546Spatrick        # below, if not, make a list out of the singleton string.  If patterns
2159061da546Spatrick        # is not a string or not a list of strings, there'll be runtime errors
2160061da546Spatrick        # later on.
2161061da546Spatrick        if not isinstance(patterns, list):
2162061da546Spatrick            patterns = [patterns]
2163061da546Spatrick
2164061da546Spatrick        interp = self.dbg.GetCommandInterpreter()
2165061da546Spatrick        match_strings = lldb.SBStringList()
2166061da546Spatrick        num_matches = interp.HandleCompletion(str_input, len(str_input), 0, -1, match_strings)
2167061da546Spatrick        common_match = match_strings.GetStringAtIndex(0)
2168061da546Spatrick        if num_matches == 0:
2169061da546Spatrick            compare_string = str_input
2170061da546Spatrick        else:
2171061da546Spatrick            if common_match != None and len(common_match) > 0:
2172061da546Spatrick                compare_string = str_input + common_match
2173061da546Spatrick            else:
2174061da546Spatrick                compare_string = ""
2175061da546Spatrick                for idx in range(1, num_matches+1):
2176061da546Spatrick                    compare_string += match_strings.GetStringAtIndex(idx) + "\n"
2177061da546Spatrick
2178061da546Spatrick        for p in patterns:
2179061da546Spatrick            if turn_off_re_match:
2180061da546Spatrick                self.expect(
2181061da546Spatrick                    compare_string, msg=COMPLETION_MSG(
2182061da546Spatrick                        str_input, p, match_strings), exe=False, substrs=[p])
2183061da546Spatrick            else:
2184061da546Spatrick                self.expect(
2185061da546Spatrick                    compare_string, msg=COMPLETION_MSG(
2186061da546Spatrick                        str_input, p, match_strings), exe=False, patterns=[p])
2187061da546Spatrick
2188061da546Spatrick    def completions_match(self, command, completions):
2189061da546Spatrick        """Checks that the completions for the given command are equal to the
2190061da546Spatrick        given list of completions"""
2191061da546Spatrick        interp = self.dbg.GetCommandInterpreter()
2192061da546Spatrick        match_strings = lldb.SBStringList()
2193061da546Spatrick        interp.HandleCompletion(command, len(command), 0, -1, match_strings)
2194061da546Spatrick        # match_strings is a 1-indexed list, so we have to slice...
2195061da546Spatrick        self.assertItemsEqual(completions, list(match_strings)[1:],
2196061da546Spatrick                              "List of returned completion is wrong")
2197061da546Spatrick
2198be691f3bSpatrick    def completions_contain(self, command, completions):
2199be691f3bSpatrick        """Checks that the completions for the given command contain the given
2200be691f3bSpatrick        list of completions."""
2201be691f3bSpatrick        interp = self.dbg.GetCommandInterpreter()
2202be691f3bSpatrick        match_strings = lldb.SBStringList()
2203be691f3bSpatrick        interp.HandleCompletion(command, len(command), 0, -1, match_strings)
2204be691f3bSpatrick        for completion in completions:
2205be691f3bSpatrick            # match_strings is a 1-indexed list, so we have to slice...
2206be691f3bSpatrick            self.assertIn(completion, list(match_strings)[1:],
2207be691f3bSpatrick                          "Couldn't find expected completion")
2208be691f3bSpatrick
2209061da546Spatrick    def filecheck(
2210061da546Spatrick            self,
2211061da546Spatrick            command,
2212061da546Spatrick            check_file,
2213061da546Spatrick            filecheck_options = '',
2214061da546Spatrick            expect_cmd_failure = False):
2215061da546Spatrick        # Run the command.
2216061da546Spatrick        self.runCmd(
2217061da546Spatrick                command,
2218061da546Spatrick                check=(not expect_cmd_failure),
2219061da546Spatrick                msg="FileCheck'ing result of `{0}`".format(command))
2220061da546Spatrick
2221061da546Spatrick        self.assertTrue((not expect_cmd_failure) == self.res.Succeeded())
2222061da546Spatrick
2223061da546Spatrick        # Get the error text if there was an error, and the regular text if not.
2224061da546Spatrick        output = self.res.GetOutput() if self.res.Succeeded() \
2225061da546Spatrick                else self.res.GetError()
2226061da546Spatrick
2227061da546Spatrick        # Assemble the absolute path to the check file. As a convenience for
2228061da546Spatrick        # LLDB inline tests, assume that the check file is a relative path to
2229061da546Spatrick        # a file within the inline test directory.
2230061da546Spatrick        if check_file.endswith('.pyc'):
2231061da546Spatrick            check_file = check_file[:-1]
2232061da546Spatrick        check_file_abs = os.path.abspath(check_file)
2233061da546Spatrick
2234061da546Spatrick        # Run FileCheck.
2235061da546Spatrick        filecheck_bin = configuration.get_filecheck_path()
2236061da546Spatrick        if not filecheck_bin:
2237061da546Spatrick            self.assertTrue(False, "No valid FileCheck executable specified")
2238061da546Spatrick        filecheck_args = [filecheck_bin, check_file_abs]
2239061da546Spatrick        if filecheck_options:
2240061da546Spatrick            filecheck_args.append(filecheck_options)
2241061da546Spatrick        subproc = Popen(filecheck_args, stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines = True)
2242061da546Spatrick        cmd_stdout, cmd_stderr = subproc.communicate(input=output)
2243061da546Spatrick        cmd_status = subproc.returncode
2244061da546Spatrick
2245061da546Spatrick        filecheck_cmd = " ".join(filecheck_args)
2246061da546Spatrick        filecheck_trace = """
2247061da546Spatrick--- FileCheck trace (code={0}) ---
2248061da546Spatrick{1}
2249061da546Spatrick
2250061da546SpatrickFileCheck input:
2251061da546Spatrick{2}
2252061da546Spatrick
2253061da546SpatrickFileCheck output:
2254061da546Spatrick{3}
2255061da546Spatrick{4}
2256061da546Spatrick""".format(cmd_status, filecheck_cmd, output, cmd_stdout, cmd_stderr)
2257061da546Spatrick
2258061da546Spatrick        trace = cmd_status != 0 or traceAlways
2259061da546Spatrick        with recording(self, trace) as sbuf:
2260061da546Spatrick            print(filecheck_trace, file=sbuf)
2261061da546Spatrick
2262061da546Spatrick        self.assertTrue(cmd_status == 0)
2263061da546Spatrick
2264061da546Spatrick    def expect(
2265061da546Spatrick            self,
2266*f6aab3d8Srobert            string,
2267061da546Spatrick            msg=None,
2268061da546Spatrick            patterns=None,
2269061da546Spatrick            startstr=None,
2270061da546Spatrick            endstr=None,
2271061da546Spatrick            substrs=None,
2272061da546Spatrick            trace=False,
2273061da546Spatrick            error=False,
2274dda28197Spatrick            ordered=True,
2275061da546Spatrick            matching=True,
2276061da546Spatrick            exe=True,
2277061da546Spatrick            inHistory=False):
2278061da546Spatrick        """
2279061da546Spatrick        Similar to runCmd; with additional expect style output matching ability.
2280061da546Spatrick
2281061da546Spatrick        Ask the command interpreter to handle the command and then check its
2282061da546Spatrick        return status.  The 'msg' parameter specifies an informational assert
2283061da546Spatrick        message.  We expect the output from running the command to start with
2284061da546Spatrick        'startstr', matches the substrings contained in 'substrs', and regexp
2285061da546Spatrick        matches the patterns contained in 'patterns'.
2286061da546Spatrick
2287dda28197Spatrick        When matching is true and ordered is true, which are both the default,
2288dda28197Spatrick        the strings in the substrs array have to appear in the command output
2289dda28197Spatrick        in the order in which they appear in the array.
2290dda28197Spatrick
2291061da546Spatrick        If the keyword argument error is set to True, it signifies that the API
2292061da546Spatrick        client is expecting the command to fail.  In this case, the error stream
2293061da546Spatrick        from running the command is retrieved and compared against the golden
2294061da546Spatrick        input, instead.
2295061da546Spatrick
2296061da546Spatrick        If the keyword argument matching is set to False, it signifies that the API
2297061da546Spatrick        client is expecting the output of the command not to match the golden
2298061da546Spatrick        input.
2299061da546Spatrick
2300*f6aab3d8Srobert        Finally, the required argument 'string' represents the lldb command to be
2301061da546Spatrick        sent to the command interpreter.  In case the keyword argument 'exe' is
2302*f6aab3d8Srobert        set to False, the 'string' is treated as a string to be matched/not-matched
2303061da546Spatrick        against the golden input.
2304061da546Spatrick        """
2305be691f3bSpatrick        # Catch cases where `expect` has been miscalled. Specifically, prevent
2306be691f3bSpatrick        # this easy to make mistake:
2307be691f3bSpatrick        #     self.expect("lldb command", "some substr")
2308be691f3bSpatrick        # The `msg` parameter is used only when a failed match occurs. A failed
2309be691f3bSpatrick        # match can only occur when one of `patterns`, `startstr`, `endstr`, or
2310be691f3bSpatrick        # `substrs` has been given. Thus, if a `msg` is given, it's an error to
2311be691f3bSpatrick        # not also provide one of the matcher parameters.
2312be691f3bSpatrick        if msg and not (patterns or startstr or endstr or substrs or error):
2313be691f3bSpatrick            assert False, "expect() missing a matcher argument"
2314be691f3bSpatrick
2315be691f3bSpatrick        # Check `patterns` and `substrs` are not accidentally given as strings.
2316*f6aab3d8Srobert        assert not isinstance(patterns, str), \
2317be691f3bSpatrick            "patterns must be a collection of strings"
2318*f6aab3d8Srobert        assert not isinstance(substrs, str), \
2319be691f3bSpatrick            "substrs must be a collection of strings"
2320be691f3bSpatrick
2321061da546Spatrick        trace = (True if traceAlways else trace)
2322061da546Spatrick
2323061da546Spatrick        if exe:
2324061da546Spatrick            # First run the command.  If we are expecting error, set check=False.
2325061da546Spatrick            # Pass the assert message along since it provides more semantic
2326061da546Spatrick            # info.
2327061da546Spatrick            self.runCmd(
2328*f6aab3d8Srobert                string,
2329061da546Spatrick                msg=msg,
2330061da546Spatrick                trace=(
2331061da546Spatrick                    True if trace else False),
2332061da546Spatrick                check=not error,
2333061da546Spatrick                inHistory=inHistory)
2334061da546Spatrick
2335061da546Spatrick            # Then compare the output against expected strings.
2336061da546Spatrick            output = self.res.GetError() if error else self.res.GetOutput()
2337061da546Spatrick
2338061da546Spatrick            # If error is True, the API client expects the command to fail!
2339061da546Spatrick            if error:
2340061da546Spatrick                self.assertFalse(self.res.Succeeded(),
2341*f6aab3d8Srobert                                 "Command '" + string + "' is expected to fail!")
2342061da546Spatrick        else:
2343*f6aab3d8Srobert            # No execution required, just compare string against the golden input.
2344*f6aab3d8Srobert            if isinstance(string, lldb.SBCommandReturnObject):
2345*f6aab3d8Srobert                output = string.GetOutput()
2346061da546Spatrick            else:
2347*f6aab3d8Srobert                output = string
2348061da546Spatrick            with recording(self, trace) as sbuf:
2349061da546Spatrick                print("looking at:", output, file=sbuf)
2350061da546Spatrick
2351be691f3bSpatrick        expecting_str = "Expecting" if matching else "Not expecting"
2352be691f3bSpatrick        def found_str(matched):
2353be691f3bSpatrick            return "was found" if matched else "was not found"
2354061da546Spatrick
2355be691f3bSpatrick        # To be used as assert fail message and/or trace content
2356be691f3bSpatrick        log_lines = [
2357be691f3bSpatrick                "{}:".format("Ran command" if exe else "Checking string"),
2358*f6aab3d8Srobert                "\"{}\"".format(string),
2359be691f3bSpatrick                # Space out command and output
2360be691f3bSpatrick                "",
2361be691f3bSpatrick        ]
2362be691f3bSpatrick        if exe:
2363be691f3bSpatrick            # Newline before output to make large strings more readable
2364be691f3bSpatrick            log_lines.append("Got output:\n{}".format(output))
2365061da546Spatrick
2366be691f3bSpatrick        # Assume that we start matched if we want a match
2367be691f3bSpatrick        # Meaning if you have no conditions, matching or
2368be691f3bSpatrick        # not matching will always pass
2369be691f3bSpatrick        matched = matching
2370be691f3bSpatrick
2371be691f3bSpatrick        # We will stop checking on first failure
2372061da546Spatrick        if startstr:
2373be691f3bSpatrick            matched = output.startswith(startstr)
2374be691f3bSpatrick            log_lines.append("{} start string: \"{}\" ({})".format(
2375be691f3bSpatrick                    expecting_str, startstr, found_str(matched)))
2376061da546Spatrick
2377be691f3bSpatrick        if endstr and matched == matching:
2378061da546Spatrick            matched = output.endswith(endstr)
2379be691f3bSpatrick            log_lines.append("{} end string: \"{}\" ({})".format(
2380be691f3bSpatrick                    expecting_str, endstr, found_str(matched)))
2381061da546Spatrick
2382be691f3bSpatrick        if substrs and matched == matching:
2383dda28197Spatrick            start = 0
2384061da546Spatrick            for substr in substrs:
2385dda28197Spatrick                index = output[start:].find(substr)
2386*f6aab3d8Srobert                start = start + index + len(substr) if ordered and matching else 0
2387dda28197Spatrick                matched = index != -1
2388be691f3bSpatrick                log_lines.append("{} sub string: \"{}\" ({})".format(
2389be691f3bSpatrick                        expecting_str, substr, found_str(matched)))
2390be691f3bSpatrick
2391be691f3bSpatrick                if matched != matching:
2392061da546Spatrick                    break
2393061da546Spatrick
2394be691f3bSpatrick        if patterns and matched == matching:
2395061da546Spatrick            for pattern in patterns:
2396be691f3bSpatrick                matched = re.search(pattern, output)
2397be691f3bSpatrick
2398be691f3bSpatrick                pattern_line = "{} regex pattern: \"{}\" ({}".format(
2399be691f3bSpatrick                        expecting_str, pattern, found_str(matched))
2400be691f3bSpatrick                if matched:
2401be691f3bSpatrick                    pattern_line += ", matched \"{}\"".format(
2402be691f3bSpatrick                            matched.group(0))
2403be691f3bSpatrick                pattern_line += ")"
2404be691f3bSpatrick                log_lines.append(pattern_line)
2405be691f3bSpatrick
2406be691f3bSpatrick                # Convert to bool because match objects
2407be691f3bSpatrick                # are True-ish but != True itself
2408be691f3bSpatrick                matched = bool(matched)
2409be691f3bSpatrick                if matched != matching:
2410061da546Spatrick                    break
2411061da546Spatrick
2412be691f3bSpatrick        # If a check failed, add any extra assert message
2413be691f3bSpatrick        if msg is not None and matched != matching:
2414be691f3bSpatrick            log_lines.append(msg)
2415be691f3bSpatrick
2416be691f3bSpatrick        log_msg = "\n".join(log_lines)
2417be691f3bSpatrick        with recording(self, trace) as sbuf:
2418be691f3bSpatrick            print(log_msg, file=sbuf)
2419be691f3bSpatrick        if matched != matching:
2420be691f3bSpatrick            self.fail(log_msg)
2421061da546Spatrick
2422061da546Spatrick    def expect_expr(
2423061da546Spatrick            self,
2424061da546Spatrick            expr,
2425061da546Spatrick            result_summary=None,
2426061da546Spatrick            result_value=None,
2427061da546Spatrick            result_type=None,
2428be691f3bSpatrick            result_children=None
2429061da546Spatrick            ):
2430061da546Spatrick        """
2431061da546Spatrick        Evaluates the given expression and verifies the result.
2432061da546Spatrick        :param expr: The expression as a string.
2433061da546Spatrick        :param result_summary: The summary that the expression should have. None if the summary should not be checked.
2434061da546Spatrick        :param result_value: The value that the expression should have. None if the value should not be checked.
2435061da546Spatrick        :param result_type: The type that the expression result should have. None if the type should not be checked.
2436be691f3bSpatrick        :param result_children: The expected children of the expression result
2437be691f3bSpatrick                                as a list of ValueChecks. None if the children shouldn't be checked.
2438061da546Spatrick        """
2439061da546Spatrick        self.assertTrue(expr.strip() == expr, "Expression contains trailing/leading whitespace: '" + expr + "'")
2440061da546Spatrick
2441061da546Spatrick        frame = self.frame()
2442dda28197Spatrick        options = lldb.SBExpressionOptions()
2443061da546Spatrick
2444dda28197Spatrick        # Disable fix-its that tests don't pass by accident.
2445dda28197Spatrick        options.SetAutoApplyFixIts(False)
2446061da546Spatrick
2447dda28197Spatrick        # Set the usual default options for normal expressions.
2448dda28197Spatrick        options.SetIgnoreBreakpoints(True)
2449dda28197Spatrick
2450dda28197Spatrick        if self.frame().IsValid():
2451dda28197Spatrick            options.SetLanguage(frame.GuessLanguage())
2452dda28197Spatrick            eval_result = self.frame().EvaluateExpression(expr, options)
2453dda28197Spatrick        else:
2454be691f3bSpatrick            target = self.target()
2455be691f3bSpatrick            # If there is no selected target, run the expression in the dummy
2456be691f3bSpatrick            # target.
2457be691f3bSpatrick            if not target.IsValid():
2458be691f3bSpatrick                target = self.dbg.GetDummyTarget()
2459be691f3bSpatrick            eval_result = target.EvaluateExpression(expr, options)
2460dda28197Spatrick
2461be691f3bSpatrick        value_check = ValueCheck(type=result_type, value=result_value,
2462be691f3bSpatrick                                 summary=result_summary, children=result_children)
2463be691f3bSpatrick        value_check.check_value(self, eval_result, str(eval_result))
2464be691f3bSpatrick        return eval_result
2465061da546Spatrick
2466be691f3bSpatrick    def expect_var_path(
2467be691f3bSpatrick            self,
2468be691f3bSpatrick            var_path,
2469be691f3bSpatrick            summary=None,
2470be691f3bSpatrick            value=None,
2471be691f3bSpatrick            type=None,
2472be691f3bSpatrick            children=None
2473be691f3bSpatrick            ):
2474be691f3bSpatrick        """
2475be691f3bSpatrick        Evaluates the given variable path and verifies the result.
2476be691f3bSpatrick        See also 'frame variable' and SBFrame.GetValueForVariablePath.
2477be691f3bSpatrick        :param var_path: The variable path as a string.
2478be691f3bSpatrick        :param summary: The summary that the variable should have. None if the summary should not be checked.
2479be691f3bSpatrick        :param value: The value that the variable should have. None if the value should not be checked.
2480be691f3bSpatrick        :param type: The type that the variable result should have. None if the type should not be checked.
2481be691f3bSpatrick        :param children: The expected children of the variable  as a list of ValueChecks.
2482be691f3bSpatrick                         None if the children shouldn't be checked.
2483be691f3bSpatrick        """
2484be691f3bSpatrick        self.assertTrue(var_path.strip() == var_path,
2485be691f3bSpatrick                        "Expression contains trailing/leading whitespace: '" + var_path + "'")
2486061da546Spatrick
2487be691f3bSpatrick        frame = self.frame()
2488be691f3bSpatrick        eval_result = frame.GetValueForVariablePath(var_path)
2489061da546Spatrick
2490be691f3bSpatrick        value_check = ValueCheck(type=type, value=value,
2491be691f3bSpatrick                                 summary=summary, children=children)
2492be691f3bSpatrick        value_check.check_value(self, eval_result, str(eval_result))
2493be691f3bSpatrick        return eval_result
2494061da546Spatrick
2495dda28197Spatrick    """Assert that an lldb.SBError is in the "success" state."""
2496dda28197Spatrick    def assertSuccess(self, obj, msg=None):
2497dda28197Spatrick        if not obj.Success():
2498dda28197Spatrick            error = obj.GetCString()
2499dda28197Spatrick            self.fail(self._formatMessage(msg,
2500dda28197Spatrick                "'{}' is not success".format(error)))
2501dda28197Spatrick
2502*f6aab3d8Srobert    """Assert that a command return object is successful"""
2503*f6aab3d8Srobert    def assertCommandReturn(self, obj, msg=None):
2504*f6aab3d8Srobert        if not obj.Succeeded():
2505*f6aab3d8Srobert            error = obj.GetError()
2506*f6aab3d8Srobert            self.fail(self._formatMessage(msg,
2507*f6aab3d8Srobert                "'{}' is not success".format(error)))
2508*f6aab3d8Srobert
2509*f6aab3d8Srobert    """Assert two states are equal"""
2510*f6aab3d8Srobert    def assertState(self, first, second, msg=None):
2511*f6aab3d8Srobert        if first != second:
2512*f6aab3d8Srobert            error = "{} ({}) != {} ({})".format(
2513*f6aab3d8Srobert                lldbutil.state_type_to_str(first), first,
2514*f6aab3d8Srobert                lldbutil.state_type_to_str(second), second)
2515*f6aab3d8Srobert            self.fail(self._formatMessage(msg, error))
2516*f6aab3d8Srobert
2517*f6aab3d8Srobert    """Assert two stop reasons are equal"""
2518*f6aab3d8Srobert    def assertStopReason(self, first, second, msg=None):
2519*f6aab3d8Srobert        if first != second:
2520*f6aab3d8Srobert            error = "{} ({}) != {} ({})".format(
2521*f6aab3d8Srobert                lldbutil.stop_reason_to_str(first), first,
2522*f6aab3d8Srobert                lldbutil.stop_reason_to_str(second), second)
2523*f6aab3d8Srobert            self.fail(self._formatMessage(msg, error))
2524*f6aab3d8Srobert
2525*f6aab3d8Srobert    def createTestTarget(self, file_path=None, msg=None,
2526*f6aab3d8Srobert                         load_dependent_modules=True):
2527be691f3bSpatrick        """
2528be691f3bSpatrick        Creates a target from the file found at the given file path.
2529be691f3bSpatrick        Asserts that the resulting target is valid.
2530be691f3bSpatrick        :param file_path: The file path that should be used to create the target.
2531be691f3bSpatrick                          The default argument opens the current default test
2532be691f3bSpatrick                          executable in the current test directory.
2533be691f3bSpatrick        :param msg: A custom error message.
2534be691f3bSpatrick        """
2535be691f3bSpatrick        if file_path is None:
2536be691f3bSpatrick            file_path = self.getBuildArtifact("a.out")
2537be691f3bSpatrick        error = lldb.SBError()
2538be691f3bSpatrick        triple = ""
2539be691f3bSpatrick        platform = ""
2540be691f3bSpatrick        target = self.dbg.CreateTarget(file_path, triple, platform,
2541be691f3bSpatrick                                       load_dependent_modules, error)
2542be691f3bSpatrick        if error.Fail():
2543be691f3bSpatrick            err = "Couldn't create target for path '{}': {}".format(file_path,
2544be691f3bSpatrick                                                                    str(error))
2545be691f3bSpatrick            self.fail(self._formatMessage(msg, err))
2546be691f3bSpatrick
2547be691f3bSpatrick        self.assertTrue(target.IsValid(), "Got invalid target without error")
2548be691f3bSpatrick        return target
2549be691f3bSpatrick
2550061da546Spatrick    # =================================================
2551061da546Spatrick    # Misc. helper methods for debugging test execution
2552061da546Spatrick    # =================================================
2553061da546Spatrick
2554061da546Spatrick    def DebugSBValue(self, val):
2555061da546Spatrick        """Debug print a SBValue object, if traceAlways is True."""
2556061da546Spatrick        from .lldbutil import value_type_to_str
2557061da546Spatrick
2558061da546Spatrick        if not traceAlways:
2559061da546Spatrick            return
2560061da546Spatrick
2561061da546Spatrick        err = sys.stderr
2562061da546Spatrick        err.write(val.GetName() + ":\n")
2563061da546Spatrick        err.write('\t' + "TypeName         -> " + val.GetTypeName() + '\n')
2564061da546Spatrick        err.write('\t' + "ByteSize         -> " +
2565061da546Spatrick                  str(val.GetByteSize()) + '\n')
2566061da546Spatrick        err.write('\t' + "NumChildren      -> " +
2567061da546Spatrick                  str(val.GetNumChildren()) + '\n')
2568061da546Spatrick        err.write('\t' + "Value            -> " + str(val.GetValue()) + '\n')
2569061da546Spatrick        err.write('\t' + "ValueAsUnsigned  -> " +
2570061da546Spatrick                  str(val.GetValueAsUnsigned()) + '\n')
2571061da546Spatrick        err.write(
2572061da546Spatrick            '\t' +
2573061da546Spatrick            "ValueType        -> " +
2574061da546Spatrick            value_type_to_str(
2575061da546Spatrick                val.GetValueType()) +
2576061da546Spatrick            '\n')
2577061da546Spatrick        err.write('\t' + "Summary          -> " + str(val.GetSummary()) + '\n')
2578061da546Spatrick        err.write('\t' + "IsPointerType    -> " +
2579061da546Spatrick                  str(val.TypeIsPointerType()) + '\n')
2580061da546Spatrick        err.write('\t' + "Location         -> " + val.GetLocation() + '\n')
2581061da546Spatrick
2582061da546Spatrick    def DebugSBType(self, type):
2583061da546Spatrick        """Debug print a SBType object, if traceAlways is True."""
2584061da546Spatrick        if not traceAlways:
2585061da546Spatrick            return
2586061da546Spatrick
2587061da546Spatrick        err = sys.stderr
2588061da546Spatrick        err.write(type.GetName() + ":\n")
2589061da546Spatrick        err.write('\t' + "ByteSize        -> " +
2590061da546Spatrick                  str(type.GetByteSize()) + '\n')
2591*f6aab3d8Srobert        err.write('\t' + "IsAggregateType   -> " +
2592*f6aab3d8Srobert                  str(type.IsAggregateType()) + '\n')
2593061da546Spatrick        err.write('\t' + "IsPointerType   -> " +
2594061da546Spatrick                  str(type.IsPointerType()) + '\n')
2595061da546Spatrick        err.write('\t' + "IsReferenceType -> " +
2596061da546Spatrick                  str(type.IsReferenceType()) + '\n')
2597061da546Spatrick
2598061da546Spatrick    def DebugPExpect(self, child):
2599061da546Spatrick        """Debug the spwaned pexpect object."""
2600061da546Spatrick        if not traceAlways:
2601061da546Spatrick            return
2602061da546Spatrick
2603061da546Spatrick        print(child)
2604061da546Spatrick
2605061da546Spatrick    @classmethod
2606061da546Spatrick    def RemoveTempFile(cls, file):
2607061da546Spatrick        if os.path.exists(file):
2608061da546Spatrick            remove_file(file)
2609061da546Spatrick
2610061da546Spatrick# On Windows, the first attempt to delete a recently-touched file can fail
2611061da546Spatrick# because of a race with antimalware scanners.  This function will detect a
2612061da546Spatrick# failure and retry.
2613061da546Spatrick
2614061da546Spatrick
2615061da546Spatrickdef remove_file(file, num_retries=1, sleep_duration=0.5):
2616061da546Spatrick    for i in range(num_retries + 1):
2617061da546Spatrick        try:
2618061da546Spatrick            os.remove(file)
2619061da546Spatrick            return True
2620061da546Spatrick        except:
2621061da546Spatrick            time.sleep(sleep_duration)
2622061da546Spatrick            continue
2623061da546Spatrick    return False
2624