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