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