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 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 # Disable Spotlight lookup. The testsuite creates 691 # different binaries with the same UUID, because they only 692 # differ in the debug info, which is not being hashed. 693 "settings set symbols.enable-external-lookup false", 694 695 # Disable fix-its by default so that incorrect expressions in tests don't 696 # pass just because Clang thinks it has a fix-it. 697 "settings set target.auto-apply-fixits false", 698 699 # Testsuite runs in parallel and the host can have also other load. 700 "settings set plugin.process.gdb-remote.packet-timeout 60", 701 702 'settings set symbols.clang-modules-cache-path "{}"'.format( 703 configuration.lldb_module_cache_dir), 704 "settings set use-color false", 705 ] 706 707 # Set any user-overridden settings. 708 for setting, value in configuration.settings: 709 commands.append('setting set %s %s'%(setting, value)) 710 711 # Make sure that a sanitizer LLDB's environment doesn't get passed on. 712 if cls.platformContext and cls.platformContext.shlib_environment_var in os.environ: 713 commands.append('settings set target.env-vars {}='.format( 714 cls.platformContext.shlib_environment_var)) 715 716 # Set environment variables for the inferior. 717 if lldbtest_config.inferior_env: 718 commands.append('settings set target.env-vars {}'.format( 719 lldbtest_config.inferior_env)) 720 return commands 721 722 def setUp(self): 723 """Fixture for unittest test case setup. 724 725 It works with the test driver to conditionally skip tests and does other 726 initializations.""" 727 #import traceback 728 # traceback.print_stack() 729 730 if "LIBCXX_PATH" in os.environ: 731 self.libcxxPath = os.environ["LIBCXX_PATH"] 732 else: 733 self.libcxxPath = None 734 735 if "LLDBVSCODE_EXEC" in os.environ: 736 self.lldbVSCodeExec = os.environ["LLDBVSCODE_EXEC"] 737 else: 738 self.lldbVSCodeExec = None 739 740 self.lldbOption = " ".join( 741 "-o '" + s + "'" for s in self.setUpCommands()) 742 743 # If we spawn an lldb process for test (via pexpect), do not load the 744 # init file unless told otherwise. 745 if os.environ.get("NO_LLDBINIT") != "NO": 746 self.lldbOption += " --no-lldbinit" 747 748 # Assign the test method name to self.testMethodName. 749 # 750 # For an example of the use of this attribute, look at test/types dir. 751 # There are a bunch of test cases under test/types and we don't want the 752 # module cacheing subsystem to be confused with executable name "a.out" 753 # used for all the test cases. 754 self.testMethodName = self._testMethodName 755 756 # This is for the case of directly spawning 'lldb'/'gdb' and interacting 757 # with it using pexpect. 758 self.child = None 759 self.child_prompt = "(lldb) " 760 # If the child is interacting with the embedded script interpreter, 761 # there are two exits required during tear down, first to quit the 762 # embedded script interpreter and second to quit the lldb command 763 # interpreter. 764 self.child_in_script_interpreter = False 765 766 # These are for customized teardown cleanup. 767 self.dict = None 768 self.doTearDownCleanup = False 769 # And in rare cases where there are multiple teardown cleanups. 770 self.dicts = [] 771 self.doTearDownCleanups = False 772 773 # List of spawned subproces.Popen objects 774 self.subprocesses = [] 775 776 # List of forked process PIDs 777 self.forkedProcessPids = [] 778 779 # Create a string buffer to record the session info, to be dumped into a 780 # test case specific file if test failure is encountered. 781 self.log_basename = self.getLogBasenameForCurrentTest() 782 783 session_file = "{}.log".format(self.log_basename) 784 # Python 3 doesn't support unbuffered I/O in text mode. Open buffered. 785 self.session = encoded_file.open(session_file, "utf-8", mode="w") 786 787 # Optimistically set __errored__, __failed__, __expected__ to False 788 # initially. If the test errored/failed, the session info 789 # (self.session) is then dumped into a session specific file for 790 # diagnosis. 791 self.__cleanup_errored__ = False 792 self.__errored__ = False 793 self.__failed__ = False 794 self.__expected__ = False 795 # We are also interested in unexpected success. 796 self.__unexpected__ = False 797 # And skipped tests. 798 self.__skipped__ = False 799 800 # See addTearDownHook(self, hook) which allows the client to add a hook 801 # function to be run during tearDown() time. 802 self.hooks = [] 803 804 # See HideStdout(self). 805 self.sys_stdout_hidden = False 806 807 if self.platformContext: 808 # set environment variable names for finding shared libraries 809 self.dylibPath = self.platformContext.shlib_environment_var 810 811 # Create the debugger instance. 812 self.dbg = lldb.SBDebugger.Create() 813 # Copy selected platform from a global instance if it exists. 814 if lldb.selected_platform is not None: 815 self.dbg.SetSelectedPlatform(lldb.selected_platform) 816 817 if not self.dbg: 818 raise Exception('Invalid debugger instance') 819 820 # Retrieve the associated command interpreter instance. 821 self.ci = self.dbg.GetCommandInterpreter() 822 if not self.ci: 823 raise Exception('Could not get the command interpreter') 824 825 # And the result object. 826 self.res = lldb.SBCommandReturnObject() 827 828 self.setPlatformWorkingDir() 829 self.enableLogChannelsForCurrentTest() 830 831 lib_dir = os.environ["LLDB_LIB_DIR"] 832 self.dsym = None 833 self.framework_dir = None 834 self.darwinWithFramework = self.platformIsDarwin() 835 if sys.platform.startswith("darwin"): 836 # Handle the framework environment variable if it is set 837 if hasattr(lldbtest_config, 'lldb_framework_path'): 838 framework_path = lldbtest_config.lldb_framework_path 839 # Framework dir should be the directory containing the framework 840 self.framework_dir = framework_path[:framework_path.rfind('LLDB.framework')] 841 # If a framework dir was not specified assume the Xcode build 842 # directory layout where the framework is in LLDB_LIB_DIR. 843 else: 844 self.framework_dir = lib_dir 845 self.dsym = os.path.join(self.framework_dir, 'LLDB.framework', 'LLDB') 846 # If the framework binary doesn't exist, assume we didn't actually 847 # build a framework, and fallback to standard *nix behavior by 848 # setting framework_dir and dsym to None. 849 if not os.path.exists(self.dsym): 850 self.framework_dir = None 851 self.dsym = None 852 self.darwinWithFramework = False 853 self.makeBuildDir() 854 855 def setAsync(self, value): 856 """ Sets async mode to True/False and ensures it is reset after the testcase completes.""" 857 old_async = self.dbg.GetAsync() 858 self.dbg.SetAsync(value) 859 self.addTearDownHook(lambda: self.dbg.SetAsync(old_async)) 860 861 def cleanupSubprocesses(self): 862 # Ensure any subprocesses are cleaned up 863 for p in self.subprocesses: 864 p.terminate() 865 del p 866 del self.subprocesses[:] 867 # Ensure any forked processes are cleaned up 868 for pid in self.forkedProcessPids: 869 if os.path.exists("/proc/" + str(pid)): 870 os.kill(pid, signal.SIGTERM) 871 872 def spawnSubprocess(self, executable, args=[], install_remote=True): 873 """ Creates a subprocess.Popen object with the specified executable and arguments, 874 saves it in self.subprocesses, and returns the object. 875 NOTE: if using this function, ensure you also call: 876 877 self.addTearDownHook(self.cleanupSubprocesses) 878 879 otherwise the test suite will leak processes. 880 """ 881 proc = _RemoteProcess( 882 install_remote) if lldb.remote_platform else _LocalProcess(self.TraceOn()) 883 proc.launch(executable, args) 884 self.subprocesses.append(proc) 885 return proc 886 887 def forkSubprocess(self, executable, args=[]): 888 """ Fork a subprocess with its own group ID. 889 NOTE: if using this function, ensure you also call: 890 891 self.addTearDownHook(self.cleanupSubprocesses) 892 893 otherwise the test suite will leak processes. 894 """ 895 child_pid = os.fork() 896 if child_pid == 0: 897 # If more I/O support is required, this can be beefed up. 898 fd = os.open(os.devnull, os.O_RDWR) 899 os.dup2(fd, 1) 900 os.dup2(fd, 2) 901 # This call causes the child to have its of group ID 902 os.setpgid(0, 0) 903 os.execvp(executable, [executable] + args) 904 # Give the child time to get through the execvp() call 905 time.sleep(0.1) 906 self.forkedProcessPids.append(child_pid) 907 return child_pid 908 909 def HideStdout(self): 910 """Hide output to stdout from the user. 911 912 During test execution, there might be cases where we don't want to show the 913 standard output to the user. For example, 914 915 self.runCmd(r'''sc print("\n\n\tHello!\n")''') 916 917 tests whether command abbreviation for 'script' works or not. There is no 918 need to show the 'Hello' output to the user as long as the 'script' command 919 succeeds and we are not in TraceOn() mode (see the '-t' option). 920 921 In this case, the test method calls self.HideStdout(self) to redirect the 922 sys.stdout to a null device, and restores the sys.stdout upon teardown. 923 924 Note that you should only call this method at most once during a test case 925 execution. Any subsequent call has no effect at all.""" 926 if self.sys_stdout_hidden: 927 return 928 929 self.sys_stdout_hidden = True 930 old_stdout = sys.stdout 931 sys.stdout = open(os.devnull, 'w') 932 933 def restore_stdout(): 934 sys.stdout = old_stdout 935 self.addTearDownHook(restore_stdout) 936 937 # ======================================================================= 938 # Methods for customized teardown cleanups as well as execution of hooks. 939 # ======================================================================= 940 941 def setTearDownCleanup(self, dictionary=None): 942 """Register a cleanup action at tearDown() time with a dictinary""" 943 self.dict = dictionary 944 self.doTearDownCleanup = True 945 946 def addTearDownCleanup(self, dictionary): 947 """Add a cleanup action at tearDown() time with a dictinary""" 948 self.dicts.append(dictionary) 949 self.doTearDownCleanups = True 950 951 def addTearDownHook(self, hook): 952 """ 953 Add a function to be run during tearDown() time. 954 955 Hooks are executed in a first come first serve manner. 956 """ 957 if six.callable(hook): 958 with recording(self, traceAlways) as sbuf: 959 print( 960 "Adding tearDown hook:", 961 getsource_if_available(hook), 962 file=sbuf) 963 self.hooks.append(hook) 964 965 return self 966 967 def deletePexpectChild(self): 968 # This is for the case of directly spawning 'lldb' and interacting with it 969 # using pexpect. 970 if self.child and self.child.isalive(): 971 import pexpect 972 with recording(self, traceAlways) as sbuf: 973 print("tearing down the child process....", file=sbuf) 974 try: 975 if self.child_in_script_interpreter: 976 self.child.sendline('quit()') 977 self.child.expect_exact(self.child_prompt) 978 self.child.sendline( 979 'settings set interpreter.prompt-on-quit false') 980 self.child.sendline('quit') 981 self.child.expect(pexpect.EOF) 982 except (ValueError, pexpect.ExceptionPexpect): 983 # child is already terminated 984 pass 985 except OSError as exception: 986 import errno 987 if exception.errno != errno.EIO: 988 # unexpected error 989 raise 990 # child is already terminated 991 finally: 992 # Give it one final blow to make sure the child is terminated. 993 self.child.close() 994 995 def tearDown(self): 996 """Fixture for unittest test case teardown.""" 997 #import traceback 998 # traceback.print_stack() 999 1000 self.deletePexpectChild() 1001 1002 # Check and run any hook functions. 1003 for hook in reversed(self.hooks): 1004 with recording(self, traceAlways) as sbuf: 1005 print( 1006 "Executing tearDown hook:", 1007 getsource_if_available(hook), 1008 file=sbuf) 1009 if funcutils.requires_self(hook): 1010 hook(self) 1011 else: 1012 hook() # try the plain call and hope it works 1013 1014 del self.hooks 1015 1016 # Perform registered teardown cleanup. 1017 if doCleanup and self.doTearDownCleanup: 1018 self.cleanup(dictionary=self.dict) 1019 1020 # In rare cases where there are multiple teardown cleanups added. 1021 if doCleanup and self.doTearDownCleanups: 1022 if self.dicts: 1023 for dict in reversed(self.dicts): 1024 self.cleanup(dictionary=dict) 1025 1026 # This must be the last statement, otherwise teardown hooks or other 1027 # lines might depend on this still being active. 1028 lldb.SBDebugger.Destroy(self.dbg) 1029 del self.dbg 1030 1031 # ========================================================= 1032 # Various callbacks to allow introspection of test progress 1033 # ========================================================= 1034 1035 def markError(self): 1036 """Callback invoked when an error (unexpected exception) errored.""" 1037 self.__errored__ = True 1038 with recording(self, False) as sbuf: 1039 # False because there's no need to write "ERROR" to the stderr twice. 1040 # Once by the Python unittest framework, and a second time by us. 1041 print("ERROR", file=sbuf) 1042 1043 def markCleanupError(self): 1044 """Callback invoked when an error occurs while a test is cleaning up.""" 1045 self.__cleanup_errored__ = True 1046 with recording(self, False) as sbuf: 1047 # False because there's no need to write "CLEANUP_ERROR" to the stderr twice. 1048 # Once by the Python unittest framework, and a second time by us. 1049 print("CLEANUP_ERROR", file=sbuf) 1050 1051 def markFailure(self): 1052 """Callback invoked when a failure (test assertion failure) occurred.""" 1053 self.__failed__ = True 1054 with recording(self, False) as sbuf: 1055 # False because there's no need to write "FAIL" to the stderr twice. 1056 # Once by the Python unittest framework, and a second time by us. 1057 print("FAIL", file=sbuf) 1058 1059 def markExpectedFailure(self, err, bugnumber): 1060 """Callback invoked when an expected failure/error occurred.""" 1061 self.__expected__ = True 1062 with recording(self, False) as sbuf: 1063 # False because there's no need to write "expected failure" to the 1064 # stderr twice. 1065 # Once by the Python unittest framework, and a second time by us. 1066 if bugnumber is None: 1067 print("expected failure", file=sbuf) 1068 else: 1069 print( 1070 "expected failure (problem id:" + str(bugnumber) + ")", 1071 file=sbuf) 1072 1073 def markSkippedTest(self): 1074 """Callback invoked when a test is skipped.""" 1075 self.__skipped__ = True 1076 with recording(self, False) as sbuf: 1077 # False because there's no need to write "skipped test" to the 1078 # stderr twice. 1079 # Once by the Python unittest framework, and a second time by us. 1080 print("skipped test", file=sbuf) 1081 1082 def markUnexpectedSuccess(self, bugnumber): 1083 """Callback invoked when an unexpected success occurred.""" 1084 self.__unexpected__ = True 1085 with recording(self, False) as sbuf: 1086 # False because there's no need to write "unexpected success" to the 1087 # stderr twice. 1088 # Once by the Python unittest framework, and a second time by us. 1089 if bugnumber is None: 1090 print("unexpected success", file=sbuf) 1091 else: 1092 print( 1093 "unexpected success (problem id:" + str(bugnumber) + ")", 1094 file=sbuf) 1095 1096 def getRerunArgs(self): 1097 return " -f %s.%s" % (self.__class__.__name__, self._testMethodName) 1098 1099 def getLogBasenameForCurrentTest(self, prefix=None): 1100 """ 1101 returns a partial path that can be used as the beginning of the name of multiple 1102 log files pertaining to this test 1103 1104 <session-dir>/<arch>-<compiler>-<test-file>.<test-class>.<test-method> 1105 """ 1106 dname = os.path.join(os.environ["LLDB_TEST_SRC"], 1107 os.environ["LLDB_SESSION_DIRNAME"]) 1108 if not os.path.isdir(dname): 1109 os.mkdir(dname) 1110 1111 components = [] 1112 if prefix is not None: 1113 components.append(prefix) 1114 for c in configuration.session_file_format: 1115 if c == 'f': 1116 components.append(self.__class__.__module__) 1117 elif c == 'n': 1118 components.append(self.__class__.__name__) 1119 elif c == 'c': 1120 compiler = self.getCompiler() 1121 1122 if compiler[1] == ':': 1123 compiler = compiler[2:] 1124 if os.path.altsep is not None: 1125 compiler = compiler.replace(os.path.altsep, os.path.sep) 1126 path_components = [x for x in compiler.split(os.path.sep) if x != ""] 1127 1128 # Add at most 4 path components to avoid generating very long 1129 # filenames 1130 components.extend(path_components[-4:]) 1131 elif c == 'a': 1132 components.append(self.getArchitecture()) 1133 elif c == 'm': 1134 components.append(self.testMethodName) 1135 fname = "-".join(components) 1136 1137 return os.path.join(dname, fname) 1138 1139 def dumpSessionInfo(self): 1140 """ 1141 Dump the debugger interactions leading to a test error/failure. This 1142 allows for more convenient postmortem analysis. 1143 1144 See also LLDBTestResult (dotest.py) which is a singlton class derived 1145 from TextTestResult and overwrites addError, addFailure, and 1146 addExpectedFailure methods to allow us to to mark the test instance as 1147 such. 1148 """ 1149 1150 # We are here because self.tearDown() detected that this test instance 1151 # either errored or failed. The lldb.test_result singleton contains 1152 # two lists (erros and failures) which get populated by the unittest 1153 # framework. Look over there for stack trace information. 1154 # 1155 # The lists contain 2-tuples of TestCase instances and strings holding 1156 # formatted tracebacks. 1157 # 1158 # See http://docs.python.org/library/unittest.html#unittest.TestResult. 1159 1160 # output tracebacks into session 1161 pairs = [] 1162 if self.__errored__: 1163 pairs = configuration.test_result.errors 1164 prefix = 'Error' 1165 elif self.__cleanup_errored__: 1166 pairs = configuration.test_result.cleanup_errors 1167 prefix = 'CleanupError' 1168 elif self.__failed__: 1169 pairs = configuration.test_result.failures 1170 prefix = 'Failure' 1171 elif self.__expected__: 1172 pairs = configuration.test_result.expectedFailures 1173 prefix = 'ExpectedFailure' 1174 elif self.__skipped__: 1175 prefix = 'SkippedTest' 1176 elif self.__unexpected__: 1177 prefix = 'UnexpectedSuccess' 1178 else: 1179 prefix = 'Success' 1180 1181 if not self.__unexpected__ and not self.__skipped__: 1182 for test, traceback in pairs: 1183 if test is self: 1184 print(traceback, file=self.session) 1185 1186 import datetime 1187 print( 1188 "Session info generated @", 1189 datetime.datetime.now().ctime(), 1190 file=self.session) 1191 self.session.close() 1192 del self.session 1193 1194 # process the log files 1195 log_files_for_this_test = glob.glob(self.log_basename + "*") 1196 1197 if prefix != 'Success' or lldbtest_config.log_success: 1198 # keep all log files, rename them to include prefix 1199 dst_log_basename = self.getLogBasenameForCurrentTest(prefix) 1200 for src in log_files_for_this_test: 1201 if os.path.isfile(src): 1202 dst = src.replace(self.log_basename, dst_log_basename) 1203 if os.name == "nt" and os.path.isfile(dst): 1204 # On Windows, renaming a -> b will throw an exception if 1205 # b exists. On non-Windows platforms it silently 1206 # replaces the destination. Ultimately this means that 1207 # atomic renames are not guaranteed to be possible on 1208 # Windows, but we need this to work anyway, so just 1209 # remove the destination first if it already exists. 1210 remove_file(dst) 1211 1212 lldbutil.mkdir_p(os.path.dirname(dst)) 1213 os.rename(src, dst) 1214 else: 1215 # success! (and we don't want log files) delete log files 1216 for log_file in log_files_for_this_test: 1217 remove_file(log_file) 1218 1219 # ==================================================== 1220 # Config. methods supported through a plugin interface 1221 # (enables reading of the current test configuration) 1222 # ==================================================== 1223 1224 def isMIPS(self): 1225 """Returns true if the architecture is MIPS.""" 1226 arch = self.getArchitecture() 1227 if re.match("mips", arch): 1228 return True 1229 return False 1230 1231 def isPPC64le(self): 1232 """Returns true if the architecture is PPC64LE.""" 1233 arch = self.getArchitecture() 1234 if re.match("powerpc64le", arch): 1235 return True 1236 return False 1237 1238 def getArchitecture(self): 1239 """Returns the architecture in effect the test suite is running with.""" 1240 module = builder_module() 1241 arch = module.getArchitecture() 1242 if arch == 'amd64': 1243 arch = 'x86_64' 1244 if arch in ['armv7l', 'armv8l'] : 1245 arch = 'arm' 1246 return arch 1247 1248 def getLldbArchitecture(self): 1249 """Returns the architecture of the lldb binary.""" 1250 if not hasattr(self, 'lldbArchitecture'): 1251 1252 # spawn local process 1253 command = [ 1254 lldbtest_config.lldbExec, 1255 "-o", 1256 "file " + lldbtest_config.lldbExec, 1257 "-o", 1258 "quit" 1259 ] 1260 1261 output = check_output(command) 1262 str = output.decode("utf-8") 1263 1264 for line in str.splitlines(): 1265 m = re.search( 1266 "Current executable set to '.*' \\((.*)\\)\\.", line) 1267 if m: 1268 self.lldbArchitecture = m.group(1) 1269 break 1270 1271 return self.lldbArchitecture 1272 1273 def getCompiler(self): 1274 """Returns the compiler in effect the test suite is running with.""" 1275 module = builder_module() 1276 return module.getCompiler() 1277 1278 def getCompilerBinary(self): 1279 """Returns the compiler binary the test suite is running with.""" 1280 return self.getCompiler().split()[0] 1281 1282 def getCompilerVersion(self): 1283 """ Returns a string that represents the compiler version. 1284 Supports: llvm, clang. 1285 """ 1286 version = 'unknown' 1287 1288 compiler = self.getCompilerBinary() 1289 version_output = system([[compiler, "-v"]])[1] 1290 for line in version_output.split(os.linesep): 1291 m = re.search('version ([0-9\.]+)', line) 1292 if m: 1293 version = m.group(1) 1294 return version 1295 1296 def getDwarfVersion(self): 1297 """ Returns the dwarf version generated by clang or '0'. """ 1298 if configuration.dwarf_version: 1299 return str(configuration.dwarf_version) 1300 if 'clang' in self.getCompiler(): 1301 try: 1302 driver_output = check_output( 1303 [self.getCompiler()] + '-g -c -x c - -o - -###'.split(), 1304 stderr=STDOUT) 1305 driver_output = driver_output.decode("utf-8") 1306 for line in driver_output.split(os.linesep): 1307 m = re.search('dwarf-version=([0-9])', line) 1308 if m: 1309 return m.group(1) 1310 except: pass 1311 return '0' 1312 1313 def platformIsDarwin(self): 1314 """Returns true if the OS triple for the selected platform is any valid apple OS""" 1315 return lldbplatformutil.platformIsDarwin() 1316 1317 def hasDarwinFramework(self): 1318 return self.darwinWithFramework 1319 1320 def getPlatform(self): 1321 """Returns the target platform the test suite is running on.""" 1322 return lldbplatformutil.getPlatform() 1323 1324 def isIntelCompiler(self): 1325 """ Returns true if using an Intel (ICC) compiler, false otherwise. """ 1326 return any([x in self.getCompiler() for x in ["icc", "icpc", "icl"]]) 1327 1328 def expectedCompilerVersion(self, compiler_version): 1329 """Returns True iff compiler_version[1] matches the current compiler version. 1330 Use compiler_version[0] to specify the operator used to determine if a match has occurred. 1331 Any operator other than the following defaults to an equality test: 1332 '>', '>=', "=>", '<', '<=', '=<', '!=', "!" or 'not' 1333 """ 1334 if (compiler_version is None): 1335 return True 1336 operator = str(compiler_version[0]) 1337 version = compiler_version[1] 1338 1339 if (version is None): 1340 return True 1341 if (operator == '>'): 1342 return LooseVersion(self.getCompilerVersion()) > LooseVersion(version) 1343 if (operator == '>=' or operator == '=>'): 1344 return LooseVersion(self.getCompilerVersion()) >= LooseVersion(version) 1345 if (operator == '<'): 1346 return LooseVersion(self.getCompilerVersion()) < LooseVersion(version) 1347 if (operator == '<=' or operator == '=<'): 1348 return LooseVersion(self.getCompilerVersion()) <= LooseVersion(version) 1349 if (operator == '!=' or operator == '!' or operator == 'not'): 1350 return str(version) not in str(self.getCompilerVersion()) 1351 return str(version) in str(self.getCompilerVersion()) 1352 1353 def expectedCompiler(self, compilers): 1354 """Returns True iff any element of compilers is a sub-string of the current compiler.""" 1355 if (compilers is None): 1356 return True 1357 1358 for compiler in compilers: 1359 if compiler in self.getCompiler(): 1360 return True 1361 1362 return False 1363 1364 def expectedArch(self, archs): 1365 """Returns True iff any element of archs is a sub-string of the current architecture.""" 1366 if (archs is None): 1367 return True 1368 1369 for arch in archs: 1370 if arch in self.getArchitecture(): 1371 return True 1372 1373 return False 1374 1375 def getRunOptions(self): 1376 """Command line option for -A and -C to run this test again, called from 1377 self.dumpSessionInfo().""" 1378 arch = self.getArchitecture() 1379 comp = self.getCompiler() 1380 option_str = "" 1381 if arch: 1382 option_str = "-A " + arch 1383 if comp: 1384 option_str += " -C " + comp 1385 return option_str 1386 1387 def getDebugInfo(self): 1388 method = getattr(self, self.testMethodName) 1389 return getattr(method, "debug_info", None) 1390 1391 # ================================================== 1392 # Build methods supported through a plugin interface 1393 # ================================================== 1394 1395 def getstdlibFlag(self): 1396 """ Returns the proper -stdlib flag, or empty if not required.""" 1397 if self.platformIsDarwin() or self.getPlatform() == "freebsd" or self.getPlatform() == "openbsd": 1398 stdlibflag = "-stdlib=libc++" 1399 else: # this includes NetBSD 1400 stdlibflag = "" 1401 return stdlibflag 1402 1403 def getstdFlag(self): 1404 """ Returns the proper stdflag. """ 1405 if "gcc" in self.getCompiler() and "4.6" in self.getCompilerVersion(): 1406 stdflag = "-std=c++0x" 1407 else: 1408 stdflag = "-std=c++11" 1409 return stdflag 1410 1411 def buildDriver(self, sources, exe_name): 1412 """ Platform-specific way to build a program that links with LLDB (via the liblldb.so 1413 or LLDB.framework). 1414 """ 1415 stdflag = self.getstdFlag() 1416 stdlibflag = self.getstdlibFlag() 1417 1418 lib_dir = configuration.lldb_libs_dir 1419 if self.hasDarwinFramework(): 1420 d = {'CXX_SOURCES': sources, 1421 'EXE': exe_name, 1422 'CFLAGS_EXTRAS': "%s %s" % (stdflag, stdlibflag), 1423 'FRAMEWORK_INCLUDES': "-F%s" % self.framework_dir, 1424 'LD_EXTRAS': "%s -Wl,-rpath,%s" % (self.dsym, self.framework_dir), 1425 } 1426 elif sys.platform.startswith('win'): 1427 d = { 1428 'CXX_SOURCES': sources, 1429 'EXE': exe_name, 1430 'CFLAGS_EXTRAS': "%s %s -I%s" % (stdflag, 1431 stdlibflag, 1432 os.path.join( 1433 os.environ["LLDB_SRC"], 1434 "include")), 1435 'LD_EXTRAS': "-L%s -lliblldb" % os.environ["LLDB_IMPLIB_DIR"]} 1436 else: 1437 d = { 1438 'CXX_SOURCES': sources, 1439 'EXE': exe_name, 1440 'CFLAGS_EXTRAS': "%s %s -I%s" % (stdflag, 1441 stdlibflag, 1442 os.path.join( 1443 os.environ["LLDB_SRC"], 1444 "include")), 1445 'LD_EXTRAS': "-L%s -llldb -Wl,-rpath,%s" % (lib_dir, lib_dir)} 1446 if self.TraceOn(): 1447 print( 1448 "Building LLDB Driver (%s) from sources %s" % 1449 (exe_name, sources)) 1450 1451 self.buildDefault(dictionary=d) 1452 1453 def buildLibrary(self, sources, lib_name): 1454 """Platform specific way to build a default library. """ 1455 1456 stdflag = self.getstdFlag() 1457 1458 lib_dir = configuration.lldb_libs_dir 1459 if self.hasDarwinFramework(): 1460 d = {'DYLIB_CXX_SOURCES': sources, 1461 'DYLIB_NAME': lib_name, 1462 'CFLAGS_EXTRAS': "%s -stdlib=libc++" % stdflag, 1463 'FRAMEWORK_INCLUDES': "-F%s" % self.framework_dir, 1464 'LD_EXTRAS': "%s -Wl,-rpath,%s -dynamiclib" % (self.dsym, self.framework_dir), 1465 } 1466 elif self.getPlatform() == 'windows': 1467 d = { 1468 'DYLIB_CXX_SOURCES': sources, 1469 'DYLIB_NAME': lib_name, 1470 'CFLAGS_EXTRAS': "%s -I%s " % (stdflag, 1471 os.path.join( 1472 os.environ["LLDB_SRC"], 1473 "include")), 1474 'LD_EXTRAS': "-shared -l%s\liblldb.lib" % self.os.environ["LLDB_IMPLIB_DIR"]} 1475 else: 1476 d = { 1477 'DYLIB_CXX_SOURCES': sources, 1478 'DYLIB_NAME': lib_name, 1479 'CFLAGS_EXTRAS': "%s -I%s -fPIC" % (stdflag, 1480 os.path.join( 1481 os.environ["LLDB_SRC"], 1482 "include")), 1483 'LD_EXTRAS': "-shared -L%s -llldb -Wl,-rpath,%s" % (lib_dir, lib_dir)} 1484 if self.TraceOn(): 1485 print( 1486 "Building LLDB Library (%s) from sources %s" % 1487 (lib_name, sources)) 1488 1489 self.buildDefault(dictionary=d) 1490 1491 def buildProgram(self, sources, exe_name): 1492 """ Platform specific way to build an executable from C/C++ sources. """ 1493 d = {'CXX_SOURCES': sources, 1494 'EXE': exe_name} 1495 self.buildDefault(dictionary=d) 1496 1497 def buildDefault( 1498 self, 1499 architecture=None, 1500 compiler=None, 1501 dictionary=None): 1502 """Platform specific way to build the default binaries.""" 1503 testdir = self.mydir 1504 testname = self.getBuildDirBasename() 1505 if self.getDebugInfo(): 1506 raise Exception("buildDefault tests must set NO_DEBUG_INFO_TESTCASE") 1507 module = builder_module() 1508 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1509 if not module.buildDefault(self, architecture, compiler, 1510 dictionary, testdir, testname): 1511 raise Exception("Don't know how to build default binary") 1512 1513 def buildDsym( 1514 self, 1515 architecture=None, 1516 compiler=None, 1517 dictionary=None): 1518 """Platform specific way to build binaries with dsym info.""" 1519 testdir = self.mydir 1520 testname = self.getBuildDirBasename() 1521 if self.getDebugInfo() != "dsym": 1522 raise Exception("NO_DEBUG_INFO_TESTCASE must build with buildDefault") 1523 1524 module = builder_module() 1525 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1526 if not module.buildDsym(self, architecture, compiler, 1527 dictionary, testdir, testname): 1528 raise Exception("Don't know how to build binary with dsym") 1529 1530 def buildDwarf( 1531 self, 1532 architecture=None, 1533 compiler=None, 1534 dictionary=None): 1535 """Platform specific way to build binaries with dwarf maps.""" 1536 testdir = self.mydir 1537 testname = self.getBuildDirBasename() 1538 if self.getDebugInfo() != "dwarf": 1539 raise Exception("NO_DEBUG_INFO_TESTCASE must build with buildDefault") 1540 1541 module = builder_module() 1542 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1543 if not module.buildDwarf(self, architecture, compiler, 1544 dictionary, testdir, testname): 1545 raise Exception("Don't know how to build binary with dwarf") 1546 1547 def buildDwo( 1548 self, 1549 architecture=None, 1550 compiler=None, 1551 dictionary=None): 1552 """Platform specific way to build binaries with dwarf maps.""" 1553 testdir = self.mydir 1554 testname = self.getBuildDirBasename() 1555 if self.getDebugInfo() != "dwo": 1556 raise Exception("NO_DEBUG_INFO_TESTCASE must build with buildDefault") 1557 1558 module = builder_module() 1559 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1560 if not module.buildDwo(self, architecture, compiler, 1561 dictionary, testdir, testname): 1562 raise Exception("Don't know how to build binary with dwo") 1563 1564 def buildGModules( 1565 self, 1566 architecture=None, 1567 compiler=None, 1568 dictionary=None): 1569 """Platform specific way to build binaries with gmodules info.""" 1570 testdir = self.mydir 1571 testname = self.getBuildDirBasename() 1572 if self.getDebugInfo() != "gmodules": 1573 raise Exception("NO_DEBUG_INFO_TESTCASE must build with buildDefault") 1574 1575 module = builder_module() 1576 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1577 if not module.buildGModules(self, architecture, compiler, 1578 dictionary, testdir, testname): 1579 raise Exception("Don't know how to build binary with gmodules") 1580 1581 def signBinary(self, binary_path): 1582 if sys.platform.startswith("darwin"): 1583 codesign_cmd = "codesign --force --sign \"%s\" %s" % ( 1584 lldbtest_config.codesign_identity, binary_path) 1585 call(codesign_cmd, shell=True) 1586 1587 def findBuiltClang(self): 1588 """Tries to find and use Clang from the build directory as the compiler (instead of the system compiler).""" 1589 paths_to_try = [ 1590 "llvm-build/Release+Asserts/x86_64/bin/clang", 1591 "llvm-build/Debug+Asserts/x86_64/bin/clang", 1592 "llvm-build/Release/x86_64/bin/clang", 1593 "llvm-build/Debug/x86_64/bin/clang", 1594 ] 1595 lldb_root_path = os.path.join( 1596 os.path.dirname(__file__), "..", "..", "..", "..") 1597 for p in paths_to_try: 1598 path = os.path.join(lldb_root_path, p) 1599 if os.path.exists(path): 1600 return path 1601 1602 # Tries to find clang at the same folder as the lldb 1603 lldb_dir = os.path.dirname(lldbtest_config.lldbExec) 1604 path = distutils.spawn.find_executable("clang", lldb_dir) 1605 if path is not None: 1606 return path 1607 1608 return os.environ["CC"] 1609 1610 def findYaml2obj(self): 1611 """ 1612 Get the path to the yaml2obj executable, which can be used to create 1613 test object files from easy to write yaml instructions. 1614 1615 Throws an Exception if the executable cannot be found. 1616 """ 1617 # Tries to find yaml2obj at the same folder as clang 1618 clang_dir = os.path.dirname(self.findBuiltClang()) 1619 path = distutils.spawn.find_executable("yaml2obj", clang_dir) 1620 if path is not None: 1621 return path 1622 raise Exception("yaml2obj executable not found") 1623 1624 1625 def yaml2obj(self, yaml_path, obj_path): 1626 """ 1627 Create an object file at the given path from a yaml file. 1628 1629 Throws subprocess.CalledProcessError if the object could not be created. 1630 """ 1631 yaml2obj = self.findYaml2obj() 1632 command = [yaml2obj, "-o=%s" % obj_path, yaml_path] 1633 system([command]) 1634 1635 def getBuildFlags( 1636 self, 1637 use_cpp11=True, 1638 use_libcxx=False, 1639 use_libstdcxx=False): 1640 """ Returns a dictionary (which can be provided to build* functions above) which 1641 contains OS-specific build flags. 1642 """ 1643 cflags = "" 1644 ldflags = "" 1645 1646 # On Mac OS X, unless specifically requested to use libstdc++, use 1647 # libc++ 1648 if not use_libstdcxx and self.platformIsDarwin(): 1649 use_libcxx = True 1650 1651 if use_libcxx and self.libcxxPath: 1652 cflags += "-stdlib=libc++ " 1653 if self.libcxxPath: 1654 libcxxInclude = os.path.join(self.libcxxPath, "include") 1655 libcxxLib = os.path.join(self.libcxxPath, "lib") 1656 if os.path.isdir(libcxxInclude) and os.path.isdir(libcxxLib): 1657 cflags += "-nostdinc++ -I%s -L%s -Wl,-rpath,%s " % ( 1658 libcxxInclude, libcxxLib, libcxxLib) 1659 1660 if use_cpp11: 1661 cflags += "-std=" 1662 if "gcc" in self.getCompiler() and "4.6" in self.getCompilerVersion(): 1663 cflags += "c++0x" 1664 else: 1665 cflags += "c++11" 1666 if self.platformIsDarwin() or self.getPlatform() == "freebsd": 1667 cflags += " -stdlib=libc++" 1668 elif self.getPlatform() == "openbsd": 1669 cflags += " -stdlib=libc++" 1670 elif self.getPlatform() == "netbsd": 1671 # NetBSD defaults to libc++ 1672 pass 1673 elif "clang" in self.getCompiler(): 1674 cflags += " -stdlib=libstdc++" 1675 1676 return {'CFLAGS_EXTRAS': cflags, 1677 'LD_EXTRAS': ldflags, 1678 } 1679 1680 def cleanup(self, dictionary=None): 1681 """Platform specific way to do cleanup after build.""" 1682 module = builder_module() 1683 if not module.cleanup(self, dictionary): 1684 raise Exception( 1685 "Don't know how to do cleanup with dictionary: " + 1686 dictionary) 1687 1688 def getLLDBLibraryEnvVal(self): 1689 """ Returns the path that the OS-specific library search environment variable 1690 (self.dylibPath) should be set to in order for a program to find the LLDB 1691 library. If an environment variable named self.dylibPath is already set, 1692 the new path is appended to it and returned. 1693 """ 1694 existing_library_path = os.environ[ 1695 self.dylibPath] if self.dylibPath in os.environ else None 1696 lib_dir = os.environ["LLDB_LIB_DIR"] 1697 if existing_library_path: 1698 return "%s:%s" % (existing_library_path, lib_dir) 1699 elif sys.platform.startswith("darwin"): 1700 return os.path.join(lib_dir, 'LLDB.framework') 1701 else: 1702 return lib_dir 1703 1704 def getLibcPlusPlusLibs(self): 1705 if self.getPlatform() in ('freebsd', 'linux', 'netbsd', 'openbsd'): 1706 return ['libc++.so.1'] 1707 else: 1708 return ['libc++.1.dylib', 'libc++abi.'] 1709 1710# Metaclass for TestBase to change the list of test metods when a new TestCase is loaded. 1711# We change the test methods to create a new test method for each test for each debug info we are 1712# testing. The name of the new test method will be '<original-name>_<debug-info>' and with adding 1713# the new test method we remove the old method at the same time. This functionality can be 1714# supressed by at test case level setting the class attribute NO_DEBUG_INFO_TESTCASE or at test 1715# level by using the decorator @no_debug_info_test. 1716 1717 1718class LLDBTestCaseFactory(type): 1719 1720 def __new__(cls, name, bases, attrs): 1721 original_testcase = super( 1722 LLDBTestCaseFactory, cls).__new__( 1723 cls, name, bases, attrs) 1724 if original_testcase.NO_DEBUG_INFO_TESTCASE: 1725 return original_testcase 1726 1727 newattrs = {} 1728 for attrname, attrvalue in attrs.items(): 1729 if attrname.startswith("test") and not getattr( 1730 attrvalue, "__no_debug_info_test__", False): 1731 1732 # If any debug info categories were explicitly tagged, assume that list to be 1733 # authoritative. If none were specified, try with all debug 1734 # info formats. 1735 all_dbginfo_categories = set(test_categories.debug_info_categories) 1736 categories = set( 1737 getattr( 1738 attrvalue, 1739 "categories", 1740 [])) & all_dbginfo_categories 1741 if not categories: 1742 categories = all_dbginfo_categories 1743 1744 for cat in categories: 1745 @decorators.add_test_categories([cat]) 1746 @wraps(attrvalue) 1747 def test_method(self, attrvalue=attrvalue): 1748 return attrvalue(self) 1749 1750 method_name = attrname + "_" + cat 1751 test_method.__name__ = method_name 1752 test_method.debug_info = cat 1753 newattrs[method_name] = test_method 1754 1755 else: 1756 newattrs[attrname] = attrvalue 1757 return super( 1758 LLDBTestCaseFactory, 1759 cls).__new__( 1760 cls, 1761 name, 1762 bases, 1763 newattrs) 1764 1765# Setup the metaclass for this class to change the list of the test 1766# methods when a new class is loaded 1767 1768 1769@add_metaclass(LLDBTestCaseFactory) 1770class TestBase(Base): 1771 """ 1772 This abstract base class is meant to be subclassed. It provides default 1773 implementations for setUpClass(), tearDownClass(), setUp(), and tearDown(), 1774 among other things. 1775 1776 Important things for test class writers: 1777 1778 - Overwrite the mydir class attribute, otherwise your test class won't 1779 run. It specifies the relative directory to the top level 'test' so 1780 the test harness can change to the correct working directory before 1781 running your test. 1782 1783 - The setUp method sets up things to facilitate subsequent interactions 1784 with the debugger as part of the test. These include: 1785 - populate the test method name 1786 - create/get a debugger set with synchronous mode (self.dbg) 1787 - get the command interpreter from with the debugger (self.ci) 1788 - create a result object for use with the command interpreter 1789 (self.res) 1790 - plus other stuffs 1791 1792 - The tearDown method tries to perform some necessary cleanup on behalf 1793 of the test to return the debugger to a good state for the next test. 1794 These include: 1795 - execute any tearDown hooks registered by the test method with 1796 TestBase.addTearDownHook(); examples can be found in 1797 settings/TestSettings.py 1798 - kill the inferior process associated with each target, if any, 1799 and, then delete the target from the debugger's target list 1800 - perform build cleanup before running the next test method in the 1801 same test class; examples of registering for this service can be 1802 found in types/TestIntegerTypes.py with the call: 1803 - self.setTearDownCleanup(dictionary=d) 1804 1805 - Similarly setUpClass and tearDownClass perform classwise setup and 1806 teardown fixtures. The tearDownClass method invokes a default build 1807 cleanup for the entire test class; also, subclasses can implement the 1808 classmethod classCleanup(cls) to perform special class cleanup action. 1809 1810 - The instance methods runCmd and expect are used heavily by existing 1811 test cases to send a command to the command interpreter and to perform 1812 string/pattern matching on the output of such command execution. The 1813 expect method also provides a mode to peform string/pattern matching 1814 without running a command. 1815 1816 - The build methods buildDefault, buildDsym, and buildDwarf are used to 1817 build the binaries used during a particular test scenario. A plugin 1818 should be provided for the sys.platform running the test suite. The 1819 Mac OS X implementation is located in plugins/darwin.py. 1820 """ 1821 1822 # Subclasses can set this to true (if they don't depend on debug info) to avoid running the 1823 # test multiple times with various debug info types. 1824 NO_DEBUG_INFO_TESTCASE = False 1825 1826 # Maximum allowed attempts when launching the inferior process. 1827 # Can be overridden by the LLDB_MAX_LAUNCH_COUNT environment variable. 1828 maxLaunchCount = 1 1829 1830 # Time to wait before the next launching attempt in second(s). 1831 # Can be overridden by the LLDB_TIME_WAIT_NEXT_LAUNCH environment variable. 1832 timeWaitNextLaunch = 1.0 1833 1834 def generateSource(self, source): 1835 template = source + '.template' 1836 temp = os.path.join(self.getSourceDir(), template) 1837 with open(temp, 'r') as f: 1838 content = f.read() 1839 1840 public_api_dir = os.path.join( 1841 os.environ["LLDB_SRC"], "include", "lldb", "API") 1842 1843 # Look under the include/lldb/API directory and add #include statements 1844 # for all the SB API headers. 1845 public_headers = os.listdir(public_api_dir) 1846 # For different platforms, the include statement can vary. 1847 if self.hasDarwinFramework(): 1848 include_stmt = "'#include <%s>' % os.path.join('LLDB', header)" 1849 else: 1850 include_stmt = "'#include <%s>' % os.path.join('" + public_api_dir + "', header)" 1851 list = [eval(include_stmt) for header in public_headers if ( 1852 header.startswith("SB") and header.endswith(".h"))] 1853 includes = '\n'.join(list) 1854 new_content = content.replace('%include_SB_APIs%', includes) 1855 src = os.path.join(self.getBuildDir(), source) 1856 with open(src, 'w') as f: 1857 f.write(new_content) 1858 1859 self.addTearDownHook(lambda: os.remove(src)) 1860 1861 def setUp(self): 1862 #import traceback 1863 # traceback.print_stack() 1864 1865 # Works with the test driver to conditionally skip tests via 1866 # decorators. 1867 Base.setUp(self) 1868 1869 for s in self.setUpCommands(): 1870 self.runCmd(s) 1871 1872 if "LLDB_MAX_LAUNCH_COUNT" in os.environ: 1873 self.maxLaunchCount = int(os.environ["LLDB_MAX_LAUNCH_COUNT"]) 1874 1875 if "LLDB_TIME_WAIT_NEXT_LAUNCH" in os.environ: 1876 self.timeWaitNextLaunch = float( 1877 os.environ["LLDB_TIME_WAIT_NEXT_LAUNCH"]) 1878 1879 # We want our debugger to be synchronous. 1880 self.dbg.SetAsync(False) 1881 1882 # Retrieve the associated command interpreter instance. 1883 self.ci = self.dbg.GetCommandInterpreter() 1884 if not self.ci: 1885 raise Exception('Could not get the command interpreter') 1886 1887 # And the result object. 1888 self.res = lldb.SBCommandReturnObject() 1889 1890 def registerSharedLibrariesWithTarget(self, target, shlibs): 1891 '''If we are remotely running the test suite, register the shared libraries with the target so they get uploaded, otherwise do nothing 1892 1893 Any modules in the target that have their remote install file specification set will 1894 get uploaded to the remote host. This function registers the local copies of the 1895 shared libraries with the target and sets their remote install locations so they will 1896 be uploaded when the target is run. 1897 ''' 1898 if not shlibs or not self.platformContext: 1899 return None 1900 1901 shlib_environment_var = self.platformContext.shlib_environment_var 1902 shlib_prefix = self.platformContext.shlib_prefix 1903 shlib_extension = '.' + self.platformContext.shlib_extension 1904 1905 working_dir = self.get_process_working_directory() 1906 environment = ['%s=%s' % (shlib_environment_var, working_dir)] 1907 # Add any shared libraries to our target if remote so they get 1908 # uploaded into the working directory on the remote side 1909 for name in shlibs: 1910 # The path can be a full path to a shared library, or a make file name like "Foo" for 1911 # "libFoo.dylib" or "libFoo.so", or "Foo.so" for "Foo.so" or "libFoo.so", or just a 1912 # basename like "libFoo.so". So figure out which one it is and resolve the local copy 1913 # of the shared library accordingly 1914 if os.path.isfile(name): 1915 local_shlib_path = name # name is the full path to the local shared library 1916 else: 1917 # Check relative names 1918 local_shlib_path = os.path.join( 1919 self.getBuildDir(), shlib_prefix + name + shlib_extension) 1920 if not os.path.exists(local_shlib_path): 1921 local_shlib_path = os.path.join( 1922 self.getBuildDir(), name + shlib_extension) 1923 if not os.path.exists(local_shlib_path): 1924 local_shlib_path = os.path.join(self.getBuildDir(), name) 1925 1926 # Make sure we found the local shared library in the above code 1927 self.assertTrue(os.path.exists(local_shlib_path)) 1928 1929 # Add the shared library to our target 1930 shlib_module = target.AddModule(local_shlib_path, None, None, None) 1931 if lldb.remote_platform: 1932 # We must set the remote install location if we want the shared library 1933 # to get uploaded to the remote target 1934 remote_shlib_path = lldbutil.append_to_process_working_directory(self, 1935 os.path.basename(local_shlib_path)) 1936 shlib_module.SetRemoteInstallFileSpec( 1937 lldb.SBFileSpec(remote_shlib_path, False)) 1938 1939 return environment 1940 1941 def registerSanitizerLibrariesWithTarget(self, target): 1942 runtimes = [] 1943 for m in target.module_iter(): 1944 libspec = m.GetFileSpec() 1945 if "clang_rt" in libspec.GetFilename(): 1946 runtimes.append(os.path.join(libspec.GetDirectory(), 1947 libspec.GetFilename())) 1948 return self.registerSharedLibrariesWithTarget(target, runtimes) 1949 1950 # utility methods that tests can use to access the current objects 1951 def target(self): 1952 if not self.dbg: 1953 raise Exception('Invalid debugger instance') 1954 return self.dbg.GetSelectedTarget() 1955 1956 def process(self): 1957 if not self.dbg: 1958 raise Exception('Invalid debugger instance') 1959 return self.dbg.GetSelectedTarget().GetProcess() 1960 1961 def thread(self): 1962 if not self.dbg: 1963 raise Exception('Invalid debugger instance') 1964 return self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread() 1965 1966 def frame(self): 1967 if not self.dbg: 1968 raise Exception('Invalid debugger instance') 1969 return self.dbg.GetSelectedTarget().GetProcess( 1970 ).GetSelectedThread().GetSelectedFrame() 1971 1972 def get_process_working_directory(self): 1973 '''Get the working directory that should be used when launching processes for local or remote processes.''' 1974 if lldb.remote_platform: 1975 # Remote tests set the platform working directory up in 1976 # TestBase.setUp() 1977 return lldb.remote_platform.GetWorkingDirectory() 1978 else: 1979 # local tests change directory into each test subdirectory 1980 return self.getBuildDir() 1981 1982 def tearDown(self): 1983 #import traceback 1984 # traceback.print_stack() 1985 1986 # Ensure all the references to SB objects have gone away so that we can 1987 # be sure that all test-specific resources have been freed before we 1988 # attempt to delete the targets. 1989 gc.collect() 1990 1991 # Delete the target(s) from the debugger as a general cleanup step. 1992 # This includes terminating the process for each target, if any. 1993 # We'd like to reuse the debugger for our next test without incurring 1994 # the initialization overhead. 1995 targets = [] 1996 for target in self.dbg: 1997 if target: 1998 targets.append(target) 1999 process = target.GetProcess() 2000 if process: 2001 rc = self.invoke(process, "Kill") 2002 self.assertTrue(rc.Success(), PROCESS_KILLED) 2003 for target in targets: 2004 self.dbg.DeleteTarget(target) 2005 2006 # Do this last, to make sure it's in reverse order from how we setup. 2007 Base.tearDown(self) 2008 2009 def switch_to_thread_with_stop_reason(self, stop_reason): 2010 """ 2011 Run the 'thread list' command, and select the thread with stop reason as 2012 'stop_reason'. If no such thread exists, no select action is done. 2013 """ 2014 from .lldbutil import stop_reason_to_str 2015 self.runCmd('thread list') 2016 output = self.res.GetOutput() 2017 thread_line_pattern = re.compile( 2018 "^[ *] thread #([0-9]+):.*stop reason = %s" % 2019 stop_reason_to_str(stop_reason)) 2020 for line in output.splitlines(): 2021 matched = thread_line_pattern.match(line) 2022 if matched: 2023 self.runCmd('thread select %s' % matched.group(1)) 2024 2025 def runCmd(self, cmd, msg=None, check=True, trace=False, inHistory=False): 2026 """ 2027 Ask the command interpreter to handle the command and then check its 2028 return status. 2029 """ 2030 # Fail fast if 'cmd' is not meaningful. 2031 if not cmd or len(cmd) == 0: 2032 raise Exception("Bad 'cmd' parameter encountered") 2033 2034 trace = (True if traceAlways else trace) 2035 2036 if cmd.startswith("target create "): 2037 cmd = cmd.replace("target create ", "file ") 2038 2039 running = (cmd.startswith("run") or cmd.startswith("process launch")) 2040 2041 for i in range(self.maxLaunchCount if running else 1): 2042 self.ci.HandleCommand(cmd, self.res, inHistory) 2043 2044 with recording(self, trace) as sbuf: 2045 print("runCmd:", cmd, file=sbuf) 2046 if not check: 2047 print("check of return status not required", file=sbuf) 2048 if self.res.Succeeded(): 2049 print("output:", self.res.GetOutput(), file=sbuf) 2050 else: 2051 print("runCmd failed!", file=sbuf) 2052 print(self.res.GetError(), file=sbuf) 2053 2054 if self.res.Succeeded(): 2055 break 2056 elif running: 2057 # For process launch, wait some time before possible next try. 2058 time.sleep(self.timeWaitNextLaunch) 2059 with recording(self, trace) as sbuf: 2060 print("Command '" + cmd + "' failed!", file=sbuf) 2061 2062 if check: 2063 output = "" 2064 if self.res.GetOutput(): 2065 output += "\nCommand output:\n" + self.res.GetOutput() 2066 if self.res.GetError(): 2067 output += "\nError output:\n" + self.res.GetError() 2068 if msg: 2069 msg += output 2070 if cmd: 2071 cmd += output 2072 self.assertTrue(self.res.Succeeded(), 2073 msg if (msg) else CMD_MSG(cmd)) 2074 2075 def match( 2076 self, 2077 str, 2078 patterns, 2079 msg=None, 2080 trace=False, 2081 error=False, 2082 matching=True, 2083 exe=True): 2084 """run command in str, and match the result against regexp in patterns returning the match object for the first matching pattern 2085 2086 Otherwise, all the arguments have the same meanings as for the expect function""" 2087 2088 trace = (True if traceAlways else trace) 2089 2090 if exe: 2091 # First run the command. If we are expecting error, set check=False. 2092 # Pass the assert message along since it provides more semantic 2093 # info. 2094 self.runCmd( 2095 str, 2096 msg=msg, 2097 trace=( 2098 True if trace else False), 2099 check=not error) 2100 2101 # Then compare the output against expected strings. 2102 output = self.res.GetError() if error else self.res.GetOutput() 2103 2104 # If error is True, the API client expects the command to fail! 2105 if error: 2106 self.assertFalse(self.res.Succeeded(), 2107 "Command '" + str + "' is expected to fail!") 2108 else: 2109 # No execution required, just compare str against the golden input. 2110 output = str 2111 with recording(self, trace) as sbuf: 2112 print("looking at:", output, file=sbuf) 2113 2114 # The heading says either "Expecting" or "Not expecting". 2115 heading = "Expecting" if matching else "Not expecting" 2116 2117 for pattern in patterns: 2118 # Match Objects always have a boolean value of True. 2119 match_object = re.search(pattern, output) 2120 matched = bool(match_object) 2121 with recording(self, trace) as sbuf: 2122 print("%s pattern: %s" % (heading, pattern), file=sbuf) 2123 print("Matched" if matched else "Not matched", file=sbuf) 2124 if matched: 2125 break 2126 2127 self.assertTrue(matched if matching else not matched, 2128 msg if msg else EXP_MSG(str, output, exe)) 2129 2130 return match_object 2131 2132 def check_completion_with_desc(self, str_input, match_desc_pairs): 2133 interp = self.dbg.GetCommandInterpreter() 2134 match_strings = lldb.SBStringList() 2135 description_strings = lldb.SBStringList() 2136 num_matches = interp.HandleCompletionWithDescriptions(str_input, len(str_input), 0, -1, match_strings, description_strings) 2137 self.assertEqual(len(description_strings), len(match_strings)) 2138 2139 missing_pairs = [] 2140 for pair in match_desc_pairs: 2141 found_pair = False 2142 for i in range(num_matches + 1): 2143 match_candidate = match_strings.GetStringAtIndex(i) 2144 description_candidate = description_strings.GetStringAtIndex(i) 2145 if match_candidate == pair[0] and description_candidate == pair[1]: 2146 found_pair = True 2147 break 2148 if not found_pair: 2149 missing_pairs.append(pair) 2150 2151 if len(missing_pairs): 2152 error_msg = "Missing pairs:\n" 2153 for pair in missing_pairs: 2154 error_msg += " [" + pair[0] + ":" + pair[1] + "]\n" 2155 error_msg += "Got the following " + str(num_matches) + " completions back:\n" 2156 for i in range(num_matches + 1): 2157 match_candidate = match_strings.GetStringAtIndex(i) 2158 description_candidate = description_strings.GetStringAtIndex(i) 2159 error_msg += "[" + match_candidate + ":" + description_candidate + "]\n" 2160 self.assertEqual(0, len(missing_pairs), error_msg) 2161 2162 def complete_exactly(self, str_input, patterns): 2163 self.complete_from_to(str_input, patterns, True) 2164 2165 def complete_from_to(self, str_input, patterns, turn_off_re_match=False): 2166 """Test that the completion mechanism completes str_input to patterns, 2167 where patterns could be a pattern-string or a list of pattern-strings""" 2168 # Patterns should not be None in order to proceed. 2169 self.assertFalse(patterns is None) 2170 # And should be either a string or list of strings. Check for list type 2171 # below, if not, make a list out of the singleton string. If patterns 2172 # is not a string or not a list of strings, there'll be runtime errors 2173 # later on. 2174 if not isinstance(patterns, list): 2175 patterns = [patterns] 2176 2177 interp = self.dbg.GetCommandInterpreter() 2178 match_strings = lldb.SBStringList() 2179 num_matches = interp.HandleCompletion(str_input, len(str_input), 0, -1, match_strings) 2180 common_match = match_strings.GetStringAtIndex(0) 2181 if num_matches == 0: 2182 compare_string = str_input 2183 else: 2184 if common_match != None and len(common_match) > 0: 2185 compare_string = str_input + common_match 2186 else: 2187 compare_string = "" 2188 for idx in range(1, num_matches+1): 2189 compare_string += match_strings.GetStringAtIndex(idx) + "\n" 2190 2191 for p in patterns: 2192 if turn_off_re_match: 2193 self.expect( 2194 compare_string, msg=COMPLETION_MSG( 2195 str_input, p, match_strings), exe=False, substrs=[p]) 2196 else: 2197 self.expect( 2198 compare_string, msg=COMPLETION_MSG( 2199 str_input, p, match_strings), exe=False, patterns=[p]) 2200 2201 def completions_match(self, command, completions): 2202 """Checks that the completions for the given command are equal to the 2203 given list of completions""" 2204 interp = self.dbg.GetCommandInterpreter() 2205 match_strings = lldb.SBStringList() 2206 interp.HandleCompletion(command, len(command), 0, -1, match_strings) 2207 # match_strings is a 1-indexed list, so we have to slice... 2208 self.assertItemsEqual(completions, list(match_strings)[1:], 2209 "List of returned completion is wrong") 2210 2211 def filecheck( 2212 self, 2213 command, 2214 check_file, 2215 filecheck_options = '', 2216 expect_cmd_failure = False): 2217 # Run the command. 2218 self.runCmd( 2219 command, 2220 check=(not expect_cmd_failure), 2221 msg="FileCheck'ing result of `{0}`".format(command)) 2222 2223 self.assertTrue((not expect_cmd_failure) == self.res.Succeeded()) 2224 2225 # Get the error text if there was an error, and the regular text if not. 2226 output = self.res.GetOutput() if self.res.Succeeded() \ 2227 else self.res.GetError() 2228 2229 # Assemble the absolute path to the check file. As a convenience for 2230 # LLDB inline tests, assume that the check file is a relative path to 2231 # a file within the inline test directory. 2232 if check_file.endswith('.pyc'): 2233 check_file = check_file[:-1] 2234 check_file_abs = os.path.abspath(check_file) 2235 2236 # Run FileCheck. 2237 filecheck_bin = configuration.get_filecheck_path() 2238 if not filecheck_bin: 2239 self.assertTrue(False, "No valid FileCheck executable specified") 2240 filecheck_args = [filecheck_bin, check_file_abs] 2241 if filecheck_options: 2242 filecheck_args.append(filecheck_options) 2243 subproc = Popen(filecheck_args, stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines = True) 2244 cmd_stdout, cmd_stderr = subproc.communicate(input=output) 2245 cmd_status = subproc.returncode 2246 2247 filecheck_cmd = " ".join(filecheck_args) 2248 filecheck_trace = """ 2249--- FileCheck trace (code={0}) --- 2250{1} 2251 2252FileCheck input: 2253{2} 2254 2255FileCheck output: 2256{3} 2257{4} 2258""".format(cmd_status, filecheck_cmd, output, cmd_stdout, cmd_stderr) 2259 2260 trace = cmd_status != 0 or traceAlways 2261 with recording(self, trace) as sbuf: 2262 print(filecheck_trace, file=sbuf) 2263 2264 self.assertTrue(cmd_status == 0) 2265 2266 def expect( 2267 self, 2268 str, 2269 msg=None, 2270 patterns=None, 2271 startstr=None, 2272 endstr=None, 2273 substrs=None, 2274 trace=False, 2275 error=False, 2276 ordered=True, 2277 matching=True, 2278 exe=True, 2279 inHistory=False): 2280 """ 2281 Similar to runCmd; with additional expect style output matching ability. 2282 2283 Ask the command interpreter to handle the command and then check its 2284 return status. The 'msg' parameter specifies an informational assert 2285 message. We expect the output from running the command to start with 2286 'startstr', matches the substrings contained in 'substrs', and regexp 2287 matches the patterns contained in 'patterns'. 2288 2289 When matching is true and ordered is true, which are both the default, 2290 the strings in the substrs array have to appear in the command output 2291 in the order in which they appear in the array. 2292 2293 If the keyword argument error is set to True, it signifies that the API 2294 client is expecting the command to fail. In this case, the error stream 2295 from running the command is retrieved and compared against the golden 2296 input, instead. 2297 2298 If the keyword argument matching is set to False, it signifies that the API 2299 client is expecting the output of the command not to match the golden 2300 input. 2301 2302 Finally, the required argument 'str' represents the lldb command to be 2303 sent to the command interpreter. In case the keyword argument 'exe' is 2304 set to False, the 'str' is treated as a string to be matched/not-matched 2305 against the golden input. 2306 """ 2307 trace = (True if traceAlways else trace) 2308 2309 if exe: 2310 # First run the command. If we are expecting error, set check=False. 2311 # Pass the assert message along since it provides more semantic 2312 # info. 2313 self.runCmd( 2314 str, 2315 msg=msg, 2316 trace=( 2317 True if trace else False), 2318 check=not error, 2319 inHistory=inHistory) 2320 2321 # Then compare the output against expected strings. 2322 output = self.res.GetError() if error else self.res.GetOutput() 2323 2324 # If error is True, the API client expects the command to fail! 2325 if error: 2326 self.assertFalse(self.res.Succeeded(), 2327 "Command '" + str + "' is expected to fail!") 2328 else: 2329 # No execution required, just compare str against the golden input. 2330 if isinstance(str, lldb.SBCommandReturnObject): 2331 output = str.GetOutput() 2332 else: 2333 output = str 2334 with recording(self, trace) as sbuf: 2335 print("looking at:", output, file=sbuf) 2336 2337 # The heading says either "Expecting" or "Not expecting". 2338 heading = "Expecting" if matching else "Not expecting" 2339 2340 # Start from the startstr, if specified. 2341 # If there's no startstr, set the initial state appropriately. 2342 matched = output.startswith(startstr) if startstr else ( 2343 True if matching else False) 2344 2345 if startstr: 2346 with recording(self, trace) as sbuf: 2347 print("%s start string: %s" % (heading, startstr), file=sbuf) 2348 print("Matched" if matched else "Not matched", file=sbuf) 2349 2350 # Look for endstr, if specified. 2351 keepgoing = matched if matching else not matched 2352 if endstr: 2353 matched = output.endswith(endstr) 2354 with recording(self, trace) as sbuf: 2355 print("%s end string: %s" % (heading, endstr), file=sbuf) 2356 print("Matched" if matched else "Not matched", file=sbuf) 2357 2358 # Look for sub strings, if specified. 2359 keepgoing = matched if matching else not matched 2360 if substrs and keepgoing: 2361 start = 0 2362 for substr in substrs: 2363 index = output[start:].find(substr) 2364 start = start + index if ordered and matching else 0 2365 matched = index != -1 2366 with recording(self, trace) as sbuf: 2367 print("%s sub string: %s" % (heading, substr), file=sbuf) 2368 print("Matched" if matched else "Not matched", file=sbuf) 2369 keepgoing = matched if matching else not matched 2370 if not keepgoing: 2371 break 2372 2373 # Search for regular expression patterns, if specified. 2374 keepgoing = matched if matching else not matched 2375 if patterns and keepgoing: 2376 for pattern in patterns: 2377 # Match Objects always have a boolean value of True. 2378 matched = bool(re.search(pattern, output)) 2379 with recording(self, trace) as sbuf: 2380 print("%s pattern: %s" % (heading, pattern), file=sbuf) 2381 print("Matched" if matched else "Not matched", file=sbuf) 2382 keepgoing = matched if matching else not matched 2383 if not keepgoing: 2384 break 2385 2386 self.assertTrue(matched if matching else not matched, 2387 msg + "\nCommand output:\n" + EXP_MSG(str, output, exe) 2388 if msg else EXP_MSG(str, output, exe)) 2389 2390 def expect_expr( 2391 self, 2392 expr, 2393 result_summary=None, 2394 result_value=None, 2395 result_type=None, 2396 error_msg=None, 2397 ): 2398 """ 2399 Evaluates the given expression and verifies the result. 2400 :param expr: The expression as a string. 2401 :param result_summary: The summary that the expression should have. None if the summary should not be checked. 2402 :param result_value: The value that the expression should have. None if the value should not be checked. 2403 :param result_type: The type that the expression result should have. None if the type should not be checked. 2404 :param error_msg: The error message the expression should return. None if the error output should not be checked. 2405 """ 2406 self.assertTrue(expr.strip() == expr, "Expression contains trailing/leading whitespace: '" + expr + "'") 2407 2408 frame = self.frame() 2409 options = lldb.SBExpressionOptions() 2410 2411 # Disable fix-its that tests don't pass by accident. 2412 options.SetAutoApplyFixIts(False) 2413 2414 # Set the usual default options for normal expressions. 2415 options.SetIgnoreBreakpoints(True) 2416 options.SetLanguage(frame.GuessLanguage()) 2417 2418 eval_result = frame.EvaluateExpression(expr, options) 2419 2420 if error_msg: 2421 self.assertFalse(eval_result.IsValid(), "Unexpected success with result: '" + str(eval_result) + "'") 2422 self.assertEqual(error_msg, eval_result.GetError().GetCString()) 2423 return 2424 2425 if not eval_result.GetError().Success(): 2426 self.assertTrue(eval_result.GetError().Success(), 2427 "Unexpected failure with msg: " + eval_result.GetError().GetCString()) 2428 2429 if result_type: 2430 self.assertEqual(result_type, eval_result.GetDisplayTypeName()) 2431 2432 if result_value: 2433 self.assertEqual(result_value, eval_result.GetValue()) 2434 2435 if result_summary: 2436 self.assertEqual(result_summary, eval_result.GetSummary()) 2437 2438 def invoke(self, obj, name, trace=False): 2439 """Use reflection to call a method dynamically with no argument.""" 2440 trace = (True if traceAlways else trace) 2441 2442 method = getattr(obj, name) 2443 import inspect 2444 self.assertTrue(inspect.ismethod(method), 2445 name + "is a method name of object: " + str(obj)) 2446 result = method() 2447 with recording(self, trace) as sbuf: 2448 print(str(method) + ":", result, file=sbuf) 2449 return result 2450 2451 def build( 2452 self, 2453 architecture=None, 2454 compiler=None, 2455 dictionary=None): 2456 """Platform specific way to build the default binaries.""" 2457 module = builder_module() 2458 2459 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 2460 if self.getDebugInfo() is None: 2461 return self.buildDefault(architecture, compiler, dictionary) 2462 elif self.getDebugInfo() == "dsym": 2463 return self.buildDsym(architecture, compiler, dictionary) 2464 elif self.getDebugInfo() == "dwarf": 2465 return self.buildDwarf(architecture, compiler, dictionary) 2466 elif self.getDebugInfo() == "dwo": 2467 return self.buildDwo(architecture, compiler, dictionary) 2468 elif self.getDebugInfo() == "gmodules": 2469 return self.buildGModules(architecture, compiler, dictionary) 2470 else: 2471 self.fail("Can't build for debug info: %s" % self.getDebugInfo()) 2472 2473 def run_platform_command(self, cmd): 2474 platform = self.dbg.GetSelectedPlatform() 2475 shell_command = lldb.SBPlatformShellCommand(cmd) 2476 err = platform.Run(shell_command) 2477 return (err, shell_command.GetStatus(), shell_command.GetOutput()) 2478 2479 # ================================================= 2480 # Misc. helper methods for debugging test execution 2481 # ================================================= 2482 2483 def DebugSBValue(self, val): 2484 """Debug print a SBValue object, if traceAlways is True.""" 2485 from .lldbutil import value_type_to_str 2486 2487 if not traceAlways: 2488 return 2489 2490 err = sys.stderr 2491 err.write(val.GetName() + ":\n") 2492 err.write('\t' + "TypeName -> " + val.GetTypeName() + '\n') 2493 err.write('\t' + "ByteSize -> " + 2494 str(val.GetByteSize()) + '\n') 2495 err.write('\t' + "NumChildren -> " + 2496 str(val.GetNumChildren()) + '\n') 2497 err.write('\t' + "Value -> " + str(val.GetValue()) + '\n') 2498 err.write('\t' + "ValueAsUnsigned -> " + 2499 str(val.GetValueAsUnsigned()) + '\n') 2500 err.write( 2501 '\t' + 2502 "ValueType -> " + 2503 value_type_to_str( 2504 val.GetValueType()) + 2505 '\n') 2506 err.write('\t' + "Summary -> " + str(val.GetSummary()) + '\n') 2507 err.write('\t' + "IsPointerType -> " + 2508 str(val.TypeIsPointerType()) + '\n') 2509 err.write('\t' + "Location -> " + val.GetLocation() + '\n') 2510 2511 def DebugSBType(self, type): 2512 """Debug print a SBType object, if traceAlways is True.""" 2513 if not traceAlways: 2514 return 2515 2516 err = sys.stderr 2517 err.write(type.GetName() + ":\n") 2518 err.write('\t' + "ByteSize -> " + 2519 str(type.GetByteSize()) + '\n') 2520 err.write('\t' + "IsPointerType -> " + 2521 str(type.IsPointerType()) + '\n') 2522 err.write('\t' + "IsReferenceType -> " + 2523 str(type.IsReferenceType()) + '\n') 2524 2525 def DebugPExpect(self, child): 2526 """Debug the spwaned pexpect object.""" 2527 if not traceAlways: 2528 return 2529 2530 print(child) 2531 2532 @classmethod 2533 def RemoveTempFile(cls, file): 2534 if os.path.exists(file): 2535 remove_file(file) 2536 2537# On Windows, the first attempt to delete a recently-touched file can fail 2538# because of a race with antimalware scanners. This function will detect a 2539# failure and retry. 2540 2541 2542def remove_file(file, num_retries=1, sleep_duration=0.5): 2543 for i in range(num_retries + 1): 2544 try: 2545 os.remove(file) 2546 return True 2547 except: 2548 time.sleep(sleep_duration) 2549 continue 2550 return False 2551