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