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