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