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 @classmethod 509 def setUpClass(cls): 510 """ 511 Python unittest framework class setup fixture. 512 Do current directory manipulation. 513 """ 514 # Fail fast if 'mydir' attribute is not overridden. 515 if not cls.mydir or len(cls.mydir) == 0: 516 raise Exception("Subclasses must override the 'mydir' attribute.") 517 518 # Save old working directory. 519 cls.oldcwd = os.getcwd() 520 521 # Change current working directory if ${LLDB_TEST_SRC} is defined. 522 # See also dotest.py which sets up ${LLDB_TEST_SRC}. 523 if ("LLDB_TEST_SRC" in os.environ): 524 full_dir = os.path.join(os.environ["LLDB_TEST_SRC"], 525 cls.mydir) 526 if traceAlways: 527 print("Change dir to:", full_dir, file=sys.stderr) 528 os.chdir(full_dir) 529 lldb.SBReproducer.SetWorkingDirectory(full_dir) 530 531 # Set platform context. 532 cls.platformContext = lldbplatformutil.createPlatformContext() 533 534 @classmethod 535 def tearDownClass(cls): 536 """ 537 Python unittest framework class teardown fixture. 538 Do class-wide cleanup. 539 """ 540 541 if doCleanup: 542 # First, let's do the platform-specific cleanup. 543 module = builder_module() 544 module.cleanup() 545 546 # Subclass might have specific cleanup function defined. 547 if getattr(cls, "classCleanup", None): 548 if traceAlways: 549 print( 550 "Call class-specific cleanup function for class:", 551 cls, 552 file=sys.stderr) 553 try: 554 cls.classCleanup() 555 except: 556 exc_type, exc_value, exc_tb = sys.exc_info() 557 traceback.print_exception(exc_type, exc_value, exc_tb) 558 559 # Restore old working directory. 560 if traceAlways: 561 print("Restore dir to:", cls.oldcwd, file=sys.stderr) 562 os.chdir(cls.oldcwd) 563 564 def enableLogChannelsForCurrentTest(self): 565 if len(lldbtest_config.channels) == 0: 566 return 567 568 # if debug channels are specified in lldbtest_config.channels, 569 # create a new set of log files for every test 570 log_basename = self.getLogBasenameForCurrentTest() 571 572 # confirm that the file is writeable 573 host_log_path = "{}-host.log".format(log_basename) 574 open(host_log_path, 'w').close() 575 576 log_enable = "log enable -Tpn -f {} ".format(host_log_path) 577 for channel_with_categories in lldbtest_config.channels: 578 channel_then_categories = channel_with_categories.split(' ', 1) 579 channel = channel_then_categories[0] 580 if len(channel_then_categories) > 1: 581 categories = channel_then_categories[1] 582 else: 583 categories = "default" 584 585 if channel == "gdb-remote" and lldb.remote_platform is None: 586 # communicate gdb-remote categories to debugserver 587 os.environ["LLDB_DEBUGSERVER_LOG_FLAGS"] = categories 588 589 self.ci.HandleCommand( 590 log_enable + channel_with_categories, self.res) 591 if not self.res.Succeeded(): 592 raise Exception( 593 'log enable failed (check LLDB_LOG_OPTION env variable)') 594 595 # Communicate log path name to debugserver & lldb-server 596 # For remote debugging, these variables need to be set when starting the platform 597 # instance. 598 if lldb.remote_platform is None: 599 server_log_path = "{}-server.log".format(log_basename) 600 open(server_log_path, 'w').close() 601 os.environ["LLDB_DEBUGSERVER_LOG_FILE"] = server_log_path 602 603 # Communicate channels to lldb-server 604 os.environ["LLDB_SERVER_LOG_CHANNELS"] = ":".join( 605 lldbtest_config.channels) 606 607 self.addTearDownHook(self.disableLogChannelsForCurrentTest) 608 609 def disableLogChannelsForCurrentTest(self): 610 # close all log files that we opened 611 for channel_and_categories in lldbtest_config.channels: 612 # channel format - <channel-name> [<category0> [<category1> ...]] 613 channel = channel_and_categories.split(' ', 1)[0] 614 self.ci.HandleCommand("log disable " + channel, self.res) 615 if not self.res.Succeeded(): 616 raise Exception( 617 'log disable failed (check LLDB_LOG_OPTION env variable)') 618 619 # Retrieve the server log (if any) from the remote system. It is assumed the server log 620 # is writing to the "server.log" file in the current test directory. This can be 621 # achieved by setting LLDB_DEBUGSERVER_LOG_FILE="server.log" when starting remote 622 # platform. If the remote logging is not enabled, then just let the Get() command silently 623 # fail. 624 if lldb.remote_platform: 625 lldb.remote_platform.Get( 626 lldb.SBFileSpec("server.log"), lldb.SBFileSpec( 627 self.getLogBasenameForCurrentTest() + "-server.log")) 628 629 def setPlatformWorkingDir(self): 630 if not lldb.remote_platform or not configuration.lldb_platform_working_dir: 631 return 632 633 components = self.mydir.split(os.path.sep) + [str(self.test_number), self.getBuildDirBasename()] 634 remote_test_dir = configuration.lldb_platform_working_dir 635 for c in components: 636 remote_test_dir = lldbutil.join_remote_paths(remote_test_dir, c) 637 error = lldb.remote_platform.MakeDirectory( 638 remote_test_dir, 448) # 448 = 0o700 639 if error.Fail(): 640 raise Exception("making remote directory '%s': %s" % ( 641 remote_test_dir, error)) 642 643 lldb.remote_platform.SetWorkingDirectory(remote_test_dir) 644 645 # This function removes all files from the current working directory while leaving 646 # the directories in place. The cleanup is required to reduce the disk space required 647 # by the test suite while leaving the directories untouched is neccessary because 648 # sub-directories might belong to an other test 649 def clean_working_directory(): 650 # TODO: Make it working on Windows when we need it for remote debugging support 651 # TODO: Replace the heuristic to remove the files with a logic what collects the 652 # list of files we have to remove during test runs. 653 shell_cmd = lldb.SBPlatformShellCommand( 654 "rm %s/*" % remote_test_dir) 655 lldb.remote_platform.Run(shell_cmd) 656 self.addTearDownHook(clean_working_directory) 657 658 def getSourceDir(self): 659 """Return the full path to the current test.""" 660 return os.path.join(os.environ["LLDB_TEST_SRC"], self.mydir) 661 662 def getBuildDirBasename(self): 663 return self.__class__.__module__ + "." + self.testMethodName 664 665 def getBuildDir(self): 666 """Return the full path to the current test.""" 667 return os.path.join(os.environ["LLDB_BUILD"], self.mydir, 668 self.getBuildDirBasename()) 669 670 def getReproducerDir(self): 671 """Return the full path to the reproducer if enabled.""" 672 if configuration.capture_path: 673 return configuration.capture_path 674 if configuration.replay_path: 675 return configuration.replay_path 676 return None 677 678 def makeBuildDir(self): 679 """Create the test-specific working directory, deleting any previous 680 contents.""" 681 # See also dotest.py which sets up ${LLDB_BUILD}. 682 bdir = self.getBuildDir() 683 if os.path.isdir(bdir): 684 shutil.rmtree(bdir) 685 lldbutil.mkdir_p(bdir) 686 687 def getBuildArtifact(self, name="a.out"): 688 """Return absolute path to an artifact in the test's build directory.""" 689 return os.path.join(self.getBuildDir(), name) 690 691 def getSourcePath(self, name): 692 """Return absolute path to a file in the test's source directory.""" 693 return os.path.join(self.getSourceDir(), name) 694 695 def getReproducerArtifact(self, name): 696 return os.path.join(self.getReproducerDir(), name) 697 698 @classmethod 699 def setUpCommands(cls): 700 commands = [ 701 # First of all, clear all settings to have clean state of global properties. 702 "settings clear -all", 703 704 # Disable Spotlight lookup. The testsuite creates 705 # different binaries with the same UUID, because they only 706 # differ in the debug info, which is not being hashed. 707 "settings set symbols.enable-external-lookup false", 708 709 # Disable fix-its by default so that incorrect expressions in tests don't 710 # pass just because Clang thinks it has a fix-it. 711 "settings set target.auto-apply-fixits false", 712 713 # Testsuite runs in parallel and the host can have also other load. 714 "settings set plugin.process.gdb-remote.packet-timeout 60", 715 716 'settings set symbols.clang-modules-cache-path "{}"'.format( 717 configuration.lldb_module_cache_dir), 718 "settings set use-color false", 719 ] 720 721 # Set any user-overridden settings. 722 for setting, value in configuration.settings: 723 commands.append('setting set %s %s'%(setting, value)) 724 725 # Make sure that a sanitizer LLDB's environment doesn't get passed on. 726 if cls.platformContext and cls.platformContext.shlib_environment_var in os.environ: 727 commands.append('settings set target.env-vars {}='.format( 728 cls.platformContext.shlib_environment_var)) 729 730 # Set environment variables for the inferior. 731 if lldbtest_config.inferior_env: 732 commands.append('settings set target.env-vars {}'.format( 733 lldbtest_config.inferior_env)) 734 return commands 735 736 def setUp(self): 737 """Fixture for unittest test case setup. 738 739 It works with the test driver to conditionally skip tests and does other 740 initializations.""" 741 #import traceback 742 # traceback.print_stack() 743 744 if "LIBCXX_PATH" in os.environ: 745 self.libcxxPath = os.environ["LIBCXX_PATH"] 746 else: 747 self.libcxxPath = None 748 749 if "LLDBVSCODE_EXEC" in os.environ: 750 self.lldbVSCodeExec = os.environ["LLDBVSCODE_EXEC"] 751 else: 752 self.lldbVSCodeExec = None 753 754 self.lldbOption = " ".join( 755 "-o '" + s + "'" for s in self.setUpCommands()) 756 757 # If we spawn an lldb process for test (via pexpect), do not load the 758 # init file unless told otherwise. 759 if os.environ.get("NO_LLDBINIT") != "NO": 760 self.lldbOption += " --no-lldbinit" 761 762 # Assign the test method name to self.testMethodName. 763 # 764 # For an example of the use of this attribute, look at test/types dir. 765 # There are a bunch of test cases under test/types and we don't want the 766 # module cacheing subsystem to be confused with executable name "a.out" 767 # used for all the test cases. 768 self.testMethodName = self._testMethodName 769 770 # This is for the case of directly spawning 'lldb'/'gdb' and interacting 771 # with it using pexpect. 772 self.child = None 773 self.child_prompt = "(lldb) " 774 # If the child is interacting with the embedded script interpreter, 775 # there are two exits required during tear down, first to quit the 776 # embedded script interpreter and second to quit the lldb command 777 # interpreter. 778 self.child_in_script_interpreter = False 779 780 # These are for customized teardown cleanup. 781 self.dict = None 782 self.doTearDownCleanup = False 783 # And in rare cases where there are multiple teardown cleanups. 784 self.dicts = [] 785 self.doTearDownCleanups = False 786 787 # List of spawned subproces.Popen objects 788 self.subprocesses = [] 789 790 # List of forked process PIDs 791 self.forkedProcessPids = [] 792 793 # Create a string buffer to record the session info, to be dumped into a 794 # test case specific file if test failure is encountered. 795 self.log_basename = self.getLogBasenameForCurrentTest() 796 797 session_file = "{}.log".format(self.log_basename) 798 # Python 3 doesn't support unbuffered I/O in text mode. Open buffered. 799 self.session = encoded_file.open(session_file, "utf-8", mode="w") 800 801 # Optimistically set __errored__, __failed__, __expected__ to False 802 # initially. If the test errored/failed, the session info 803 # (self.session) is then dumped into a session specific file for 804 # diagnosis. 805 self.__cleanup_errored__ = False 806 self.__errored__ = False 807 self.__failed__ = False 808 self.__expected__ = False 809 # We are also interested in unexpected success. 810 self.__unexpected__ = False 811 # And skipped tests. 812 self.__skipped__ = False 813 814 # See addTearDownHook(self, hook) which allows the client to add a hook 815 # function to be run during tearDown() time. 816 self.hooks = [] 817 818 # See HideStdout(self). 819 self.sys_stdout_hidden = False 820 821 if self.platformContext: 822 # set environment variable names for finding shared libraries 823 self.dylibPath = self.platformContext.shlib_environment_var 824 825 # Create the debugger instance. 826 self.dbg = lldb.SBDebugger.Create() 827 # Copy selected platform from a global instance if it exists. 828 if lldb.selected_platform is not None: 829 self.dbg.SetSelectedPlatform(lldb.selected_platform) 830 831 if not self.dbg: 832 raise Exception('Invalid debugger instance') 833 834 # Retrieve the associated command interpreter instance. 835 self.ci = self.dbg.GetCommandInterpreter() 836 if not self.ci: 837 raise Exception('Could not get the command interpreter') 838 839 # And the result object. 840 self.res = lldb.SBCommandReturnObject() 841 842 self.setPlatformWorkingDir() 843 self.enableLogChannelsForCurrentTest() 844 845 lib_dir = os.environ["LLDB_LIB_DIR"] 846 self.dsym = None 847 self.framework_dir = None 848 self.darwinWithFramework = self.platformIsDarwin() 849 if sys.platform.startswith("darwin"): 850 # Handle the framework environment variable if it is set 851 if hasattr(lldbtest_config, 'lldb_framework_path'): 852 framework_path = lldbtest_config.lldb_framework_path 853 # Framework dir should be the directory containing the framework 854 self.framework_dir = framework_path[:framework_path.rfind('LLDB.framework')] 855 # If a framework dir was not specified assume the Xcode build 856 # directory layout where the framework is in LLDB_LIB_DIR. 857 else: 858 self.framework_dir = lib_dir 859 self.dsym = os.path.join(self.framework_dir, 'LLDB.framework', 'LLDB') 860 # If the framework binary doesn't exist, assume we didn't actually 861 # build a framework, and fallback to standard *nix behavior by 862 # setting framework_dir and dsym to None. 863 if not os.path.exists(self.dsym): 864 self.framework_dir = None 865 self.dsym = None 866 self.darwinWithFramework = False 867 self.makeBuildDir() 868 869 def setAsync(self, value): 870 """ Sets async mode to True/False and ensures it is reset after the testcase completes.""" 871 old_async = self.dbg.GetAsync() 872 self.dbg.SetAsync(value) 873 self.addTearDownHook(lambda: self.dbg.SetAsync(old_async)) 874 875 def cleanupSubprocesses(self): 876 # Ensure any subprocesses are cleaned up 877 for p in self.subprocesses: 878 p.terminate() 879 del p 880 del self.subprocesses[:] 881 # Ensure any forked processes are cleaned up 882 for pid in self.forkedProcessPids: 883 if os.path.exists("/proc/" + str(pid)): 884 os.kill(pid, signal.SIGTERM) 885 886 def spawnSubprocess(self, executable, args=[], install_remote=True): 887 """ Creates a subprocess.Popen object with the specified executable and arguments, 888 saves it in self.subprocesses, and returns the object. 889 NOTE: if using this function, ensure you also call: 890 891 self.addTearDownHook(self.cleanupSubprocesses) 892 893 otherwise the test suite will leak processes. 894 """ 895 proc = _RemoteProcess( 896 install_remote) if lldb.remote_platform else _LocalProcess(self.TraceOn()) 897 proc.launch(executable, args) 898 self.subprocesses.append(proc) 899 return proc 900 901 def forkSubprocess(self, executable, args=[]): 902 """ Fork a subprocess with its own group ID. 903 NOTE: if using this function, ensure you also call: 904 905 self.addTearDownHook(self.cleanupSubprocesses) 906 907 otherwise the test suite will leak processes. 908 """ 909 child_pid = os.fork() 910 if child_pid == 0: 911 # If more I/O support is required, this can be beefed up. 912 fd = os.open(os.devnull, os.O_RDWR) 913 os.dup2(fd, 1) 914 os.dup2(fd, 2) 915 # This call causes the child to have its of group ID 916 os.setpgid(0, 0) 917 os.execvp(executable, [executable] + args) 918 # Give the child time to get through the execvp() call 919 time.sleep(0.1) 920 self.forkedProcessPids.append(child_pid) 921 return child_pid 922 923 def HideStdout(self): 924 """Hide output to stdout from the user. 925 926 During test execution, there might be cases where we don't want to show the 927 standard output to the user. For example, 928 929 self.runCmd(r'''sc print("\n\n\tHello!\n")''') 930 931 tests whether command abbreviation for 'script' works or not. There is no 932 need to show the 'Hello' output to the user as long as the 'script' command 933 succeeds and we are not in TraceOn() mode (see the '-t' option). 934 935 In this case, the test method calls self.HideStdout(self) to redirect the 936 sys.stdout to a null device, and restores the sys.stdout upon teardown. 937 938 Note that you should only call this method at most once during a test case 939 execution. Any subsequent call has no effect at all.""" 940 if self.sys_stdout_hidden: 941 return 942 943 self.sys_stdout_hidden = True 944 old_stdout = sys.stdout 945 sys.stdout = open(os.devnull, 'w') 946 947 def restore_stdout(): 948 sys.stdout = old_stdout 949 self.addTearDownHook(restore_stdout) 950 951 # ======================================================================= 952 # Methods for customized teardown cleanups as well as execution of hooks. 953 # ======================================================================= 954 955 def setTearDownCleanup(self, dictionary=None): 956 """Register a cleanup action at tearDown() time with a dictionary""" 957 self.dict = dictionary 958 self.doTearDownCleanup = True 959 960 def addTearDownCleanup(self, dictionary): 961 """Add a cleanup action at tearDown() time with a dictionary""" 962 self.dicts.append(dictionary) 963 self.doTearDownCleanups = True 964 965 def addTearDownHook(self, hook): 966 """ 967 Add a function to be run during tearDown() time. 968 969 Hooks are executed in a first come first serve manner. 970 """ 971 if six.callable(hook): 972 with recording(self, traceAlways) as sbuf: 973 print( 974 "Adding tearDown hook:", 975 getsource_if_available(hook), 976 file=sbuf) 977 self.hooks.append(hook) 978 979 return self 980 981 def deletePexpectChild(self): 982 # This is for the case of directly spawning 'lldb' and interacting with it 983 # using pexpect. 984 if self.child and self.child.isalive(): 985 import pexpect 986 with recording(self, traceAlways) as sbuf: 987 print("tearing down the child process....", file=sbuf) 988 try: 989 if self.child_in_script_interpreter: 990 self.child.sendline('quit()') 991 self.child.expect_exact(self.child_prompt) 992 self.child.sendline( 993 'settings set interpreter.prompt-on-quit false') 994 self.child.sendline('quit') 995 self.child.expect(pexpect.EOF) 996 except (ValueError, pexpect.ExceptionPexpect): 997 # child is already terminated 998 pass 999 except OSError as exception: 1000 import errno 1001 if exception.errno != errno.EIO: 1002 # unexpected error 1003 raise 1004 # child is already terminated 1005 finally: 1006 # Give it one final blow to make sure the child is terminated. 1007 self.child.close() 1008 1009 def tearDown(self): 1010 """Fixture for unittest test case teardown.""" 1011 #import traceback 1012 # traceback.print_stack() 1013 1014 self.deletePexpectChild() 1015 1016 # Check and run any hook functions. 1017 for hook in reversed(self.hooks): 1018 with recording(self, traceAlways) as sbuf: 1019 print( 1020 "Executing tearDown hook:", 1021 getsource_if_available(hook), 1022 file=sbuf) 1023 if funcutils.requires_self(hook): 1024 hook(self) 1025 else: 1026 hook() # try the plain call and hope it works 1027 1028 del self.hooks 1029 1030 # Perform registered teardown cleanup. 1031 if doCleanup and self.doTearDownCleanup: 1032 self.cleanup(dictionary=self.dict) 1033 1034 # In rare cases where there are multiple teardown cleanups added. 1035 if doCleanup and self.doTearDownCleanups: 1036 if self.dicts: 1037 for dict in reversed(self.dicts): 1038 self.cleanup(dictionary=dict) 1039 1040 # This must be the last statement, otherwise teardown hooks or other 1041 # lines might depend on this still being active. 1042 lldb.SBDebugger.Destroy(self.dbg) 1043 del self.dbg 1044 1045 # ========================================================= 1046 # Various callbacks to allow introspection of test progress 1047 # ========================================================= 1048 1049 def markError(self): 1050 """Callback invoked when an error (unexpected exception) errored.""" 1051 self.__errored__ = True 1052 with recording(self, False) as sbuf: 1053 # False because there's no need to write "ERROR" to the stderr twice. 1054 # Once by the Python unittest framework, and a second time by us. 1055 print("ERROR", file=sbuf) 1056 1057 def markCleanupError(self): 1058 """Callback invoked when an error occurs while a test is cleaning up.""" 1059 self.__cleanup_errored__ = True 1060 with recording(self, False) as sbuf: 1061 # False because there's no need to write "CLEANUP_ERROR" to the stderr twice. 1062 # Once by the Python unittest framework, and a second time by us. 1063 print("CLEANUP_ERROR", file=sbuf) 1064 1065 def markFailure(self): 1066 """Callback invoked when a failure (test assertion failure) occurred.""" 1067 self.__failed__ = True 1068 with recording(self, False) as sbuf: 1069 # False because there's no need to write "FAIL" to the stderr twice. 1070 # Once by the Python unittest framework, and a second time by us. 1071 print("FAIL", file=sbuf) 1072 1073 def markExpectedFailure(self, err, bugnumber): 1074 """Callback invoked when an expected failure/error occurred.""" 1075 self.__expected__ = True 1076 with recording(self, False) as sbuf: 1077 # False because there's no need to write "expected failure" to the 1078 # stderr twice. 1079 # Once by the Python unittest framework, and a second time by us. 1080 if bugnumber is None: 1081 print("expected failure", file=sbuf) 1082 else: 1083 print( 1084 "expected failure (problem id:" + str(bugnumber) + ")", 1085 file=sbuf) 1086 1087 def markSkippedTest(self): 1088 """Callback invoked when a test is skipped.""" 1089 self.__skipped__ = True 1090 with recording(self, False) as sbuf: 1091 # False because there's no need to write "skipped test" to the 1092 # stderr twice. 1093 # Once by the Python unittest framework, and a second time by us. 1094 print("skipped test", file=sbuf) 1095 1096 def markUnexpectedSuccess(self, bugnumber): 1097 """Callback invoked when an unexpected success occurred.""" 1098 self.__unexpected__ = True 1099 with recording(self, False) as sbuf: 1100 # False because there's no need to write "unexpected success" to the 1101 # stderr twice. 1102 # Once by the Python unittest framework, and a second time by us. 1103 if bugnumber is None: 1104 print("unexpected success", file=sbuf) 1105 else: 1106 print( 1107 "unexpected success (problem id:" + str(bugnumber) + ")", 1108 file=sbuf) 1109 1110 def getRerunArgs(self): 1111 return " -f %s.%s" % (self.__class__.__name__, self._testMethodName) 1112 1113 def getLogBasenameForCurrentTest(self, prefix=None): 1114 """ 1115 returns a partial path that can be used as the beginning of the name of multiple 1116 log files pertaining to this test 1117 1118 <session-dir>/<arch>-<compiler>-<test-file>.<test-class>.<test-method> 1119 """ 1120 dname = os.path.join(os.environ["LLDB_TEST_SRC"], 1121 os.environ["LLDB_SESSION_DIRNAME"]) 1122 if not os.path.isdir(dname): 1123 os.mkdir(dname) 1124 1125 components = [] 1126 if prefix is not None: 1127 components.append(prefix) 1128 for c in configuration.session_file_format: 1129 if c == 'f': 1130 components.append(self.__class__.__module__) 1131 elif c == 'n': 1132 components.append(self.__class__.__name__) 1133 elif c == 'c': 1134 compiler = self.getCompiler() 1135 1136 if compiler[1] == ':': 1137 compiler = compiler[2:] 1138 if os.path.altsep is not None: 1139 compiler = compiler.replace(os.path.altsep, os.path.sep) 1140 path_components = [x for x in compiler.split(os.path.sep) if x != ""] 1141 1142 # Add at most 4 path components to avoid generating very long 1143 # filenames 1144 components.extend(path_components[-4:]) 1145 elif c == 'a': 1146 components.append(self.getArchitecture()) 1147 elif c == 'm': 1148 components.append(self.testMethodName) 1149 fname = "-".join(components) 1150 1151 return os.path.join(dname, fname) 1152 1153 def dumpSessionInfo(self): 1154 """ 1155 Dump the debugger interactions leading to a test error/failure. This 1156 allows for more convenient postmortem analysis. 1157 1158 See also LLDBTestResult (dotest.py) which is a singlton class derived 1159 from TextTestResult and overwrites addError, addFailure, and 1160 addExpectedFailure methods to allow us to to mark the test instance as 1161 such. 1162 """ 1163 1164 # We are here because self.tearDown() detected that this test instance 1165 # either errored or failed. The lldb.test_result singleton contains 1166 # two lists (errors and failures) which get populated by the unittest 1167 # framework. Look over there for stack trace information. 1168 # 1169 # The lists contain 2-tuples of TestCase instances and strings holding 1170 # formatted tracebacks. 1171 # 1172 # See http://docs.python.org/library/unittest.html#unittest.TestResult. 1173 1174 # output tracebacks into session 1175 pairs = [] 1176 if self.__errored__: 1177 pairs = configuration.test_result.errors 1178 prefix = 'Error' 1179 elif self.__cleanup_errored__: 1180 pairs = configuration.test_result.cleanup_errors 1181 prefix = 'CleanupError' 1182 elif self.__failed__: 1183 pairs = configuration.test_result.failures 1184 prefix = 'Failure' 1185 elif self.__expected__: 1186 pairs = configuration.test_result.expectedFailures 1187 prefix = 'ExpectedFailure' 1188 elif self.__skipped__: 1189 prefix = 'SkippedTest' 1190 elif self.__unexpected__: 1191 prefix = 'UnexpectedSuccess' 1192 else: 1193 prefix = 'Success' 1194 1195 if not self.__unexpected__ and not self.__skipped__: 1196 for test, traceback in pairs: 1197 if test is self: 1198 print(traceback, file=self.session) 1199 1200 import datetime 1201 print( 1202 "Session info generated @", 1203 datetime.datetime.now().ctime(), 1204 file=self.session) 1205 self.session.close() 1206 del self.session 1207 1208 # process the log files 1209 log_files_for_this_test = glob.glob(self.log_basename + "*") 1210 1211 if prefix != 'Success' or lldbtest_config.log_success: 1212 # keep all log files, rename them to include prefix 1213 dst_log_basename = self.getLogBasenameForCurrentTest(prefix) 1214 for src in log_files_for_this_test: 1215 if os.path.isfile(src): 1216 dst = src.replace(self.log_basename, dst_log_basename) 1217 if os.name == "nt" and os.path.isfile(dst): 1218 # On Windows, renaming a -> b will throw an exception if 1219 # b exists. On non-Windows platforms it silently 1220 # replaces the destination. Ultimately this means that 1221 # atomic renames are not guaranteed to be possible on 1222 # Windows, but we need this to work anyway, so just 1223 # remove the destination first if it already exists. 1224 remove_file(dst) 1225 1226 lldbutil.mkdir_p(os.path.dirname(dst)) 1227 os.rename(src, dst) 1228 else: 1229 # success! (and we don't want log files) delete log files 1230 for log_file in log_files_for_this_test: 1231 remove_file(log_file) 1232 1233 # ==================================================== 1234 # Config. methods supported through a plugin interface 1235 # (enables reading of the current test configuration) 1236 # ==================================================== 1237 1238 def isMIPS(self): 1239 """Returns true if the architecture is MIPS.""" 1240 arch = self.getArchitecture() 1241 if re.match("mips", arch): 1242 return True 1243 return False 1244 1245 def isPPC64le(self): 1246 """Returns true if the architecture is PPC64LE.""" 1247 arch = self.getArchitecture() 1248 if re.match("powerpc64le", arch): 1249 return True 1250 return False 1251 1252 def getArchitecture(self): 1253 """Returns the architecture in effect the test suite is running with.""" 1254 module = builder_module() 1255 arch = module.getArchitecture() 1256 if arch == 'amd64': 1257 arch = 'x86_64' 1258 if arch in ['armv7l', 'armv8l'] : 1259 arch = 'arm' 1260 return arch 1261 1262 def getLldbArchitecture(self): 1263 """Returns the architecture of the lldb binary.""" 1264 if not hasattr(self, 'lldbArchitecture'): 1265 1266 # spawn local process 1267 command = [ 1268 lldbtest_config.lldbExec, 1269 "-o", 1270 "file " + lldbtest_config.lldbExec, 1271 "-o", 1272 "quit" 1273 ] 1274 1275 output = check_output(command) 1276 str = output.decode("utf-8") 1277 1278 for line in str.splitlines(): 1279 m = re.search( 1280 "Current executable set to '.*' \\((.*)\\)\\.", line) 1281 if m: 1282 self.lldbArchitecture = m.group(1) 1283 break 1284 1285 return self.lldbArchitecture 1286 1287 def getCompiler(self): 1288 """Returns the compiler in effect the test suite is running with.""" 1289 module = builder_module() 1290 return module.getCompiler() 1291 1292 def getCompilerBinary(self): 1293 """Returns the compiler binary the test suite is running with.""" 1294 return self.getCompiler().split()[0] 1295 1296 def getCompilerVersion(self): 1297 """ Returns a string that represents the compiler version. 1298 Supports: llvm, clang. 1299 """ 1300 version = 'unknown' 1301 1302 compiler = self.getCompilerBinary() 1303 version_output = system([[compiler, "-v"]])[1] 1304 for line in version_output.split(os.linesep): 1305 m = re.search('version ([0-9\.]+)', line) 1306 if m: 1307 version = m.group(1) 1308 return version 1309 1310 def getDwarfVersion(self): 1311 """ Returns the dwarf version generated by clang or '0'. """ 1312 if configuration.dwarf_version: 1313 return str(configuration.dwarf_version) 1314 if 'clang' in self.getCompiler(): 1315 try: 1316 driver_output = check_output( 1317 [self.getCompiler()] + '-g -c -x c - -o - -###'.split(), 1318 stderr=STDOUT) 1319 driver_output = driver_output.decode("utf-8") 1320 for line in driver_output.split(os.linesep): 1321 m = re.search('dwarf-version=([0-9])', line) 1322 if m: 1323 return m.group(1) 1324 except: pass 1325 return '0' 1326 1327 def platformIsDarwin(self): 1328 """Returns true if the OS triple for the selected platform is any valid apple OS""" 1329 return lldbplatformutil.platformIsDarwin() 1330 1331 def hasDarwinFramework(self): 1332 return self.darwinWithFramework 1333 1334 def getPlatform(self): 1335 """Returns the target platform the test suite is running on.""" 1336 return lldbplatformutil.getPlatform() 1337 1338 def isIntelCompiler(self): 1339 """ Returns true if using an Intel (ICC) compiler, false otherwise. """ 1340 return any([x in self.getCompiler() for x in ["icc", "icpc", "icl"]]) 1341 1342 def expectedCompilerVersion(self, compiler_version): 1343 """Returns True iff compiler_version[1] matches the current compiler version. 1344 Use compiler_version[0] to specify the operator used to determine if a match has occurred. 1345 Any operator other than the following defaults to an equality test: 1346 '>', '>=', "=>", '<', '<=', '=<', '!=', "!" or 'not' 1347 """ 1348 if (compiler_version is None): 1349 return True 1350 operator = str(compiler_version[0]) 1351 version = compiler_version[1] 1352 1353 if (version is None): 1354 return True 1355 if (operator == '>'): 1356 return LooseVersion(self.getCompilerVersion()) > LooseVersion(version) 1357 if (operator == '>=' or operator == '=>'): 1358 return LooseVersion(self.getCompilerVersion()) >= LooseVersion(version) 1359 if (operator == '<'): 1360 return LooseVersion(self.getCompilerVersion()) < LooseVersion(version) 1361 if (operator == '<=' or operator == '=<'): 1362 return LooseVersion(self.getCompilerVersion()) <= LooseVersion(version) 1363 if (operator == '!=' or operator == '!' or operator == 'not'): 1364 return str(version) not in str(self.getCompilerVersion()) 1365 return str(version) in str(self.getCompilerVersion()) 1366 1367 def expectedCompiler(self, compilers): 1368 """Returns True iff any element of compilers is a sub-string of the current compiler.""" 1369 if (compilers is None): 1370 return True 1371 1372 for compiler in compilers: 1373 if compiler in self.getCompiler(): 1374 return True 1375 1376 return False 1377 1378 def expectedArch(self, archs): 1379 """Returns True iff any element of archs is a sub-string of the current architecture.""" 1380 if (archs is None): 1381 return True 1382 1383 for arch in archs: 1384 if arch in self.getArchitecture(): 1385 return True 1386 1387 return False 1388 1389 def getRunOptions(self): 1390 """Command line option for -A and -C to run this test again, called from 1391 self.dumpSessionInfo().""" 1392 arch = self.getArchitecture() 1393 comp = self.getCompiler() 1394 option_str = "" 1395 if arch: 1396 option_str = "-A " + arch 1397 if comp: 1398 option_str += " -C " + comp 1399 return option_str 1400 1401 def getDebugInfo(self): 1402 method = getattr(self, self.testMethodName) 1403 return getattr(method, "debug_info", None) 1404 1405 # ================================================== 1406 # Build methods supported through a plugin interface 1407 # ================================================== 1408 1409 def getstdlibFlag(self): 1410 """ Returns the proper -stdlib flag, or empty if not required.""" 1411 if self.platformIsDarwin() or self.getPlatform() == "freebsd" or self.getPlatform() == "openbsd": 1412 stdlibflag = "-stdlib=libc++" 1413 else: # this includes NetBSD 1414 stdlibflag = "" 1415 return stdlibflag 1416 1417 def getstdFlag(self): 1418 """ Returns the proper stdflag. """ 1419 if "gcc" in self.getCompiler() and "4.6" in self.getCompilerVersion(): 1420 stdflag = "-std=c++0x" 1421 else: 1422 stdflag = "-std=c++11" 1423 return stdflag 1424 1425 def buildDriver(self, sources, exe_name): 1426 """ Platform-specific way to build a program that links with LLDB (via the liblldb.so 1427 or LLDB.framework). 1428 """ 1429 stdflag = self.getstdFlag() 1430 stdlibflag = self.getstdlibFlag() 1431 1432 lib_dir = configuration.lldb_libs_dir 1433 if self.hasDarwinFramework(): 1434 d = {'CXX_SOURCES': sources, 1435 'EXE': exe_name, 1436 'CFLAGS_EXTRAS': "%s %s" % (stdflag, stdlibflag), 1437 'FRAMEWORK_INCLUDES': "-F%s" % self.framework_dir, 1438 'LD_EXTRAS': "%s -Wl,-rpath,%s" % (self.dsym, self.framework_dir), 1439 } 1440 elif sys.platform.startswith('win'): 1441 d = { 1442 'CXX_SOURCES': sources, 1443 'EXE': exe_name, 1444 'CFLAGS_EXTRAS': "%s %s -I%s" % (stdflag, 1445 stdlibflag, 1446 os.path.join( 1447 os.environ["LLDB_SRC"], 1448 "include")), 1449 'LD_EXTRAS': "-L%s -lliblldb" % os.environ["LLDB_IMPLIB_DIR"]} 1450 else: 1451 d = { 1452 'CXX_SOURCES': sources, 1453 'EXE': exe_name, 1454 'CFLAGS_EXTRAS': "%s %s -I%s" % (stdflag, 1455 stdlibflag, 1456 os.path.join( 1457 os.environ["LLDB_SRC"], 1458 "include")), 1459 'LD_EXTRAS': "-L%s -llldb -Wl,-rpath,%s" % (lib_dir, lib_dir)} 1460 if self.TraceOn(): 1461 print( 1462 "Building LLDB Driver (%s) from sources %s" % 1463 (exe_name, sources)) 1464 1465 self.buildDefault(dictionary=d) 1466 1467 def buildLibrary(self, sources, lib_name): 1468 """Platform specific way to build a default library. """ 1469 1470 stdflag = self.getstdFlag() 1471 1472 lib_dir = configuration.lldb_libs_dir 1473 if self.hasDarwinFramework(): 1474 d = {'DYLIB_CXX_SOURCES': sources, 1475 'DYLIB_NAME': lib_name, 1476 'CFLAGS_EXTRAS': "%s -stdlib=libc++" % stdflag, 1477 'FRAMEWORK_INCLUDES': "-F%s" % self.framework_dir, 1478 'LD_EXTRAS': "%s -Wl,-rpath,%s -dynamiclib" % (self.dsym, self.framework_dir), 1479 } 1480 elif self.getPlatform() == 'windows': 1481 d = { 1482 'DYLIB_CXX_SOURCES': sources, 1483 'DYLIB_NAME': lib_name, 1484 'CFLAGS_EXTRAS': "%s -I%s " % (stdflag, 1485 os.path.join( 1486 os.environ["LLDB_SRC"], 1487 "include")), 1488 'LD_EXTRAS': "-shared -l%s\liblldb.lib" % self.os.environ["LLDB_IMPLIB_DIR"]} 1489 else: 1490 d = { 1491 'DYLIB_CXX_SOURCES': sources, 1492 'DYLIB_NAME': lib_name, 1493 'CFLAGS_EXTRAS': "%s -I%s -fPIC" % (stdflag, 1494 os.path.join( 1495 os.environ["LLDB_SRC"], 1496 "include")), 1497 'LD_EXTRAS': "-shared -L%s -llldb -Wl,-rpath,%s" % (lib_dir, lib_dir)} 1498 if self.TraceOn(): 1499 print( 1500 "Building LLDB Library (%s) from sources %s" % 1501 (lib_name, sources)) 1502 1503 self.buildDefault(dictionary=d) 1504 1505 def buildProgram(self, sources, exe_name): 1506 """ Platform specific way to build an executable from C/C++ sources. """ 1507 d = {'CXX_SOURCES': sources, 1508 'EXE': exe_name} 1509 self.buildDefault(dictionary=d) 1510 1511 def buildDefault( 1512 self, 1513 architecture=None, 1514 compiler=None, 1515 dictionary=None): 1516 """Platform specific way to build the default binaries.""" 1517 testdir = self.mydir 1518 testname = self.getBuildDirBasename() 1519 if self.getDebugInfo(): 1520 raise Exception("buildDefault tests must set NO_DEBUG_INFO_TESTCASE") 1521 module = builder_module() 1522 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1523 if not module.buildDefault(self, architecture, compiler, 1524 dictionary, testdir, testname): 1525 raise Exception("Don't know how to build default binary") 1526 1527 def buildDsym( 1528 self, 1529 architecture=None, 1530 compiler=None, 1531 dictionary=None): 1532 """Platform specific way to build binaries with dsym info.""" 1533 testdir = self.mydir 1534 testname = self.getBuildDirBasename() 1535 if self.getDebugInfo() != "dsym": 1536 raise Exception("NO_DEBUG_INFO_TESTCASE must build with buildDefault") 1537 1538 module = builder_module() 1539 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1540 if not module.buildDsym(self, architecture, compiler, 1541 dictionary, testdir, testname): 1542 raise Exception("Don't know how to build binary with dsym") 1543 1544 def buildDwarf( 1545 self, 1546 architecture=None, 1547 compiler=None, 1548 dictionary=None): 1549 """Platform specific way to build binaries with dwarf maps.""" 1550 testdir = self.mydir 1551 testname = self.getBuildDirBasename() 1552 if self.getDebugInfo() != "dwarf": 1553 raise Exception("NO_DEBUG_INFO_TESTCASE must build with buildDefault") 1554 1555 module = builder_module() 1556 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1557 if not module.buildDwarf(self, architecture, compiler, 1558 dictionary, testdir, testname): 1559 raise Exception("Don't know how to build binary with dwarf") 1560 1561 def buildDwo( 1562 self, 1563 architecture=None, 1564 compiler=None, 1565 dictionary=None): 1566 """Platform specific way to build binaries with dwarf maps.""" 1567 testdir = self.mydir 1568 testname = self.getBuildDirBasename() 1569 if self.getDebugInfo() != "dwo": 1570 raise Exception("NO_DEBUG_INFO_TESTCASE must build with buildDefault") 1571 1572 module = builder_module() 1573 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1574 if not module.buildDwo(self, architecture, compiler, 1575 dictionary, testdir, testname): 1576 raise Exception("Don't know how to build binary with dwo") 1577 1578 def buildGModules( 1579 self, 1580 architecture=None, 1581 compiler=None, 1582 dictionary=None): 1583 """Platform specific way to build binaries with gmodules info.""" 1584 testdir = self.mydir 1585 testname = self.getBuildDirBasename() 1586 if self.getDebugInfo() != "gmodules": 1587 raise Exception("NO_DEBUG_INFO_TESTCASE must build with buildDefault") 1588 1589 module = builder_module() 1590 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1591 if not module.buildGModules(self, architecture, compiler, 1592 dictionary, testdir, testname): 1593 raise Exception("Don't know how to build binary with gmodules") 1594 1595 def signBinary(self, binary_path): 1596 if sys.platform.startswith("darwin"): 1597 codesign_cmd = "codesign --force --sign \"%s\" %s" % ( 1598 lldbtest_config.codesign_identity, binary_path) 1599 call(codesign_cmd, shell=True) 1600 1601 def findBuiltClang(self): 1602 """Tries to find and use Clang from the build directory as the compiler (instead of the system compiler).""" 1603 paths_to_try = [ 1604 "llvm-build/Release+Asserts/x86_64/bin/clang", 1605 "llvm-build/Debug+Asserts/x86_64/bin/clang", 1606 "llvm-build/Release/x86_64/bin/clang", 1607 "llvm-build/Debug/x86_64/bin/clang", 1608 ] 1609 lldb_root_path = os.path.join( 1610 os.path.dirname(__file__), "..", "..", "..", "..") 1611 for p in paths_to_try: 1612 path = os.path.join(lldb_root_path, p) 1613 if os.path.exists(path): 1614 return path 1615 1616 # Tries to find clang at the same folder as the lldb 1617 lldb_dir = os.path.dirname(lldbtest_config.lldbExec) 1618 path = distutils.spawn.find_executable("clang", lldb_dir) 1619 if path is not None: 1620 return path 1621 1622 return os.environ["CC"] 1623 1624 def findYaml2obj(self): 1625 """ 1626 Get the path to the yaml2obj executable, which can be used to create 1627 test object files from easy to write yaml instructions. 1628 1629 Throws an Exception if the executable cannot be found. 1630 """ 1631 # Tries to find yaml2obj at the same folder as clang 1632 clang_dir = os.path.dirname(self.findBuiltClang()) 1633 path = distutils.spawn.find_executable("yaml2obj", clang_dir) 1634 if path is not None: 1635 return path 1636 raise Exception("yaml2obj executable not found") 1637 1638 1639 def yaml2obj(self, yaml_path, obj_path): 1640 """ 1641 Create an object file at the given path from a yaml file. 1642 1643 Throws subprocess.CalledProcessError if the object could not be created. 1644 """ 1645 yaml2obj = self.findYaml2obj() 1646 command = [yaml2obj, "-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 self.assertTrue(rc.Success(), PROCESS_KILLED) 2017 for target in targets: 2018 self.dbg.DeleteTarget(target) 2019 2020 # Do this last, to make sure it's in reverse order from how we setup. 2021 Base.tearDown(self) 2022 2023 def switch_to_thread_with_stop_reason(self, stop_reason): 2024 """ 2025 Run the 'thread list' command, and select the thread with stop reason as 2026 'stop_reason'. If no such thread exists, no select action is done. 2027 """ 2028 from .lldbutil import stop_reason_to_str 2029 self.runCmd('thread list') 2030 output = self.res.GetOutput() 2031 thread_line_pattern = re.compile( 2032 "^[ *] thread #([0-9]+):.*stop reason = %s" % 2033 stop_reason_to_str(stop_reason)) 2034 for line in output.splitlines(): 2035 matched = thread_line_pattern.match(line) 2036 if matched: 2037 self.runCmd('thread select %s' % matched.group(1)) 2038 2039 def runCmd(self, cmd, msg=None, check=True, trace=False, inHistory=False): 2040 """ 2041 Ask the command interpreter to handle the command and then check its 2042 return status. 2043 """ 2044 # Fail fast if 'cmd' is not meaningful. 2045 if not cmd or len(cmd) == 0: 2046 raise Exception("Bad 'cmd' parameter encountered") 2047 2048 trace = (True if traceAlways else trace) 2049 2050 if cmd.startswith("target create "): 2051 cmd = cmd.replace("target create ", "file ") 2052 2053 running = (cmd.startswith("run") or cmd.startswith("process launch")) 2054 2055 for i in range(self.maxLaunchCount if running else 1): 2056 self.ci.HandleCommand(cmd, self.res, inHistory) 2057 2058 with recording(self, trace) as sbuf: 2059 print("runCmd:", cmd, file=sbuf) 2060 if not check: 2061 print("check of return status not required", file=sbuf) 2062 if self.res.Succeeded(): 2063 print("output:", self.res.GetOutput(), file=sbuf) 2064 else: 2065 print("runCmd failed!", file=sbuf) 2066 print(self.res.GetError(), file=sbuf) 2067 2068 if self.res.Succeeded(): 2069 break 2070 elif running: 2071 # For process launch, wait some time before possible next try. 2072 time.sleep(self.timeWaitNextLaunch) 2073 with recording(self, trace) as sbuf: 2074 print("Command '" + cmd + "' failed!", file=sbuf) 2075 2076 if check: 2077 output = "" 2078 if self.res.GetOutput(): 2079 output += "\nCommand output:\n" + self.res.GetOutput() 2080 if self.res.GetError(): 2081 output += "\nError output:\n" + self.res.GetError() 2082 if msg: 2083 msg += output 2084 if cmd: 2085 cmd += output 2086 self.assertTrue(self.res.Succeeded(), 2087 msg if (msg) else CMD_MSG(cmd)) 2088 2089 def match( 2090 self, 2091 str, 2092 patterns, 2093 msg=None, 2094 trace=False, 2095 error=False, 2096 matching=True, 2097 exe=True): 2098 """run command in str, and match the result against regexp in patterns returning the match object for the first matching pattern 2099 2100 Otherwise, all the arguments have the same meanings as for the expect function""" 2101 2102 trace = (True if traceAlways else trace) 2103 2104 if exe: 2105 # First run the command. If we are expecting error, set check=False. 2106 # Pass the assert message along since it provides more semantic 2107 # info. 2108 self.runCmd( 2109 str, 2110 msg=msg, 2111 trace=( 2112 True if trace else False), 2113 check=not error) 2114 2115 # Then compare the output against expected strings. 2116 output = self.res.GetError() if error else self.res.GetOutput() 2117 2118 # If error is True, the API client expects the command to fail! 2119 if error: 2120 self.assertFalse(self.res.Succeeded(), 2121 "Command '" + str + "' is expected to fail!") 2122 else: 2123 # No execution required, just compare str against the golden input. 2124 output = str 2125 with recording(self, trace) as sbuf: 2126 print("looking at:", output, file=sbuf) 2127 2128 # The heading says either "Expecting" or "Not expecting". 2129 heading = "Expecting" if matching else "Not expecting" 2130 2131 for pattern in patterns: 2132 # Match Objects always have a boolean value of True. 2133 match_object = re.search(pattern, output) 2134 matched = bool(match_object) 2135 with recording(self, trace) as sbuf: 2136 print("%s pattern: %s" % (heading, pattern), file=sbuf) 2137 print("Matched" if matched else "Not matched", file=sbuf) 2138 if matched: 2139 break 2140 2141 self.assertTrue(matched if matching else not matched, 2142 msg if msg else EXP_MSG(str, output, exe)) 2143 2144 return match_object 2145 2146 def check_completion_with_desc(self, str_input, match_desc_pairs): 2147 interp = self.dbg.GetCommandInterpreter() 2148 match_strings = lldb.SBStringList() 2149 description_strings = lldb.SBStringList() 2150 num_matches = interp.HandleCompletionWithDescriptions(str_input, len(str_input), 0, -1, match_strings, description_strings) 2151 self.assertEqual(len(description_strings), len(match_strings)) 2152 2153 missing_pairs = [] 2154 for pair in match_desc_pairs: 2155 found_pair = False 2156 for i in range(num_matches + 1): 2157 match_candidate = match_strings.GetStringAtIndex(i) 2158 description_candidate = description_strings.GetStringAtIndex(i) 2159 if match_candidate == pair[0] and description_candidate == pair[1]: 2160 found_pair = True 2161 break 2162 if not found_pair: 2163 missing_pairs.append(pair) 2164 2165 if len(missing_pairs): 2166 error_msg = "Missing pairs:\n" 2167 for pair in missing_pairs: 2168 error_msg += " [" + pair[0] + ":" + pair[1] + "]\n" 2169 error_msg += "Got the following " + str(num_matches) + " completions back:\n" 2170 for i in range(num_matches + 1): 2171 match_candidate = match_strings.GetStringAtIndex(i) 2172 description_candidate = description_strings.GetStringAtIndex(i) 2173 error_msg += "[" + match_candidate + ":" + description_candidate + "]\n" 2174 self.assertEqual(0, len(missing_pairs), error_msg) 2175 2176 def complete_exactly(self, str_input, patterns): 2177 self.complete_from_to(str_input, patterns, True) 2178 2179 def complete_from_to(self, str_input, patterns, turn_off_re_match=False): 2180 """Test that the completion mechanism completes str_input to patterns, 2181 where patterns could be a pattern-string or a list of pattern-strings""" 2182 # Patterns should not be None in order to proceed. 2183 self.assertFalse(patterns is None) 2184 # And should be either a string or list of strings. Check for list type 2185 # below, if not, make a list out of the singleton string. If patterns 2186 # is not a string or not a list of strings, there'll be runtime errors 2187 # later on. 2188 if not isinstance(patterns, list): 2189 patterns = [patterns] 2190 2191 interp = self.dbg.GetCommandInterpreter() 2192 match_strings = lldb.SBStringList() 2193 num_matches = interp.HandleCompletion(str_input, len(str_input), 0, -1, match_strings) 2194 common_match = match_strings.GetStringAtIndex(0) 2195 if num_matches == 0: 2196 compare_string = str_input 2197 else: 2198 if common_match != None and len(common_match) > 0: 2199 compare_string = str_input + common_match 2200 else: 2201 compare_string = "" 2202 for idx in range(1, num_matches+1): 2203 compare_string += match_strings.GetStringAtIndex(idx) + "\n" 2204 2205 for p in patterns: 2206 if turn_off_re_match: 2207 self.expect( 2208 compare_string, msg=COMPLETION_MSG( 2209 str_input, p, match_strings), exe=False, substrs=[p]) 2210 else: 2211 self.expect( 2212 compare_string, msg=COMPLETION_MSG( 2213 str_input, p, match_strings), exe=False, patterns=[p]) 2214 2215 def completions_match(self, command, completions): 2216 """Checks that the completions for the given command are equal to the 2217 given list of completions""" 2218 interp = self.dbg.GetCommandInterpreter() 2219 match_strings = lldb.SBStringList() 2220 interp.HandleCompletion(command, len(command), 0, -1, match_strings) 2221 # match_strings is a 1-indexed list, so we have to slice... 2222 self.assertItemsEqual(completions, list(match_strings)[1:], 2223 "List of returned completion is wrong") 2224 2225 def filecheck( 2226 self, 2227 command, 2228 check_file, 2229 filecheck_options = '', 2230 expect_cmd_failure = False): 2231 # Run the command. 2232 self.runCmd( 2233 command, 2234 check=(not expect_cmd_failure), 2235 msg="FileCheck'ing result of `{0}`".format(command)) 2236 2237 self.assertTrue((not expect_cmd_failure) == self.res.Succeeded()) 2238 2239 # Get the error text if there was an error, and the regular text if not. 2240 output = self.res.GetOutput() if self.res.Succeeded() \ 2241 else self.res.GetError() 2242 2243 # Assemble the absolute path to the check file. As a convenience for 2244 # LLDB inline tests, assume that the check file is a relative path to 2245 # a file within the inline test directory. 2246 if check_file.endswith('.pyc'): 2247 check_file = check_file[:-1] 2248 check_file_abs = os.path.abspath(check_file) 2249 2250 # Run FileCheck. 2251 filecheck_bin = configuration.get_filecheck_path() 2252 if not filecheck_bin: 2253 self.assertTrue(False, "No valid FileCheck executable specified") 2254 filecheck_args = [filecheck_bin, check_file_abs] 2255 if filecheck_options: 2256 filecheck_args.append(filecheck_options) 2257 subproc = Popen(filecheck_args, stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines = True) 2258 cmd_stdout, cmd_stderr = subproc.communicate(input=output) 2259 cmd_status = subproc.returncode 2260 2261 filecheck_cmd = " ".join(filecheck_args) 2262 filecheck_trace = """ 2263--- FileCheck trace (code={0}) --- 2264{1} 2265 2266FileCheck input: 2267{2} 2268 2269FileCheck output: 2270{3} 2271{4} 2272""".format(cmd_status, filecheck_cmd, output, cmd_stdout, cmd_stderr) 2273 2274 trace = cmd_status != 0 or traceAlways 2275 with recording(self, trace) as sbuf: 2276 print(filecheck_trace, file=sbuf) 2277 2278 self.assertTrue(cmd_status == 0) 2279 2280 def expect( 2281 self, 2282 str, 2283 msg=None, 2284 patterns=None, 2285 startstr=None, 2286 endstr=None, 2287 substrs=None, 2288 trace=False, 2289 error=False, 2290 ordered=True, 2291 matching=True, 2292 exe=True, 2293 inHistory=False): 2294 """ 2295 Similar to runCmd; with additional expect style output matching ability. 2296 2297 Ask the command interpreter to handle the command and then check its 2298 return status. The 'msg' parameter specifies an informational assert 2299 message. We expect the output from running the command to start with 2300 'startstr', matches the substrings contained in 'substrs', and regexp 2301 matches the patterns contained in 'patterns'. 2302 2303 When matching is true and ordered is true, which are both the default, 2304 the strings in the substrs array have to appear in the command output 2305 in the order in which they appear in the array. 2306 2307 If the keyword argument error is set to True, it signifies that the API 2308 client is expecting the command to fail. In this case, the error stream 2309 from running the command is retrieved and compared against the golden 2310 input, instead. 2311 2312 If the keyword argument matching is set to False, it signifies that the API 2313 client is expecting the output of the command not to match the golden 2314 input. 2315 2316 Finally, the required argument 'str' represents the lldb command to be 2317 sent to the command interpreter. In case the keyword argument 'exe' is 2318 set to False, the 'str' is treated as a string to be matched/not-matched 2319 against the golden input. 2320 """ 2321 trace = (True if traceAlways else trace) 2322 2323 if exe: 2324 # First run the command. If we are expecting error, set check=False. 2325 # Pass the assert message along since it provides more semantic 2326 # info. 2327 self.runCmd( 2328 str, 2329 msg=msg, 2330 trace=( 2331 True if trace else False), 2332 check=not error, 2333 inHistory=inHistory) 2334 2335 # Then compare the output against expected strings. 2336 output = self.res.GetError() if error else self.res.GetOutput() 2337 2338 # If error is True, the API client expects the command to fail! 2339 if error: 2340 self.assertFalse(self.res.Succeeded(), 2341 "Command '" + str + "' is expected to fail!") 2342 else: 2343 # No execution required, just compare str against the golden input. 2344 if isinstance(str, lldb.SBCommandReturnObject): 2345 output = str.GetOutput() 2346 else: 2347 output = str 2348 with recording(self, trace) as sbuf: 2349 print("looking at:", output, file=sbuf) 2350 2351 # The heading says either "Expecting" or "Not expecting". 2352 heading = "Expecting" if matching else "Not expecting" 2353 2354 # Start from the startstr, if specified. 2355 # If there's no startstr, set the initial state appropriately. 2356 matched = output.startswith(startstr) if startstr else ( 2357 True if matching else False) 2358 2359 if startstr: 2360 with recording(self, trace) as sbuf: 2361 print("%s start string: %s" % (heading, startstr), file=sbuf) 2362 print("Matched" if matched else "Not matched", file=sbuf) 2363 2364 # Look for endstr, if specified. 2365 keepgoing = matched if matching else not matched 2366 if endstr: 2367 matched = output.endswith(endstr) 2368 with recording(self, trace) as sbuf: 2369 print("%s end string: %s" % (heading, endstr), file=sbuf) 2370 print("Matched" if matched else "Not matched", file=sbuf) 2371 2372 # Look for sub strings, if specified. 2373 keepgoing = matched if matching else not matched 2374 if substrs and keepgoing: 2375 start = 0 2376 for substr in substrs: 2377 index = output[start:].find(substr) 2378 start = start + index if ordered and matching else 0 2379 matched = index != -1 2380 with recording(self, trace) as sbuf: 2381 print("%s sub string: %s" % (heading, substr), file=sbuf) 2382 print("Matched" if matched else "Not matched", file=sbuf) 2383 keepgoing = matched if matching else not matched 2384 if not keepgoing: 2385 break 2386 2387 # Search for regular expression patterns, if specified. 2388 keepgoing = matched if matching else not matched 2389 if patterns and keepgoing: 2390 for pattern in patterns: 2391 # Match Objects always have a boolean value of True. 2392 matched = bool(re.search(pattern, output)) 2393 with recording(self, trace) as sbuf: 2394 print("%s pattern: %s" % (heading, pattern), file=sbuf) 2395 print("Matched" if matched else "Not matched", file=sbuf) 2396 keepgoing = matched if matching else not matched 2397 if not keepgoing: 2398 break 2399 2400 self.assertTrue(matched if matching else not matched, 2401 msg + "\nCommand output:\n" + EXP_MSG(str, output, exe) 2402 if msg else EXP_MSG(str, output, exe)) 2403 2404 def expect_expr( 2405 self, 2406 expr, 2407 result_summary=None, 2408 result_value=None, 2409 result_type=None, 2410 ): 2411 """ 2412 Evaluates the given expression and verifies the result. 2413 :param expr: The expression as a string. 2414 :param result_summary: The summary that the expression should have. None if the summary should not be checked. 2415 :param result_value: The value that the expression should have. None if the value should not be checked. 2416 :param result_type: The type that the expression result should have. None if the type should not be checked. 2417 """ 2418 self.assertTrue(expr.strip() == expr, "Expression contains trailing/leading whitespace: '" + expr + "'") 2419 2420 frame = self.frame() 2421 options = lldb.SBExpressionOptions() 2422 2423 # Disable fix-its that tests don't pass by accident. 2424 options.SetAutoApplyFixIts(False) 2425 2426 # Set the usual default options for normal expressions. 2427 options.SetIgnoreBreakpoints(True) 2428 2429 if self.frame().IsValid(): 2430 options.SetLanguage(frame.GuessLanguage()) 2431 eval_result = self.frame().EvaluateExpression(expr, options) 2432 else: 2433 eval_result = self.target().EvaluateExpression(expr, options) 2434 2435 if not eval_result.GetError().Success(): 2436 self.assertTrue(eval_result.GetError().Success(), 2437 "Unexpected failure with msg: " + eval_result.GetError().GetCString()) 2438 2439 if result_type: 2440 self.assertEqual(result_type, eval_result.GetDisplayTypeName()) 2441 2442 if result_value: 2443 self.assertEqual(result_value, eval_result.GetValue()) 2444 2445 if result_summary: 2446 self.assertEqual(result_summary, eval_result.GetSummary()) 2447 2448 def invoke(self, obj, name, trace=False): 2449 """Use reflection to call a method dynamically with no argument.""" 2450 trace = (True if traceAlways else trace) 2451 2452 method = getattr(obj, name) 2453 import inspect 2454 self.assertTrue(inspect.ismethod(method), 2455 name + "is a method name of object: " + str(obj)) 2456 result = method() 2457 with recording(self, trace) as sbuf: 2458 print(str(method) + ":", result, file=sbuf) 2459 return result 2460 2461 def build( 2462 self, 2463 architecture=None, 2464 compiler=None, 2465 dictionary=None): 2466 """Platform specific way to build the default binaries.""" 2467 module = builder_module() 2468 2469 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 2470 if self.getDebugInfo() is None: 2471 return self.buildDefault(architecture, compiler, dictionary) 2472 elif self.getDebugInfo() == "dsym": 2473 return self.buildDsym(architecture, compiler, dictionary) 2474 elif self.getDebugInfo() == "dwarf": 2475 return self.buildDwarf(architecture, compiler, dictionary) 2476 elif self.getDebugInfo() == "dwo": 2477 return self.buildDwo(architecture, compiler, dictionary) 2478 elif self.getDebugInfo() == "gmodules": 2479 return self.buildGModules(architecture, compiler, dictionary) 2480 else: 2481 self.fail("Can't build for debug info: %s" % self.getDebugInfo()) 2482 2483 def run_platform_command(self, cmd): 2484 platform = self.dbg.GetSelectedPlatform() 2485 shell_command = lldb.SBPlatformShellCommand(cmd) 2486 err = platform.Run(shell_command) 2487 return (err, shell_command.GetStatus(), shell_command.GetOutput()) 2488 2489 # ================================================= 2490 # Misc. helper methods for debugging test execution 2491 # ================================================= 2492 2493 def DebugSBValue(self, val): 2494 """Debug print a SBValue object, if traceAlways is True.""" 2495 from .lldbutil import value_type_to_str 2496 2497 if not traceAlways: 2498 return 2499 2500 err = sys.stderr 2501 err.write(val.GetName() + ":\n") 2502 err.write('\t' + "TypeName -> " + val.GetTypeName() + '\n') 2503 err.write('\t' + "ByteSize -> " + 2504 str(val.GetByteSize()) + '\n') 2505 err.write('\t' + "NumChildren -> " + 2506 str(val.GetNumChildren()) + '\n') 2507 err.write('\t' + "Value -> " + str(val.GetValue()) + '\n') 2508 err.write('\t' + "ValueAsUnsigned -> " + 2509 str(val.GetValueAsUnsigned()) + '\n') 2510 err.write( 2511 '\t' + 2512 "ValueType -> " + 2513 value_type_to_str( 2514 val.GetValueType()) + 2515 '\n') 2516 err.write('\t' + "Summary -> " + str(val.GetSummary()) + '\n') 2517 err.write('\t' + "IsPointerType -> " + 2518 str(val.TypeIsPointerType()) + '\n') 2519 err.write('\t' + "Location -> " + val.GetLocation() + '\n') 2520 2521 def DebugSBType(self, type): 2522 """Debug print a SBType object, if traceAlways is True.""" 2523 if not traceAlways: 2524 return 2525 2526 err = sys.stderr 2527 err.write(type.GetName() + ":\n") 2528 err.write('\t' + "ByteSize -> " + 2529 str(type.GetByteSize()) + '\n') 2530 err.write('\t' + "IsPointerType -> " + 2531 str(type.IsPointerType()) + '\n') 2532 err.write('\t' + "IsReferenceType -> " + 2533 str(type.IsReferenceType()) + '\n') 2534 2535 def DebugPExpect(self, child): 2536 """Debug the spwaned pexpect object.""" 2537 if not traceAlways: 2538 return 2539 2540 print(child) 2541 2542 @classmethod 2543 def RemoveTempFile(cls, file): 2544 if os.path.exists(file): 2545 remove_file(file) 2546 2547# On Windows, the first attempt to delete a recently-touched file can fail 2548# because of a race with antimalware scanners. This function will detect a 2549# failure and retry. 2550 2551 2552def remove_file(file, num_retries=1, sleep_duration=0.5): 2553 for i in range(num_retries + 1): 2554 try: 2555 os.remove(file) 2556 return True 2557 except: 2558 time.sleep(sleep_duration) 2559 continue 2560 return False 2561