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