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