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