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, 'lldb_framework_path'): 829 framework_path = lldbtest_config.lldb_framework_path 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 import datetime 1173 print( 1174 "Session info generated @", 1175 datetime.datetime.now().ctime(), 1176 file=self.session) 1177 self.session.close() 1178 del self.session 1179 1180 # process the log files 1181 log_files_for_this_test = glob.glob(self.log_basename + "*") 1182 1183 if prefix != 'Success' or lldbtest_config.log_success: 1184 # keep all log files, rename them to include prefix 1185 dst_log_basename = self.getLogBasenameForCurrentTest(prefix) 1186 for src in log_files_for_this_test: 1187 if os.path.isfile(src): 1188 dst = src.replace(self.log_basename, dst_log_basename) 1189 if os.name == "nt" and os.path.isfile(dst): 1190 # On Windows, renaming a -> b will throw an exception if 1191 # b exists. On non-Windows platforms it silently 1192 # replaces the destination. Ultimately this means that 1193 # atomic renames are not guaranteed to be possible on 1194 # Windows, but we need this to work anyway, so just 1195 # remove the destination first if it already exists. 1196 remove_file(dst) 1197 1198 lldbutil.mkdir_p(os.path.dirname(dst)) 1199 os.rename(src, dst) 1200 else: 1201 # success! (and we don't want log files) delete log files 1202 for log_file in log_files_for_this_test: 1203 remove_file(log_file) 1204 1205 # ==================================================== 1206 # Config. methods supported through a plugin interface 1207 # (enables reading of the current test configuration) 1208 # ==================================================== 1209 1210 def isMIPS(self): 1211 """Returns true if the architecture is MIPS.""" 1212 arch = self.getArchitecture() 1213 if re.match("mips", arch): 1214 return True 1215 return False 1216 1217 def isPPC64le(self): 1218 """Returns true if the architecture is PPC64LE.""" 1219 arch = self.getArchitecture() 1220 if re.match("powerpc64le", arch): 1221 return True 1222 return False 1223 1224 def getArchitecture(self): 1225 """Returns the architecture in effect the test suite is running with.""" 1226 module = builder_module() 1227 arch = module.getArchitecture() 1228 if arch == 'amd64': 1229 arch = 'x86_64' 1230 return arch 1231 1232 def getLldbArchitecture(self): 1233 """Returns the architecture of the lldb binary.""" 1234 if not hasattr(self, 'lldbArchitecture'): 1235 1236 # spawn local process 1237 command = [ 1238 lldbtest_config.lldbExec, 1239 "-o", 1240 "file " + lldbtest_config.lldbExec, 1241 "-o", 1242 "quit" 1243 ] 1244 1245 output = check_output(command) 1246 str = output.decode("utf-8") 1247 1248 for line in str.splitlines(): 1249 m = re.search( 1250 "Current executable set to '.*' \\((.*)\\)\\.", line) 1251 if m: 1252 self.lldbArchitecture = m.group(1) 1253 break 1254 1255 return self.lldbArchitecture 1256 1257 def getCompiler(self): 1258 """Returns the compiler in effect the test suite is running with.""" 1259 module = builder_module() 1260 return module.getCompiler() 1261 1262 def getCompilerBinary(self): 1263 """Returns the compiler binary the test suite is running with.""" 1264 return self.getCompiler().split()[0] 1265 1266 def getCompilerVersion(self): 1267 """ Returns a string that represents the compiler version. 1268 Supports: llvm, clang. 1269 """ 1270 version = 'unknown' 1271 1272 compiler = self.getCompilerBinary() 1273 version_output = system([[compiler, "-v"]])[1] 1274 for line in version_output.split(os.linesep): 1275 m = re.search('version ([0-9\.]+)', line) 1276 if m: 1277 version = m.group(1) 1278 return version 1279 1280 def getDwarfVersion(self): 1281 """ Returns the dwarf version generated by clang or '0'. """ 1282 if configuration.dwarf_version: 1283 return str(configuration.dwarf_version) 1284 if 'clang' in self.getCompiler(): 1285 try: 1286 driver_output = check_output( 1287 [self.getCompiler()] + '-g -c -x c - -o - -###'.split(), 1288 stderr=STDOUT) 1289 driver_output = driver_output.decode("utf-8") 1290 for line in driver_output.split(os.linesep): 1291 m = re.search('dwarf-version=([0-9])', line) 1292 if m: 1293 return m.group(1) 1294 except: pass 1295 return '0' 1296 1297 def platformIsDarwin(self): 1298 """Returns true if the OS triple for the selected platform is any valid apple OS""" 1299 return lldbplatformutil.platformIsDarwin() 1300 1301 def hasDarwinFramework(self): 1302 return self.darwinWithFramework 1303 1304 def getPlatform(self): 1305 """Returns the target platform the test suite is running on.""" 1306 return lldbplatformutil.getPlatform() 1307 1308 def isIntelCompiler(self): 1309 """ Returns true if using an Intel (ICC) compiler, false otherwise. """ 1310 return any([x in self.getCompiler() for x in ["icc", "icpc", "icl"]]) 1311 1312 def expectedCompilerVersion(self, compiler_version): 1313 """Returns True iff compiler_version[1] matches the current compiler version. 1314 Use compiler_version[0] to specify the operator used to determine if a match has occurred. 1315 Any operator other than the following defaults to an equality test: 1316 '>', '>=', "=>", '<', '<=', '=<', '!=', "!" or 'not' 1317 """ 1318 if (compiler_version is None): 1319 return True 1320 operator = str(compiler_version[0]) 1321 version = compiler_version[1] 1322 1323 if (version is None): 1324 return True 1325 if (operator == '>'): 1326 return LooseVersion(self.getCompilerVersion()) > LooseVersion(version) 1327 if (operator == '>=' or operator == '=>'): 1328 return LooseVersion(self.getCompilerVersion()) >= LooseVersion(version) 1329 if (operator == '<'): 1330 return LooseVersion(self.getCompilerVersion()) < LooseVersion(version) 1331 if (operator == '<=' or operator == '=<'): 1332 return LooseVersion(self.getCompilerVersion()) <= LooseVersion(version) 1333 if (operator == '!=' or operator == '!' or operator == 'not'): 1334 return str(version) not in str(self.getCompilerVersion()) 1335 return str(version) in str(self.getCompilerVersion()) 1336 1337 def expectedCompiler(self, compilers): 1338 """Returns True iff any element of compilers is a sub-string of the current compiler.""" 1339 if (compilers is None): 1340 return True 1341 1342 for compiler in compilers: 1343 if compiler in self.getCompiler(): 1344 return True 1345 1346 return False 1347 1348 def expectedArch(self, archs): 1349 """Returns True iff any element of archs is a sub-string of the current architecture.""" 1350 if (archs is None): 1351 return True 1352 1353 for arch in archs: 1354 if arch in self.getArchitecture(): 1355 return True 1356 1357 return False 1358 1359 def getRunOptions(self): 1360 """Command line option for -A and -C to run this test again, called from 1361 self.dumpSessionInfo().""" 1362 arch = self.getArchitecture() 1363 comp = self.getCompiler() 1364 option_str = "" 1365 if arch: 1366 option_str = "-A " + arch 1367 if comp: 1368 option_str += " -C " + comp 1369 return option_str 1370 1371 def getDebugInfo(self): 1372 method = getattr(self, self.testMethodName) 1373 return getattr(method, "debug_info", None) 1374 1375 # ================================================== 1376 # Build methods supported through a plugin interface 1377 # ================================================== 1378 1379 def getstdlibFlag(self): 1380 """ Returns the proper -stdlib flag, or empty if not required.""" 1381 if self.platformIsDarwin() or self.getPlatform() == "freebsd" or self.getPlatform() == "openbsd": 1382 stdlibflag = "-stdlib=libc++" 1383 else: # this includes NetBSD 1384 stdlibflag = "" 1385 return stdlibflag 1386 1387 def getstdFlag(self): 1388 """ Returns the proper stdflag. """ 1389 if "gcc" in self.getCompiler() and "4.6" in self.getCompilerVersion(): 1390 stdflag = "-std=c++0x" 1391 else: 1392 stdflag = "-std=c++11" 1393 return stdflag 1394 1395 def buildDriver(self, sources, exe_name): 1396 """ Platform-specific way to build a program that links with LLDB (via the liblldb.so 1397 or LLDB.framework). 1398 """ 1399 stdflag = self.getstdFlag() 1400 stdlibflag = self.getstdlibFlag() 1401 1402 lib_dir = os.environ["LLDB_LIB_DIR"] 1403 if self.hasDarwinFramework(): 1404 d = {'CXX_SOURCES': sources, 1405 'EXE': exe_name, 1406 'CFLAGS_EXTRAS': "%s %s" % (stdflag, stdlibflag), 1407 'FRAMEWORK_INCLUDES': "-F%s" % self.framework_dir, 1408 'LD_EXTRAS': "%s -Wl,-rpath,%s" % (self.dsym, self.framework_dir), 1409 } 1410 elif sys.platform.startswith('win'): 1411 d = { 1412 'CXX_SOURCES': sources, 1413 'EXE': exe_name, 1414 'CFLAGS_EXTRAS': "%s %s -I%s" % (stdflag, 1415 stdlibflag, 1416 os.path.join( 1417 os.environ["LLDB_SRC"], 1418 "include")), 1419 'LD_EXTRAS': "-L%s -lliblldb" % os.environ["LLDB_IMPLIB_DIR"]} 1420 else: 1421 d = { 1422 'CXX_SOURCES': sources, 1423 'EXE': exe_name, 1424 'CFLAGS_EXTRAS': "%s %s -I%s" % (stdflag, 1425 stdlibflag, 1426 os.path.join( 1427 os.environ["LLDB_SRC"], 1428 "include")), 1429 'LD_EXTRAS': "-L%s/../lib -llldb -Wl,-rpath,%s/../lib" % (lib_dir, lib_dir)} 1430 if self.TraceOn(): 1431 print( 1432 "Building LLDB Driver (%s) from sources %s" % 1433 (exe_name, sources)) 1434 1435 self.buildDefault(dictionary=d) 1436 1437 def buildLibrary(self, sources, lib_name): 1438 """Platform specific way to build a default library. """ 1439 1440 stdflag = self.getstdFlag() 1441 1442 lib_dir = os.environ["LLDB_LIB_DIR"] 1443 if self.hasDarwinFramework(): 1444 d = {'DYLIB_CXX_SOURCES': sources, 1445 'DYLIB_NAME': lib_name, 1446 'CFLAGS_EXTRAS': "%s -stdlib=libc++" % stdflag, 1447 'FRAMEWORK_INCLUDES': "-F%s" % self.framework_dir, 1448 'LD_EXTRAS': "%s -Wl,-rpath,%s -dynamiclib" % (self.dsym, self.framework_dir), 1449 } 1450 elif self.getPlatform() == 'windows': 1451 d = { 1452 'DYLIB_CXX_SOURCES': sources, 1453 'DYLIB_NAME': lib_name, 1454 'CFLAGS_EXTRAS': "%s -I%s " % (stdflag, 1455 os.path.join( 1456 os.environ["LLDB_SRC"], 1457 "include")), 1458 'LD_EXTRAS': "-shared -l%s\liblldb.lib" % self.os.environ["LLDB_IMPLIB_DIR"]} 1459 else: 1460 d = { 1461 'DYLIB_CXX_SOURCES': sources, 1462 'DYLIB_NAME': lib_name, 1463 'CFLAGS_EXTRAS': "%s -I%s -fPIC" % (stdflag, 1464 os.path.join( 1465 os.environ["LLDB_SRC"], 1466 "include")), 1467 'LD_EXTRAS': "-shared -L%s/../lib -llldb -Wl,-rpath,%s/../lib" % (lib_dir, lib_dir)} 1468 if self.TraceOn(): 1469 print( 1470 "Building LLDB Library (%s) from sources %s" % 1471 (lib_name, sources)) 1472 1473 self.buildDefault(dictionary=d) 1474 1475 def buildProgram(self, sources, exe_name): 1476 """ Platform specific way to build an executable from C/C++ sources. """ 1477 d = {'CXX_SOURCES': sources, 1478 'EXE': exe_name} 1479 self.buildDefault(dictionary=d) 1480 1481 def buildDefault( 1482 self, 1483 architecture=None, 1484 compiler=None, 1485 dictionary=None): 1486 """Platform specific way to build the default binaries.""" 1487 testdir = self.mydir 1488 testname = self.getBuildDirBasename() 1489 if self.getDebugInfo(): 1490 raise Exception("buildDefault tests must set NO_DEBUG_INFO_TESTCASE") 1491 module = builder_module() 1492 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1493 if not module.buildDefault(self, architecture, compiler, 1494 dictionary, testdir, testname): 1495 raise Exception("Don't know how to build default binary") 1496 1497 def buildDsym( 1498 self, 1499 architecture=None, 1500 compiler=None, 1501 dictionary=None): 1502 """Platform specific way to build binaries with dsym info.""" 1503 testdir = self.mydir 1504 testname = self.getBuildDirBasename() 1505 if self.getDebugInfo() != "dsym": 1506 raise Exception("NO_DEBUG_INFO_TESTCASE must build with buildDefault") 1507 1508 module = builder_module() 1509 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1510 if not module.buildDsym(self, architecture, compiler, 1511 dictionary, testdir, testname): 1512 raise Exception("Don't know how to build binary with dsym") 1513 1514 def buildDwarf( 1515 self, 1516 architecture=None, 1517 compiler=None, 1518 dictionary=None): 1519 """Platform specific way to build binaries with dwarf maps.""" 1520 testdir = self.mydir 1521 testname = self.getBuildDirBasename() 1522 if self.getDebugInfo() != "dwarf": 1523 raise Exception("NO_DEBUG_INFO_TESTCASE must build with buildDefault") 1524 1525 module = builder_module() 1526 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1527 if not module.buildDwarf(self, architecture, compiler, 1528 dictionary, testdir, testname): 1529 raise Exception("Don't know how to build binary with dwarf") 1530 1531 def buildDwo( 1532 self, 1533 architecture=None, 1534 compiler=None, 1535 dictionary=None): 1536 """Platform specific way to build binaries with dwarf maps.""" 1537 testdir = self.mydir 1538 testname = self.getBuildDirBasename() 1539 if self.getDebugInfo() != "dwo": 1540 raise Exception("NO_DEBUG_INFO_TESTCASE must build with buildDefault") 1541 1542 module = builder_module() 1543 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1544 if not module.buildDwo(self, architecture, compiler, 1545 dictionary, testdir, testname): 1546 raise Exception("Don't know how to build binary with dwo") 1547 1548 def buildGModules( 1549 self, 1550 architecture=None, 1551 compiler=None, 1552 dictionary=None): 1553 """Platform specific way to build binaries with gmodules info.""" 1554 testdir = self.mydir 1555 testname = self.getBuildDirBasename() 1556 if self.getDebugInfo() != "gmodules": 1557 raise Exception("NO_DEBUG_INFO_TESTCASE must build with buildDefault") 1558 1559 module = builder_module() 1560 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1561 if not module.buildGModules(self, architecture, compiler, 1562 dictionary, testdir, testname): 1563 raise Exception("Don't know how to build binary with gmodules") 1564 1565 def signBinary(self, binary_path): 1566 if sys.platform.startswith("darwin"): 1567 codesign_cmd = "codesign --force --sign \"%s\" %s" % ( 1568 lldbtest_config.codesign_identity, binary_path) 1569 call(codesign_cmd, shell=True) 1570 1571 def findBuiltClang(self): 1572 """Tries to find and use Clang from the build directory as the compiler (instead of the system compiler).""" 1573 paths_to_try = [ 1574 "llvm-build/Release+Asserts/x86_64/bin/clang", 1575 "llvm-build/Debug+Asserts/x86_64/bin/clang", 1576 "llvm-build/Release/x86_64/bin/clang", 1577 "llvm-build/Debug/x86_64/bin/clang", 1578 ] 1579 lldb_root_path = os.path.join( 1580 os.path.dirname(__file__), "..", "..", "..", "..") 1581 for p in paths_to_try: 1582 path = os.path.join(lldb_root_path, p) 1583 if os.path.exists(path): 1584 return path 1585 1586 # Tries to find clang at the same folder as the lldb 1587 lldb_dir = os.path.dirname(lldbtest_config.lldbExec) 1588 path = distutils.spawn.find_executable("clang", lldb_dir) 1589 if path is not None: 1590 return path 1591 1592 return os.environ["CC"] 1593 1594 def findYaml2obj(self): 1595 """ 1596 Get the path to the yaml2obj executable, which can be used to create 1597 test object files from easy to write yaml instructions. 1598 1599 Throws an Exception if the executable cannot be found. 1600 """ 1601 # Tries to find yaml2obj at the same folder as clang 1602 clang_dir = os.path.dirname(self.findBuiltClang()) 1603 path = distutils.spawn.find_executable("yaml2obj", clang_dir) 1604 if path is not None: 1605 return path 1606 raise Exception("yaml2obj executable not found") 1607 1608 1609 def yaml2obj(self, yaml_path, obj_path): 1610 """ 1611 Create an object file at the given path from a yaml file. 1612 1613 Throws subprocess.CalledProcessError if the object could not be created. 1614 """ 1615 yaml2obj = self.findYaml2obj() 1616 command = [yaml2obj, "-o=%s" % obj_path, yaml_path] 1617 system([command]) 1618 1619 def getBuildFlags( 1620 self, 1621 use_cpp11=True, 1622 use_libcxx=False, 1623 use_libstdcxx=False): 1624 """ Returns a dictionary (which can be provided to build* functions above) which 1625 contains OS-specific build flags. 1626 """ 1627 cflags = "" 1628 ldflags = "" 1629 1630 # On Mac OS X, unless specifically requested to use libstdc++, use 1631 # libc++ 1632 if not use_libstdcxx and self.platformIsDarwin(): 1633 use_libcxx = True 1634 1635 if use_libcxx and self.libcxxPath: 1636 cflags += "-stdlib=libc++ " 1637 if self.libcxxPath: 1638 libcxxInclude = os.path.join(self.libcxxPath, "include") 1639 libcxxLib = os.path.join(self.libcxxPath, "lib") 1640 if os.path.isdir(libcxxInclude) and os.path.isdir(libcxxLib): 1641 cflags += "-nostdinc++ -I%s -L%s -Wl,-rpath,%s " % ( 1642 libcxxInclude, libcxxLib, libcxxLib) 1643 1644 if use_cpp11: 1645 cflags += "-std=" 1646 if "gcc" in self.getCompiler() and "4.6" in self.getCompilerVersion(): 1647 cflags += "c++0x" 1648 else: 1649 cflags += "c++11" 1650 if self.platformIsDarwin() or self.getPlatform() == "freebsd": 1651 cflags += " -stdlib=libc++" 1652 elif self.getPlatform() == "openbsd": 1653 cflags += " -stdlib=libc++" 1654 elif self.getPlatform() == "netbsd": 1655 # NetBSD defaults to libc++ 1656 pass 1657 elif "clang" in self.getCompiler(): 1658 cflags += " -stdlib=libstdc++" 1659 1660 return {'CFLAGS_EXTRAS': cflags, 1661 'LD_EXTRAS': ldflags, 1662 } 1663 1664 def cleanup(self, dictionary=None): 1665 """Platform specific way to do cleanup after build.""" 1666 module = builder_module() 1667 if not module.cleanup(self, dictionary): 1668 raise Exception( 1669 "Don't know how to do cleanup with dictionary: " + 1670 dictionary) 1671 1672 def getLLDBLibraryEnvVal(self): 1673 """ Returns the path that the OS-specific library search environment variable 1674 (self.dylibPath) should be set to in order for a program to find the LLDB 1675 library. If an environment variable named self.dylibPath is already set, 1676 the new path is appended to it and returned. 1677 """ 1678 existing_library_path = os.environ[ 1679 self.dylibPath] if self.dylibPath in os.environ else None 1680 lib_dir = os.environ["LLDB_LIB_DIR"] 1681 if existing_library_path: 1682 return "%s:%s" % (existing_library_path, lib_dir) 1683 elif sys.platform.startswith("darwin"): 1684 return os.path.join(lib_dir, 'LLDB.framework') 1685 else: 1686 return lib_dir 1687 1688 def getLibcPlusPlusLibs(self): 1689 if self.getPlatform() in ('freebsd', 'linux', 'netbsd', 'openbsd'): 1690 return ['libc++.so.1'] 1691 else: 1692 return ['libc++.1.dylib', 'libc++abi.'] 1693 1694# Metaclass for TestBase to change the list of test metods when a new TestCase is loaded. 1695# We change the test methods to create a new test method for each test for each debug info we are 1696# testing. The name of the new test method will be '<original-name>_<debug-info>' and with adding 1697# the new test method we remove the old method at the same time. This functionality can be 1698# supressed by at test case level setting the class attribute NO_DEBUG_INFO_TESTCASE or at test 1699# level by using the decorator @no_debug_info_test. 1700 1701 1702class LLDBTestCaseFactory(type): 1703 1704 def __new__(cls, name, bases, attrs): 1705 original_testcase = super( 1706 LLDBTestCaseFactory, cls).__new__( 1707 cls, name, bases, attrs) 1708 if original_testcase.NO_DEBUG_INFO_TESTCASE: 1709 return original_testcase 1710 1711 newattrs = {} 1712 for attrname, attrvalue in attrs.items(): 1713 if attrname.startswith("test") and not getattr( 1714 attrvalue, "__no_debug_info_test__", False): 1715 1716 # If any debug info categories were explicitly tagged, assume that list to be 1717 # authoritative. If none were specified, try with all debug 1718 # info formats. 1719 all_dbginfo_categories = set(test_categories.debug_info_categories) 1720 categories = set( 1721 getattr( 1722 attrvalue, 1723 "categories", 1724 [])) & all_dbginfo_categories 1725 if not categories: 1726 categories = all_dbginfo_categories 1727 1728 for cat in categories: 1729 @decorators.add_test_categories([cat]) 1730 @wraps(attrvalue) 1731 def test_method(self, attrvalue=attrvalue): 1732 return attrvalue(self) 1733 1734 method_name = attrname + "_" + cat 1735 test_method.__name__ = method_name 1736 test_method.debug_info = cat 1737 newattrs[method_name] = test_method 1738 1739 else: 1740 newattrs[attrname] = attrvalue 1741 return super( 1742 LLDBTestCaseFactory, 1743 cls).__new__( 1744 cls, 1745 name, 1746 bases, 1747 newattrs) 1748 1749# Setup the metaclass for this class to change the list of the test 1750# methods when a new class is loaded 1751 1752 1753@add_metaclass(LLDBTestCaseFactory) 1754class TestBase(Base): 1755 """ 1756 This abstract base class is meant to be subclassed. It provides default 1757 implementations for setUpClass(), tearDownClass(), setUp(), and tearDown(), 1758 among other things. 1759 1760 Important things for test class writers: 1761 1762 - Overwrite the mydir class attribute, otherwise your test class won't 1763 run. It specifies the relative directory to the top level 'test' so 1764 the test harness can change to the correct working directory before 1765 running your test. 1766 1767 - The setUp method sets up things to facilitate subsequent interactions 1768 with the debugger as part of the test. These include: 1769 - populate the test method name 1770 - create/get a debugger set with synchronous mode (self.dbg) 1771 - get the command interpreter from with the debugger (self.ci) 1772 - create a result object for use with the command interpreter 1773 (self.res) 1774 - plus other stuffs 1775 1776 - The tearDown method tries to perform some necessary cleanup on behalf 1777 of the test to return the debugger to a good state for the next test. 1778 These include: 1779 - execute any tearDown hooks registered by the test method with 1780 TestBase.addTearDownHook(); examples can be found in 1781 settings/TestSettings.py 1782 - kill the inferior process associated with each target, if any, 1783 and, then delete the target from the debugger's target list 1784 - perform build cleanup before running the next test method in the 1785 same test class; examples of registering for this service can be 1786 found in types/TestIntegerTypes.py with the call: 1787 - self.setTearDownCleanup(dictionary=d) 1788 1789 - Similarly setUpClass and tearDownClass perform classwise setup and 1790 teardown fixtures. The tearDownClass method invokes a default build 1791 cleanup for the entire test class; also, subclasses can implement the 1792 classmethod classCleanup(cls) to perform special class cleanup action. 1793 1794 - The instance methods runCmd and expect are used heavily by existing 1795 test cases to send a command to the command interpreter and to perform 1796 string/pattern matching on the output of such command execution. The 1797 expect method also provides a mode to peform string/pattern matching 1798 without running a command. 1799 1800 - The build methods buildDefault, buildDsym, and buildDwarf are used to 1801 build the binaries used during a particular test scenario. A plugin 1802 should be provided for the sys.platform running the test suite. The 1803 Mac OS X implementation is located in plugins/darwin.py. 1804 """ 1805 1806 # Subclasses can set this to true (if they don't depend on debug info) to avoid running the 1807 # test multiple times with various debug info types. 1808 NO_DEBUG_INFO_TESTCASE = False 1809 1810 # Maximum allowed attempts when launching the inferior process. 1811 # Can be overridden by the LLDB_MAX_LAUNCH_COUNT environment variable. 1812 maxLaunchCount = 1 1813 1814 # Time to wait before the next launching attempt in second(s). 1815 # Can be overridden by the LLDB_TIME_WAIT_NEXT_LAUNCH environment variable. 1816 timeWaitNextLaunch = 1.0 1817 1818 def generateSource(self, source): 1819 template = source + '.template' 1820 temp = os.path.join(self.getSourceDir(), template) 1821 with open(temp, 'r') as f: 1822 content = f.read() 1823 1824 public_api_dir = os.path.join( 1825 os.environ["LLDB_SRC"], "include", "lldb", "API") 1826 1827 # Look under the include/lldb/API directory and add #include statements 1828 # for all the SB API headers. 1829 public_headers = os.listdir(public_api_dir) 1830 # For different platforms, the include statement can vary. 1831 if self.hasDarwinFramework(): 1832 include_stmt = "'#include <%s>' % os.path.join('LLDB', header)" 1833 else: 1834 include_stmt = "'#include <%s>' % os.path.join('" + public_api_dir + "', header)" 1835 list = [eval(include_stmt) for header in public_headers if ( 1836 header.startswith("SB") and header.endswith(".h"))] 1837 includes = '\n'.join(list) 1838 new_content = content.replace('%include_SB_APIs%', includes) 1839 src = os.path.join(self.getBuildDir(), source) 1840 with open(src, 'w') as f: 1841 f.write(new_content) 1842 1843 self.addTearDownHook(lambda: os.remove(src)) 1844 1845 def setUp(self): 1846 #import traceback 1847 # traceback.print_stack() 1848 1849 # Works with the test driver to conditionally skip tests via 1850 # decorators. 1851 Base.setUp(self) 1852 1853 for s in self.setUpCommands(): 1854 self.runCmd(s) 1855 1856 if "LLDB_MAX_LAUNCH_COUNT" in os.environ: 1857 self.maxLaunchCount = int(os.environ["LLDB_MAX_LAUNCH_COUNT"]) 1858 1859 if "LLDB_TIME_WAIT_NEXT_LAUNCH" in os.environ: 1860 self.timeWaitNextLaunch = float( 1861 os.environ["LLDB_TIME_WAIT_NEXT_LAUNCH"]) 1862 1863 # We want our debugger to be synchronous. 1864 self.dbg.SetAsync(False) 1865 1866 # Retrieve the associated command interpreter instance. 1867 self.ci = self.dbg.GetCommandInterpreter() 1868 if not self.ci: 1869 raise Exception('Could not get the command interpreter') 1870 1871 # And the result object. 1872 self.res = lldb.SBCommandReturnObject() 1873 1874 def registerSharedLibrariesWithTarget(self, target, shlibs): 1875 '''If we are remotely running the test suite, register the shared libraries with the target so they get uploaded, otherwise do nothing 1876 1877 Any modules in the target that have their remote install file specification set will 1878 get uploaded to the remote host. This function registers the local copies of the 1879 shared libraries with the target and sets their remote install locations so they will 1880 be uploaded when the target is run. 1881 ''' 1882 if not shlibs or not self.platformContext: 1883 return None 1884 1885 shlib_environment_var = self.platformContext.shlib_environment_var 1886 shlib_prefix = self.platformContext.shlib_prefix 1887 shlib_extension = '.' + self.platformContext.shlib_extension 1888 1889 working_dir = self.get_process_working_directory() 1890 environment = ['%s=%s' % (shlib_environment_var, working_dir)] 1891 # Add any shared libraries to our target if remote so they get 1892 # uploaded into the working directory on the remote side 1893 for name in shlibs: 1894 # The path can be a full path to a shared library, or a make file name like "Foo" for 1895 # "libFoo.dylib" or "libFoo.so", or "Foo.so" for "Foo.so" or "libFoo.so", or just a 1896 # basename like "libFoo.so". So figure out which one it is and resolve the local copy 1897 # of the shared library accordingly 1898 if os.path.isfile(name): 1899 local_shlib_path = name # name is the full path to the local shared library 1900 else: 1901 # Check relative names 1902 local_shlib_path = os.path.join( 1903 self.getBuildDir(), shlib_prefix + name + shlib_extension) 1904 if not os.path.exists(local_shlib_path): 1905 local_shlib_path = os.path.join( 1906 self.getBuildDir(), name + shlib_extension) 1907 if not os.path.exists(local_shlib_path): 1908 local_shlib_path = os.path.join(self.getBuildDir(), name) 1909 1910 # Make sure we found the local shared library in the above code 1911 self.assertTrue(os.path.exists(local_shlib_path)) 1912 1913 # Add the shared library to our target 1914 shlib_module = target.AddModule(local_shlib_path, None, None, None) 1915 if lldb.remote_platform: 1916 # We must set the remote install location if we want the shared library 1917 # to get uploaded to the remote target 1918 remote_shlib_path = lldbutil.append_to_process_working_directory(self, 1919 os.path.basename(local_shlib_path)) 1920 shlib_module.SetRemoteInstallFileSpec( 1921 lldb.SBFileSpec(remote_shlib_path, False)) 1922 1923 return environment 1924 1925 def registerSanitizerLibrariesWithTarget(self, target): 1926 runtimes = [] 1927 for m in target.module_iter(): 1928 libspec = m.GetFileSpec() 1929 if "clang_rt" in libspec.GetFilename(): 1930 runtimes.append(os.path.join(libspec.GetDirectory(), 1931 libspec.GetFilename())) 1932 return self.registerSharedLibrariesWithTarget(target, runtimes) 1933 1934 # utility methods that tests can use to access the current objects 1935 def target(self): 1936 if not self.dbg: 1937 raise Exception('Invalid debugger instance') 1938 return self.dbg.GetSelectedTarget() 1939 1940 def process(self): 1941 if not self.dbg: 1942 raise Exception('Invalid debugger instance') 1943 return self.dbg.GetSelectedTarget().GetProcess() 1944 1945 def thread(self): 1946 if not self.dbg: 1947 raise Exception('Invalid debugger instance') 1948 return self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread() 1949 1950 def frame(self): 1951 if not self.dbg: 1952 raise Exception('Invalid debugger instance') 1953 return self.dbg.GetSelectedTarget().GetProcess( 1954 ).GetSelectedThread().GetSelectedFrame() 1955 1956 def get_process_working_directory(self): 1957 '''Get the working directory that should be used when launching processes for local or remote processes.''' 1958 if lldb.remote_platform: 1959 # Remote tests set the platform working directory up in 1960 # TestBase.setUp() 1961 return lldb.remote_platform.GetWorkingDirectory() 1962 else: 1963 # local tests change directory into each test subdirectory 1964 return self.getBuildDir() 1965 1966 def tearDown(self): 1967 #import traceback 1968 # traceback.print_stack() 1969 1970 # Ensure all the references to SB objects have gone away so that we can 1971 # be sure that all test-specific resources have been freed before we 1972 # attempt to delete the targets. 1973 gc.collect() 1974 1975 # Delete the target(s) from the debugger as a general cleanup step. 1976 # This includes terminating the process for each target, if any. 1977 # We'd like to reuse the debugger for our next test without incurring 1978 # the initialization overhead. 1979 targets = [] 1980 for target in self.dbg: 1981 if target: 1982 targets.append(target) 1983 process = target.GetProcess() 1984 if process: 1985 rc = self.invoke(process, "Kill") 1986 self.assertTrue(rc.Success(), PROCESS_KILLED) 1987 for target in targets: 1988 self.dbg.DeleteTarget(target) 1989 1990 # Do this last, to make sure it's in reverse order from how we setup. 1991 Base.tearDown(self) 1992 1993 # This must be the last statement, otherwise teardown hooks or other 1994 # lines might depend on this still being active. 1995 del self.dbg 1996 1997 def switch_to_thread_with_stop_reason(self, stop_reason): 1998 """ 1999 Run the 'thread list' command, and select the thread with stop reason as 2000 'stop_reason'. If no such thread exists, no select action is done. 2001 """ 2002 from .lldbutil import stop_reason_to_str 2003 self.runCmd('thread list') 2004 output = self.res.GetOutput() 2005 thread_line_pattern = re.compile( 2006 "^[ *] thread #([0-9]+):.*stop reason = %s" % 2007 stop_reason_to_str(stop_reason)) 2008 for line in output.splitlines(): 2009 matched = thread_line_pattern.match(line) 2010 if matched: 2011 self.runCmd('thread select %s' % matched.group(1)) 2012 2013 def runCmd(self, cmd, msg=None, check=True, trace=False, inHistory=False): 2014 """ 2015 Ask the command interpreter to handle the command and then check its 2016 return status. 2017 """ 2018 # Fail fast if 'cmd' is not meaningful. 2019 if not cmd or len(cmd) == 0: 2020 raise Exception("Bad 'cmd' parameter encountered") 2021 2022 trace = (True if traceAlways else trace) 2023 2024 if cmd.startswith("target create "): 2025 cmd = cmd.replace("target create ", "file ") 2026 2027 running = (cmd.startswith("run") or cmd.startswith("process launch")) 2028 2029 for i in range(self.maxLaunchCount if running else 1): 2030 self.ci.HandleCommand(cmd, self.res, inHistory) 2031 2032 with recording(self, trace) as sbuf: 2033 print("runCmd:", cmd, file=sbuf) 2034 if not check: 2035 print("check of return status not required", file=sbuf) 2036 if self.res.Succeeded(): 2037 print("output:", self.res.GetOutput(), file=sbuf) 2038 else: 2039 print("runCmd failed!", file=sbuf) 2040 print(self.res.GetError(), file=sbuf) 2041 2042 if self.res.Succeeded(): 2043 break 2044 elif running: 2045 # For process launch, wait some time before possible next try. 2046 time.sleep(self.timeWaitNextLaunch) 2047 with recording(self, trace) as sbuf: 2048 print("Command '" + cmd + "' failed!", file=sbuf) 2049 2050 if check: 2051 output = "" 2052 if self.res.GetOutput(): 2053 output += "\nCommand output:\n" + self.res.GetOutput() 2054 if self.res.GetError(): 2055 output += "\nError output:\n" + self.res.GetError() 2056 if msg: 2057 msg += output 2058 if cmd: 2059 cmd += output 2060 self.assertTrue(self.res.Succeeded(), 2061 msg if (msg) else CMD_MSG(cmd)) 2062 2063 def match( 2064 self, 2065 str, 2066 patterns, 2067 msg=None, 2068 trace=False, 2069 error=False, 2070 matching=True, 2071 exe=True): 2072 """run command in str, and match the result against regexp in patterns returning the match object for the first matching pattern 2073 2074 Otherwise, all the arguments have the same meanings as for the expect function""" 2075 2076 trace = (True if traceAlways else trace) 2077 2078 if exe: 2079 # First run the command. If we are expecting error, set check=False. 2080 # Pass the assert message along since it provides more semantic 2081 # info. 2082 self.runCmd( 2083 str, 2084 msg=msg, 2085 trace=( 2086 True if trace else False), 2087 check=not error) 2088 2089 # Then compare the output against expected strings. 2090 output = self.res.GetError() if error else self.res.GetOutput() 2091 2092 # If error is True, the API client expects the command to fail! 2093 if error: 2094 self.assertFalse(self.res.Succeeded(), 2095 "Command '" + str + "' is expected to fail!") 2096 else: 2097 # No execution required, just compare str against the golden input. 2098 output = str 2099 with recording(self, trace) as sbuf: 2100 print("looking at:", output, file=sbuf) 2101 2102 # The heading says either "Expecting" or "Not expecting". 2103 heading = "Expecting" if matching else "Not expecting" 2104 2105 for pattern in patterns: 2106 # Match Objects always have a boolean value of True. 2107 match_object = re.search(pattern, output) 2108 matched = bool(match_object) 2109 with recording(self, trace) as sbuf: 2110 print("%s pattern: %s" % (heading, pattern), file=sbuf) 2111 print("Matched" if matched else "Not matched", file=sbuf) 2112 if matched: 2113 break 2114 2115 self.assertTrue(matched if matching else not matched, 2116 msg if msg else EXP_MSG(str, output, exe)) 2117 2118 return match_object 2119 2120 def check_completion_with_desc(self, str_input, match_desc_pairs): 2121 interp = self.dbg.GetCommandInterpreter() 2122 match_strings = lldb.SBStringList() 2123 description_strings = lldb.SBStringList() 2124 num_matches = interp.HandleCompletionWithDescriptions(str_input, len(str_input), 0, -1, match_strings, description_strings) 2125 self.assertEqual(len(description_strings), len(match_strings)) 2126 2127 missing_pairs = [] 2128 for pair in match_desc_pairs: 2129 found_pair = False 2130 for i in range(num_matches + 1): 2131 match_candidate = match_strings.GetStringAtIndex(i) 2132 description_candidate = description_strings.GetStringAtIndex(i) 2133 if match_candidate == pair[0] and description_candidate == pair[1]: 2134 found_pair = True 2135 break 2136 if not found_pair: 2137 missing_pairs.append(pair) 2138 2139 if len(missing_pairs): 2140 error_msg = "Missing pairs:\n" 2141 for pair in missing_pairs: 2142 error_msg += " [" + pair[0] + ":" + pair[1] + "]\n" 2143 error_msg += "Got the following " + str(num_matches) + " completions back:\n" 2144 for i in range(num_matches + 1): 2145 match_candidate = match_strings.GetStringAtIndex(i) 2146 description_candidate = description_strings.GetStringAtIndex(i) 2147 error_msg += "[" + match_candidate + ":" + description_candidate + "]\n" 2148 self.assertEqual(0, len(missing_pairs), error_msg) 2149 2150 def complete_exactly(self, str_input, patterns): 2151 self.complete_from_to(str_input, patterns, True) 2152 2153 def complete_from_to(self, str_input, patterns, turn_off_re_match=False): 2154 """Test that the completion mechanism completes str_input to patterns, 2155 where patterns could be a pattern-string or a list of pattern-strings""" 2156 # Patterns should not be None in order to proceed. 2157 self.assertFalse(patterns is None) 2158 # And should be either a string or list of strings. Check for list type 2159 # below, if not, make a list out of the singleton string. If patterns 2160 # is not a string or not a list of strings, there'll be runtime errors 2161 # later on. 2162 if not isinstance(patterns, list): 2163 patterns = [patterns] 2164 2165 interp = self.dbg.GetCommandInterpreter() 2166 match_strings = lldb.SBStringList() 2167 num_matches = interp.HandleCompletion(str_input, len(str_input), 0, -1, match_strings) 2168 common_match = match_strings.GetStringAtIndex(0) 2169 if num_matches == 0: 2170 compare_string = str_input 2171 else: 2172 if common_match != None and len(common_match) > 0: 2173 compare_string = str_input + common_match 2174 else: 2175 compare_string = "" 2176 for idx in range(1, num_matches+1): 2177 compare_string += match_strings.GetStringAtIndex(idx) + "\n" 2178 2179 for p in patterns: 2180 if turn_off_re_match: 2181 self.expect( 2182 compare_string, msg=COMPLETION_MSG( 2183 str_input, p, match_strings), exe=False, substrs=[p]) 2184 else: 2185 self.expect( 2186 compare_string, msg=COMPLETION_MSG( 2187 str_input, p, match_strings), exe=False, patterns=[p]) 2188 2189 def completions_match(self, command, completions): 2190 """Checks that the completions for the given command are equal to the 2191 given list of completions""" 2192 interp = self.dbg.GetCommandInterpreter() 2193 match_strings = lldb.SBStringList() 2194 interp.HandleCompletion(command, len(command), 0, -1, match_strings) 2195 # match_strings is a 1-indexed list, so we have to slice... 2196 self.assertItemsEqual(completions, list(match_strings)[1:], 2197 "List of returned completion is wrong") 2198 2199 def filecheck( 2200 self, 2201 command, 2202 check_file, 2203 filecheck_options = '', 2204 expect_cmd_failure = False): 2205 # Run the command. 2206 self.runCmd( 2207 command, 2208 check=(not expect_cmd_failure), 2209 msg="FileCheck'ing result of `{0}`".format(command)) 2210 2211 self.assertTrue((not expect_cmd_failure) == self.res.Succeeded()) 2212 2213 # Get the error text if there was an error, and the regular text if not. 2214 output = self.res.GetOutput() if self.res.Succeeded() \ 2215 else self.res.GetError() 2216 2217 # Assemble the absolute path to the check file. As a convenience for 2218 # LLDB inline tests, assume that the check file is a relative path to 2219 # a file within the inline test directory. 2220 if check_file.endswith('.pyc'): 2221 check_file = check_file[:-1] 2222 check_file_abs = os.path.abspath(check_file) 2223 2224 # Run FileCheck. 2225 filecheck_bin = configuration.get_filecheck_path() 2226 if not filecheck_bin: 2227 self.assertTrue(False, "No valid FileCheck executable specified") 2228 filecheck_args = [filecheck_bin, check_file_abs] 2229 if filecheck_options: 2230 filecheck_args.append(filecheck_options) 2231 subproc = Popen(filecheck_args, stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines = True) 2232 cmd_stdout, cmd_stderr = subproc.communicate(input=output) 2233 cmd_status = subproc.returncode 2234 2235 filecheck_cmd = " ".join(filecheck_args) 2236 filecheck_trace = """ 2237--- FileCheck trace (code={0}) --- 2238{1} 2239 2240FileCheck input: 2241{2} 2242 2243FileCheck output: 2244{3} 2245{4} 2246""".format(cmd_status, filecheck_cmd, output, cmd_stdout, cmd_stderr) 2247 2248 trace = cmd_status != 0 or traceAlways 2249 with recording(self, trace) as sbuf: 2250 print(filecheck_trace, file=sbuf) 2251 2252 self.assertTrue(cmd_status == 0) 2253 2254 def expect( 2255 self, 2256 str, 2257 msg=None, 2258 patterns=None, 2259 startstr=None, 2260 endstr=None, 2261 substrs=None, 2262 trace=False, 2263 error=False, 2264 matching=True, 2265 exe=True, 2266 inHistory=False): 2267 """ 2268 Similar to runCmd; with additional expect style output matching ability. 2269 2270 Ask the command interpreter to handle the command and then check its 2271 return status. The 'msg' parameter specifies an informational assert 2272 message. We expect the output from running the command to start with 2273 'startstr', matches the substrings contained in 'substrs', and regexp 2274 matches the patterns contained in 'patterns'. 2275 2276 If the keyword argument error is set to True, it signifies that the API 2277 client is expecting the command to fail. In this case, the error stream 2278 from running the command is retrieved and compared against the golden 2279 input, instead. 2280 2281 If the keyword argument matching is set to False, it signifies that the API 2282 client is expecting the output of the command not to match the golden 2283 input. 2284 2285 Finally, the required argument 'str' represents the lldb command to be 2286 sent to the command interpreter. In case the keyword argument 'exe' is 2287 set to False, the 'str' is treated as a string to be matched/not-matched 2288 against the golden input. 2289 """ 2290 trace = (True if traceAlways else trace) 2291 2292 if exe: 2293 # First run the command. If we are expecting error, set check=False. 2294 # Pass the assert message along since it provides more semantic 2295 # info. 2296 self.runCmd( 2297 str, 2298 msg=msg, 2299 trace=( 2300 True if trace else False), 2301 check=not error, 2302 inHistory=inHistory) 2303 2304 # Then compare the output against expected strings. 2305 output = self.res.GetError() if error else self.res.GetOutput() 2306 2307 # If error is True, the API client expects the command to fail! 2308 if error: 2309 self.assertFalse(self.res.Succeeded(), 2310 "Command '" + str + "' is expected to fail!") 2311 else: 2312 # No execution required, just compare str against the golden input. 2313 if isinstance(str, lldb.SBCommandReturnObject): 2314 output = str.GetOutput() 2315 else: 2316 output = str 2317 with recording(self, trace) as sbuf: 2318 print("looking at:", output, file=sbuf) 2319 2320 # The heading says either "Expecting" or "Not expecting". 2321 heading = "Expecting" if matching else "Not expecting" 2322 2323 # Start from the startstr, if specified. 2324 # If there's no startstr, set the initial state appropriately. 2325 matched = output.startswith(startstr) if startstr else ( 2326 True if matching else False) 2327 2328 if startstr: 2329 with recording(self, trace) as sbuf: 2330 print("%s start string: %s" % (heading, startstr), file=sbuf) 2331 print("Matched" if matched else "Not matched", file=sbuf) 2332 2333 # Look for endstr, if specified. 2334 keepgoing = matched if matching else not matched 2335 if endstr: 2336 matched = output.endswith(endstr) 2337 with recording(self, trace) as sbuf: 2338 print("%s end string: %s" % (heading, endstr), file=sbuf) 2339 print("Matched" if matched else "Not matched", file=sbuf) 2340 2341 # Look for sub strings, if specified. 2342 keepgoing = matched if matching else not matched 2343 if substrs and keepgoing: 2344 for substr in substrs: 2345 matched = output.find(substr) != -1 2346 with recording(self, trace) as sbuf: 2347 print("%s sub string: %s" % (heading, substr), file=sbuf) 2348 print("Matched" if matched else "Not matched", file=sbuf) 2349 keepgoing = matched if matching else not matched 2350 if not keepgoing: 2351 break 2352 2353 # Search for regular expression patterns, if specified. 2354 keepgoing = matched if matching else not matched 2355 if patterns and keepgoing: 2356 for pattern in patterns: 2357 # Match Objects always have a boolean value of True. 2358 matched = bool(re.search(pattern, output)) 2359 with recording(self, trace) as sbuf: 2360 print("%s pattern: %s" % (heading, pattern), file=sbuf) 2361 print("Matched" if matched else "Not matched", file=sbuf) 2362 keepgoing = matched if matching else not matched 2363 if not keepgoing: 2364 break 2365 2366 self.assertTrue(matched if matching else not matched, 2367 msg if msg else EXP_MSG(str, output, exe)) 2368 2369 def expect_expr( 2370 self, 2371 expr, 2372 result_summary=None, 2373 result_value=None, 2374 result_type=None, 2375 error_msg=None, 2376 ): 2377 """ 2378 Evaluates the given expression and verifies the result. 2379 :param expr: The expression as a string. 2380 :param result_summary: The summary that the expression should have. None if the summary should not be checked. 2381 :param result_value: The value that the expression should have. None if the value should not be checked. 2382 :param result_type: The type that the expression result should have. None if the type should not be checked. 2383 :param error_msg: The error message the expression should return. None if the error output should not be checked. 2384 """ 2385 self.assertTrue(expr.strip() == expr, "Expression contains trailing/leading whitespace: '" + expr + "'") 2386 2387 frame = self.frame() 2388 eval_result = frame.EvaluateExpression(expr) 2389 2390 if error_msg: 2391 self.assertFalse(eval_result.IsValid()) 2392 self.assertEqual(error_msg, eval_result.GetError().GetCString()) 2393 return 2394 2395 if not eval_result.GetError().Success(): 2396 self.assertTrue(eval_result.GetError().Success(), 2397 "Unexpected failure with msg: " + eval_result.GetError().GetCString()) 2398 2399 if result_type: 2400 self.assertEqual(result_type, eval_result.GetTypeName()) 2401 2402 if result_value: 2403 self.assertEqual(result_value, eval_result.GetValue()) 2404 2405 if result_summary: 2406 self.assertEqual(result_summary, eval_result.GetSummary()) 2407 2408 def invoke(self, obj, name, trace=False): 2409 """Use reflection to call a method dynamically with no argument.""" 2410 trace = (True if traceAlways else trace) 2411 2412 method = getattr(obj, name) 2413 import inspect 2414 self.assertTrue(inspect.ismethod(method), 2415 name + "is a method name of object: " + str(obj)) 2416 result = method() 2417 with recording(self, trace) as sbuf: 2418 print(str(method) + ":", result, file=sbuf) 2419 return result 2420 2421 def build( 2422 self, 2423 architecture=None, 2424 compiler=None, 2425 dictionary=None): 2426 """Platform specific way to build the default binaries.""" 2427 module = builder_module() 2428 2429 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 2430 if self.getDebugInfo() is None: 2431 return self.buildDefault(architecture, compiler, dictionary) 2432 elif self.getDebugInfo() == "dsym": 2433 return self.buildDsym(architecture, compiler, dictionary) 2434 elif self.getDebugInfo() == "dwarf": 2435 return self.buildDwarf(architecture, compiler, dictionary) 2436 elif self.getDebugInfo() == "dwo": 2437 return self.buildDwo(architecture, compiler, dictionary) 2438 elif self.getDebugInfo() == "gmodules": 2439 return self.buildGModules(architecture, compiler, dictionary) 2440 else: 2441 self.fail("Can't build for debug info: %s" % self.getDebugInfo()) 2442 2443 def run_platform_command(self, cmd): 2444 platform = self.dbg.GetSelectedPlatform() 2445 shell_command = lldb.SBPlatformShellCommand(cmd) 2446 err = platform.Run(shell_command) 2447 return (err, shell_command.GetStatus(), shell_command.GetOutput()) 2448 2449 # ================================================= 2450 # Misc. helper methods for debugging test execution 2451 # ================================================= 2452 2453 def DebugSBValue(self, val): 2454 """Debug print a SBValue object, if traceAlways is True.""" 2455 from .lldbutil import value_type_to_str 2456 2457 if not traceAlways: 2458 return 2459 2460 err = sys.stderr 2461 err.write(val.GetName() + ":\n") 2462 err.write('\t' + "TypeName -> " + val.GetTypeName() + '\n') 2463 err.write('\t' + "ByteSize -> " + 2464 str(val.GetByteSize()) + '\n') 2465 err.write('\t' + "NumChildren -> " + 2466 str(val.GetNumChildren()) + '\n') 2467 err.write('\t' + "Value -> " + str(val.GetValue()) + '\n') 2468 err.write('\t' + "ValueAsUnsigned -> " + 2469 str(val.GetValueAsUnsigned()) + '\n') 2470 err.write( 2471 '\t' + 2472 "ValueType -> " + 2473 value_type_to_str( 2474 val.GetValueType()) + 2475 '\n') 2476 err.write('\t' + "Summary -> " + str(val.GetSummary()) + '\n') 2477 err.write('\t' + "IsPointerType -> " + 2478 str(val.TypeIsPointerType()) + '\n') 2479 err.write('\t' + "Location -> " + val.GetLocation() + '\n') 2480 2481 def DebugSBType(self, type): 2482 """Debug print a SBType object, if traceAlways is True.""" 2483 if not traceAlways: 2484 return 2485 2486 err = sys.stderr 2487 err.write(type.GetName() + ":\n") 2488 err.write('\t' + "ByteSize -> " + 2489 str(type.GetByteSize()) + '\n') 2490 err.write('\t' + "IsPointerType -> " + 2491 str(type.IsPointerType()) + '\n') 2492 err.write('\t' + "IsReferenceType -> " + 2493 str(type.IsReferenceType()) + '\n') 2494 2495 def DebugPExpect(self, child): 2496 """Debug the spwaned pexpect object.""" 2497 if not traceAlways: 2498 return 2499 2500 print(child) 2501 2502 @classmethod 2503 def RemoveTempFile(cls, file): 2504 if os.path.exists(file): 2505 remove_file(file) 2506 2507# On Windows, the first attempt to delete a recently-touched file can fail 2508# because of a race with antimalware scanners. This function will detect a 2509# failure and retry. 2510 2511 2512def remove_file(file, num_retries=1, sleep_duration=0.5): 2513 for i in range(num_retries + 1): 2514 try: 2515 os.remove(file) 2516 return True 2517 except: 2518 time.sleep(sleep_duration) 2519 continue 2520 return False 2521