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