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