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