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 count = 1" 117 118BREAKPOINT_HIT_TWICE = "Breakpoint resolved with hit count = 2" 119 120BREAKPOINT_HIT_THRICE = "Breakpoint resolved with hit count = 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_BREAKPOINT_JITTED_CONDITION = "Stopped due to breakpoint jitted condition" 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 @staticmethod 700 def setUpCommands(): 701 return [ 702 # Disable Spotlight lookup. The testsuite creates 703 # different binaries with the same UUID, because they only 704 # differ in the debug info, which is not being hashed. 705 "settings set symbols.enable-external-lookup false", 706 707 # Testsuite runs in parallel and the host can have also other load. 708 "settings set plugin.process.gdb-remote.packet-timeout 60"] 709 710 def setUp(self): 711 """Fixture for unittest test case setup. 712 713 It works with the test driver to conditionally skip tests and does other 714 initializations.""" 715 #import traceback 716 # traceback.print_stack() 717 718 if "LIBCXX_PATH" in os.environ: 719 self.libcxxPath = os.environ["LIBCXX_PATH"] 720 else: 721 self.libcxxPath = None 722 723 if "LLDBVSCODE_EXEC" in os.environ: 724 self.lldbVSCodeExec = os.environ["LLDBVSCODE_EXEC"] 725 else: 726 self.lldbVSCodeExec = None 727 728 self.lldbOption = " ".join( 729 "-o '" + s + "'" for s in self.setUpCommands()) 730 731 # If we spawn an lldb process for test (via pexpect), do not load the 732 # init file unless told otherwise. 733 if os.environ.get("NO_LLDBINIT") != "NO": 734 self.lldbOption += " --no-lldbinit" 735 736 # Assign the test method name to self.testMethodName. 737 # 738 # For an example of the use of this attribute, look at test/types dir. 739 # There are a bunch of test cases under test/types and we don't want the 740 # module cacheing subsystem to be confused with executable name "a.out" 741 # used for all the test cases. 742 self.testMethodName = self._testMethodName 743 744 # This is for the case of directly spawning 'lldb'/'gdb' and interacting 745 # with it using pexpect. 746 self.child = None 747 self.child_prompt = "(lldb) " 748 # If the child is interacting with the embedded script interpreter, 749 # there are two exits required during tear down, first to quit the 750 # embedded script interpreter and second to quit the lldb command 751 # interpreter. 752 self.child_in_script_interpreter = False 753 754 # These are for customized teardown cleanup. 755 self.dict = None 756 self.doTearDownCleanup = False 757 # And in rare cases where there are multiple teardown cleanups. 758 self.dicts = [] 759 self.doTearDownCleanups = False 760 761 # List of spawned subproces.Popen objects 762 self.subprocesses = [] 763 764 # List of forked process PIDs 765 self.forkedProcessPids = [] 766 767 # Create a string buffer to record the session info, to be dumped into a 768 # test case specific file if test failure is encountered. 769 self.log_basename = self.getLogBasenameForCurrentTest() 770 771 session_file = "{}.log".format(self.log_basename) 772 # Python 3 doesn't support unbuffered I/O in text mode. Open buffered. 773 self.session = encoded_file.open(session_file, "utf-8", mode="w") 774 775 # Optimistically set __errored__, __failed__, __expected__ to False 776 # initially. If the test errored/failed, the session info 777 # (self.session) is then dumped into a session specific file for 778 # diagnosis. 779 self.__cleanup_errored__ = False 780 self.__errored__ = False 781 self.__failed__ = False 782 self.__expected__ = False 783 # We are also interested in unexpected success. 784 self.__unexpected__ = False 785 # And skipped tests. 786 self.__skipped__ = False 787 788 # See addTearDownHook(self, hook) which allows the client to add a hook 789 # function to be run during tearDown() time. 790 self.hooks = [] 791 792 # See HideStdout(self). 793 self.sys_stdout_hidden = False 794 795 if self.platformContext: 796 # set environment variable names for finding shared libraries 797 self.dylibPath = self.platformContext.shlib_environment_var 798 799 # Create the debugger instance if necessary. 800 try: 801 self.dbg = lldb.DBG 802 except AttributeError: 803 self.dbg = lldb.SBDebugger.Create() 804 805 if not self.dbg: 806 raise Exception('Invalid debugger instance') 807 808 # Retrieve the associated command interpreter instance. 809 self.ci = self.dbg.GetCommandInterpreter() 810 if not self.ci: 811 raise Exception('Could not get the command interpreter') 812 813 # And the result object. 814 self.res = lldb.SBCommandReturnObject() 815 816 self.setPlatformWorkingDir() 817 self.enableLogChannelsForCurrentTest() 818 819 lib_dir = os.environ["LLDB_LIB_DIR"] 820 self.dsym = None 821 self.framework_dir = None 822 self.darwinWithFramework = self.platformIsDarwin() 823 if sys.platform.startswith("darwin"): 824 # Handle the framework environment variable if it is set 825 if hasattr(lldbtest_config, 'lldbFrameworkPath'): 826 framework_path = lldbtest_config.lldbFrameworkPath 827 # Framework dir should be the directory containing the framework 828 self.framework_dir = framework_path[:framework_path.rfind('LLDB.framework')] 829 # If a framework dir was not specified assume the Xcode build 830 # directory layout where the framework is in LLDB_LIB_DIR. 831 else: 832 self.framework_dir = lib_dir 833 self.dsym = os.path.join(self.framework_dir, 'LLDB.framework', 'LLDB') 834 # If the framework binary doesn't exist, assume we didn't actually 835 # build a framework, and fallback to standard *nix behavior by 836 # setting framework_dir and dsym to None. 837 if not os.path.exists(self.dsym): 838 self.framework_dir = None 839 self.dsym = None 840 self.darwinWithFramework = False 841 self.makeBuildDir() 842 843 def setAsync(self, value): 844 """ Sets async mode to True/False and ensures it is reset after the testcase completes.""" 845 old_async = self.dbg.GetAsync() 846 self.dbg.SetAsync(value) 847 self.addTearDownHook(lambda: self.dbg.SetAsync(old_async)) 848 849 def cleanupSubprocesses(self): 850 # Ensure any subprocesses are cleaned up 851 for p in self.subprocesses: 852 p.terminate() 853 del p 854 del self.subprocesses[:] 855 # Ensure any forked processes are cleaned up 856 for pid in self.forkedProcessPids: 857 if os.path.exists("/proc/" + str(pid)): 858 os.kill(pid, signal.SIGTERM) 859 860 def spawnSubprocess(self, executable, args=[], install_remote=True): 861 """ Creates a subprocess.Popen object with the specified executable and arguments, 862 saves it in self.subprocesses, and returns the object. 863 NOTE: if using this function, ensure you also call: 864 865 self.addTearDownHook(self.cleanupSubprocesses) 866 867 otherwise the test suite will leak processes. 868 """ 869 proc = _RemoteProcess( 870 install_remote) if lldb.remote_platform else _LocalProcess(self.TraceOn()) 871 proc.launch(executable, args) 872 self.subprocesses.append(proc) 873 return proc 874 875 def forkSubprocess(self, executable, args=[]): 876 """ Fork a subprocess with its own group ID. 877 NOTE: if using this function, ensure you also call: 878 879 self.addTearDownHook(self.cleanupSubprocesses) 880 881 otherwise the test suite will leak processes. 882 """ 883 child_pid = os.fork() 884 if child_pid == 0: 885 # If more I/O support is required, this can be beefed up. 886 fd = os.open(os.devnull, os.O_RDWR) 887 os.dup2(fd, 1) 888 os.dup2(fd, 2) 889 # This call causes the child to have its of group ID 890 os.setpgid(0, 0) 891 os.execvp(executable, [executable] + args) 892 # Give the child time to get through the execvp() call 893 time.sleep(0.1) 894 self.forkedProcessPids.append(child_pid) 895 return child_pid 896 897 def HideStdout(self): 898 """Hide output to stdout from the user. 899 900 During test execution, there might be cases where we don't want to show the 901 standard output to the user. For example, 902 903 self.runCmd(r'''sc print("\n\n\tHello!\n")''') 904 905 tests whether command abbreviation for 'script' works or not. There is no 906 need to show the 'Hello' output to the user as long as the 'script' command 907 succeeds and we are not in TraceOn() mode (see the '-t' option). 908 909 In this case, the test method calls self.HideStdout(self) to redirect the 910 sys.stdout to a null device, and restores the sys.stdout upon teardown. 911 912 Note that you should only call this method at most once during a test case 913 execution. Any subsequent call has no effect at all.""" 914 if self.sys_stdout_hidden: 915 return 916 917 self.sys_stdout_hidden = True 918 old_stdout = sys.stdout 919 sys.stdout = open(os.devnull, 'w') 920 921 def restore_stdout(): 922 sys.stdout = old_stdout 923 self.addTearDownHook(restore_stdout) 924 925 # ======================================================================= 926 # Methods for customized teardown cleanups as well as execution of hooks. 927 # ======================================================================= 928 929 def setTearDownCleanup(self, dictionary=None): 930 """Register a cleanup action at tearDown() time with a dictinary""" 931 self.dict = dictionary 932 self.doTearDownCleanup = True 933 934 def addTearDownCleanup(self, dictionary): 935 """Add a cleanup action at tearDown() time with a dictinary""" 936 self.dicts.append(dictionary) 937 self.doTearDownCleanups = True 938 939 def addTearDownHook(self, hook): 940 """ 941 Add a function to be run during tearDown() time. 942 943 Hooks are executed in a first come first serve manner. 944 """ 945 if six.callable(hook): 946 with recording(self, traceAlways) as sbuf: 947 print( 948 "Adding tearDown hook:", 949 getsource_if_available(hook), 950 file=sbuf) 951 self.hooks.append(hook) 952 953 return self 954 955 def deletePexpectChild(self): 956 # This is for the case of directly spawning 'lldb' and interacting with it 957 # using pexpect. 958 if self.child and self.child.isalive(): 959 import pexpect 960 with recording(self, traceAlways) as sbuf: 961 print("tearing down the child process....", file=sbuf) 962 try: 963 if self.child_in_script_interpreter: 964 self.child.sendline('quit()') 965 self.child.expect_exact(self.child_prompt) 966 self.child.sendline( 967 'settings set interpreter.prompt-on-quit false') 968 self.child.sendline('quit') 969 self.child.expect(pexpect.EOF) 970 except (ValueError, pexpect.ExceptionPexpect): 971 # child is already terminated 972 pass 973 except OSError as exception: 974 import errno 975 if exception.errno != errno.EIO: 976 # unexpected error 977 raise 978 # child is already terminated 979 finally: 980 # Give it one final blow to make sure the child is terminated. 981 self.child.close() 982 983 def tearDown(self): 984 """Fixture for unittest test case teardown.""" 985 #import traceback 986 # traceback.print_stack() 987 988 self.deletePexpectChild() 989 990 # Check and run any hook functions. 991 for hook in reversed(self.hooks): 992 with recording(self, traceAlways) as sbuf: 993 print( 994 "Executing tearDown hook:", 995 getsource_if_available(hook), 996 file=sbuf) 997 if funcutils.requires_self(hook): 998 hook(self) 999 else: 1000 hook() # try the plain call and hope it works 1001 1002 del self.hooks 1003 1004 # Perform registered teardown cleanup. 1005 if doCleanup and self.doTearDownCleanup: 1006 self.cleanup(dictionary=self.dict) 1007 1008 # In rare cases where there are multiple teardown cleanups added. 1009 if doCleanup and self.doTearDownCleanups: 1010 if self.dicts: 1011 for dict in reversed(self.dicts): 1012 self.cleanup(dictionary=dict) 1013 1014 # ========================================================= 1015 # Various callbacks to allow introspection of test progress 1016 # ========================================================= 1017 1018 def markError(self): 1019 """Callback invoked when an error (unexpected exception) errored.""" 1020 self.__errored__ = True 1021 with recording(self, False) as sbuf: 1022 # False because there's no need to write "ERROR" to the stderr twice. 1023 # Once by the Python unittest framework, and a second time by us. 1024 print("ERROR", file=sbuf) 1025 1026 def markCleanupError(self): 1027 """Callback invoked when an error occurs while a test is cleaning up.""" 1028 self.__cleanup_errored__ = True 1029 with recording(self, False) as sbuf: 1030 # False because there's no need to write "CLEANUP_ERROR" to the stderr twice. 1031 # Once by the Python unittest framework, and a second time by us. 1032 print("CLEANUP_ERROR", file=sbuf) 1033 1034 def markFailure(self): 1035 """Callback invoked when a failure (test assertion failure) occurred.""" 1036 self.__failed__ = True 1037 with recording(self, False) as sbuf: 1038 # False because there's no need to write "FAIL" to the stderr twice. 1039 # Once by the Python unittest framework, and a second time by us. 1040 print("FAIL", file=sbuf) 1041 1042 def markExpectedFailure(self, err, bugnumber): 1043 """Callback invoked when an expected failure/error occurred.""" 1044 self.__expected__ = True 1045 with recording(self, False) as sbuf: 1046 # False because there's no need to write "expected failure" to the 1047 # stderr twice. 1048 # Once by the Python unittest framework, and a second time by us. 1049 if bugnumber is None: 1050 print("expected failure", file=sbuf) 1051 else: 1052 print( 1053 "expected failure (problem id:" + str(bugnumber) + ")", 1054 file=sbuf) 1055 1056 def markSkippedTest(self): 1057 """Callback invoked when a test is skipped.""" 1058 self.__skipped__ = True 1059 with recording(self, False) as sbuf: 1060 # False because there's no need to write "skipped test" to the 1061 # stderr twice. 1062 # Once by the Python unittest framework, and a second time by us. 1063 print("skipped test", file=sbuf) 1064 1065 def markUnexpectedSuccess(self, bugnumber): 1066 """Callback invoked when an unexpected success occurred.""" 1067 self.__unexpected__ = True 1068 with recording(self, False) as sbuf: 1069 # False because there's no need to write "unexpected success" to the 1070 # stderr twice. 1071 # Once by the Python unittest framework, and a second time by us. 1072 if bugnumber is None: 1073 print("unexpected success", file=sbuf) 1074 else: 1075 print( 1076 "unexpected success (problem id:" + str(bugnumber) + ")", 1077 file=sbuf) 1078 1079 def getRerunArgs(self): 1080 return " -f %s.%s" % (self.__class__.__name__, self._testMethodName) 1081 1082 def getLogBasenameForCurrentTest(self, prefix=None): 1083 """ 1084 returns a partial path that can be used as the beginning of the name of multiple 1085 log files pertaining to this test 1086 1087 <session-dir>/<arch>-<compiler>-<test-file>.<test-class>.<test-method> 1088 """ 1089 dname = os.path.join(os.environ["LLDB_TEST"], 1090 os.environ["LLDB_SESSION_DIRNAME"]) 1091 if not os.path.isdir(dname): 1092 os.mkdir(dname) 1093 1094 components = [] 1095 if prefix is not None: 1096 components.append(prefix) 1097 for c in configuration.session_file_format: 1098 if c == 'f': 1099 components.append(self.__class__.__module__) 1100 elif c == 'n': 1101 components.append(self.__class__.__name__) 1102 elif c == 'c': 1103 compiler = self.getCompiler() 1104 1105 if compiler[1] == ':': 1106 compiler = compiler[2:] 1107 if os.path.altsep is not None: 1108 compiler = compiler.replace(os.path.altsep, os.path.sep) 1109 path_components = [x for x in compiler.split(os.path.sep) if x != ""] 1110 1111 # Add at most 4 path components to avoid generating very long 1112 # filenames 1113 components.extend(path_components[-4:]) 1114 elif c == 'a': 1115 components.append(self.getArchitecture()) 1116 elif c == 'm': 1117 components.append(self.testMethodName) 1118 fname = "-".join(components) 1119 1120 return os.path.join(dname, fname) 1121 1122 def dumpSessionInfo(self): 1123 """ 1124 Dump the debugger interactions leading to a test error/failure. This 1125 allows for more convenient postmortem analysis. 1126 1127 See also LLDBTestResult (dotest.py) which is a singlton class derived 1128 from TextTestResult and overwrites addError, addFailure, and 1129 addExpectedFailure methods to allow us to to mark the test instance as 1130 such. 1131 """ 1132 1133 # We are here because self.tearDown() detected that this test instance 1134 # either errored or failed. The lldb.test_result singleton contains 1135 # two lists (erros and failures) which get populated by the unittest 1136 # framework. Look over there for stack trace information. 1137 # 1138 # The lists contain 2-tuples of TestCase instances and strings holding 1139 # formatted tracebacks. 1140 # 1141 # See http://docs.python.org/library/unittest.html#unittest.TestResult. 1142 1143 # output tracebacks into session 1144 pairs = [] 1145 if self.__errored__: 1146 pairs = configuration.test_result.errors 1147 prefix = 'Error' 1148 elif self.__cleanup_errored__: 1149 pairs = configuration.test_result.cleanup_errors 1150 prefix = 'CleanupError' 1151 elif self.__failed__: 1152 pairs = configuration.test_result.failures 1153 prefix = 'Failure' 1154 elif self.__expected__: 1155 pairs = configuration.test_result.expectedFailures 1156 prefix = 'ExpectedFailure' 1157 elif self.__skipped__: 1158 prefix = 'SkippedTest' 1159 elif self.__unexpected__: 1160 prefix = 'UnexpectedSuccess' 1161 else: 1162 prefix = 'Success' 1163 1164 if not self.__unexpected__ and not self.__skipped__: 1165 for test, traceback in pairs: 1166 if test is self: 1167 print(traceback, file=self.session) 1168 1169 # put footer (timestamp/rerun instructions) into session 1170 testMethod = getattr(self, self._testMethodName) 1171 if getattr(testMethod, "__benchmarks_test__", False): 1172 benchmarks = True 1173 else: 1174 benchmarks = False 1175 1176 import datetime 1177 print( 1178 "Session info generated @", 1179 datetime.datetime.now().ctime(), 1180 file=self.session) 1181 print( 1182 "To rerun this test, issue the following command from the 'test' directory:\n", 1183 file=self.session) 1184 print( 1185 "./dotest.py %s -v %s %s" % 1186 (self.getRunOptions(), 1187 ('+b' if benchmarks else '-t'), 1188 self.getRerunArgs()), 1189 file=self.session) 1190 self.session.close() 1191 del self.session 1192 1193 # process the log files 1194 log_files_for_this_test = glob.glob(self.log_basename + "*") 1195 1196 if prefix != 'Success' or lldbtest_config.log_success: 1197 # keep all log files, rename them to include prefix 1198 dst_log_basename = self.getLogBasenameForCurrentTest(prefix) 1199 for src in log_files_for_this_test: 1200 if os.path.isfile(src): 1201 dst = src.replace(self.log_basename, dst_log_basename) 1202 if os.name == "nt" and os.path.isfile(dst): 1203 # On Windows, renaming a -> b will throw an exception if 1204 # b exists. On non-Windows platforms it silently 1205 # replaces the destination. Ultimately this means that 1206 # atomic renames are not guaranteed to be possible on 1207 # Windows, but we need this to work anyway, so just 1208 # remove the destination first if it already exists. 1209 remove_file(dst) 1210 1211 lldbutil.mkdir_p(os.path.dirname(dst)) 1212 os.rename(src, dst) 1213 else: 1214 # success! (and we don't want log files) delete log files 1215 for log_file in log_files_for_this_test: 1216 remove_file(log_file) 1217 1218 # ==================================================== 1219 # Config. methods supported through a plugin interface 1220 # (enables reading of the current test configuration) 1221 # ==================================================== 1222 1223 def isMIPS(self): 1224 """Returns true if the architecture is MIPS.""" 1225 arch = self.getArchitecture() 1226 if re.match("mips", arch): 1227 return True 1228 return False 1229 1230 def isPPC64le(self): 1231 """Returns true if the architecture is PPC64LE.""" 1232 arch = self.getArchitecture() 1233 if re.match("powerpc64le", arch): 1234 return True 1235 return False 1236 1237 def getArchitecture(self): 1238 """Returns the architecture in effect the test suite is running with.""" 1239 module = builder_module() 1240 arch = module.getArchitecture() 1241 if arch == 'amd64': 1242 arch = 'x86_64' 1243 return arch 1244 1245 def getLldbArchitecture(self): 1246 """Returns the architecture of the lldb binary.""" 1247 if not hasattr(self, 'lldbArchitecture'): 1248 1249 # spawn local process 1250 command = [ 1251 lldbtest_config.lldbExec, 1252 "-o", 1253 "file " + lldbtest_config.lldbExec, 1254 "-o", 1255 "quit" 1256 ] 1257 1258 output = check_output(command) 1259 str = output.decode("utf-8") 1260 1261 for line in str.splitlines(): 1262 m = re.search( 1263 "Current executable set to '.*' \\((.*)\\)\\.", line) 1264 if m: 1265 self.lldbArchitecture = m.group(1) 1266 break 1267 1268 return self.lldbArchitecture 1269 1270 def getCompiler(self): 1271 """Returns the compiler in effect the test suite is running with.""" 1272 module = builder_module() 1273 return module.getCompiler() 1274 1275 def getCompilerBinary(self): 1276 """Returns the compiler binary the test suite is running with.""" 1277 return self.getCompiler().split()[0] 1278 1279 def getCompilerVersion(self): 1280 """ Returns a string that represents the compiler version. 1281 Supports: llvm, clang. 1282 """ 1283 version = 'unknown' 1284 1285 compiler = self.getCompilerBinary() 1286 version_output = system([[compiler, "-v"]])[1] 1287 for line in version_output.split(os.linesep): 1288 m = re.search('version ([0-9\.]+)', line) 1289 if m: 1290 version = m.group(1) 1291 return version 1292 1293 def getDwarfVersion(self): 1294 """ Returns the dwarf version generated by clang or '0'. """ 1295 if configuration.dwarf_version: 1296 return str(configuration.dwarf_version) 1297 if 'clang' in self.getCompiler(): 1298 try: 1299 driver_output = check_output( 1300 [self.getCompiler()] + '-g -c -x c - -o - -###'.split(), 1301 stderr=STDOUT) 1302 for line in driver_output.split(os.linesep): 1303 m = re.search('dwarf-version=([0-9])', line) 1304 if m: 1305 return m.group(1) 1306 except: pass 1307 return '0' 1308 1309 def platformIsDarwin(self): 1310 """Returns true if the OS triple for the selected platform is any valid apple OS""" 1311 return lldbplatformutil.platformIsDarwin() 1312 1313 def hasDarwinFramework(self): 1314 return self.darwinWithFramework 1315 1316 def getPlatform(self): 1317 """Returns the target platform the test suite is running on.""" 1318 return lldbplatformutil.getPlatform() 1319 1320 def isIntelCompiler(self): 1321 """ Returns true if using an Intel (ICC) compiler, false otherwise. """ 1322 return any([x in self.getCompiler() for x in ["icc", "icpc", "icl"]]) 1323 1324 def expectedCompilerVersion(self, compiler_version): 1325 """Returns True iff compiler_version[1] matches the current compiler version. 1326 Use compiler_version[0] to specify the operator used to determine if a match has occurred. 1327 Any operator other than the following defaults to an equality test: 1328 '>', '>=', "=>", '<', '<=', '=<', '!=', "!" or 'not' 1329 """ 1330 if (compiler_version is None): 1331 return True 1332 operator = str(compiler_version[0]) 1333 version = compiler_version[1] 1334 1335 if (version is None): 1336 return True 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 == '<'): 1342 return LooseVersion(self.getCompilerVersion()) < LooseVersion(version) 1343 if (operator == '<=' or operator == '=<'): 1344 return LooseVersion(self.getCompilerVersion()) <= LooseVersion(version) 1345 if (operator == '!=' or operator == '!' or operator == 'not'): 1346 return str(version) not in str(self.getCompilerVersion()) 1347 return str(version) in str(self.getCompilerVersion()) 1348 1349 def expectedCompiler(self, compilers): 1350 """Returns True iff any element of compilers is a sub-string of the current compiler.""" 1351 if (compilers is None): 1352 return True 1353 1354 for compiler in compilers: 1355 if compiler in self.getCompiler(): 1356 return True 1357 1358 return False 1359 1360 def expectedArch(self, archs): 1361 """Returns True iff any element of archs is a sub-string of the current architecture.""" 1362 if (archs is None): 1363 return True 1364 1365 for arch in archs: 1366 if arch in self.getArchitecture(): 1367 return True 1368 1369 return False 1370 1371 def getRunOptions(self): 1372 """Command line option for -A and -C to run this test again, called from 1373 self.dumpSessionInfo().""" 1374 arch = self.getArchitecture() 1375 comp = self.getCompiler() 1376 option_str = "" 1377 if arch: 1378 option_str = "-A " + arch 1379 if comp: 1380 option_str += " -C " + comp 1381 return option_str 1382 1383 def getDebugInfo(self): 1384 method = getattr(self, self.testMethodName) 1385 return getattr(method, "debug_info", None) 1386 1387 # ================================================== 1388 # Build methods supported through a plugin interface 1389 # ================================================== 1390 1391 def getstdlibFlag(self): 1392 """ Returns the proper -stdlib flag, or empty if not required.""" 1393 if self.platformIsDarwin() or self.getPlatform() == "freebsd" or self.getPlatform() == "openbsd": 1394 stdlibflag = "-stdlib=libc++" 1395 else: # this includes NetBSD 1396 stdlibflag = "" 1397 return stdlibflag 1398 1399 def getstdFlag(self): 1400 """ Returns the proper stdflag. """ 1401 if "gcc" in self.getCompiler() and "4.6" in self.getCompilerVersion(): 1402 stdflag = "-std=c++0x" 1403 else: 1404 stdflag = "-std=c++11" 1405 return stdflag 1406 1407 def buildDriver(self, sources, exe_name): 1408 """ Platform-specific way to build a program that links with LLDB (via the liblldb.so 1409 or LLDB.framework). 1410 """ 1411 stdflag = self.getstdFlag() 1412 stdlibflag = self.getstdlibFlag() 1413 1414 lib_dir = os.environ["LLDB_LIB_DIR"] 1415 if self.hasDarwinFramework(): 1416 d = {'CXX_SOURCES': sources, 1417 'EXE': exe_name, 1418 'CFLAGS_EXTRAS': "%s %s" % (stdflag, stdlibflag), 1419 'FRAMEWORK_INCLUDES': "-F%s" % self.framework_dir, 1420 'LD_EXTRAS': "%s -Wl,-rpath,%s" % (self.dsym, self.framework_dir), 1421 } 1422 elif sys.platform.startswith('win'): 1423 d = { 1424 'CXX_SOURCES': sources, 1425 'EXE': exe_name, 1426 'CFLAGS_EXTRAS': "%s %s -I%s" % (stdflag, 1427 stdlibflag, 1428 os.path.join( 1429 os.environ["LLDB_SRC"], 1430 "include")), 1431 'LD_EXTRAS': "-L%s -lliblldb" % os.environ["LLDB_IMPLIB_DIR"]} 1432 else: 1433 d = { 1434 'CXX_SOURCES': sources, 1435 'EXE': exe_name, 1436 'CFLAGS_EXTRAS': "%s %s -I%s" % (stdflag, 1437 stdlibflag, 1438 os.path.join( 1439 os.environ["LLDB_SRC"], 1440 "include")), 1441 'LD_EXTRAS': "-L%s/../lib -llldb -Wl,-rpath,%s/../lib" % (lib_dir, lib_dir)} 1442 if self.TraceOn(): 1443 print( 1444 "Building LLDB Driver (%s) from sources %s" % 1445 (exe_name, sources)) 1446 1447 self.buildDefault(dictionary=d) 1448 1449 def buildLibrary(self, sources, lib_name): 1450 """Platform specific way to build a default library. """ 1451 1452 stdflag = self.getstdFlag() 1453 1454 lib_dir = os.environ["LLDB_LIB_DIR"] 1455 if self.hasDarwinFramework(): 1456 d = {'DYLIB_CXX_SOURCES': sources, 1457 'DYLIB_NAME': lib_name, 1458 'CFLAGS_EXTRAS': "%s -stdlib=libc++" % stdflag, 1459 'FRAMEWORK_INCLUDES': "-F%s" % self.framework_dir, 1460 'LD_EXTRAS': "%s -Wl,-rpath,%s -dynamiclib" % (self.dsym, self.framework_dir), 1461 } 1462 elif self.getPlatform() == 'windows': 1463 d = { 1464 'DYLIB_CXX_SOURCES': sources, 1465 'DYLIB_NAME': lib_name, 1466 'CFLAGS_EXTRAS': "%s -I%s " % (stdflag, 1467 os.path.join( 1468 os.environ["LLDB_SRC"], 1469 "include")), 1470 'LD_EXTRAS': "-shared -l%s\liblldb.lib" % self.os.environ["LLDB_IMPLIB_DIR"]} 1471 else: 1472 d = { 1473 'DYLIB_CXX_SOURCES': sources, 1474 'DYLIB_NAME': lib_name, 1475 'CFLAGS_EXTRAS': "%s -I%s -fPIC" % (stdflag, 1476 os.path.join( 1477 os.environ["LLDB_SRC"], 1478 "include")), 1479 'LD_EXTRAS': "-shared -L%s/../lib -llldb -Wl,-rpath,%s/../lib" % (lib_dir, lib_dir)} 1480 if self.TraceOn(): 1481 print( 1482 "Building LLDB Library (%s) from sources %s" % 1483 (lib_name, sources)) 1484 1485 self.buildDefault(dictionary=d) 1486 1487 def buildProgram(self, sources, exe_name): 1488 """ Platform specific way to build an executable from C/C++ sources. """ 1489 d = {'CXX_SOURCES': sources, 1490 'EXE': exe_name} 1491 self.buildDefault(dictionary=d) 1492 1493 def buildDefault( 1494 self, 1495 architecture=None, 1496 compiler=None, 1497 dictionary=None): 1498 """Platform specific way to build the default binaries.""" 1499 testdir = self.mydir 1500 testname = self.getBuildDirBasename() 1501 if self.getDebugInfo(): 1502 raise Exception("buildDefault tests must set NO_DEBUG_INFO_TESTCASE") 1503 module = builder_module() 1504 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1505 if not module.buildDefault(self, architecture, compiler, 1506 dictionary, testdir, testname): 1507 raise Exception("Don't know how to build default binary") 1508 1509 def buildDsym( 1510 self, 1511 architecture=None, 1512 compiler=None, 1513 dictionary=None): 1514 """Platform specific way to build binaries with dsym info.""" 1515 testdir = self.mydir 1516 testname = self.getBuildDirBasename() 1517 if self.getDebugInfo() != "dsym": 1518 raise Exception("NO_DEBUG_INFO_TESTCASE must build with buildDefault") 1519 1520 module = builder_module() 1521 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1522 if not module.buildDsym(self, architecture, compiler, 1523 dictionary, testdir, testname): 1524 raise Exception("Don't know how to build binary with dsym") 1525 1526 def buildDwarf( 1527 self, 1528 architecture=None, 1529 compiler=None, 1530 dictionary=None): 1531 """Platform specific way to build binaries with dwarf maps.""" 1532 testdir = self.mydir 1533 testname = self.getBuildDirBasename() 1534 if self.getDebugInfo() != "dwarf": 1535 raise Exception("NO_DEBUG_INFO_TESTCASE must build with buildDefault") 1536 1537 module = builder_module() 1538 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1539 if not module.buildDwarf(self, architecture, compiler, 1540 dictionary, testdir, testname): 1541 raise Exception("Don't know how to build binary with dwarf") 1542 1543 def buildDwo( 1544 self, 1545 architecture=None, 1546 compiler=None, 1547 dictionary=None): 1548 """Platform specific way to build binaries with dwarf maps.""" 1549 testdir = self.mydir 1550 testname = self.getBuildDirBasename() 1551 if self.getDebugInfo() != "dwo": 1552 raise Exception("NO_DEBUG_INFO_TESTCASE must build with buildDefault") 1553 1554 module = builder_module() 1555 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1556 if not module.buildDwo(self, architecture, compiler, 1557 dictionary, testdir, testname): 1558 raise Exception("Don't know how to build binary with dwo") 1559 1560 def buildGModules( 1561 self, 1562 architecture=None, 1563 compiler=None, 1564 dictionary=None): 1565 """Platform specific way to build binaries with gmodules info.""" 1566 testdir = self.mydir 1567 testname = self.getBuildDirBasename() 1568 if self.getDebugInfo() != "gmodules": 1569 raise Exception("NO_DEBUG_INFO_TESTCASE must build with buildDefault") 1570 1571 module = builder_module() 1572 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1573 if not module.buildGModules(self, architecture, compiler, 1574 dictionary, testdir, testname): 1575 raise Exception("Don't know how to build binary with gmodules") 1576 1577 def signBinary(self, binary_path): 1578 if sys.platform.startswith("darwin"): 1579 codesign_cmd = "codesign --force --sign \"%s\" %s" % ( 1580 lldbtest_config.codesign_identity, binary_path) 1581 call(codesign_cmd, shell=True) 1582 1583 def findBuiltClang(self): 1584 """Tries to find and use Clang from the build directory as the compiler (instead of the system compiler).""" 1585 paths_to_try = [ 1586 "llvm-build/Release+Asserts/x86_64/bin/clang", 1587 "llvm-build/Debug+Asserts/x86_64/bin/clang", 1588 "llvm-build/Release/x86_64/bin/clang", 1589 "llvm-build/Debug/x86_64/bin/clang", 1590 ] 1591 lldb_root_path = os.path.join( 1592 os.path.dirname(__file__), "..", "..", "..", "..") 1593 for p in paths_to_try: 1594 path = os.path.join(lldb_root_path, p) 1595 if os.path.exists(path): 1596 return path 1597 1598 # Tries to find clang at the same folder as the lldb 1599 lldb_dir = os.path.dirname(lldbtest_config.lldbExec) 1600 path = distutils.spawn.find_executable("clang", lldb_dir) 1601 if path is not None: 1602 return path 1603 1604 return os.environ["CC"] 1605 1606 def findYaml2obj(self): 1607 """ 1608 Get the path to the yaml2obj executable, which can be used to create 1609 test object files from easy to write yaml instructions. 1610 1611 Throws an Exception if the executable cannot be found. 1612 """ 1613 # Tries to find yaml2obj at the same folder as clang 1614 clang_dir = os.path.dirname(self.findBuiltClang()) 1615 path = distutils.spawn.find_executable("yaml2obj", clang_dir) 1616 if path is not None: 1617 return path 1618 raise Exception("yaml2obj executable not found") 1619 1620 1621 def yaml2obj(self, yaml_path, obj_path): 1622 """ 1623 Create an object file at the given path from a yaml file. 1624 1625 Throws subprocess.CalledProcessError if the object could not be created. 1626 """ 1627 yaml2obj = self.findYaml2obj() 1628 command = [yaml2obj, "-o=%s" % obj_path, yaml_path] 1629 system([command]) 1630 1631 def getBuildFlags( 1632 self, 1633 use_cpp11=True, 1634 use_libcxx=False, 1635 use_libstdcxx=False): 1636 """ Returns a dictionary (which can be provided to build* functions above) which 1637 contains OS-specific build flags. 1638 """ 1639 cflags = "" 1640 ldflags = "" 1641 1642 # On Mac OS X, unless specifically requested to use libstdc++, use 1643 # libc++ 1644 if not use_libstdcxx and self.platformIsDarwin(): 1645 use_libcxx = True 1646 1647 if use_libcxx and self.libcxxPath: 1648 cflags += "-stdlib=libc++ " 1649 if self.libcxxPath: 1650 libcxxInclude = os.path.join(self.libcxxPath, "include") 1651 libcxxLib = os.path.join(self.libcxxPath, "lib") 1652 if os.path.isdir(libcxxInclude) and os.path.isdir(libcxxLib): 1653 cflags += "-nostdinc++ -I%s -L%s -Wl,-rpath,%s " % ( 1654 libcxxInclude, libcxxLib, libcxxLib) 1655 1656 if use_cpp11: 1657 cflags += "-std=" 1658 if "gcc" in self.getCompiler() and "4.6" in self.getCompilerVersion(): 1659 cflags += "c++0x" 1660 else: 1661 cflags += "c++11" 1662 if self.platformIsDarwin() or self.getPlatform() == "freebsd": 1663 cflags += " -stdlib=libc++" 1664 elif self.getPlatform() == "openbsd": 1665 cflags += " -stdlib=libc++" 1666 elif self.getPlatform() == "netbsd": 1667 # NetBSD defaults to libc++ 1668 pass 1669 elif "clang" in self.getCompiler(): 1670 cflags += " -stdlib=libstdc++" 1671 1672 return {'CFLAGS_EXTRAS': cflags, 1673 'LD_EXTRAS': ldflags, 1674 } 1675 1676 def cleanup(self, dictionary=None): 1677 """Platform specific way to do cleanup after build.""" 1678 module = builder_module() 1679 if not module.cleanup(self, dictionary): 1680 raise Exception( 1681 "Don't know how to do cleanup with dictionary: " + 1682 dictionary) 1683 1684 def getLLDBLibraryEnvVal(self): 1685 """ Returns the path that the OS-specific library search environment variable 1686 (self.dylibPath) should be set to in order for a program to find the LLDB 1687 library. If an environment variable named self.dylibPath is already set, 1688 the new path is appended to it and returned. 1689 """ 1690 existing_library_path = os.environ[ 1691 self.dylibPath] if self.dylibPath in os.environ else None 1692 lib_dir = os.environ["LLDB_LIB_DIR"] 1693 if existing_library_path: 1694 return "%s:%s" % (existing_library_path, lib_dir) 1695 elif sys.platform.startswith("darwin"): 1696 return os.path.join(lib_dir, 'LLDB.framework') 1697 else: 1698 return lib_dir 1699 1700 def getLibcPlusPlusLibs(self): 1701 if self.getPlatform() in ('freebsd', 'linux', 'netbsd', 'openbsd'): 1702 return ['libc++.so.1'] 1703 else: 1704 return ['libc++.1.dylib', 'libc++abi.'] 1705 1706# Metaclass for TestBase to change the list of test metods when a new TestCase is loaded. 1707# We change the test methods to create a new test method for each test for each debug info we are 1708# testing. The name of the new test method will be '<original-name>_<debug-info>' and with adding 1709# the new test method we remove the old method at the same time. This functionality can be 1710# supressed by at test case level setting the class attribute NO_DEBUG_INFO_TESTCASE or at test 1711# level by using the decorator @no_debug_info_test. 1712 1713 1714class LLDBTestCaseFactory(type): 1715 1716 def __new__(cls, name, bases, attrs): 1717 original_testcase = super( 1718 LLDBTestCaseFactory, cls).__new__( 1719 cls, name, bases, attrs) 1720 if original_testcase.NO_DEBUG_INFO_TESTCASE: 1721 return original_testcase 1722 1723 newattrs = {} 1724 for attrname, attrvalue in attrs.items(): 1725 if attrname.startswith("test") and not getattr( 1726 attrvalue, "__no_debug_info_test__", False): 1727 1728 # If any debug info categories were explicitly tagged, assume that list to be 1729 # authoritative. If none were specified, try with all debug 1730 # info formats. 1731 all_dbginfo_categories = set(test_categories.debug_info_categories) 1732 categories = set( 1733 getattr( 1734 attrvalue, 1735 "categories", 1736 [])) & all_dbginfo_categories 1737 if not categories: 1738 categories = all_dbginfo_categories 1739 1740 for cat in categories: 1741 @decorators.add_test_categories([cat]) 1742 @wraps(attrvalue) 1743 def test_method(self, attrvalue=attrvalue): 1744 return attrvalue(self) 1745 1746 method_name = attrname + "_" + cat 1747 test_method.__name__ = method_name 1748 test_method.debug_info = cat 1749 newattrs[method_name] = test_method 1750 1751 else: 1752 newattrs[attrname] = attrvalue 1753 return super( 1754 LLDBTestCaseFactory, 1755 cls).__new__( 1756 cls, 1757 name, 1758 bases, 1759 newattrs) 1760 1761# Setup the metaclass for this class to change the list of the test 1762# methods when a new class is loaded 1763 1764 1765@add_metaclass(LLDBTestCaseFactory) 1766class TestBase(Base): 1767 """ 1768 This abstract base class is meant to be subclassed. It provides default 1769 implementations for setUpClass(), tearDownClass(), setUp(), and tearDown(), 1770 among other things. 1771 1772 Important things for test class writers: 1773 1774 - Overwrite the mydir class attribute, otherwise your test class won't 1775 run. It specifies the relative directory to the top level 'test' so 1776 the test harness can change to the correct working directory before 1777 running your test. 1778 1779 - The setUp method sets up things to facilitate subsequent interactions 1780 with the debugger as part of the test. These include: 1781 - populate the test method name 1782 - create/get a debugger set with synchronous mode (self.dbg) 1783 - get the command interpreter from with the debugger (self.ci) 1784 - create a result object for use with the command interpreter 1785 (self.res) 1786 - plus other stuffs 1787 1788 - The tearDown method tries to perform some necessary cleanup on behalf 1789 of the test to return the debugger to a good state for the next test. 1790 These include: 1791 - execute any tearDown hooks registered by the test method with 1792 TestBase.addTearDownHook(); examples can be found in 1793 settings/TestSettings.py 1794 - kill the inferior process associated with each target, if any, 1795 and, then delete the target from the debugger's target list 1796 - perform build cleanup before running the next test method in the 1797 same test class; examples of registering for this service can be 1798 found in types/TestIntegerTypes.py with the call: 1799 - self.setTearDownCleanup(dictionary=d) 1800 1801 - Similarly setUpClass and tearDownClass perform classwise setup and 1802 teardown fixtures. The tearDownClass method invokes a default build 1803 cleanup for the entire test class; also, subclasses can implement the 1804 classmethod classCleanup(cls) to perform special class cleanup action. 1805 1806 - The instance methods runCmd and expect are used heavily by existing 1807 test cases to send a command to the command interpreter and to perform 1808 string/pattern matching on the output of such command execution. The 1809 expect method also provides a mode to peform string/pattern matching 1810 without running a command. 1811 1812 - The build methods buildDefault, buildDsym, and buildDwarf are used to 1813 build the binaries used during a particular test scenario. A plugin 1814 should be provided for the sys.platform running the test suite. The 1815 Mac OS X implementation is located in plugins/darwin.py. 1816 """ 1817 1818 # Subclasses can set this to true (if they don't depend on debug info) to avoid running the 1819 # test multiple times with various debug info types. 1820 NO_DEBUG_INFO_TESTCASE = False 1821 1822 # Maximum allowed attempts when launching the inferior process. 1823 # Can be overridden by the LLDB_MAX_LAUNCH_COUNT environment variable. 1824 maxLaunchCount = 1 1825 1826 # Time to wait before the next launching attempt in second(s). 1827 # Can be overridden by the LLDB_TIME_WAIT_NEXT_LAUNCH environment variable. 1828 timeWaitNextLaunch = 1.0 1829 1830 def generateSource(self, source): 1831 template = source + '.template' 1832 temp = os.path.join(self.getSourceDir(), template) 1833 with open(temp, 'r') as f: 1834 content = f.read() 1835 1836 public_api_dir = os.path.join( 1837 os.environ["LLDB_SRC"], "include", "lldb", "API") 1838 1839 # Look under the include/lldb/API directory and add #include statements 1840 # for all the SB API headers. 1841 public_headers = os.listdir(public_api_dir) 1842 # For different platforms, the include statement can vary. 1843 if self.hasDarwinFramework(): 1844 include_stmt = "'#include <%s>' % os.path.join('LLDB', header)" 1845 else: 1846 include_stmt = "'#include <%s>' % os.path.join('" + public_api_dir + "', header)" 1847 list = [eval(include_stmt) for header in public_headers if ( 1848 header.startswith("SB") and header.endswith(".h"))] 1849 includes = '\n'.join(list) 1850 new_content = content.replace('%include_SB_APIs%', includes) 1851 src = os.path.join(self.getBuildDir(), source) 1852 with open(src, 'w') as f: 1853 f.write(new_content) 1854 1855 self.addTearDownHook(lambda: os.remove(src)) 1856 1857 def setUp(self): 1858 #import traceback 1859 # traceback.print_stack() 1860 1861 # Works with the test driver to conditionally skip tests via 1862 # decorators. 1863 Base.setUp(self) 1864 1865 # Set the clang modules cache path used by LLDB. 1866 mod_cache = os.path.join(os.environ["LLDB_BUILD"], "module-cache-lldb") 1867 self.runCmd('settings set symbols.clang-modules-cache-path "%s"' 1868 % mod_cache) 1869 1870 for s in self.setUpCommands(): 1871 self.runCmd(s) 1872 1873 # Disable color. 1874 self.runCmd("settings set use-color false") 1875 1876 # Make sure that a sanitizer LLDB's environment doesn't get passed on. 1877 if 'DYLD_LIBRARY_PATH' in os.environ: 1878 self.runCmd('settings set target.env-vars DYLD_LIBRARY_PATH=') 1879 1880 # Set environment variables for the inferior. 1881 if lldbtest_config.inferior_env: 1882 self.runCmd('settings set target.env-vars {}'.format(lldbtest_config.inferior_env)) 1883 1884 if "LLDB_MAX_LAUNCH_COUNT" in os.environ: 1885 self.maxLaunchCount = int(os.environ["LLDB_MAX_LAUNCH_COUNT"]) 1886 1887 if "LLDB_TIME_WAIT_NEXT_LAUNCH" in os.environ: 1888 self.timeWaitNextLaunch = float( 1889 os.environ["LLDB_TIME_WAIT_NEXT_LAUNCH"]) 1890 1891 # We want our debugger to be synchronous. 1892 self.dbg.SetAsync(False) 1893 1894 # Retrieve the associated command interpreter instance. 1895 self.ci = self.dbg.GetCommandInterpreter() 1896 if not self.ci: 1897 raise Exception('Could not get the command interpreter') 1898 1899 # And the result object. 1900 self.res = lldb.SBCommandReturnObject() 1901 1902 def registerSharedLibrariesWithTarget(self, target, shlibs): 1903 '''If we are remotely running the test suite, register the shared libraries with the target so they get uploaded, otherwise do nothing 1904 1905 Any modules in the target that have their remote install file specification set will 1906 get uploaded to the remote host. This function registers the local copies of the 1907 shared libraries with the target and sets their remote install locations so they will 1908 be uploaded when the target is run. 1909 ''' 1910 if not shlibs or not self.platformContext: 1911 return None 1912 1913 shlib_environment_var = self.platformContext.shlib_environment_var 1914 shlib_prefix = self.platformContext.shlib_prefix 1915 shlib_extension = '.' + self.platformContext.shlib_extension 1916 1917 working_dir = self.get_process_working_directory() 1918 environment = ['%s=%s' % (shlib_environment_var, working_dir)] 1919 # Add any shared libraries to our target if remote so they get 1920 # uploaded into the working directory on the remote side 1921 for name in shlibs: 1922 # The path can be a full path to a shared library, or a make file name like "Foo" for 1923 # "libFoo.dylib" or "libFoo.so", or "Foo.so" for "Foo.so" or "libFoo.so", or just a 1924 # basename like "libFoo.so". So figure out which one it is and resolve the local copy 1925 # of the shared library accordingly 1926 if os.path.isfile(name): 1927 local_shlib_path = name # name is the full path to the local shared library 1928 else: 1929 # Check relative names 1930 local_shlib_path = os.path.join( 1931 self.getBuildDir(), shlib_prefix + name + shlib_extension) 1932 if not os.path.exists(local_shlib_path): 1933 local_shlib_path = os.path.join( 1934 self.getBuildDir(), name + shlib_extension) 1935 if not os.path.exists(local_shlib_path): 1936 local_shlib_path = os.path.join(self.getBuildDir(), name) 1937 1938 # Make sure we found the local shared library in the above code 1939 self.assertTrue(os.path.exists(local_shlib_path)) 1940 1941 # Add the shared library to our target 1942 shlib_module = target.AddModule(local_shlib_path, None, None, None) 1943 if lldb.remote_platform: 1944 # We must set the remote install location if we want the shared library 1945 # to get uploaded to the remote target 1946 remote_shlib_path = lldbutil.append_to_process_working_directory(self, 1947 os.path.basename(local_shlib_path)) 1948 shlib_module.SetRemoteInstallFileSpec( 1949 lldb.SBFileSpec(remote_shlib_path, False)) 1950 1951 return environment 1952 1953 # utility methods that tests can use to access the current objects 1954 def target(self): 1955 if not self.dbg: 1956 raise Exception('Invalid debugger instance') 1957 return self.dbg.GetSelectedTarget() 1958 1959 def process(self): 1960 if not self.dbg: 1961 raise Exception('Invalid debugger instance') 1962 return self.dbg.GetSelectedTarget().GetProcess() 1963 1964 def thread(self): 1965 if not self.dbg: 1966 raise Exception('Invalid debugger instance') 1967 return self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread() 1968 1969 def frame(self): 1970 if not self.dbg: 1971 raise Exception('Invalid debugger instance') 1972 return self.dbg.GetSelectedTarget().GetProcess( 1973 ).GetSelectedThread().GetSelectedFrame() 1974 1975 def get_process_working_directory(self): 1976 '''Get the working directory that should be used when launching processes for local or remote processes.''' 1977 if lldb.remote_platform: 1978 # Remote tests set the platform working directory up in 1979 # TestBase.setUp() 1980 return lldb.remote_platform.GetWorkingDirectory() 1981 else: 1982 # local tests change directory into each test subdirectory 1983 return self.getBuildDir() 1984 1985 def tearDown(self): 1986 #import traceback 1987 # traceback.print_stack() 1988 1989 # Ensure all the references to SB objects have gone away so that we can 1990 # be sure that all test-specific resources have been freed before we 1991 # attempt to delete the targets. 1992 gc.collect() 1993 1994 # Delete the target(s) from the debugger as a general cleanup step. 1995 # This includes terminating the process for each target, if any. 1996 # We'd like to reuse the debugger for our next test without incurring 1997 # the initialization overhead. 1998 targets = [] 1999 for target in self.dbg: 2000 if target: 2001 targets.append(target) 2002 process = target.GetProcess() 2003 if process: 2004 rc = self.invoke(process, "Kill") 2005 self.assertTrue(rc.Success(), PROCESS_KILLED) 2006 for target in targets: 2007 self.dbg.DeleteTarget(target) 2008 2009 # Do this last, to make sure it's in reverse order from how we setup. 2010 Base.tearDown(self) 2011 2012 # This must be the last statement, otherwise teardown hooks or other 2013 # lines might depend on this still being active. 2014 del self.dbg 2015 2016 def switch_to_thread_with_stop_reason(self, stop_reason): 2017 """ 2018 Run the 'thread list' command, and select the thread with stop reason as 2019 'stop_reason'. If no such thread exists, no select action is done. 2020 """ 2021 from .lldbutil import stop_reason_to_str 2022 self.runCmd('thread list') 2023 output = self.res.GetOutput() 2024 thread_line_pattern = re.compile( 2025 "^[ *] thread #([0-9]+):.*stop reason = %s" % 2026 stop_reason_to_str(stop_reason)) 2027 for line in output.splitlines(): 2028 matched = thread_line_pattern.match(line) 2029 if matched: 2030 self.runCmd('thread select %s' % matched.group(1)) 2031 2032 def runCmd(self, cmd, msg=None, check=True, trace=False, inHistory=False): 2033 """ 2034 Ask the command interpreter to handle the command and then check its 2035 return status. 2036 """ 2037 # Fail fast if 'cmd' is not meaningful. 2038 if not cmd or len(cmd) == 0: 2039 raise Exception("Bad 'cmd' parameter encountered") 2040 2041 trace = (True if traceAlways else trace) 2042 2043 if cmd.startswith("target create "): 2044 cmd = cmd.replace("target create ", "file ") 2045 2046 running = (cmd.startswith("run") or cmd.startswith("process launch")) 2047 2048 for i in range(self.maxLaunchCount if running else 1): 2049 self.ci.HandleCommand(cmd, self.res, inHistory) 2050 2051 with recording(self, trace) as sbuf: 2052 print("runCmd:", cmd, file=sbuf) 2053 if not check: 2054 print("check of return status not required", file=sbuf) 2055 if self.res.Succeeded(): 2056 print("output:", self.res.GetOutput(), file=sbuf) 2057 else: 2058 print("runCmd failed!", file=sbuf) 2059 print(self.res.GetError(), file=sbuf) 2060 2061 if self.res.Succeeded(): 2062 break 2063 elif running: 2064 # For process launch, wait some time before possible next try. 2065 time.sleep(self.timeWaitNextLaunch) 2066 with recording(self, trace) as sbuf: 2067 print("Command '" + cmd + "' failed!", file=sbuf) 2068 2069 if check: 2070 output = "" 2071 if self.res.GetOutput(): 2072 output += "\nCommand output:\n" + self.res.GetOutput() 2073 if self.res.GetError(): 2074 output += "\nError output:\n" + self.res.GetError() 2075 if msg: 2076 msg += output 2077 if cmd: 2078 cmd += output 2079 self.assertTrue(self.res.Succeeded(), 2080 msg if (msg) else CMD_MSG(cmd)) 2081 2082 def match( 2083 self, 2084 str, 2085 patterns, 2086 msg=None, 2087 trace=False, 2088 error=False, 2089 matching=True, 2090 exe=True): 2091 """run command in str, and match the result against regexp in patterns returning the match object for the first matching pattern 2092 2093 Otherwise, all the arguments have the same meanings as for the expect function""" 2094 2095 trace = (True if traceAlways else trace) 2096 2097 if exe: 2098 # First run the command. If we are expecting error, set check=False. 2099 # Pass the assert message along since it provides more semantic 2100 # info. 2101 self.runCmd( 2102 str, 2103 msg=msg, 2104 trace=( 2105 True if trace else False), 2106 check=not error) 2107 2108 # Then compare the output against expected strings. 2109 output = self.res.GetError() if error else self.res.GetOutput() 2110 2111 # If error is True, the API client expects the command to fail! 2112 if error: 2113 self.assertFalse(self.res.Succeeded(), 2114 "Command '" + str + "' is expected to fail!") 2115 else: 2116 # No execution required, just compare str against the golden input. 2117 output = str 2118 with recording(self, trace) as sbuf: 2119 print("looking at:", output, file=sbuf) 2120 2121 # The heading says either "Expecting" or "Not expecting". 2122 heading = "Expecting" if matching else "Not expecting" 2123 2124 for pattern in patterns: 2125 # Match Objects always have a boolean value of True. 2126 match_object = re.search(pattern, output) 2127 matched = bool(match_object) 2128 with recording(self, trace) as sbuf: 2129 print("%s pattern: %s" % (heading, pattern), file=sbuf) 2130 print("Matched" if matched else "Not matched", file=sbuf) 2131 if matched: 2132 break 2133 2134 self.assertTrue(matched if matching else not matched, 2135 msg if msg else EXP_MSG(str, output, exe)) 2136 2137 return match_object 2138 2139 def check_completion_with_desc(self, str_input, match_desc_pairs): 2140 interp = self.dbg.GetCommandInterpreter() 2141 match_strings = lldb.SBStringList() 2142 description_strings = lldb.SBStringList() 2143 num_matches = interp.HandleCompletionWithDescriptions(str_input, len(str_input), 0, -1, match_strings, description_strings) 2144 self.assertEqual(len(description_strings), len(match_strings)) 2145 2146 missing_pairs = [] 2147 for pair in match_desc_pairs: 2148 found_pair = False 2149 for i in range(num_matches + 1): 2150 match_candidate = match_strings.GetStringAtIndex(i) 2151 description_candidate = description_strings.GetStringAtIndex(i) 2152 if match_candidate == pair[0] and description_candidate == pair[1]: 2153 found_pair = True 2154 break 2155 if not found_pair: 2156 missing_pairs.append(pair) 2157 2158 if len(missing_pairs): 2159 error_msg = "Missing pairs:\n" 2160 for pair in missing_pairs: 2161 error_msg += " [" + pair[0] + ":" + pair[1] + "]\n" 2162 error_msg += "Got the following " + str(num_matches) + " completions back:\n" 2163 for i in range(num_matches + 1): 2164 match_candidate = match_strings.GetStringAtIndex(i) 2165 description_candidate = description_strings.GetStringAtIndex(i) 2166 error_msg += "[" + match_candidate + ":" + description_candidate + "]\n" 2167 self.assertEqual(0, len(missing_pairs), error_msg) 2168 2169 def complete_exactly(self, str_input, patterns): 2170 self.complete_from_to(str_input, patterns, True) 2171 2172 def complete_from_to(self, str_input, patterns, turn_off_re_match=False): 2173 """Test that the completion mechanism completes str_input to patterns, 2174 where patterns could be a pattern-string or a list of pattern-strings""" 2175 # Patterns should not be None in order to proceed. 2176 self.assertFalse(patterns is None) 2177 # And should be either a string or list of strings. Check for list type 2178 # below, if not, make a list out of the singleton string. If patterns 2179 # is not a string or not a list of strings, there'll be runtime errors 2180 # later on. 2181 if not isinstance(patterns, list): 2182 patterns = [patterns] 2183 2184 interp = self.dbg.GetCommandInterpreter() 2185 match_strings = lldb.SBStringList() 2186 num_matches = interp.HandleCompletion(str_input, len(str_input), 0, -1, match_strings) 2187 common_match = match_strings.GetStringAtIndex(0) 2188 if num_matches == 0: 2189 compare_string = str_input 2190 else: 2191 if common_match != None and len(common_match) > 0: 2192 compare_string = str_input + common_match 2193 else: 2194 compare_string = "" 2195 for idx in range(1, num_matches+1): 2196 compare_string += match_strings.GetStringAtIndex(idx) + "\n" 2197 2198 for p in patterns: 2199 if turn_off_re_match: 2200 self.expect( 2201 compare_string, msg=COMPLETION_MSG( 2202 str_input, p, match_strings), exe=False, substrs=[p]) 2203 else: 2204 self.expect( 2205 compare_string, msg=COMPLETION_MSG( 2206 str_input, p, match_strings), exe=False, patterns=[p]) 2207 2208 def filecheck( 2209 self, 2210 command, 2211 check_file, 2212 filecheck_options = ''): 2213 # Run the command. 2214 self.runCmd( 2215 command, 2216 msg="FileCheck'ing result of `{0}`".format(command)) 2217 2218 # Get the error text if there was an error, and the regular text if not. 2219 output = self.res.GetOutput() if self.res.Succeeded() \ 2220 else self.res.GetError() 2221 2222 # Assemble the absolute path to the check file. As a convenience for 2223 # LLDB inline tests, assume that the check file is a relative path to 2224 # a file within the inline test directory. 2225 if check_file.endswith('.pyc'): 2226 check_file = check_file[:-1] 2227 check_file_abs = os.path.abspath(check_file) 2228 2229 # Run FileCheck. 2230 filecheck_bin = configuration.get_filecheck_path() 2231 if not filecheck_bin: 2232 self.assertTrue(False, "No valid FileCheck executable specified") 2233 filecheck_args = [filecheck_bin, check_file_abs] 2234 if filecheck_options: 2235 filecheck_args.append(filecheck_options) 2236 subproc = Popen(filecheck_args, stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines = True) 2237 cmd_stdout, cmd_stderr = subproc.communicate(input=output) 2238 cmd_status = subproc.returncode 2239 2240 filecheck_cmd = " ".join(filecheck_args) 2241 filecheck_trace = """ 2242--- FileCheck trace (code={0}) --- 2243{1} 2244 2245FileCheck input: 2246{2} 2247 2248FileCheck output: 2249{3} 2250{4} 2251""".format(cmd_status, filecheck_cmd, output, cmd_stdout, cmd_stderr) 2252 2253 trace = cmd_status != 0 or traceAlways 2254 with recording(self, trace) as sbuf: 2255 print(filecheck_trace, file=sbuf) 2256 2257 self.assertTrue(cmd_status == 0) 2258 2259 def expect( 2260 self, 2261 str, 2262 msg=None, 2263 patterns=None, 2264 startstr=None, 2265 endstr=None, 2266 substrs=None, 2267 trace=False, 2268 error=False, 2269 matching=True, 2270 exe=True, 2271 inHistory=False): 2272 """ 2273 Similar to runCmd; with additional expect style output matching ability. 2274 2275 Ask the command interpreter to handle the command and then check its 2276 return status. The 'msg' parameter specifies an informational assert 2277 message. We expect the output from running the command to start with 2278 'startstr', matches the substrings contained in 'substrs', and regexp 2279 matches the patterns contained in 'patterns'. 2280 2281 If the keyword argument error is set to True, it signifies that the API 2282 client is expecting the command to fail. In this case, the error stream 2283 from running the command is retrieved and compared against the golden 2284 input, instead. 2285 2286 If the keyword argument matching is set to False, it signifies that the API 2287 client is expecting the output of the command not to match the golden 2288 input. 2289 2290 Finally, the required argument 'str' represents the lldb command to be 2291 sent to the command interpreter. In case the keyword argument 'exe' is 2292 set to False, the 'str' is treated as a string to be matched/not-matched 2293 against the golden input. 2294 """ 2295 trace = (True if traceAlways else trace) 2296 2297 if exe: 2298 # First run the command. If we are expecting error, set check=False. 2299 # Pass the assert message along since it provides more semantic 2300 # info. 2301 self.runCmd( 2302 str, 2303 msg=msg, 2304 trace=( 2305 True if trace else False), 2306 check=not error, 2307 inHistory=inHistory) 2308 2309 # Then compare the output against expected strings. 2310 output = self.res.GetError() if error else self.res.GetOutput() 2311 2312 # If error is True, the API client expects the command to fail! 2313 if error: 2314 self.assertFalse(self.res.Succeeded(), 2315 "Command '" + str + "' is expected to fail!") 2316 else: 2317 # No execution required, just compare str against the golden input. 2318 if isinstance(str, lldb.SBCommandReturnObject): 2319 output = str.GetOutput() 2320 else: 2321 output = str 2322 with recording(self, trace) as sbuf: 2323 print("looking at:", output, file=sbuf) 2324 2325 # The heading says either "Expecting" or "Not expecting". 2326 heading = "Expecting" if matching else "Not expecting" 2327 2328 # Start from the startstr, if specified. 2329 # If there's no startstr, set the initial state appropriately. 2330 matched = output.startswith(startstr) if startstr else ( 2331 True if matching else False) 2332 2333 if startstr: 2334 with recording(self, trace) as sbuf: 2335 print("%s start string: %s" % (heading, startstr), file=sbuf) 2336 print("Matched" if matched else "Not matched", file=sbuf) 2337 2338 # Look for endstr, if specified. 2339 keepgoing = matched if matching else not matched 2340 if endstr: 2341 matched = output.endswith(endstr) 2342 with recording(self, trace) as sbuf: 2343 print("%s end string: %s" % (heading, endstr), file=sbuf) 2344 print("Matched" if matched else "Not matched", file=sbuf) 2345 2346 # Look for sub strings, if specified. 2347 keepgoing = matched if matching else not matched 2348 if substrs and keepgoing: 2349 for substr in substrs: 2350 matched = output.find(substr) != -1 2351 with recording(self, trace) as sbuf: 2352 print("%s sub string: %s" % (heading, substr), file=sbuf) 2353 print("Matched" if matched else "Not matched", file=sbuf) 2354 keepgoing = matched if matching else not matched 2355 if not keepgoing: 2356 break 2357 2358 # Search for regular expression patterns, if specified. 2359 keepgoing = matched if matching else not matched 2360 if patterns and keepgoing: 2361 for pattern in patterns: 2362 # Match Objects always have a boolean value of True. 2363 matched = bool(re.search(pattern, output)) 2364 with recording(self, trace) as sbuf: 2365 print("%s pattern: %s" % (heading, pattern), file=sbuf) 2366 print("Matched" if matched else "Not matched", file=sbuf) 2367 keepgoing = matched if matching else not matched 2368 if not keepgoing: 2369 break 2370 2371 self.assertTrue(matched if matching else not matched, 2372 msg if msg else EXP_MSG(str, output, exe)) 2373 2374 def invoke(self, obj, name, trace=False): 2375 """Use reflection to call a method dynamically with no argument.""" 2376 trace = (True if traceAlways else trace) 2377 2378 method = getattr(obj, name) 2379 import inspect 2380 self.assertTrue(inspect.ismethod(method), 2381 name + "is a method name of object: " + str(obj)) 2382 result = method() 2383 with recording(self, trace) as sbuf: 2384 print(str(method) + ":", result, file=sbuf) 2385 return result 2386 2387 def build( 2388 self, 2389 architecture=None, 2390 compiler=None, 2391 dictionary=None): 2392 """Platform specific way to build the default binaries.""" 2393 module = builder_module() 2394 2395 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 2396 if self.getDebugInfo() is None: 2397 return self.buildDefault(architecture, compiler, dictionary) 2398 elif self.getDebugInfo() == "dsym": 2399 return self.buildDsym(architecture, compiler, dictionary) 2400 elif self.getDebugInfo() == "dwarf": 2401 return self.buildDwarf(architecture, compiler, dictionary) 2402 elif self.getDebugInfo() == "dwo": 2403 return self.buildDwo(architecture, compiler, dictionary) 2404 elif self.getDebugInfo() == "gmodules": 2405 return self.buildGModules(architecture, compiler, dictionary) 2406 else: 2407 self.fail("Can't build for debug info: %s" % self.getDebugInfo()) 2408 2409 def run_platform_command(self, cmd): 2410 platform = self.dbg.GetSelectedPlatform() 2411 shell_command = lldb.SBPlatformShellCommand(cmd) 2412 err = platform.Run(shell_command) 2413 return (err, shell_command.GetStatus(), shell_command.GetOutput()) 2414 2415 # ================================================= 2416 # Misc. helper methods for debugging test execution 2417 # ================================================= 2418 2419 def DebugSBValue(self, val): 2420 """Debug print a SBValue object, if traceAlways is True.""" 2421 from .lldbutil import value_type_to_str 2422 2423 if not traceAlways: 2424 return 2425 2426 err = sys.stderr 2427 err.write(val.GetName() + ":\n") 2428 err.write('\t' + "TypeName -> " + val.GetTypeName() + '\n') 2429 err.write('\t' + "ByteSize -> " + 2430 str(val.GetByteSize()) + '\n') 2431 err.write('\t' + "NumChildren -> " + 2432 str(val.GetNumChildren()) + '\n') 2433 err.write('\t' + "Value -> " + str(val.GetValue()) + '\n') 2434 err.write('\t' + "ValueAsUnsigned -> " + 2435 str(val.GetValueAsUnsigned()) + '\n') 2436 err.write( 2437 '\t' + 2438 "ValueType -> " + 2439 value_type_to_str( 2440 val.GetValueType()) + 2441 '\n') 2442 err.write('\t' + "Summary -> " + str(val.GetSummary()) + '\n') 2443 err.write('\t' + "IsPointerType -> " + 2444 str(val.TypeIsPointerType()) + '\n') 2445 err.write('\t' + "Location -> " + val.GetLocation() + '\n') 2446 2447 def DebugSBType(self, type): 2448 """Debug print a SBType object, if traceAlways is True.""" 2449 if not traceAlways: 2450 return 2451 2452 err = sys.stderr 2453 err.write(type.GetName() + ":\n") 2454 err.write('\t' + "ByteSize -> " + 2455 str(type.GetByteSize()) + '\n') 2456 err.write('\t' + "IsPointerType -> " + 2457 str(type.IsPointerType()) + '\n') 2458 err.write('\t' + "IsReferenceType -> " + 2459 str(type.IsReferenceType()) + '\n') 2460 2461 def DebugPExpect(self, child): 2462 """Debug the spwaned pexpect object.""" 2463 if not traceAlways: 2464 return 2465 2466 print(child) 2467 2468 @classmethod 2469 def RemoveTempFile(cls, file): 2470 if os.path.exists(file): 2471 remove_file(file) 2472 2473# On Windows, the first attempt to delete a recently-touched file can fail 2474# because of a race with antimalware scanners. This function will detect a 2475# failure and retry. 2476 2477 2478def remove_file(file, num_retries=1, sleep_duration=0.5): 2479 for i in range(num_retries + 1): 2480 try: 2481 os.remove(file) 2482 return True 2483 except: 2484 time.sleep(sleep_duration) 2485 continue 2486 return False 2487