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