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