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