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