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