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