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