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