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
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
22 Configuration: arch=x86_64 compiler=clang
23 ----------------------------------------------------------------------
26 ........................................................................
27 ----------------------------------------------------------------------
28 Ran 72 tests in 135.468s
34 from __future__ import absolute_import
35 from __future__ import print_function
40 from functools import wraps
48 from subprocess import *
56 from six import add_metaclass
57 from six import StringIO as SixStringIO
63 from . import configuration
64 from . import decorators
65 from . import lldbplatformutil
66 from . import lldbtest_config
67 from . import lldbutil
68 from . import test_categories
69 from lldbsuite.support import encoded_file
70 from lldbsuite.support import funcutils
72 # dosep.py starts lots and lots of dotest instances
73 # This option helps you find if two (or more) dotest instances are using the same
74 # directory at the same time
75 # Enable it to cause test failures and stderr messages if dotest instances try to run in
76 # the same directory simultaneously
77 # it is disabled by default because it litters the test directories with ".dirlock" files
78 debug_confirm_directory_exclusivity = False
80 # See also dotest.parseOptionsAndInitTestdirs(), where the environment variables
81 # LLDB_COMMAND_TRACE and LLDB_DO_CLEANUP are set from '-t' and '-r dir' options.
83 # By default, traceAlways is False.
84 if "LLDB_COMMAND_TRACE" in os.environ and os.environ["LLDB_COMMAND_TRACE"]=="YES":
89 # By default, doCleanup is True.
90 if "LLDB_DO_CLEANUP" in os.environ and os.environ["LLDB_DO_CLEANUP"]=="NO":
97 # Some commonly used assert messages.
100 COMMAND_FAILED_AS_EXPECTED = "Command has failed as expected"
102 CURRENT_EXECUTABLE_SET = "Current executable set successfully"
104 PROCESS_IS_VALID = "Process is valid"
106 PROCESS_KILLED = "Process is killed successfully"
108 PROCESS_EXITED = "Process exited successfully"
110 PROCESS_STOPPED = "Process status should be stopped"
112 RUN_SUCCEEDED = "Process is launched successfully"
114 RUN_COMPLETED = "Process exited successfully"
116 BACKTRACE_DISPLAYED_CORRECTLY = "Backtrace displayed correctly"
118 BREAKPOINT_CREATED = "Breakpoint created successfully"
120 BREAKPOINT_STATE_CORRECT = "Breakpoint state is correct"
122 BREAKPOINT_PENDING_CREATED = "Pending breakpoint created successfully"
124 BREAKPOINT_HIT_ONCE = "Breakpoint resolved with hit cout = 1"
126 BREAKPOINT_HIT_TWICE = "Breakpoint resolved with hit cout = 2"
128 BREAKPOINT_HIT_THRICE = "Breakpoint resolved with hit cout = 3"
130 MISSING_EXPECTED_REGISTERS = "At least one expected register is unavailable."
132 OBJECT_PRINTED_CORRECTLY = "Object printed correctly"
134 SOURCE_DISPLAYED_CORRECTLY = "Source code displayed correctly"
136 STEP_OUT_SUCCEEDED = "Thread step-out succeeded"
138 STOPPED_DUE_TO_EXC_BAD_ACCESS = "Process should be stopped due to bad access exception"
140 STOPPED_DUE_TO_ASSERT = "Process should be stopped due to an assertion"
142 STOPPED_DUE_TO_BREAKPOINT = "Process should be stopped due to breakpoint"
144 STOPPED_DUE_TO_BREAKPOINT_WITH_STOP_REASON_AS = "%s, %s" % (
145 STOPPED_DUE_TO_BREAKPOINT, "instead, the actual stop reason is: '%s'")
147 STOPPED_DUE_TO_BREAKPOINT_CONDITION = "Stopped due to breakpoint condition"
149 STOPPED_DUE_TO_BREAKPOINT_IGNORE_COUNT = "Stopped due to breakpoint and ignore count"
151 STOPPED_DUE_TO_SIGNAL = "Process state is stopped due to signal"
153 STOPPED_DUE_TO_STEP_IN = "Process state is stopped due to step in"
155 STOPPED_DUE_TO_WATCHPOINT = "Process should be stopped due to watchpoint"
157 DATA_TYPES_DISPLAYED_CORRECTLY = "Data type(s) displayed correctly"
159 VALID_BREAKPOINT = "Got a valid breakpoint"
161 VALID_BREAKPOINT_LOCATION = "Got a valid breakpoint location"
163 VALID_COMMAND_INTERPRETER = "Got a valid command interpreter"
165 VALID_FILESPEC = "Got a valid filespec"
167 VALID_MODULE = "Got a valid module"
169 VALID_PROCESS = "Got a valid process"
171 VALID_SYMBOL = "Got a valid symbol"
173 VALID_TARGET = "Got a valid target"
175 VALID_PLATFORM = "Got a valid platform"
177 VALID_TYPE = "Got a valid type"
179 VALID_VARIABLE = "Got a valid variable"
181 VARIABLES_DISPLAYED_CORRECTLY = "Variable(s) displayed correctly"
183 WATCHPOINT_CREATED = "Watchpoint created successfully"
186 '''A generic "Command '%s' returns successfully" message generator.'''
187 return "Command '%s' returns successfully" % str
189 def COMPLETION_MSG(str_before, str_after):
190 '''A generic message generator for the completion mechanism.'''
191 return "'%s' successfully completes to '%s'" % (str_before, str_after)
193 def EXP_MSG(str, actual, exe):
194 '''A generic "'%s' returns expected result" message generator if exe.
195 Otherwise, it generates "'%s' matches expected result" message.'''
197 return "'%s' %s expected result, got '%s'" % (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 """Returns an env variable array from the os.environ map object."""
205 return list(map(lambda k,v: k+"="+v, list(os.environ.keys()), list(os.environ.values())))
207 def line_number(filename, string_to_match):
208 """Helper function to return the line number of the first matched string."""
209 with io.open(filename, mode='r', encoding="utf-8") as f:
210 for i, line in enumerate(f):
211 if line.find(string_to_match) != -1:
214 raise Exception("Unable to find '%s' within file %s" % (string_to_match, filename))
217 """Return the pointer size of the host system."""
219 a_pointer = ctypes.c_void_p(0xffff)
220 return 8 * ctypes.sizeof(a_pointer)
223 """Returns true if fpath is an executable."""
224 return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
227 """Returns the full path to a program; None otherwise."""
228 fpath, fname = os.path.split(program)
233 for path in os.environ["PATH"].split(os.pathsep):
234 exe_file = os.path.join(path, program)
239 class recording(SixStringIO):
241 A nice little context manager for recording the debugger interactions into
242 our session object. If trace flag is ON, it also emits the interactions
245 def __init__(self, test, trace):
246 """Create a SixStringIO instance; record the session obj and trace flag."""
247 SixStringIO.__init__(self)
248 # The test might not have undergone the 'setUp(self)' phase yet, so that
249 # the attribute 'session' might not even exist yet.
250 self.session = getattr(test, "session", None) if test else None
255 Context management protocol on entry to the body of the with statement.
256 Just return the SixStringIO object.
260 def __exit__(self, type, value, tb):
262 Context management protocol on exit from the body of the with statement.
263 If trace is ON, it emits the recordings into stderr. Always add the
264 recordings to our session object. And close the SixStringIO object, too.
267 print(self.getvalue(), file=sys.stderr)
269 print(self.getvalue(), file=self.session)
272 @add_metaclass(abc.ABCMeta)
273 class _BaseProcess(object):
275 @abc.abstractproperty
277 """Returns process PID if has been launched already."""
280 def launch(self, executable, args):
281 """Launches new process with given executable and args."""
285 """Terminates previously launched process.."""
287 class _LocalProcess(_BaseProcess):
289 def __init__(self, trace_on):
291 self._trace_on = trace_on
292 self._delayafterterminate = 0.1
296 return self._proc.pid
298 def launch(self, executable, args):
299 self._proc = Popen([executable] + args,
300 stdout = open(os.devnull) if not self._trace_on else None,
304 if self._proc.poll() == None:
305 # Terminate _proc like it does the pexpect
306 signals_to_try = [sig for sig in ['SIGHUP', 'SIGCONT', 'SIGINT'] if sig in dir(signal)]
307 for sig in signals_to_try:
309 self._proc.send_signal(getattr(signal, sig))
310 time.sleep(self._delayafterterminate)
311 if self._proc.poll() != None:
314 pass # Windows says SIGINT is not a valid signal to send
315 self._proc.terminate()
316 time.sleep(self._delayafterterminate)
317 if self._proc.poll() != None:
320 time.sleep(self._delayafterterminate)
323 return self._proc.poll()
325 class _RemoteProcess(_BaseProcess):
327 def __init__(self, install_remote):
329 self._install_remote = install_remote
335 def launch(self, executable, args):
336 if self._install_remote:
337 src_path = executable
338 dst_path = lldbutil.append_to_process_working_directory(os.path.basename(executable))
340 dst_file_spec = lldb.SBFileSpec(dst_path, False)
341 err = lldb.remote_platform.Install(lldb.SBFileSpec(src_path, True), dst_file_spec)
343 raise Exception("remote_platform.Install('%s', '%s') failed: %s" % (src_path, dst_path, err))
345 dst_path = executable
346 dst_file_spec = lldb.SBFileSpec(executable, False)
348 launch_info = lldb.SBLaunchInfo(args)
349 launch_info.SetExecutableFile(dst_file_spec, True)
350 launch_info.SetWorkingDirectory(lldb.remote_platform.GetWorkingDirectory())
352 # Redirect stdout and stderr to /dev/null
353 launch_info.AddSuppressFileAction(1, False, True)
354 launch_info.AddSuppressFileAction(2, False, True)
356 err = lldb.remote_platform.Launch(launch_info)
358 raise Exception("remote_platform.Launch('%s', '%s') failed: %s" % (dst_path, args, err))
359 self._pid = launch_info.GetProcessID()
362 lldb.remote_platform.Kill(self._pid)
364 # From 2.7's subprocess.check_output() convenience function.
365 # Return a tuple (stdoutdata, stderrdata).
366 def system(commands, **kwargs):
367 r"""Run an os command with arguments and return its output as a byte string.
369 If the exit code was non-zero it raises a CalledProcessError. The
370 CalledProcessError object will have the return code in the returncode
371 attribute and output in the output attribute.
373 The arguments are the same as for the Popen constructor. Example:
375 >>> check_output(["ls", "-l", "/dev/null"])
376 'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n'
378 The stdout argument is not allowed as it is used internally.
379 To capture standard error in the result, use stderr=STDOUT.
381 >>> check_output(["/bin/sh", "-c",
382 ... "ls -l non_existent_file ; exit 0"],
384 'ls: non_existent_file: No such file or directory\n'
387 # Assign the sender object to variable 'test' and remove it from kwargs.
388 test = kwargs.pop('sender', None)
390 # [['make', 'clean', 'foo'], ['make', 'foo']] -> ['make clean foo', 'make foo']
391 commandList = [' '.join(x) for x in commands]
394 for shellCommand in commandList:
395 if 'stdout' in kwargs:
396 raise ValueError('stdout argument not allowed, it will be overridden.')
397 if 'shell' in kwargs and kwargs['shell']==False:
398 raise ValueError('shell=False not allowed')
399 process = Popen(shellCommand, stdout=PIPE, stderr=PIPE, shell=True, universal_newlines=True, **kwargs)
401 this_output, this_error = process.communicate()
402 retcode = process.poll()
404 # Enable trace on failure return while tracking down FreeBSD buildbot issues
406 if not trace and retcode and sys.platform.startswith("freebsd"):
409 with recording(test, trace) as sbuf:
411 print("os command:", shellCommand, file=sbuf)
412 print("with pid:", pid, file=sbuf)
413 print("stdout:", this_output, file=sbuf)
414 print("stderr:", this_error, file=sbuf)
415 print("retcode:", retcode, file=sbuf)
419 cmd = kwargs.get("args")
422 cpe = CalledProcessError(retcode, cmd)
423 # Ensure caller can access the stdout/stderr.
424 cpe.lldb_extensions = {
425 "stdout_content": this_output,
426 "stderr_content": this_error,
427 "command": shellCommand
430 output = output + this_output
431 error = error + this_error
432 return (output, error)
434 def getsource_if_available(obj):
436 Return the text of the source code for an object if available. Otherwise,
437 a print representation is returned.
441 return inspect.getsource(obj)
445 def builder_module():
446 if sys.platform.startswith("freebsd"):
447 return __import__("builder_freebsd")
448 if sys.platform.startswith("netbsd"):
449 return __import__("builder_netbsd")
450 if sys.platform.startswith("linux"):
451 # sys.platform with Python-3.x returns 'linux', but with
452 # Python-2.x it returns 'linux2'.
453 return __import__("builder_linux")
454 return __import__("builder_" + sys.platform)
457 class Base(unittest2.TestCase):
459 Abstract base for performing lldb (see TestBase) or other generic tests (see
460 BenchBase for one example). lldbtest.Base works with the test driver to
465 # The concrete subclass should override this attribute.
468 # Keep track of the old current working directory.
472 def compute_mydir(test_file):
473 '''Subclasses should call this function to correctly calculate the required "mydir" attribute as follows:
475 mydir = TestBase.compute_mydir(__file__)'''
476 test_dir = os.path.dirname(test_file)
477 return test_dir[len(os.environ["LLDB_TEST"])+1:]
480 """Returns True if we are in trace mode (tracing detailed test execution)."""
486 Python unittest framework class setup fixture.
487 Do current directory manipulation.
489 # Fail fast if 'mydir' attribute is not overridden.
490 if not cls.mydir or len(cls.mydir) == 0:
491 raise Exception("Subclasses must override the 'mydir' attribute.")
493 # Save old working directory.
494 cls.oldcwd = os.getcwd()
496 # Change current working directory if ${LLDB_TEST} is defined.
497 # See also dotest.py which sets up ${LLDB_TEST}.
498 if ("LLDB_TEST" in os.environ):
499 full_dir = os.path.join(os.environ["LLDB_TEST"], cls.mydir)
501 print("Change dir to:", full_dir, file=sys.stderr)
502 os.chdir(os.path.join(os.environ["LLDB_TEST"], cls.mydir))
504 if debug_confirm_directory_exclusivity:
506 cls.dir_lock = lock.Lock(os.path.join(full_dir, ".dirlock"))
508 cls.dir_lock.try_acquire()
509 # write the class that owns the lock into the lock file
510 cls.dir_lock.handle.write(cls.__name__)
511 except IOError as ioerror:
512 # nothing else should have this directory lock
513 # wait here until we get a lock
514 cls.dir_lock.acquire()
515 # read the previous owner from the lock file
516 lock_id = cls.dir_lock.handle.read()
517 print("LOCK ERROR: {} wants to lock '{}' but it is already locked by '{}'".format(cls.__name__, full_dir, lock_id), file=sys.stderr)
520 # Set platform context.
521 cls.platformContext = lldbplatformutil.createPlatformContext()
524 def tearDownClass(cls):
526 Python unittest framework class teardown fixture.
527 Do class-wide cleanup.
531 # First, let's do the platform-specific cleanup.
532 module = builder_module()
535 # Subclass might have specific cleanup function defined.
536 if getattr(cls, "classCleanup", None):
538 print("Call class-specific cleanup function for class:", cls, file=sys.stderr)
542 exc_type, exc_value, exc_tb = sys.exc_info()
543 traceback.print_exception(exc_type, exc_value, exc_tb)
545 if debug_confirm_directory_exclusivity:
546 cls.dir_lock.release()
549 # Restore old working directory.
551 print("Restore dir to:", cls.oldcwd, file=sys.stderr)
555 def skipLongRunningTest(cls):
557 By default, we skip long running test case.
558 This can be overridden by passing '-l' to the test driver (dotest.py).
560 if "LLDB_SKIP_LONG_RUNNING_TEST" in os.environ and "NO" == os.environ["LLDB_SKIP_LONG_RUNNING_TEST"]:
565 def enableLogChannelsForCurrentTest(self):
566 if len(lldbtest_config.channels) == 0:
569 # if debug channels are specified in lldbtest_config.channels,
570 # create a new set of log files for every test
571 log_basename = self.getLogBasenameForCurrentTest()
573 # confirm that the file is writeable
574 host_log_path = "{}-host.log".format(log_basename)
575 open(host_log_path, 'w').close()
577 log_enable = "log enable -Tpn -f {} ".format(host_log_path)
578 for channel_with_categories in lldbtest_config.channels:
579 channel_then_categories = channel_with_categories.split(' ', 1)
580 channel = channel_then_categories[0]
581 if len(channel_then_categories) > 1:
582 categories = channel_then_categories[1]
584 categories = "default"
586 if channel == "gdb-remote" and lldb.remote_platform is None:
587 # communicate gdb-remote categories to debugserver
588 os.environ["LLDB_DEBUGSERVER_LOG_FLAGS"] = categories
590 self.ci.HandleCommand(log_enable + channel_with_categories, self.res)
591 if not self.res.Succeeded():
592 raise Exception('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
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(lldbtest_config.channels)
605 self.addTearDownHook(self.disableLogChannelsForCurrentTest)
607 def disableLogChannelsForCurrentTest(self):
608 # close all log files that we opened
609 for channel_and_categories in lldbtest_config.channels:
610 # channel format - <channel-name> [<category0> [<category1> ...]]
611 channel = channel_and_categories.split(' ', 1)[0]
612 self.ci.HandleCommand("log disable " + channel, self.res)
613 if not self.res.Succeeded():
614 raise Exception('log disable failed (check LLDB_LOG_OPTION env variable)')
616 # Retrieve the server log (if any) from the remote system. It is assumed the server log
617 # is writing to the "server.log" file in the current test directory. This can be
618 # achieved by setting LLDB_DEBUGSERVER_LOG_FILE="server.log" when starting remote
619 # platform. If the remote logging is not enabled, then just let the Get() command silently
621 if lldb.remote_platform:
622 lldb.remote_platform.Get(lldb.SBFileSpec("server.log"),
623 lldb.SBFileSpec(self.getLogBasenameForCurrentTest()+"-server.log"))
625 def setPlatformWorkingDir(self):
626 if not lldb.remote_platform or not configuration.lldb_platform_working_dir:
629 remote_test_dir = lldbutil.join_remote_paths(
630 configuration.lldb_platform_working_dir,
631 self.getArchitecture(),
632 str(self.test_number),
634 error = lldb.remote_platform.MakeDirectory(remote_test_dir, 448) # 448 = 0o700
636 lldb.remote_platform.SetWorkingDirectory(remote_test_dir)
638 # This function removes all files from the current working directory while leaving
639 # the directories in place. The cleaup is required to reduce the disk space required
640 # by the test suit while leaving the directories untached is neccessary because
641 # sub-directories might belong to an other test
642 def clean_working_directory():
643 # TODO: Make it working on Windows when we need it for remote debugging support
644 # TODO: Replace the heuristic to remove the files with a logic what collects the
645 # list of files we have to remove during test runs.
646 shell_cmd = lldb.SBPlatformShellCommand("rm %s/*" % remote_test_dir)
647 lldb.remote_platform.Run(shell_cmd)
648 self.addTearDownHook(clean_working_directory)
650 print("error: making remote directory '%s': %s" % (remote_test_dir, error))
653 """Fixture for unittest test case setup.
655 It works with the test driver to conditionally skip tests and does other
658 #traceback.print_stack()
660 if "LIBCXX_PATH" in os.environ:
661 self.libcxxPath = os.environ["LIBCXX_PATH"]
663 self.libcxxPath = None
665 if "LLDBMI_EXEC" in os.environ:
666 self.lldbMiExec = os.environ["LLDBMI_EXEC"]
668 self.lldbMiExec = None
670 # If we spawn an lldb process for test (via pexpect), do not load the
671 # init file unless told otherwise.
672 if "NO_LLDBINIT" in os.environ and "NO" == os.environ["NO_LLDBINIT"]:
675 self.lldbOption = "--no-lldbinit"
677 # Assign the test method name to self.testMethodName.
679 # For an example of the use of this attribute, look at test/types dir.
680 # There are a bunch of test cases under test/types and we don't want the
681 # module cacheing subsystem to be confused with executable name "a.out"
682 # used for all the test cases.
683 self.testMethodName = self._testMethodName
685 # This is for the case of directly spawning 'lldb'/'gdb' and interacting
686 # with it using pexpect.
688 self.child_prompt = "(lldb) "
689 # If the child is interacting with the embedded script interpreter,
690 # there are two exits required during tear down, first to quit the
691 # embedded script interpreter and second to quit the lldb command
693 self.child_in_script_interpreter = False
695 # These are for customized teardown cleanup.
697 self.doTearDownCleanup = False
698 # And in rare cases where there are multiple teardown cleanups.
700 self.doTearDownCleanups = False
702 # List of spawned subproces.Popen objects
703 self.subprocesses = []
705 # List of forked process PIDs
706 self.forkedProcessPids = []
708 # Create a string buffer to record the session info, to be dumped into a
709 # test case specific file if test failure is encountered.
710 self.log_basename = self.getLogBasenameForCurrentTest()
712 session_file = "{}.log".format(self.log_basename)
713 # Python 3 doesn't support unbuffered I/O in text mode. Open buffered.
714 self.session = encoded_file.open(session_file, "utf-8", mode="w")
716 # Optimistically set __errored__, __failed__, __expected__ to False
717 # initially. If the test errored/failed, the session info
718 # (self.session) is then dumped into a session specific file for
720 self.__cleanup_errored__ = False
721 self.__errored__ = False
722 self.__failed__ = False
723 self.__expected__ = False
724 # We are also interested in unexpected success.
725 self.__unexpected__ = False
727 self.__skipped__ = False
729 # See addTearDownHook(self, hook) which allows the client to add a hook
730 # function to be run during tearDown() time.
733 # See HideStdout(self).
734 self.sys_stdout_hidden = False
736 if self.platformContext:
737 # set environment variable names for finding shared libraries
738 self.dylibPath = self.platformContext.shlib_environment_var
740 # Create the debugger instance if necessary.
743 except AttributeError:
744 self.dbg = lldb.SBDebugger.Create()
747 raise Exception('Invalid debugger instance')
749 # Retrieve the associated command interpreter instance.
750 self.ci = self.dbg.GetCommandInterpreter()
752 raise Exception('Could not get the command interpreter')
754 # And the result object.
755 self.res = lldb.SBCommandReturnObject()
757 self.setPlatformWorkingDir()
758 self.enableLogChannelsForCurrentTest()
760 #Initialize debug_info
761 self.debug_info = None
763 def setAsync(self, value):
764 """ Sets async mode to True/False and ensures it is reset after the testcase completes."""
765 old_async = self.dbg.GetAsync()
766 self.dbg.SetAsync(value)
767 self.addTearDownHook(lambda: self.dbg.SetAsync(old_async))
769 def cleanupSubprocesses(self):
770 # Ensure any subprocesses are cleaned up
771 for p in self.subprocesses:
774 del self.subprocesses[:]
775 # Ensure any forked processes are cleaned up
776 for pid in self.forkedProcessPids:
777 if os.path.exists("/proc/" + str(pid)):
778 os.kill(pid, signal.SIGTERM)
780 def spawnSubprocess(self, executable, args=[], install_remote=True):
781 """ Creates a subprocess.Popen object with the specified executable and arguments,
782 saves it in self.subprocesses, and returns the object.
783 NOTE: if using this function, ensure you also call:
785 self.addTearDownHook(self.cleanupSubprocesses)
787 otherwise the test suite will leak processes.
789 proc = _RemoteProcess(install_remote) if lldb.remote_platform else _LocalProcess(self.TraceOn())
790 proc.launch(executable, args)
791 self.subprocesses.append(proc)
794 def forkSubprocess(self, executable, args=[]):
795 """ Fork a subprocess with its own group ID.
796 NOTE: if using this function, ensure you also call:
798 self.addTearDownHook(self.cleanupSubprocesses)
800 otherwise the test suite will leak processes.
802 child_pid = os.fork()
804 # If more I/O support is required, this can be beefed up.
805 fd = os.open(os.devnull, os.O_RDWR)
808 # This call causes the child to have its of group ID
810 os.execvp(executable, [executable] + args)
811 # Give the child time to get through the execvp() call
813 self.forkedProcessPids.append(child_pid)
816 def HideStdout(self):
817 """Hide output to stdout from the user.
819 During test execution, there might be cases where we don't want to show the
820 standard output to the user. For example,
822 self.runCmd(r'''sc print("\n\n\tHello!\n")''')
824 tests whether command abbreviation for 'script' works or not. There is no
825 need to show the 'Hello' output to the user as long as the 'script' command
826 succeeds and we are not in TraceOn() mode (see the '-t' option).
828 In this case, the test method calls self.HideStdout(self) to redirect the
829 sys.stdout to a null device, and restores the sys.stdout upon teardown.
831 Note that you should only call this method at most once during a test case
832 execution. Any subsequent call has no effect at all."""
833 if self.sys_stdout_hidden:
836 self.sys_stdout_hidden = True
837 old_stdout = sys.stdout
838 sys.stdout = open(os.devnull, 'w')
839 def restore_stdout():
840 sys.stdout = old_stdout
841 self.addTearDownHook(restore_stdout)
843 # =======================================================================
844 # Methods for customized teardown cleanups as well as execution of hooks.
845 # =======================================================================
847 def setTearDownCleanup(self, dictionary=None):
848 """Register a cleanup action at tearDown() time with a dictinary"""
849 self.dict = dictionary
850 self.doTearDownCleanup = True
852 def addTearDownCleanup(self, dictionary):
853 """Add a cleanup action at tearDown() time with a dictinary"""
854 self.dicts.append(dictionary)
855 self.doTearDownCleanups = True
857 def addTearDownHook(self, hook):
859 Add a function to be run during tearDown() time.
861 Hooks are executed in a first come first serve manner.
863 if six.callable(hook):
864 with recording(self, traceAlways) as sbuf:
865 print("Adding tearDown hook:", getsource_if_available(hook), file=sbuf)
866 self.hooks.append(hook)
870 def deletePexpectChild(self):
871 # This is for the case of directly spawning 'lldb' and interacting with it
873 if self.child and self.child.isalive():
875 with recording(self, traceAlways) as sbuf:
876 print("tearing down the child process....", file=sbuf)
878 if self.child_in_script_interpreter:
879 self.child.sendline('quit()')
880 self.child.expect_exact(self.child_prompt)
881 self.child.sendline('settings set interpreter.prompt-on-quit false')
882 self.child.sendline('quit')
883 self.child.expect(pexpect.EOF)
884 except (ValueError, pexpect.ExceptionPexpect):
885 # child is already terminated
887 except OSError as exception:
889 if exception.errno != errno.EIO:
892 # child is already terminated
895 # Give it one final blow to make sure the child is terminated.
899 """Fixture for unittest test case teardown."""
901 #traceback.print_stack()
903 self.deletePexpectChild()
905 # Check and run any hook functions.
906 for hook in reversed(self.hooks):
907 with recording(self, traceAlways) as sbuf:
908 print("Executing tearDown hook:", getsource_if_available(hook), file=sbuf)
909 if funcutils.requires_self(hook):
912 hook() # try the plain call and hope it works
916 # Perform registered teardown cleanup.
917 if doCleanup and self.doTearDownCleanup:
918 self.cleanup(dictionary=self.dict)
920 # In rare cases where there are multiple teardown cleanups added.
921 if doCleanup and self.doTearDownCleanups:
923 for dict in reversed(self.dicts):
924 self.cleanup(dictionary=dict)
926 # =========================================================
927 # Various callbacks to allow introspection of test progress
928 # =========================================================
931 """Callback invoked when an error (unexpected exception) errored."""
932 self.__errored__ = True
933 with recording(self, False) as sbuf:
934 # False because there's no need to write "ERROR" to the stderr twice.
935 # Once by the Python unittest framework, and a second time by us.
936 print("ERROR", file=sbuf)
938 def markCleanupError(self):
939 """Callback invoked when an error occurs while a test is cleaning up."""
940 self.__cleanup_errored__ = True
941 with recording(self, False) as sbuf:
942 # False because there's no need to write "CLEANUP_ERROR" to the stderr twice.
943 # Once by the Python unittest framework, and a second time by us.
944 print("CLEANUP_ERROR", file=sbuf)
946 def markFailure(self):
947 """Callback invoked when a failure (test assertion failure) occurred."""
948 self.__failed__ = True
949 with recording(self, False) as sbuf:
950 # False because there's no need to write "FAIL" to the stderr twice.
951 # Once by the Python unittest framework, and a second time by us.
952 print("FAIL", file=sbuf)
954 def markExpectedFailure(self,err,bugnumber):
955 """Callback invoked when an expected failure/error occurred."""
956 self.__expected__ = True
957 with recording(self, False) as sbuf:
958 # False because there's no need to write "expected failure" to the
960 # Once by the Python unittest framework, and a second time by us.
961 if bugnumber == None:
962 print("expected failure", file=sbuf)
964 print("expected failure (problem id:" + str(bugnumber) + ")", file=sbuf)
966 def markSkippedTest(self):
967 """Callback invoked when a test is skipped."""
968 self.__skipped__ = True
969 with recording(self, False) as sbuf:
970 # False because there's no need to write "skipped test" to the
972 # Once by the Python unittest framework, and a second time by us.
973 print("skipped test", file=sbuf)
975 def markUnexpectedSuccess(self, bugnumber):
976 """Callback invoked when an unexpected success occurred."""
977 self.__unexpected__ = True
978 with recording(self, False) as sbuf:
979 # False because there's no need to write "unexpected success" to the
981 # Once by the Python unittest framework, and a second time by us.
982 if bugnumber == None:
983 print("unexpected success", file=sbuf)
985 print("unexpected success (problem id:" + str(bugnumber) + ")", file=sbuf)
987 def getRerunArgs(self):
988 return " -f %s.%s" % (self.__class__.__name__, self._testMethodName)
990 def getLogBasenameForCurrentTest(self, prefix=None):
992 returns a partial path that can be used as the beginning of the name of multiple
993 log files pertaining to this test
995 <session-dir>/<arch>-<compiler>-<test-file>.<test-class>.<test-method>
997 dname = os.path.join(os.environ["LLDB_TEST"],
998 os.environ["LLDB_SESSION_DIRNAME"])
999 if not os.path.isdir(dname):
1003 if prefix is not None:
1004 components.append(prefix)
1005 for c in configuration.session_file_format:
1007 components.append(self.__class__.__module__)
1009 components.append(self.__class__.__name__)
1011 compiler = self.getCompiler()
1013 if compiler[1] == ':':
1014 compiler = compiler[2:]
1015 if os.path.altsep is not None:
1016 compiler = compiler.replace(os.path.altsep, os.path.sep)
1017 components.extend([x for x in compiler.split(os.path.sep) if x != ""])
1019 components.append(self.getArchitecture())
1021 components.append(self.testMethodName)
1022 fname = "-".join(components)
1024 return os.path.join(dname, fname)
1026 def dumpSessionInfo(self):
1028 Dump the debugger interactions leading to a test error/failure. This
1029 allows for more convenient postmortem analysis.
1031 See also LLDBTestResult (dotest.py) which is a singlton class derived
1032 from TextTestResult and overwrites addError, addFailure, and
1033 addExpectedFailure methods to allow us to to mark the test instance as
1037 # We are here because self.tearDown() detected that this test instance
1038 # either errored or failed. The lldb.test_result singleton contains
1039 # two lists (erros and failures) which get populated by the unittest
1040 # framework. Look over there for stack trace information.
1042 # The lists contain 2-tuples of TestCase instances and strings holding
1043 # formatted tracebacks.
1045 # See http://docs.python.org/library/unittest.html#unittest.TestResult.
1047 # output tracebacks into session
1049 if self.__errored__:
1050 pairs = configuration.test_result.errors
1052 elif self.__cleanup_errored__:
1053 pairs = configuration.test_result.cleanup_errors
1054 prefix = 'CleanupError'
1055 elif self.__failed__:
1056 pairs = configuration.test_result.failures
1058 elif self.__expected__:
1059 pairs = configuration.test_result.expectedFailures
1060 prefix = 'ExpectedFailure'
1061 elif self.__skipped__:
1062 prefix = 'SkippedTest'
1063 elif self.__unexpected__:
1064 prefix = 'UnexpectedSuccess'
1068 if not self.__unexpected__ and not self.__skipped__:
1069 for test, traceback in pairs:
1071 print(traceback, file=self.session)
1073 # put footer (timestamp/rerun instructions) into session
1074 testMethod = getattr(self, self._testMethodName)
1075 if getattr(testMethod, "__benchmarks_test__", False):
1081 print("Session info generated @", datetime.datetime.now().ctime(), file=self.session)
1082 print("To rerun this test, issue the following command from the 'test' directory:\n", file=self.session)
1083 print("./dotest.py %s -v %s %s" % (self.getRunOptions(),
1084 ('+b' if benchmarks else '-t'),
1085 self.getRerunArgs()), file=self.session)
1086 self.session.close()
1089 # process the log files
1090 log_files_for_this_test = glob.glob(self.log_basename + "*")
1092 if prefix != 'Success' or lldbtest_config.log_success:
1093 # keep all log files, rename them to include prefix
1094 dst_log_basename = self.getLogBasenameForCurrentTest(prefix)
1095 for src in log_files_for_this_test:
1096 if os.path.isfile(src):
1097 dst = src.replace(self.log_basename, dst_log_basename)
1098 if os.name == "nt" and os.path.isfile(dst):
1099 # On Windows, renaming a -> b will throw an exception if b exists. On non-Windows platforms
1100 # it silently replaces the destination. Ultimately this means that atomic renames are not
1101 # guaranteed to be possible on Windows, but we need this to work anyway, so just remove the
1102 # destination first if it already exists.
1107 # success! (and we don't want log files) delete log files
1108 for log_file in log_files_for_this_test:
1109 remove_file(log_file)
1111 # ====================================================
1112 # Config. methods supported through a plugin interface
1113 # (enables reading of the current test configuration)
1114 # ====================================================
1116 def getArchitecture(self):
1117 """Returns the architecture in effect the test suite is running with."""
1118 module = builder_module()
1119 arch = module.getArchitecture()
1124 def getLldbArchitecture(self):
1125 """Returns the architecture of the lldb binary."""
1126 if not hasattr(self, 'lldbArchitecture'):
1128 # spawn local process
1130 lldbtest_config.lldbExec,
1132 "file " + lldbtest_config.lldbExec,
1137 output = check_output(command)
1138 str = output.decode("utf-8");
1140 for line in str.splitlines():
1141 m = re.search("Current executable set to '.*' \\((.*)\\)\\.", line)
1143 self.lldbArchitecture = m.group(1)
1146 return self.lldbArchitecture
1148 def getCompiler(self):
1149 """Returns the compiler in effect the test suite is running with."""
1150 module = builder_module()
1151 return module.getCompiler()
1153 def getCompilerBinary(self):
1154 """Returns the compiler binary the test suite is running with."""
1155 return self.getCompiler().split()[0]
1157 def getCompilerVersion(self):
1158 """ Returns a string that represents the compiler version.
1159 Supports: llvm, clang.
1163 compiler = self.getCompilerBinary()
1164 version_output = system([[compiler, "-v"]])[1]
1165 for line in version_output.split(os.linesep):
1166 m = re.search('version ([0-9\.]+)', line)
1168 version = m.group(1)
1171 def getGoCompilerVersion(self):
1172 """ Returns a string that represents the go compiler version, or None if go is not found.
1174 compiler = which("go")
1176 version_output = system([[compiler, "version"]])[0]
1177 for line in version_output.split(os.linesep):
1178 m = re.search('go version (devel|go\\S+)', line)
1183 def platformIsDarwin(self):
1184 """Returns true if the OS triple for the selected platform is any valid apple OS"""
1185 return lldbplatformutil.platformIsDarwin()
1187 def getPlatform(self):
1188 """Returns the target platform the test suite is running on."""
1189 return lldbplatformutil.getPlatform()
1191 def isIntelCompiler(self):
1192 """ Returns true if using an Intel (ICC) compiler, false otherwise. """
1193 return any([x in self.getCompiler() for x in ["icc", "icpc", "icl"]])
1195 def expectedCompilerVersion(self, compiler_version):
1196 """Returns True iff compiler_version[1] matches the current compiler version.
1197 Use compiler_version[0] to specify the operator used to determine if a match has occurred.
1198 Any operator other than the following defaults to an equality test:
1199 '>', '>=', "=>", '<', '<=', '=<', '!=', "!" or 'not'
1201 if (compiler_version == None):
1203 operator = str(compiler_version[0])
1204 version = compiler_version[1]
1206 if (version == None):
1208 if (operator == '>'):
1209 return self.getCompilerVersion() > version
1210 if (operator == '>=' or operator == '=>'):
1211 return self.getCompilerVersion() >= version
1212 if (operator == '<'):
1213 return self.getCompilerVersion() < version
1214 if (operator == '<=' or operator == '=<'):
1215 return self.getCompilerVersion() <= version
1216 if (operator == '!=' or operator == '!' or operator == 'not'):
1217 return str(version) not in str(self.getCompilerVersion())
1218 return str(version) in str(self.getCompilerVersion())
1220 def expectedCompiler(self, compilers):
1221 """Returns True iff any element of compilers is a sub-string of the current compiler."""
1222 if (compilers == None):
1225 for compiler in compilers:
1226 if compiler in self.getCompiler():
1231 def expectedArch(self, archs):
1232 """Returns True iff any element of archs is a sub-string of the current architecture."""
1237 if arch in self.getArchitecture():
1242 def getRunOptions(self):
1243 """Command line option for -A and -C to run this test again, called from
1244 self.dumpSessionInfo()."""
1245 arch = self.getArchitecture()
1246 comp = self.getCompiler()
1248 option_str = "-A " + arch
1252 option_str += " -C " + comp
1255 # ==================================================
1256 # Build methods supported through a plugin interface
1257 # ==================================================
1259 def getstdlibFlag(self):
1260 """ Returns the proper -stdlib flag, or empty if not required."""
1261 if self.platformIsDarwin() or self.getPlatform() == "freebsd":
1262 stdlibflag = "-stdlib=libc++"
1263 else: # this includes NetBSD
1267 def getstdFlag(self):
1268 """ Returns the proper stdflag. """
1269 if "gcc" in self.getCompiler() and "4.6" in self.getCompilerVersion():
1270 stdflag = "-std=c++0x"
1272 stdflag = "-std=c++11"
1275 def buildDriver(self, sources, exe_name):
1276 """ Platform-specific way to build a program that links with LLDB (via the liblldb.so
1280 stdflag = self.getstdFlag()
1281 stdlibflag = self.getstdlibFlag()
1283 lib_dir = os.environ["LLDB_LIB_DIR"]
1284 if sys.platform.startswith("darwin"):
1285 dsym = os.path.join(lib_dir, 'LLDB.framework', 'LLDB')
1286 d = {'CXX_SOURCES' : sources,
1288 'CFLAGS_EXTRAS' : "%s %s" % (stdflag, stdlibflag),
1289 'FRAMEWORK_INCLUDES' : "-F%s" % lib_dir,
1290 'LD_EXTRAS' : "%s -Wl,-rpath,%s" % (dsym, lib_dir),
1292 elif sys.platform.rstrip('0123456789') in ('freebsd', 'linux', 'netbsd') or os.environ.get('LLDB_BUILD_TYPE') == 'Makefile':
1293 d = {'CXX_SOURCES' : sources,
1295 'CFLAGS_EXTRAS' : "%s %s -I%s" % (stdflag, stdlibflag, os.path.join(os.environ["LLDB_SRC"], "include")),
1296 'LD_EXTRAS' : "-L%s -llldb" % lib_dir}
1297 elif sys.platform.startswith('win'):
1298 d = {'CXX_SOURCES' : sources,
1300 'CFLAGS_EXTRAS' : "%s %s -I%s" % (stdflag, stdlibflag, os.path.join(os.environ["LLDB_SRC"], "include")),
1301 'LD_EXTRAS' : "-L%s -lliblldb" % os.environ["LLDB_IMPLIB_DIR"]}
1303 print("Building LLDB Driver (%s) from sources %s" % (exe_name, sources))
1305 self.buildDefault(dictionary=d)
1307 def buildLibrary(self, sources, lib_name):
1308 """Platform specific way to build a default library. """
1310 stdflag = self.getstdFlag()
1312 lib_dir = os.environ["LLDB_LIB_DIR"]
1313 if self.platformIsDarwin():
1314 dsym = os.path.join(lib_dir, 'LLDB.framework', 'LLDB')
1315 d = {'DYLIB_CXX_SOURCES' : sources,
1316 'DYLIB_NAME' : lib_name,
1317 'CFLAGS_EXTRAS' : "%s -stdlib=libc++" % stdflag,
1318 'FRAMEWORK_INCLUDES' : "-F%s" % lib_dir,
1319 'LD_EXTRAS' : "%s -Wl,-rpath,%s -dynamiclib" % (dsym, lib_dir),
1321 elif self.getPlatform() in ('freebsd', 'linux', 'netbsd') or os.environ.get('LLDB_BUILD_TYPE') == 'Makefile':
1322 d = {'DYLIB_CXX_SOURCES' : sources,
1323 'DYLIB_NAME' : lib_name,
1324 'CFLAGS_EXTRAS' : "%s -I%s -fPIC" % (stdflag, os.path.join(os.environ["LLDB_SRC"], "include")),
1325 'LD_EXTRAS' : "-shared -L%s -llldb" % lib_dir}
1326 elif self.getPlatform() == 'windows':
1327 d = {'DYLIB_CXX_SOURCES' : sources,
1328 'DYLIB_NAME' : lib_name,
1329 'CFLAGS_EXTRAS' : "%s -I%s -fPIC" % (stdflag, os.path.join(os.environ["LLDB_SRC"], "include")),
1330 'LD_EXTRAS' : "-shared -l%s\liblldb.lib" % self.os.environ["LLDB_IMPLIB_DIR"]}
1332 print("Building LLDB Library (%s) from sources %s" % (lib_name, sources))
1334 self.buildDefault(dictionary=d)
1336 def buildProgram(self, sources, exe_name):
1337 """ Platform specific way to build an executable from C/C++ sources. """
1338 d = {'CXX_SOURCES' : sources,
1340 self.buildDefault(dictionary=d)
1342 def buildDefault(self, architecture=None, compiler=None, dictionary=None, clean=True):
1343 """Platform specific way to build the default binaries."""
1344 module = builder_module()
1345 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary)
1346 if not module.buildDefault(self, architecture, compiler, dictionary, clean):
1347 raise Exception("Don't know how to build default binary")
1349 def buildDsym(self, architecture=None, compiler=None, dictionary=None, clean=True):
1350 """Platform specific way to build binaries with dsym info."""
1351 module = builder_module()
1352 if not module.buildDsym(self, architecture, compiler, dictionary, clean):
1353 raise Exception("Don't know how to build binary with dsym")
1355 def buildDwarf(self, architecture=None, compiler=None, dictionary=None, clean=True):
1356 """Platform specific way to build binaries with dwarf maps."""
1357 module = builder_module()
1358 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary)
1359 if not module.buildDwarf(self, architecture, compiler, dictionary, clean):
1360 raise Exception("Don't know how to build binary with dwarf")
1362 def buildDwo(self, architecture=None, compiler=None, dictionary=None, clean=True):
1363 """Platform specific way to build binaries with dwarf maps."""
1364 module = builder_module()
1365 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary)
1366 if not module.buildDwo(self, architecture, compiler, dictionary, clean):
1367 raise Exception("Don't know how to build binary with dwo")
1369 def buildGModules(self, architecture=None, compiler=None, dictionary=None, clean=True):
1370 """Platform specific way to build binaries with gmodules info."""
1371 module = builder_module()
1372 if not module.buildGModules(self, architecture, compiler, dictionary, clean):
1373 raise Exception("Don't know how to build binary with gmodules")
1376 """Build the default go binary.
1378 system([[which('go'), 'build -gcflags "-N -l" -o a.out main.go']])
1380 def signBinary(self, binary_path):
1381 if sys.platform.startswith("darwin"):
1382 codesign_cmd = "codesign --force --sign lldb_codesign %s" % (binary_path)
1383 call(codesign_cmd, shell=True)
1385 def findBuiltClang(self):
1386 """Tries to find and use Clang from the build directory as the compiler (instead of the system compiler)."""
1388 "llvm-build/Release+Asserts/x86_64/Release+Asserts/bin/clang",
1389 "llvm-build/Debug+Asserts/x86_64/Debug+Asserts/bin/clang",
1390 "llvm-build/Release/x86_64/Release/bin/clang",
1391 "llvm-build/Debug/x86_64/Debug/bin/clang",
1393 lldb_root_path = os.path.join(os.path.dirname(__file__), "..", "..", "..", "..")
1394 for p in paths_to_try:
1395 path = os.path.join(lldb_root_path, p)
1396 if os.path.exists(path):
1399 # Tries to find clang at the same folder as the lldb
1400 path = os.path.join(os.path.dirname(lldbtest_config.lldbExec), "clang")
1401 if os.path.exists(path):
1404 return os.environ["CC"]
1406 def getBuildFlags(self, use_cpp11=True, use_libcxx=False, use_libstdcxx=False):
1407 """ Returns a dictionary (which can be provided to build* functions above) which
1408 contains OS-specific build flags.
1413 # On Mac OS X, unless specifically requested to use libstdc++, use libc++
1414 if not use_libstdcxx and self.platformIsDarwin():
1417 if use_libcxx and self.libcxxPath:
1418 cflags += "-stdlib=libc++ "
1420 libcxxInclude = os.path.join(self.libcxxPath, "include")
1421 libcxxLib = os.path.join(self.libcxxPath, "lib")
1422 if os.path.isdir(libcxxInclude) and os.path.isdir(libcxxLib):
1423 cflags += "-nostdinc++ -I%s -L%s -Wl,-rpath,%s " % (libcxxInclude, libcxxLib, libcxxLib)
1427 if "gcc" in self.getCompiler() and "4.6" in self.getCompilerVersion():
1431 if self.platformIsDarwin() or self.getPlatform() == "freebsd":
1432 cflags += " -stdlib=libc++"
1433 elif self.getPlatform() == "netbsd":
1434 cflags += " -stdlib=libstdc++"
1435 elif "clang" in self.getCompiler():
1436 cflags += " -stdlib=libstdc++"
1438 return {'CFLAGS_EXTRAS' : cflags,
1439 'LD_EXTRAS' : ldflags,
1442 def cleanup(self, dictionary=None):
1443 """Platform specific way to do cleanup after build."""
1444 module = builder_module()
1445 if not module.cleanup(self, dictionary):
1446 raise Exception("Don't know how to do cleanup with dictionary: "+dictionary)
1448 def getLLDBLibraryEnvVal(self):
1449 """ Returns the path that the OS-specific library search environment variable
1450 (self.dylibPath) should be set to in order for a program to find the LLDB
1451 library. If an environment variable named self.dylibPath is already set,
1452 the new path is appended to it and returned.
1454 existing_library_path = os.environ[self.dylibPath] if self.dylibPath in os.environ else None
1455 lib_dir = os.environ["LLDB_LIB_DIR"]
1456 if existing_library_path:
1457 return "%s:%s" % (existing_library_path, lib_dir)
1458 elif sys.platform.startswith("darwin"):
1459 return os.path.join(lib_dir, 'LLDB.framework')
1463 def getLibcPlusPlusLibs(self):
1464 if self.getPlatform() in ('freebsd', 'linux', 'netbsd'):
1465 return ['libc++.so.1']
1467 return ['libc++.1.dylib','libc++abi.dylib']
1469 # Metaclass for TestBase to change the list of test metods when a new TestCase is loaded.
1470 # We change the test methods to create a new test method for each test for each debug info we are
1471 # testing. The name of the new test method will be '<original-name>_<debug-info>' and with adding
1472 # the new test method we remove the old method at the same time. This functionality can be
1473 # supressed by at test case level setting the class attribute NO_DEBUG_INFO_TESTCASE or at test
1474 # level by using the decorator @no_debug_info_test.
1475 class LLDBTestCaseFactory(type):
1476 def __new__(cls, name, bases, attrs):
1477 original_testcase = super(LLDBTestCaseFactory, cls).__new__(cls, name, bases, attrs)
1478 if original_testcase.NO_DEBUG_INFO_TESTCASE:
1479 return original_testcase
1482 for attrname, attrvalue in attrs.items():
1483 if attrname.startswith("test") and not getattr(attrvalue, "__no_debug_info_test__", False):
1484 target_platform = lldb.DBG.GetSelectedPlatform().GetTriple().split('-')[2]
1486 # If any debug info categories were explicitly tagged, assume that list to be
1487 # authoritative. If none were specified, try with all debug info formats.
1488 all_dbginfo_categories = set(test_categories.debug_info_categories)
1489 categories = set(getattr(attrvalue, "categories", [])) & all_dbginfo_categories
1491 categories = all_dbginfo_categories
1493 supported_categories = [x for x in categories
1494 if test_categories.is_supported_on_platform(
1495 x, target_platform, configuration.compilers)]
1496 if "dsym" in supported_categories:
1497 @decorators.add_test_categories(["dsym"])
1499 def dsym_test_method(self, attrvalue=attrvalue):
1500 self.debug_info = "dsym"
1501 return attrvalue(self)
1502 dsym_method_name = attrname + "_dsym"
1503 dsym_test_method.__name__ = dsym_method_name
1504 newattrs[dsym_method_name] = dsym_test_method
1506 if "dwarf" in supported_categories:
1507 @decorators.add_test_categories(["dwarf"])
1509 def dwarf_test_method(self, attrvalue=attrvalue):
1510 self.debug_info = "dwarf"
1511 return attrvalue(self)
1512 dwarf_method_name = attrname + "_dwarf"
1513 dwarf_test_method.__name__ = dwarf_method_name
1514 newattrs[dwarf_method_name] = dwarf_test_method
1516 if "dwo" in supported_categories:
1517 @decorators.add_test_categories(["dwo"])
1519 def dwo_test_method(self, attrvalue=attrvalue):
1520 self.debug_info = "dwo"
1521 return attrvalue(self)
1522 dwo_method_name = attrname + "_dwo"
1523 dwo_test_method.__name__ = dwo_method_name
1524 newattrs[dwo_method_name] = dwo_test_method
1526 if "gmodules" in supported_categories:
1527 @decorators.add_test_categories(["gmodules"])
1529 def gmodules_test_method(self, attrvalue=attrvalue):
1530 self.debug_info = "gmodules"
1531 return attrvalue(self)
1532 gmodules_method_name = attrname + "_gmodules"
1533 gmodules_test_method.__name__ = gmodules_method_name
1534 newattrs[gmodules_method_name] = gmodules_test_method
1537 newattrs[attrname] = attrvalue
1538 return super(LLDBTestCaseFactory, cls).__new__(cls, name, bases, newattrs)
1540 # Setup the metaclass for this class to change the list of the test methods when a new class is loaded
1541 @add_metaclass(LLDBTestCaseFactory)
1542 class TestBase(Base):
1544 This abstract base class is meant to be subclassed. It provides default
1545 implementations for setUpClass(), tearDownClass(), setUp(), and tearDown(),
1548 Important things for test class writers:
1550 - Overwrite the mydir class attribute, otherwise your test class won't
1551 run. It specifies the relative directory to the top level 'test' so
1552 the test harness can change to the correct working directory before
1555 - The setUp method sets up things to facilitate subsequent interactions
1556 with the debugger as part of the test. These include:
1557 - populate the test method name
1558 - create/get a debugger set with synchronous mode (self.dbg)
1559 - get the command interpreter from with the debugger (self.ci)
1560 - create a result object for use with the command interpreter
1564 - The tearDown method tries to perform some necessary cleanup on behalf
1565 of the test to return the debugger to a good state for the next test.
1567 - execute any tearDown hooks registered by the test method with
1568 TestBase.addTearDownHook(); examples can be found in
1569 settings/TestSettings.py
1570 - kill the inferior process associated with each target, if any,
1571 and, then delete the target from the debugger's target list
1572 - perform build cleanup before running the next test method in the
1573 same test class; examples of registering for this service can be
1574 found in types/TestIntegerTypes.py with the call:
1575 - self.setTearDownCleanup(dictionary=d)
1577 - Similarly setUpClass and tearDownClass perform classwise setup and
1578 teardown fixtures. The tearDownClass method invokes a default build
1579 cleanup for the entire test class; also, subclasses can implement the
1580 classmethod classCleanup(cls) to perform special class cleanup action.
1582 - The instance methods runCmd and expect are used heavily by existing
1583 test cases to send a command to the command interpreter and to perform
1584 string/pattern matching on the output of such command execution. The
1585 expect method also provides a mode to peform string/pattern matching
1586 without running a command.
1588 - The build methods buildDefault, buildDsym, and buildDwarf are used to
1589 build the binaries used during a particular test scenario. A plugin
1590 should be provided for the sys.platform running the test suite. The
1591 Mac OS X implementation is located in plugins/darwin.py.
1594 # Subclasses can set this to true (if they don't depend on debug info) to avoid running the
1595 # test multiple times with various debug info types.
1596 NO_DEBUG_INFO_TESTCASE = False
1598 # Maximum allowed attempts when launching the inferior process.
1599 # Can be overridden by the LLDB_MAX_LAUNCH_COUNT environment variable.
1602 # Time to wait before the next launching attempt in second(s).
1603 # Can be overridden by the LLDB_TIME_WAIT_NEXT_LAUNCH environment variable.
1604 timeWaitNextLaunch = 1.0;
1606 # Returns the list of categories to which this test case belongs
1607 # by default, look for a ".categories" file, and read its contents
1608 # if no such file exists, traverse the hierarchy - we guarantee
1609 # a .categories to exist at the top level directory so we do not end up
1610 # looping endlessly - subclasses are free to define their own categories
1611 # in whatever way makes sense to them
1612 def getCategories(self):
1615 folder = inspect.getfile(self.__class__)
1616 folder = os.path.dirname(folder)
1617 while folder != '/':
1618 categories_file_name = os.path.join(folder,".categories")
1619 if os.path.exists(categories_file_name):
1620 categories_file = open(categories_file_name,'r')
1621 categories = categories_file.readline()
1622 categories_file.close()
1623 categories = str.replace(categories,'\n','')
1624 categories = str.replace(categories,'\r','')
1625 return categories.split(',')
1627 folder = os.path.dirname(folder)
1632 #traceback.print_stack()
1634 # Works with the test driver to conditionally skip tests via decorators.
1637 if "LLDB_MAX_LAUNCH_COUNT" in os.environ:
1638 self.maxLaunchCount = int(os.environ["LLDB_MAX_LAUNCH_COUNT"])
1640 if "LLDB_TIME_WAIT_NEXT_LAUNCH" in os.environ:
1641 self.timeWaitNextLaunch = float(os.environ["LLDB_TIME_WAIT_NEXT_LAUNCH"])
1643 # We want our debugger to be synchronous.
1644 self.dbg.SetAsync(False)
1646 # Retrieve the associated command interpreter instance.
1647 self.ci = self.dbg.GetCommandInterpreter()
1649 raise Exception('Could not get the command interpreter')
1651 # And the result object.
1652 self.res = lldb.SBCommandReturnObject()
1654 def registerSharedLibrariesWithTarget(self, target, shlibs):
1655 '''If we are remotely running the test suite, register the shared libraries with the target so they get uploaded, otherwise do nothing
1657 Any modules in the target that have their remote install file specification set will
1658 get uploaded to the remote host. This function registers the local copies of the
1659 shared libraries with the target and sets their remote install locations so they will
1660 be uploaded when the target is run.
1662 if not shlibs or not self.platformContext:
1665 shlib_environment_var = self.platformContext.shlib_environment_var
1666 shlib_prefix = self.platformContext.shlib_prefix
1667 shlib_extension = '.' + self.platformContext.shlib_extension
1669 working_dir = self.get_process_working_directory()
1670 environment = ['%s=%s' % (shlib_environment_var, working_dir)]
1671 # Add any shared libraries to our target if remote so they get
1672 # uploaded into the working directory on the remote side
1674 # The path can be a full path to a shared library, or a make file name like "Foo" for
1675 # "libFoo.dylib" or "libFoo.so", or "Foo.so" for "Foo.so" or "libFoo.so", or just a
1676 # basename like "libFoo.so". So figure out which one it is and resolve the local copy
1677 # of the shared library accordingly
1678 if os.path.exists(name):
1679 local_shlib_path = name # name is the full path to the local shared library
1681 # Check relative names
1682 local_shlib_path = os.path.join(os.getcwd(), shlib_prefix + name + shlib_extension)
1683 if not os.path.exists(local_shlib_path):
1684 local_shlib_path = os.path.join(os.getcwd(), name + shlib_extension)
1685 if not os.path.exists(local_shlib_path):
1686 local_shlib_path = os.path.join(os.getcwd(), name)
1688 # Make sure we found the local shared library in the above code
1689 self.assertTrue(os.path.exists(local_shlib_path))
1691 # Add the shared library to our target
1692 shlib_module = target.AddModule(local_shlib_path, None, None, None)
1693 if lldb.remote_platform:
1694 # We must set the remote install location if we want the shared library
1695 # to get uploaded to the remote target
1696 remote_shlib_path = lldbutil.append_to_process_working_directory(os.path.basename(local_shlib_path))
1697 shlib_module.SetRemoteInstallFileSpec(lldb.SBFileSpec(remote_shlib_path, False))
1701 # utility methods that tests can use to access the current objects
1704 raise Exception('Invalid debugger instance')
1705 return self.dbg.GetSelectedTarget()
1709 raise Exception('Invalid debugger instance')
1710 return self.dbg.GetSelectedTarget().GetProcess()
1714 raise Exception('Invalid debugger instance')
1715 return self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread()
1719 raise Exception('Invalid debugger instance')
1720 return self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
1722 def get_process_working_directory(self):
1723 '''Get the working directory that should be used when launching processes for local or remote processes.'''
1724 if lldb.remote_platform:
1725 # Remote tests set the platform working directory up in TestBase.setUp()
1726 return lldb.remote_platform.GetWorkingDirectory()
1728 # local tests change directory into each test subdirectory
1733 #traceback.print_stack()
1735 # Ensure all the references to SB objects have gone away so that we can
1736 # be sure that all test-specific resources have been freed before we
1737 # attempt to delete the targets.
1740 # Delete the target(s) from the debugger as a general cleanup step.
1741 # This includes terminating the process for each target, if any.
1742 # We'd like to reuse the debugger for our next test without incurring
1743 # the initialization overhead.
1745 for target in self.dbg:
1747 targets.append(target)
1748 process = target.GetProcess()
1750 rc = self.invoke(process, "Kill")
1751 self.assertTrue(rc.Success(), PROCESS_KILLED)
1752 for target in targets:
1753 self.dbg.DeleteTarget(target)
1755 # Do this last, to make sure it's in reverse order from how we setup.
1758 # This must be the last statement, otherwise teardown hooks or other
1759 # lines might depend on this still being active.
1762 def switch_to_thread_with_stop_reason(self, stop_reason):
1764 Run the 'thread list' command, and select the thread with stop reason as
1765 'stop_reason'. If no such thread exists, no select action is done.
1767 from .lldbutil import stop_reason_to_str
1768 self.runCmd('thread list')
1769 output = self.res.GetOutput()
1770 thread_line_pattern = re.compile("^[ *] thread #([0-9]+):.*stop reason = %s" %
1771 stop_reason_to_str(stop_reason))
1772 for line in output.splitlines():
1773 matched = thread_line_pattern.match(line)
1775 self.runCmd('thread select %s' % matched.group(1))
1777 def runCmd(self, cmd, msg=None, check=True, trace=False, inHistory=False):
1779 Ask the command interpreter to handle the command and then check its
1782 # Fail fast if 'cmd' is not meaningful.
1783 if not cmd or len(cmd) == 0:
1784 raise Exception("Bad 'cmd' parameter encountered")
1786 trace = (True if traceAlways else trace)
1788 if cmd.startswith("target create "):
1789 cmd = cmd.replace("target create ", "file ")
1791 running = (cmd.startswith("run") or cmd.startswith("process launch"))
1793 for i in range(self.maxLaunchCount if running else 1):
1794 self.ci.HandleCommand(cmd, self.res, inHistory)
1796 with recording(self, trace) as sbuf:
1797 print("runCmd:", cmd, file=sbuf)
1799 print("check of return status not required", file=sbuf)
1800 if self.res.Succeeded():
1801 print("output:", self.res.GetOutput(), file=sbuf)
1803 print("runCmd failed!", file=sbuf)
1804 print(self.res.GetError(), file=sbuf)
1806 if self.res.Succeeded():
1809 # For process launch, wait some time before possible next try.
1810 time.sleep(self.timeWaitNextLaunch)
1811 with recording(self, trace) as sbuf:
1812 print("Command '" + cmd + "' failed!", file=sbuf)
1815 self.assertTrue(self.res.Succeeded(),
1816 msg if msg else CMD_MSG(cmd))
1818 def match (self, str, patterns, msg=None, trace=False, error=False, matching=True, exe=True):
1819 """run command in str, and match the result against regexp in patterns returning the match object for the first matching pattern
1821 Otherwise, all the arguments have the same meanings as for the expect function"""
1823 trace = (True if traceAlways else trace)
1826 # First run the command. If we are expecting error, set check=False.
1827 # Pass the assert message along since it provides more semantic info.
1828 self.runCmd(str, msg=msg, trace = (True if trace else False), check = not error)
1830 # Then compare the output against expected strings.
1831 output = self.res.GetError() if error else self.res.GetOutput()
1833 # If error is True, the API client expects the command to fail!
1835 self.assertFalse(self.res.Succeeded(),
1836 "Command '" + str + "' is expected to fail!")
1838 # No execution required, just compare str against the golden input.
1840 with recording(self, trace) as sbuf:
1841 print("looking at:", output, file=sbuf)
1843 # The heading says either "Expecting" or "Not expecting".
1844 heading = "Expecting" if matching else "Not expecting"
1846 for pattern in patterns:
1847 # Match Objects always have a boolean value of True.
1848 match_object = re.search(pattern, output)
1849 matched = bool(match_object)
1850 with recording(self, trace) as sbuf:
1851 print("%s pattern: %s" % (heading, pattern), file=sbuf)
1852 print("Matched" if matched else "Not matched", file=sbuf)
1856 self.assertTrue(matched if matching else not matched,
1857 msg if msg else EXP_MSG(str, output, exe))
1861 def expect(self, str, msg=None, patterns=None, startstr=None, endstr=None, substrs=None, trace=False, error=False, matching=True, exe=True, inHistory=False):
1863 Similar to runCmd; with additional expect style output matching ability.
1865 Ask the command interpreter to handle the command and then check its
1866 return status. The 'msg' parameter specifies an informational assert
1867 message. We expect the output from running the command to start with
1868 'startstr', matches the substrings contained in 'substrs', and regexp
1869 matches the patterns contained in 'patterns'.
1871 If the keyword argument error is set to True, it signifies that the API
1872 client is expecting the command to fail. In this case, the error stream
1873 from running the command is retrieved and compared against the golden
1876 If the keyword argument matching is set to False, it signifies that the API
1877 client is expecting the output of the command not to match the golden
1880 Finally, the required argument 'str' represents the lldb command to be
1881 sent to the command interpreter. In case the keyword argument 'exe' is
1882 set to False, the 'str' is treated as a string to be matched/not-matched
1883 against the golden input.
1885 trace = (True if traceAlways else trace)
1888 # First run the command. If we are expecting error, set check=False.
1889 # Pass the assert message along since it provides more semantic info.
1890 self.runCmd(str, msg=msg, trace = (True if trace else False), check = not error, inHistory=inHistory)
1892 # Then compare the output against expected strings.
1893 output = self.res.GetError() if error else self.res.GetOutput()
1895 # If error is True, the API client expects the command to fail!
1897 self.assertFalse(self.res.Succeeded(),
1898 "Command '" + str + "' is expected to fail!")
1900 # No execution required, just compare str against the golden input.
1901 if isinstance(str,lldb.SBCommandReturnObject):
1902 output = str.GetOutput()
1905 with recording(self, trace) as sbuf:
1906 print("looking at:", output, file=sbuf)
1908 # The heading says either "Expecting" or "Not expecting".
1909 heading = "Expecting" if matching else "Not expecting"
1911 # Start from the startstr, if specified.
1912 # If there's no startstr, set the initial state appropriately.
1913 matched = output.startswith(startstr) if startstr else (True if matching else False)
1916 with recording(self, trace) as sbuf:
1917 print("%s start string: %s" % (heading, startstr), file=sbuf)
1918 print("Matched" if matched else "Not matched", file=sbuf)
1920 # Look for endstr, if specified.
1921 keepgoing = matched if matching else not matched
1923 matched = output.endswith(endstr)
1924 with recording(self, trace) as sbuf:
1925 print("%s end string: %s" % (heading, endstr), file=sbuf)
1926 print("Matched" if matched else "Not matched", file=sbuf)
1928 # Look for sub strings, if specified.
1929 keepgoing = matched if matching else not matched
1930 if substrs and keepgoing:
1931 for substr in substrs:
1932 matched = output.find(substr) != -1
1933 with recording(self, trace) as sbuf:
1934 print("%s sub string: %s" % (heading, substr), file=sbuf)
1935 print("Matched" if matched else "Not matched", file=sbuf)
1936 keepgoing = matched if matching else not matched
1940 # Search for regular expression patterns, if specified.
1941 keepgoing = matched if matching else not matched
1942 if patterns and keepgoing:
1943 for pattern in patterns:
1944 # Match Objects always have a boolean value of True.
1945 matched = bool(re.search(pattern, output))
1946 with recording(self, trace) as sbuf:
1947 print("%s pattern: %s" % (heading, pattern), file=sbuf)
1948 print("Matched" if matched else "Not matched", file=sbuf)
1949 keepgoing = matched if matching else not matched
1953 self.assertTrue(matched if matching else not matched,
1954 msg if msg else EXP_MSG(str, output, exe))
1956 def invoke(self, obj, name, trace=False):
1957 """Use reflection to call a method dynamically with no argument."""
1958 trace = (True if traceAlways else trace)
1960 method = getattr(obj, name)
1962 self.assertTrue(inspect.ismethod(method),
1963 name + "is a method name of object: " + str(obj))
1965 with recording(self, trace) as sbuf:
1966 print(str(method) + ":", result, file=sbuf)
1969 def build(self, architecture=None, compiler=None, dictionary=None, clean=True):
1970 """Platform specific way to build the default binaries."""
1971 module = builder_module()
1972 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary)
1973 if self.debug_info is None:
1974 return self.buildDefault(architecture, compiler, dictionary, clean)
1975 elif self.debug_info == "dsym":
1976 return self.buildDsym(architecture, compiler, dictionary, clean)
1977 elif self.debug_info == "dwarf":
1978 return self.buildDwarf(architecture, compiler, dictionary, clean)
1979 elif self.debug_info == "dwo":
1980 return self.buildDwo(architecture, compiler, dictionary, clean)
1981 elif self.debug_info == "gmodules":
1982 return self.buildGModules(architecture, compiler, dictionary, clean)
1984 self.fail("Can't build for debug info: %s" % self.debug_info)
1986 def run_platform_command(self, cmd):
1987 platform = self.dbg.GetSelectedPlatform()
1988 shell_command = lldb.SBPlatformShellCommand(cmd)
1989 err = platform.Run(shell_command)
1990 return (err, shell_command.GetStatus(), shell_command.GetOutput())
1992 # =================================================
1993 # Misc. helper methods for debugging test execution
1994 # =================================================
1996 def DebugSBValue(self, val):
1997 """Debug print a SBValue object, if traceAlways is True."""
1998 from .lldbutil import value_type_to_str
2004 err.write(val.GetName() + ":\n")
2005 err.write('\t' + "TypeName -> " + val.GetTypeName() + '\n')
2006 err.write('\t' + "ByteSize -> " + str(val.GetByteSize()) + '\n')
2007 err.write('\t' + "NumChildren -> " + str(val.GetNumChildren()) + '\n')
2008 err.write('\t' + "Value -> " + str(val.GetValue()) + '\n')
2009 err.write('\t' + "ValueAsUnsigned -> " + str(val.GetValueAsUnsigned())+ '\n')
2010 err.write('\t' + "ValueType -> " + value_type_to_str(val.GetValueType()) + '\n')
2011 err.write('\t' + "Summary -> " + str(val.GetSummary()) + '\n')
2012 err.write('\t' + "IsPointerType -> " + str(val.TypeIsPointerType()) + '\n')
2013 err.write('\t' + "Location -> " + val.GetLocation() + '\n')
2015 def DebugSBType(self, type):
2016 """Debug print a SBType object, if traceAlways is True."""
2021 err.write(type.GetName() + ":\n")
2022 err.write('\t' + "ByteSize -> " + str(type.GetByteSize()) + '\n')
2023 err.write('\t' + "IsPointerType -> " + str(type.IsPointerType()) + '\n')
2024 err.write('\t' + "IsReferenceType -> " + str(type.IsReferenceType()) + '\n')
2026 def DebugPExpect(self, child):
2027 """Debug the spwaned pexpect object."""
2034 def RemoveTempFile(cls, file):
2035 if os.path.exists(file):
2038 # On Windows, the first attempt to delete a recently-touched file can fail
2039 # because of a race with antimalware scanners. This function will detect a
2040 # failure and retry.
2041 def remove_file(file, num_retries = 1, sleep_duration = 0.5):
2042 for i in range(num_retries+1):
2047 time.sleep(sleep_duration)