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