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