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