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