1""" 2LLDB module which provides the abstract base class of lldb test case. 3 4The concrete subclass can override lldbtest.TesBase 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 39import collections 40from functools import wraps 41import gc 42import glob 43import inspect 44import io 45import os.path 46import re 47import signal 48from subprocess import * 49import sys 50import time 51import traceback 52import types 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 use_lldb_suite 62import lldb 63from . import configuration 64from . import decorators 65from . import lldbplatformutil 66from . import lldbtest_config 67from . import lldbutil 68from . import test_categories 69from lldbsuite.support import encoded_file 70from lldbsuite.support import funcutils 71 72# dosep.py starts lots and lots of dotest instances 73# This option helps you find if two (or more) dotest instances are using the same 74# directory at the same time 75# Enable it to cause test failures and stderr messages if dotest instances try to run in 76# the same directory simultaneously 77# it is disabled by default because it litters the test directories with 78# ".dirlock" files 79debug_confirm_directory_exclusivity = False 80 81# See also dotest.parseOptionsAndInitTestdirs(), where the environment variables 82# LLDB_COMMAND_TRACE and LLDB_DO_CLEANUP are set from '-t' and '-r dir' 83# options. 84 85# By default, traceAlways is False. 86if "LLDB_COMMAND_TRACE" in os.environ and os.environ[ 87 "LLDB_COMMAND_TRACE"] == "YES": 88 traceAlways = True 89else: 90 traceAlways = False 91 92# By default, doCleanup is True. 93if "LLDB_DO_CLEANUP" in os.environ and os.environ["LLDB_DO_CLEANUP"] == "NO": 94 doCleanup = False 95else: 96 doCleanup = True 97 98 99# 100# Some commonly used assert messages. 101# 102 103COMMAND_FAILED_AS_EXPECTED = "Command has failed as expected" 104 105CURRENT_EXECUTABLE_SET = "Current executable set successfully" 106 107PROCESS_IS_VALID = "Process is valid" 108 109PROCESS_KILLED = "Process is killed successfully" 110 111PROCESS_EXITED = "Process exited successfully" 112 113PROCESS_STOPPED = "Process status should be stopped" 114 115RUN_SUCCEEDED = "Process is launched successfully" 116 117RUN_COMPLETED = "Process exited successfully" 118 119BACKTRACE_DISPLAYED_CORRECTLY = "Backtrace displayed correctly" 120 121BREAKPOINT_CREATED = "Breakpoint created successfully" 122 123BREAKPOINT_STATE_CORRECT = "Breakpoint state is correct" 124 125BREAKPOINT_PENDING_CREATED = "Pending breakpoint created successfully" 126 127BREAKPOINT_HIT_ONCE = "Breakpoint resolved with hit cout = 1" 128 129BREAKPOINT_HIT_TWICE = "Breakpoint resolved with hit cout = 2" 130 131BREAKPOINT_HIT_THRICE = "Breakpoint resolved with hit cout = 3" 132 133MISSING_EXPECTED_REGISTERS = "At least one expected register is unavailable." 134 135OBJECT_PRINTED_CORRECTLY = "Object printed correctly" 136 137SOURCE_DISPLAYED_CORRECTLY = "Source code displayed correctly" 138 139STEP_OUT_SUCCEEDED = "Thread step-out succeeded" 140 141STOPPED_DUE_TO_EXC_BAD_ACCESS = "Process should be stopped due to bad access exception" 142 143STOPPED_DUE_TO_ASSERT = "Process should be stopped due to an assertion" 144 145STOPPED_DUE_TO_BREAKPOINT = "Process should be stopped due to breakpoint" 146 147STOPPED_DUE_TO_BREAKPOINT_WITH_STOP_REASON_AS = "%s, %s" % ( 148 STOPPED_DUE_TO_BREAKPOINT, "instead, the actual stop reason is: '%s'") 149 150STOPPED_DUE_TO_BREAKPOINT_CONDITION = "Stopped due to breakpoint condition" 151 152STOPPED_DUE_TO_BREAKPOINT_IGNORE_COUNT = "Stopped due to breakpoint and ignore count" 153 154STOPPED_DUE_TO_SIGNAL = "Process state is stopped due to signal" 155 156STOPPED_DUE_TO_STEP_IN = "Process state is stopped due to step in" 157 158STOPPED_DUE_TO_WATCHPOINT = "Process should be stopped due to watchpoint" 159 160DATA_TYPES_DISPLAYED_CORRECTLY = "Data type(s) displayed correctly" 161 162VALID_BREAKPOINT = "Got a valid breakpoint" 163 164VALID_BREAKPOINT_LOCATION = "Got a valid breakpoint location" 165 166VALID_COMMAND_INTERPRETER = "Got a valid command interpreter" 167 168VALID_FILESPEC = "Got a valid filespec" 169 170VALID_MODULE = "Got a valid module" 171 172VALID_PROCESS = "Got a valid process" 173 174VALID_SYMBOL = "Got a valid symbol" 175 176VALID_TARGET = "Got a valid target" 177 178VALID_PLATFORM = "Got a valid platform" 179 180VALID_TYPE = "Got a valid type" 181 182VALID_VARIABLE = "Got a valid variable" 183 184VARIABLES_DISPLAYED_CORRECTLY = "Variable(s) displayed correctly" 185 186WATCHPOINT_CREATED = "Watchpoint created successfully" 187 188 189def CMD_MSG(str): 190 '''A generic "Command '%s' returns successfully" message generator.''' 191 return "Command '%s' returns successfully" % str 192 193 194def COMPLETION_MSG(str_before, str_after): 195 '''A generic message generator for the completion mechanism.''' 196 return "'%s' successfully completes to '%s'" % (str_before, str_after) 197 198 199def EXP_MSG(str, actual, exe): 200 '''A generic "'%s' returns expected result" message generator if exe. 201 Otherwise, it generates "'%s' matches expected result" message.''' 202 203 return "'%s' %s expected result, got '%s'" % ( 204 str, 'returns' if exe else 'matches', actual.strip()) 205 206 207def SETTING_MSG(setting): 208 '''A generic "Value of setting '%s' is correct" message generator.''' 209 return "Value of setting '%s' is correct" % setting 210 211 212def EnvArray(): 213 """Returns an env variable array from the os.environ map object.""" 214 return list(map(lambda k, 215 v: k + "=" + v, 216 list(os.environ.keys()), 217 list(os.environ.values()))) 218 219 220def line_number(filename, string_to_match): 221 """Helper function to return the line number of the first matched string.""" 222 with io.open(filename, mode='r', encoding="utf-8") as f: 223 for i, line in enumerate(f): 224 if line.find(string_to_match) != -1: 225 # Found our match. 226 return i + 1 227 raise Exception( 228 "Unable to find '%s' within file %s" % 229 (string_to_match, filename)) 230 231 232def pointer_size(): 233 """Return the pointer size of the host system.""" 234 import ctypes 235 a_pointer = ctypes.c_void_p(0xffff) 236 return 8 * ctypes.sizeof(a_pointer) 237 238 239def is_exe(fpath): 240 """Returns true if fpath is an executable.""" 241 return os.path.isfile(fpath) and os.access(fpath, os.X_OK) 242 243 244def which(program): 245 """Returns the full path to a program; None otherwise.""" 246 fpath, fname = os.path.split(program) 247 if fpath: 248 if is_exe(program): 249 return program 250 else: 251 for path in os.environ["PATH"].split(os.pathsep): 252 exe_file = os.path.join(path, program) 253 if is_exe(exe_file): 254 return exe_file 255 return None 256 257 258class recording(SixStringIO): 259 """ 260 A nice little context manager for recording the debugger interactions into 261 our session object. If trace flag is ON, it also emits the interactions 262 into the stderr. 263 """ 264 265 def __init__(self, test, trace): 266 """Create a SixStringIO instance; record the session obj and trace flag.""" 267 SixStringIO.__init__(self) 268 # The test might not have undergone the 'setUp(self)' phase yet, so that 269 # the attribute 'session' might not even exist yet. 270 self.session = getattr(test, "session", None) if test else None 271 self.trace = trace 272 273 def __enter__(self): 274 """ 275 Context management protocol on entry to the body of the with statement. 276 Just return the SixStringIO object. 277 """ 278 return self 279 280 def __exit__(self, type, value, tb): 281 """ 282 Context management protocol on exit from the body of the with statement. 283 If trace is ON, it emits the recordings into stderr. Always add the 284 recordings to our session object. And close the SixStringIO object, too. 285 """ 286 if self.trace: 287 print(self.getvalue(), file=sys.stderr) 288 if self.session: 289 print(self.getvalue(), file=self.session) 290 self.close() 291 292 293@add_metaclass(abc.ABCMeta) 294class _BaseProcess(object): 295 296 @abc.abstractproperty 297 def pid(self): 298 """Returns process PID if has been launched already.""" 299 300 @abc.abstractmethod 301 def launch(self, executable, args): 302 """Launches new process with given executable and args.""" 303 304 @abc.abstractmethod 305 def terminate(self): 306 """Terminates previously launched process..""" 307 308 309class _LocalProcess(_BaseProcess): 310 311 def __init__(self, trace_on): 312 self._proc = None 313 self._trace_on = trace_on 314 self._delayafterterminate = 0.1 315 316 @property 317 def pid(self): 318 return self._proc.pid 319 320 def launch(self, executable, args): 321 self._proc = Popen( 322 [executable] + args, 323 stdout=open( 324 os.devnull) if not self._trace_on else None, 325 stdin=PIPE) 326 327 def terminate(self): 328 if self._proc.poll() is None: 329 # Terminate _proc like it does the pexpect 330 signals_to_try = [ 331 sig for sig in [ 332 'SIGHUP', 333 'SIGCONT', 334 'SIGINT'] if sig in dir(signal)] 335 for sig in signals_to_try: 336 try: 337 self._proc.send_signal(getattr(signal, sig)) 338 time.sleep(self._delayafterterminate) 339 if self._proc.poll() is not None: 340 return 341 except ValueError: 342 pass # Windows says SIGINT is not a valid signal to send 343 self._proc.terminate() 344 time.sleep(self._delayafterterminate) 345 if self._proc.poll() is not None: 346 return 347 self._proc.kill() 348 time.sleep(self._delayafterterminate) 349 350 def poll(self): 351 return self._proc.poll() 352 353 354class _RemoteProcess(_BaseProcess): 355 356 def __init__(self, install_remote): 357 self._pid = None 358 self._install_remote = install_remote 359 360 @property 361 def pid(self): 362 return self._pid 363 364 def launch(self, executable, args): 365 if self._install_remote: 366 src_path = executable 367 dst_path = lldbutil.append_to_process_working_directory( 368 os.path.basename(executable)) 369 370 dst_file_spec = lldb.SBFileSpec(dst_path, False) 371 err = lldb.remote_platform.Install( 372 lldb.SBFileSpec(src_path, True), dst_file_spec) 373 if err.Fail(): 374 raise Exception( 375 "remote_platform.Install('%s', '%s') failed: %s" % 376 (src_path, dst_path, err)) 377 else: 378 dst_path = executable 379 dst_file_spec = lldb.SBFileSpec(executable, False) 380 381 launch_info = lldb.SBLaunchInfo(args) 382 launch_info.SetExecutableFile(dst_file_spec, True) 383 launch_info.SetWorkingDirectory( 384 lldb.remote_platform.GetWorkingDirectory()) 385 386 # Redirect stdout and stderr to /dev/null 387 launch_info.AddSuppressFileAction(1, False, True) 388 launch_info.AddSuppressFileAction(2, False, True) 389 390 err = lldb.remote_platform.Launch(launch_info) 391 if err.Fail(): 392 raise Exception( 393 "remote_platform.Launch('%s', '%s') failed: %s" % 394 (dst_path, args, err)) 395 self._pid = launch_info.GetProcessID() 396 397 def terminate(self): 398 lldb.remote_platform.Kill(self._pid) 399 400# From 2.7's subprocess.check_output() convenience function. 401# Return a tuple (stdoutdata, stderrdata). 402 403 404def system(commands, **kwargs): 405 r"""Run an os command with arguments and return its output as a byte string. 406 407 If the exit code was non-zero it raises a CalledProcessError. The 408 CalledProcessError object will have the return code in the returncode 409 attribute and output in the output attribute. 410 411 The arguments are the same as for the Popen constructor. Example: 412 413 >>> check_output(["ls", "-l", "/dev/null"]) 414 'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n' 415 416 The stdout argument is not allowed as it is used internally. 417 To capture standard error in the result, use stderr=STDOUT. 418 419 >>> check_output(["/bin/sh", "-c", 420 ... "ls -l non_existent_file ; exit 0"], 421 ... stderr=STDOUT) 422 'ls: non_existent_file: No such file or directory\n' 423 """ 424 425 # Assign the sender object to variable 'test' and remove it from kwargs. 426 test = kwargs.pop('sender', None) 427 428 # [['make', 'clean', 'foo'], ['make', 'foo']] -> ['make clean foo', 'make foo'] 429 commandList = [' '.join(x) for x in commands] 430 output = "" 431 error = "" 432 for shellCommand in commandList: 433 if 'stdout' in kwargs: 434 raise ValueError( 435 'stdout argument not allowed, it will be overridden.') 436 if 'shell' in kwargs and kwargs['shell'] == False: 437 raise ValueError('shell=False not allowed') 438 process = Popen( 439 shellCommand, 440 stdout=PIPE, 441 stderr=PIPE, 442 shell=True, 443 universal_newlines=True, 444 **kwargs) 445 pid = process.pid 446 this_output, this_error = process.communicate() 447 retcode = process.poll() 448 449 # Enable trace on failure return while tracking down FreeBSD buildbot 450 # issues 451 trace = traceAlways 452 if not trace and retcode and sys.platform.startswith("freebsd"): 453 trace = True 454 455 with recording(test, trace) as sbuf: 456 print(file=sbuf) 457 print("os command:", shellCommand, file=sbuf) 458 print("with pid:", pid, file=sbuf) 459 print("stdout:", this_output, file=sbuf) 460 print("stderr:", this_error, file=sbuf) 461 print("retcode:", retcode, file=sbuf) 462 print(file=sbuf) 463 464 if retcode: 465 cmd = kwargs.get("args") 466 if cmd is None: 467 cmd = shellCommand 468 cpe = CalledProcessError(retcode, cmd) 469 # Ensure caller can access the stdout/stderr. 470 cpe.lldb_extensions = { 471 "stdout_content": this_output, 472 "stderr_content": this_error, 473 "command": shellCommand 474 } 475 raise cpe 476 output = output + this_output 477 error = error + this_error 478 return (output, error) 479 480 481def getsource_if_available(obj): 482 """ 483 Return the text of the source code for an object if available. Otherwise, 484 a print representation is returned. 485 """ 486 import inspect 487 try: 488 return inspect.getsource(obj) 489 except: 490 return repr(obj) 491 492 493def builder_module(): 494 if sys.platform.startswith("freebsd"): 495 return __import__("builder_freebsd") 496 if sys.platform.startswith("netbsd"): 497 return __import__("builder_netbsd") 498 if sys.platform.startswith("linux"): 499 # sys.platform with Python-3.x returns 'linux', but with 500 # Python-2.x it returns 'linux2'. 501 return __import__("builder_linux") 502 return __import__("builder_" + sys.platform) 503 504 505class Base(unittest2.TestCase): 506 """ 507 Abstract base for performing lldb (see TestBase) or other generic tests (see 508 BenchBase for one example). lldbtest.Base works with the test driver to 509 accomplish things. 510 511 """ 512 513 # The concrete subclass should override this attribute. 514 mydir = None 515 516 # Keep track of the old current working directory. 517 oldcwd = None 518 519 @staticmethod 520 def compute_mydir(test_file): 521 '''Subclasses should call this function to correctly calculate the required "mydir" attribute as follows: 522 523 mydir = TestBase.compute_mydir(__file__)''' 524 test_dir = os.path.dirname(test_file) 525 return test_dir[len(os.environ["LLDB_TEST"]) + 1:] 526 527 def TraceOn(self): 528 """Returns True if we are in trace mode (tracing detailed test execution).""" 529 return traceAlways 530 531 @classmethod 532 def setUpClass(cls): 533 """ 534 Python unittest framework class setup fixture. 535 Do current directory manipulation. 536 """ 537 # Fail fast if 'mydir' attribute is not overridden. 538 if not cls.mydir or len(cls.mydir) == 0: 539 raise Exception("Subclasses must override the 'mydir' attribute.") 540 541 # Save old working directory. 542 cls.oldcwd = os.getcwd() 543 544 # Change current working directory if ${LLDB_TEST} is defined. 545 # See also dotest.py which sets up ${LLDB_TEST}. 546 if ("LLDB_TEST" in os.environ): 547 full_dir = os.path.join(os.environ["LLDB_TEST"], cls.mydir) 548 if traceAlways: 549 print("Change dir to:", full_dir, file=sys.stderr) 550 os.chdir(os.path.join(os.environ["LLDB_TEST"], cls.mydir)) 551 552 if debug_confirm_directory_exclusivity: 553 import lock 554 cls.dir_lock = lock.Lock(os.path.join(full_dir, ".dirlock")) 555 try: 556 cls.dir_lock.try_acquire() 557 # write the class that owns the lock into the lock file 558 cls.dir_lock.handle.write(cls.__name__) 559 except IOError as ioerror: 560 # nothing else should have this directory lock 561 # wait here until we get a lock 562 cls.dir_lock.acquire() 563 # read the previous owner from the lock file 564 lock_id = cls.dir_lock.handle.read() 565 print( 566 "LOCK ERROR: {} wants to lock '{}' but it is already locked by '{}'".format( 567 cls.__name__, 568 full_dir, 569 lock_id), 570 file=sys.stderr) 571 raise ioerror 572 573 # Set platform context. 574 cls.platformContext = lldbplatformutil.createPlatformContext() 575 576 @classmethod 577 def tearDownClass(cls): 578 """ 579 Python unittest framework class teardown fixture. 580 Do class-wide cleanup. 581 """ 582 583 if doCleanup: 584 # First, let's do the platform-specific cleanup. 585 module = builder_module() 586 module.cleanup() 587 588 # Subclass might have specific cleanup function defined. 589 if getattr(cls, "classCleanup", None): 590 if traceAlways: 591 print( 592 "Call class-specific cleanup function for class:", 593 cls, 594 file=sys.stderr) 595 try: 596 cls.classCleanup() 597 except: 598 exc_type, exc_value, exc_tb = sys.exc_info() 599 traceback.print_exception(exc_type, exc_value, exc_tb) 600 601 if debug_confirm_directory_exclusivity: 602 cls.dir_lock.release() 603 del cls.dir_lock 604 605 # Restore old working directory. 606 if traceAlways: 607 print("Restore dir to:", cls.oldcwd, file=sys.stderr) 608 os.chdir(cls.oldcwd) 609 610 @classmethod 611 def skipLongRunningTest(cls): 612 """ 613 By default, we skip long running test case. 614 This can be overridden by passing '-l' to the test driver (dotest.py). 615 """ 616 if "LLDB_SKIP_LONG_RUNNING_TEST" in os.environ and "NO" == os.environ[ 617 "LLDB_SKIP_LONG_RUNNING_TEST"]: 618 return False 619 else: 620 return True 621 622 def enableLogChannelsForCurrentTest(self): 623 if len(lldbtest_config.channels) == 0: 624 return 625 626 # if debug channels are specified in lldbtest_config.channels, 627 # create a new set of log files for every test 628 log_basename = self.getLogBasenameForCurrentTest() 629 630 # confirm that the file is writeable 631 host_log_path = "{}-host.log".format(log_basename) 632 open(host_log_path, 'w').close() 633 634 log_enable = "log enable -Tpn -f {} ".format(host_log_path) 635 for channel_with_categories in lldbtest_config.channels: 636 channel_then_categories = channel_with_categories.split(' ', 1) 637 channel = channel_then_categories[0] 638 if len(channel_then_categories) > 1: 639 categories = channel_then_categories[1] 640 else: 641 categories = "default" 642 643 if channel == "gdb-remote" and lldb.remote_platform is None: 644 # communicate gdb-remote categories to debugserver 645 os.environ["LLDB_DEBUGSERVER_LOG_FLAGS"] = categories 646 647 self.ci.HandleCommand( 648 log_enable + channel_with_categories, self.res) 649 if not self.res.Succeeded(): 650 raise Exception( 651 'log enable failed (check LLDB_LOG_OPTION env variable)') 652 653 # Communicate log path name to debugserver & lldb-server 654 # For remote debugging, these variables need to be set when starting the platform 655 # instance. 656 if lldb.remote_platform is None: 657 server_log_path = "{}-server.log".format(log_basename) 658 open(server_log_path, 'w').close() 659 os.environ["LLDB_DEBUGSERVER_LOG_FILE"] = server_log_path 660 661 # Communicate channels to lldb-server 662 os.environ["LLDB_SERVER_LOG_CHANNELS"] = ":".join( 663 lldbtest_config.channels) 664 665 self.addTearDownHook(self.disableLogChannelsForCurrentTest) 666 667 def disableLogChannelsForCurrentTest(self): 668 # close all log files that we opened 669 for channel_and_categories in lldbtest_config.channels: 670 # channel format - <channel-name> [<category0> [<category1> ...]] 671 channel = channel_and_categories.split(' ', 1)[0] 672 self.ci.HandleCommand("log disable " + channel, self.res) 673 if not self.res.Succeeded(): 674 raise Exception( 675 'log disable failed (check LLDB_LOG_OPTION env variable)') 676 677 # Retrieve the server log (if any) from the remote system. It is assumed the server log 678 # is writing to the "server.log" file in the current test directory. This can be 679 # achieved by setting LLDB_DEBUGSERVER_LOG_FILE="server.log" when starting remote 680 # platform. If the remote logging is not enabled, then just let the Get() command silently 681 # fail. 682 if lldb.remote_platform: 683 lldb.remote_platform.Get( 684 lldb.SBFileSpec("server.log"), lldb.SBFileSpec( 685 self.getLogBasenameForCurrentTest() + "-server.log")) 686 687 def setPlatformWorkingDir(self): 688 if not lldb.remote_platform or not configuration.lldb_platform_working_dir: 689 return 690 691 remote_test_dir = lldbutil.join_remote_paths( 692 configuration.lldb_platform_working_dir, 693 self.getArchitecture(), 694 str(self.test_number), 695 self.mydir) 696 error = lldb.remote_platform.MakeDirectory( 697 remote_test_dir, 448) # 448 = 0o700 698 if error.Success(): 699 lldb.remote_platform.SetWorkingDirectory(remote_test_dir) 700 701 # This function removes all files from the current working directory while leaving 702 # the directories in place. The cleaup is required to reduce the disk space required 703 # by the test suit while leaving the directories untached is neccessary because 704 # sub-directories might belong to an other test 705 def clean_working_directory(): 706 # TODO: Make it working on Windows when we need it for remote debugging support 707 # TODO: Replace the heuristic to remove the files with a logic what collects the 708 # list of files we have to remove during test runs. 709 shell_cmd = lldb.SBPlatformShellCommand( 710 "rm %s/*" % remote_test_dir) 711 lldb.remote_platform.Run(shell_cmd) 712 self.addTearDownHook(clean_working_directory) 713 else: 714 print("error: making remote directory '%s': %s" % ( 715 remote_test_dir, error)) 716 717 def setUp(self): 718 """Fixture for unittest test case setup. 719 720 It works with the test driver to conditionally skip tests and does other 721 initializations.""" 722 #import traceback 723 # traceback.print_stack() 724 725 if "LIBCXX_PATH" in os.environ: 726 self.libcxxPath = os.environ["LIBCXX_PATH"] 727 else: 728 self.libcxxPath = None 729 730 if "LLDBMI_EXEC" in os.environ: 731 self.lldbMiExec = os.environ["LLDBMI_EXEC"] 732 else: 733 self.lldbMiExec = None 734 735 # If we spawn an lldb process for test (via pexpect), do not load the 736 # init file unless told otherwise. 737 if "NO_LLDBINIT" in os.environ and "NO" == os.environ["NO_LLDBINIT"]: 738 self.lldbOption = "" 739 else: 740 self.lldbOption = "--no-lldbinit" 741 742 # Assign the test method name to self.testMethodName. 743 # 744 # For an example of the use of this attribute, look at test/types dir. 745 # There are a bunch of test cases under test/types and we don't want the 746 # module cacheing subsystem to be confused with executable name "a.out" 747 # used for all the test cases. 748 self.testMethodName = self._testMethodName 749 750 # This is for the case of directly spawning 'lldb'/'gdb' and interacting 751 # with it using pexpect. 752 self.child = None 753 self.child_prompt = "(lldb) " 754 # If the child is interacting with the embedded script interpreter, 755 # there are two exits required during tear down, first to quit the 756 # embedded script interpreter and second to quit the lldb command 757 # interpreter. 758 self.child_in_script_interpreter = False 759 760 # These are for customized teardown cleanup. 761 self.dict = None 762 self.doTearDownCleanup = False 763 # And in rare cases where there are multiple teardown cleanups. 764 self.dicts = [] 765 self.doTearDownCleanups = False 766 767 # List of spawned subproces.Popen objects 768 self.subprocesses = [] 769 770 # List of forked process PIDs 771 self.forkedProcessPids = [] 772 773 # Create a string buffer to record the session info, to be dumped into a 774 # test case specific file if test failure is encountered. 775 self.log_basename = self.getLogBasenameForCurrentTest() 776 777 session_file = "{}.log".format(self.log_basename) 778 # Python 3 doesn't support unbuffered I/O in text mode. Open buffered. 779 self.session = encoded_file.open(session_file, "utf-8", mode="w") 780 781 # Optimistically set __errored__, __failed__, __expected__ to False 782 # initially. If the test errored/failed, the session info 783 # (self.session) is then dumped into a session specific file for 784 # diagnosis. 785 self.__cleanup_errored__ = False 786 self.__errored__ = False 787 self.__failed__ = False 788 self.__expected__ = False 789 # We are also interested in unexpected success. 790 self.__unexpected__ = False 791 # And skipped tests. 792 self.__skipped__ = False 793 794 # See addTearDownHook(self, hook) which allows the client to add a hook 795 # function to be run during tearDown() time. 796 self.hooks = [] 797 798 # See HideStdout(self). 799 self.sys_stdout_hidden = False 800 801 if self.platformContext: 802 # set environment variable names for finding shared libraries 803 self.dylibPath = self.platformContext.shlib_environment_var 804 805 # Create the debugger instance if necessary. 806 try: 807 self.dbg = lldb.DBG 808 except AttributeError: 809 self.dbg = lldb.SBDebugger.Create() 810 811 if not self.dbg: 812 raise Exception('Invalid debugger instance') 813 814 # Retrieve the associated command interpreter instance. 815 self.ci = self.dbg.GetCommandInterpreter() 816 if not self.ci: 817 raise Exception('Could not get the command interpreter') 818 819 # And the result object. 820 self.res = lldb.SBCommandReturnObject() 821 822 self.setPlatformWorkingDir() 823 self.enableLogChannelsForCurrentTest() 824 825 # Initialize debug_info 826 self.debug_info = None 827 828 def setAsync(self, value): 829 """ Sets async mode to True/False and ensures it is reset after the testcase completes.""" 830 old_async = self.dbg.GetAsync() 831 self.dbg.SetAsync(value) 832 self.addTearDownHook(lambda: self.dbg.SetAsync(old_async)) 833 834 def cleanupSubprocesses(self): 835 # Ensure any subprocesses are cleaned up 836 for p in self.subprocesses: 837 p.terminate() 838 del p 839 del self.subprocesses[:] 840 # Ensure any forked processes are cleaned up 841 for pid in self.forkedProcessPids: 842 if os.path.exists("/proc/" + str(pid)): 843 os.kill(pid, signal.SIGTERM) 844 845 def spawnSubprocess(self, executable, args=[], install_remote=True): 846 """ Creates a subprocess.Popen object with the specified executable and arguments, 847 saves it in self.subprocesses, and returns the object. 848 NOTE: if using this function, ensure you also call: 849 850 self.addTearDownHook(self.cleanupSubprocesses) 851 852 otherwise the test suite will leak processes. 853 """ 854 proc = _RemoteProcess( 855 install_remote) if lldb.remote_platform else _LocalProcess(self.TraceOn()) 856 proc.launch(executable, args) 857 self.subprocesses.append(proc) 858 return proc 859 860 def forkSubprocess(self, executable, args=[]): 861 """ Fork a subprocess with its own group ID. 862 NOTE: if using this function, ensure you also call: 863 864 self.addTearDownHook(self.cleanupSubprocesses) 865 866 otherwise the test suite will leak processes. 867 """ 868 child_pid = os.fork() 869 if child_pid == 0: 870 # If more I/O support is required, this can be beefed up. 871 fd = os.open(os.devnull, os.O_RDWR) 872 os.dup2(fd, 1) 873 os.dup2(fd, 2) 874 # This call causes the child to have its of group ID 875 os.setpgid(0, 0) 876 os.execvp(executable, [executable] + args) 877 # Give the child time to get through the execvp() call 878 time.sleep(0.1) 879 self.forkedProcessPids.append(child_pid) 880 return child_pid 881 882 def HideStdout(self): 883 """Hide output to stdout from the user. 884 885 During test execution, there might be cases where we don't want to show the 886 standard output to the user. For example, 887 888 self.runCmd(r'''sc print("\n\n\tHello!\n")''') 889 890 tests whether command abbreviation for 'script' works or not. There is no 891 need to show the 'Hello' output to the user as long as the 'script' command 892 succeeds and we are not in TraceOn() mode (see the '-t' option). 893 894 In this case, the test method calls self.HideStdout(self) to redirect the 895 sys.stdout to a null device, and restores the sys.stdout upon teardown. 896 897 Note that you should only call this method at most once during a test case 898 execution. Any subsequent call has no effect at all.""" 899 if self.sys_stdout_hidden: 900 return 901 902 self.sys_stdout_hidden = True 903 old_stdout = sys.stdout 904 sys.stdout = open(os.devnull, 'w') 905 906 def restore_stdout(): 907 sys.stdout = old_stdout 908 self.addTearDownHook(restore_stdout) 909 910 # ======================================================================= 911 # Methods for customized teardown cleanups as well as execution of hooks. 912 # ======================================================================= 913 914 def setTearDownCleanup(self, dictionary=None): 915 """Register a cleanup action at tearDown() time with a dictinary""" 916 self.dict = dictionary 917 self.doTearDownCleanup = True 918 919 def addTearDownCleanup(self, dictionary): 920 """Add a cleanup action at tearDown() time with a dictinary""" 921 self.dicts.append(dictionary) 922 self.doTearDownCleanups = True 923 924 def addTearDownHook(self, hook): 925 """ 926 Add a function to be run during tearDown() time. 927 928 Hooks are executed in a first come first serve manner. 929 """ 930 if six.callable(hook): 931 with recording(self, traceAlways) as sbuf: 932 print( 933 "Adding tearDown hook:", 934 getsource_if_available(hook), 935 file=sbuf) 936 self.hooks.append(hook) 937 938 return self 939 940 def deletePexpectChild(self): 941 # This is for the case of directly spawning 'lldb' and interacting with it 942 # using pexpect. 943 if self.child and self.child.isalive(): 944 import pexpect 945 with recording(self, traceAlways) as sbuf: 946 print("tearing down the child process....", file=sbuf) 947 try: 948 if self.child_in_script_interpreter: 949 self.child.sendline('quit()') 950 self.child.expect_exact(self.child_prompt) 951 self.child.sendline( 952 'settings set interpreter.prompt-on-quit false') 953 self.child.sendline('quit') 954 self.child.expect(pexpect.EOF) 955 except (ValueError, pexpect.ExceptionPexpect): 956 # child is already terminated 957 pass 958 except OSError as exception: 959 import errno 960 if exception.errno != errno.EIO: 961 # unexpected error 962 raise 963 # child is already terminated 964 pass 965 finally: 966 # Give it one final blow to make sure the child is terminated. 967 self.child.close() 968 969 def tearDown(self): 970 """Fixture for unittest test case teardown.""" 971 #import traceback 972 # traceback.print_stack() 973 974 self.deletePexpectChild() 975 976 # Check and run any hook functions. 977 for hook in reversed(self.hooks): 978 with recording(self, traceAlways) as sbuf: 979 print( 980 "Executing tearDown hook:", 981 getsource_if_available(hook), 982 file=sbuf) 983 if funcutils.requires_self(hook): 984 hook(self) 985 else: 986 hook() # try the plain call and hope it works 987 988 del self.hooks 989 990 # Perform registered teardown cleanup. 991 if doCleanup and self.doTearDownCleanup: 992 self.cleanup(dictionary=self.dict) 993 994 # In rare cases where there are multiple teardown cleanups added. 995 if doCleanup and self.doTearDownCleanups: 996 if self.dicts: 997 for dict in reversed(self.dicts): 998 self.cleanup(dictionary=dict) 999 1000 # ========================================================= 1001 # Various callbacks to allow introspection of test progress 1002 # ========================================================= 1003 1004 def markError(self): 1005 """Callback invoked when an error (unexpected exception) errored.""" 1006 self.__errored__ = True 1007 with recording(self, False) as sbuf: 1008 # False because there's no need to write "ERROR" to the stderr twice. 1009 # Once by the Python unittest framework, and a second time by us. 1010 print("ERROR", file=sbuf) 1011 1012 def markCleanupError(self): 1013 """Callback invoked when an error occurs while a test is cleaning up.""" 1014 self.__cleanup_errored__ = True 1015 with recording(self, False) as sbuf: 1016 # False because there's no need to write "CLEANUP_ERROR" to the stderr twice. 1017 # Once by the Python unittest framework, and a second time by us. 1018 print("CLEANUP_ERROR", file=sbuf) 1019 1020 def markFailure(self): 1021 """Callback invoked when a failure (test assertion failure) occurred.""" 1022 self.__failed__ = True 1023 with recording(self, False) as sbuf: 1024 # False because there's no need to write "FAIL" to the stderr twice. 1025 # Once by the Python unittest framework, and a second time by us. 1026 print("FAIL", file=sbuf) 1027 1028 def markExpectedFailure(self, err, bugnumber): 1029 """Callback invoked when an expected failure/error occurred.""" 1030 self.__expected__ = True 1031 with recording(self, False) as sbuf: 1032 # False because there's no need to write "expected failure" to the 1033 # stderr twice. 1034 # Once by the Python unittest framework, and a second time by us. 1035 if bugnumber is None: 1036 print("expected failure", file=sbuf) 1037 else: 1038 print( 1039 "expected failure (problem id:" + str(bugnumber) + ")", 1040 file=sbuf) 1041 1042 def markSkippedTest(self): 1043 """Callback invoked when a test is skipped.""" 1044 self.__skipped__ = True 1045 with recording(self, False) as sbuf: 1046 # False because there's no need to write "skipped test" to the 1047 # stderr twice. 1048 # Once by the Python unittest framework, and a second time by us. 1049 print("skipped test", file=sbuf) 1050 1051 def markUnexpectedSuccess(self, bugnumber): 1052 """Callback invoked when an unexpected success occurred.""" 1053 self.__unexpected__ = True 1054 with recording(self, False) as sbuf: 1055 # False because there's no need to write "unexpected success" to the 1056 # stderr twice. 1057 # Once by the Python unittest framework, and a second time by us. 1058 if bugnumber is None: 1059 print("unexpected success", file=sbuf) 1060 else: 1061 print( 1062 "unexpected success (problem id:" + str(bugnumber) + ")", 1063 file=sbuf) 1064 1065 def getRerunArgs(self): 1066 return " -f %s.%s" % (self.__class__.__name__, self._testMethodName) 1067 1068 def getLogBasenameForCurrentTest(self, prefix=None): 1069 """ 1070 returns a partial path that can be used as the beginning of the name of multiple 1071 log files pertaining to this test 1072 1073 <session-dir>/<arch>-<compiler>-<test-file>.<test-class>.<test-method> 1074 """ 1075 dname = os.path.join(os.environ["LLDB_TEST"], 1076 os.environ["LLDB_SESSION_DIRNAME"]) 1077 if not os.path.isdir(dname): 1078 os.mkdir(dname) 1079 1080 components = [] 1081 if prefix is not None: 1082 components.append(prefix) 1083 for c in configuration.session_file_format: 1084 if c == 'f': 1085 components.append(self.__class__.__module__) 1086 elif c == 'n': 1087 components.append(self.__class__.__name__) 1088 elif c == 'c': 1089 compiler = self.getCompiler() 1090 1091 if compiler[1] == ':': 1092 compiler = compiler[2:] 1093 if os.path.altsep is not None: 1094 compiler = compiler.replace(os.path.altsep, os.path.sep) 1095 components.extend( 1096 [x for x in compiler.split(os.path.sep) if x != ""]) 1097 elif c == 'a': 1098 components.append(self.getArchitecture()) 1099 elif c == 'm': 1100 components.append(self.testMethodName) 1101 fname = "-".join(components) 1102 1103 return os.path.join(dname, fname) 1104 1105 def dumpSessionInfo(self): 1106 """ 1107 Dump the debugger interactions leading to a test error/failure. This 1108 allows for more convenient postmortem analysis. 1109 1110 See also LLDBTestResult (dotest.py) which is a singlton class derived 1111 from TextTestResult and overwrites addError, addFailure, and 1112 addExpectedFailure methods to allow us to to mark the test instance as 1113 such. 1114 """ 1115 1116 # We are here because self.tearDown() detected that this test instance 1117 # either errored or failed. The lldb.test_result singleton contains 1118 # two lists (erros and failures) which get populated by the unittest 1119 # framework. Look over there for stack trace information. 1120 # 1121 # The lists contain 2-tuples of TestCase instances and strings holding 1122 # formatted tracebacks. 1123 # 1124 # See http://docs.python.org/library/unittest.html#unittest.TestResult. 1125 1126 # output tracebacks into session 1127 pairs = [] 1128 if self.__errored__: 1129 pairs = configuration.test_result.errors 1130 prefix = 'Error' 1131 elif self.__cleanup_errored__: 1132 pairs = configuration.test_result.cleanup_errors 1133 prefix = 'CleanupError' 1134 elif self.__failed__: 1135 pairs = configuration.test_result.failures 1136 prefix = 'Failure' 1137 elif self.__expected__: 1138 pairs = configuration.test_result.expectedFailures 1139 prefix = 'ExpectedFailure' 1140 elif self.__skipped__: 1141 prefix = 'SkippedTest' 1142 elif self.__unexpected__: 1143 prefix = 'UnexpectedSuccess' 1144 else: 1145 prefix = 'Success' 1146 1147 if not self.__unexpected__ and not self.__skipped__: 1148 for test, traceback in pairs: 1149 if test is self: 1150 print(traceback, file=self.session) 1151 1152 # put footer (timestamp/rerun instructions) into session 1153 testMethod = getattr(self, self._testMethodName) 1154 if getattr(testMethod, "__benchmarks_test__", False): 1155 benchmarks = True 1156 else: 1157 benchmarks = False 1158 1159 import datetime 1160 print( 1161 "Session info generated @", 1162 datetime.datetime.now().ctime(), 1163 file=self.session) 1164 print( 1165 "To rerun this test, issue the following command from the 'test' directory:\n", 1166 file=self.session) 1167 print( 1168 "./dotest.py %s -v %s %s" % 1169 (self.getRunOptions(), 1170 ('+b' if benchmarks else '-t'), 1171 self.getRerunArgs()), 1172 file=self.session) 1173 self.session.close() 1174 del self.session 1175 1176 # process the log files 1177 log_files_for_this_test = glob.glob(self.log_basename + "*") 1178 1179 if prefix != 'Success' or lldbtest_config.log_success: 1180 # keep all log files, rename them to include prefix 1181 dst_log_basename = self.getLogBasenameForCurrentTest(prefix) 1182 for src in log_files_for_this_test: 1183 if os.path.isfile(src): 1184 dst = src.replace(self.log_basename, dst_log_basename) 1185 if os.name == "nt" and os.path.isfile(dst): 1186 # On Windows, renaming a -> b will throw an exception if b exists. On non-Windows platforms 1187 # it silently replaces the destination. Ultimately this means that atomic renames are not 1188 # guaranteed to be possible on Windows, but we need this to work anyway, so just remove the 1189 # destination first if it already exists. 1190 remove_file(dst) 1191 1192 os.rename(src, dst) 1193 else: 1194 # success! (and we don't want log files) delete log files 1195 for log_file in log_files_for_this_test: 1196 remove_file(log_file) 1197 1198 # ==================================================== 1199 # Config. methods supported through a plugin interface 1200 # (enables reading of the current test configuration) 1201 # ==================================================== 1202 1203 def getArchitecture(self): 1204 """Returns the architecture in effect the test suite is running with.""" 1205 module = builder_module() 1206 arch = module.getArchitecture() 1207 if arch == 'amd64': 1208 arch = 'x86_64' 1209 return arch 1210 1211 def getLldbArchitecture(self): 1212 """Returns the architecture of the lldb binary.""" 1213 if not hasattr(self, 'lldbArchitecture'): 1214 1215 # spawn local process 1216 command = [ 1217 lldbtest_config.lldbExec, 1218 "-o", 1219 "file " + lldbtest_config.lldbExec, 1220 "-o", 1221 "quit" 1222 ] 1223 1224 output = check_output(command) 1225 str = output.decode("utf-8") 1226 1227 for line in str.splitlines(): 1228 m = re.search( 1229 "Current executable set to '.*' \\((.*)\\)\\.", line) 1230 if m: 1231 self.lldbArchitecture = m.group(1) 1232 break 1233 1234 return self.lldbArchitecture 1235 1236 def getCompiler(self): 1237 """Returns the compiler in effect the test suite is running with.""" 1238 module = builder_module() 1239 return module.getCompiler() 1240 1241 def getCompilerBinary(self): 1242 """Returns the compiler binary the test suite is running with.""" 1243 return self.getCompiler().split()[0] 1244 1245 def getCompilerVersion(self): 1246 """ Returns a string that represents the compiler version. 1247 Supports: llvm, clang. 1248 """ 1249 version = 'unknown' 1250 1251 compiler = self.getCompilerBinary() 1252 version_output = system([[compiler, "-v"]])[1] 1253 for line in version_output.split(os.linesep): 1254 m = re.search('version ([0-9\.]+)', line) 1255 if m: 1256 version = m.group(1) 1257 return version 1258 1259 def getGoCompilerVersion(self): 1260 """ Returns a string that represents the go compiler version, or None if go is not found. 1261 """ 1262 compiler = which("go") 1263 if compiler: 1264 version_output = system([[compiler, "version"]])[0] 1265 for line in version_output.split(os.linesep): 1266 m = re.search('go version (devel|go\\S+)', line) 1267 if m: 1268 return m.group(1) 1269 return None 1270 1271 def platformIsDarwin(self): 1272 """Returns true if the OS triple for the selected platform is any valid apple OS""" 1273 return lldbplatformutil.platformIsDarwin() 1274 1275 def getPlatform(self): 1276 """Returns the target platform the test suite is running on.""" 1277 return lldbplatformutil.getPlatform() 1278 1279 def isIntelCompiler(self): 1280 """ Returns true if using an Intel (ICC) compiler, false otherwise. """ 1281 return any([x in self.getCompiler() for x in ["icc", "icpc", "icl"]]) 1282 1283 def expectedCompilerVersion(self, compiler_version): 1284 """Returns True iff compiler_version[1] matches the current compiler version. 1285 Use compiler_version[0] to specify the operator used to determine if a match has occurred. 1286 Any operator other than the following defaults to an equality test: 1287 '>', '>=', "=>", '<', '<=', '=<', '!=', "!" or 'not' 1288 """ 1289 if (compiler_version is None): 1290 return True 1291 operator = str(compiler_version[0]) 1292 version = compiler_version[1] 1293 1294 if (version is None): 1295 return True 1296 if (operator == '>'): 1297 return self.getCompilerVersion() > version 1298 if (operator == '>=' or operator == '=>'): 1299 return self.getCompilerVersion() >= version 1300 if (operator == '<'): 1301 return self.getCompilerVersion() < version 1302 if (operator == '<=' or operator == '=<'): 1303 return self.getCompilerVersion() <= version 1304 if (operator == '!=' or operator == '!' or operator == 'not'): 1305 return str(version) not in str(self.getCompilerVersion()) 1306 return str(version) in str(self.getCompilerVersion()) 1307 1308 def expectedCompiler(self, compilers): 1309 """Returns True iff any element of compilers is a sub-string of the current compiler.""" 1310 if (compilers is None): 1311 return True 1312 1313 for compiler in compilers: 1314 if compiler in self.getCompiler(): 1315 return True 1316 1317 return False 1318 1319 def expectedArch(self, archs): 1320 """Returns True iff any element of archs is a sub-string of the current architecture.""" 1321 if (archs is None): 1322 return True 1323 1324 for arch in archs: 1325 if arch in self.getArchitecture(): 1326 return True 1327 1328 return False 1329 1330 def getRunOptions(self): 1331 """Command line option for -A and -C to run this test again, called from 1332 self.dumpSessionInfo().""" 1333 arch = self.getArchitecture() 1334 comp = self.getCompiler() 1335 if arch: 1336 option_str = "-A " + arch 1337 else: 1338 option_str = "" 1339 if comp: 1340 option_str += " -C " + comp 1341 return option_str 1342 1343 # ================================================== 1344 # Build methods supported through a plugin interface 1345 # ================================================== 1346 1347 def getstdlibFlag(self): 1348 """ Returns the proper -stdlib flag, or empty if not required.""" 1349 if self.platformIsDarwin() or self.getPlatform() == "freebsd": 1350 stdlibflag = "-stdlib=libc++" 1351 else: # this includes NetBSD 1352 stdlibflag = "" 1353 return stdlibflag 1354 1355 def getstdFlag(self): 1356 """ Returns the proper stdflag. """ 1357 if "gcc" in self.getCompiler() and "4.6" in self.getCompilerVersion(): 1358 stdflag = "-std=c++0x" 1359 else: 1360 stdflag = "-std=c++11" 1361 return stdflag 1362 1363 def buildDriver(self, sources, exe_name): 1364 """ Platform-specific way to build a program that links with LLDB (via the liblldb.so 1365 or LLDB.framework). 1366 """ 1367 1368 stdflag = self.getstdFlag() 1369 stdlibflag = self.getstdlibFlag() 1370 1371 lib_dir = os.environ["LLDB_LIB_DIR"] 1372 if sys.platform.startswith("darwin"): 1373 dsym = os.path.join(lib_dir, 'LLDB.framework', 'LLDB') 1374 d = {'CXX_SOURCES': sources, 1375 'EXE': exe_name, 1376 'CFLAGS_EXTRAS': "%s %s" % (stdflag, stdlibflag), 1377 'FRAMEWORK_INCLUDES': "-F%s" % lib_dir, 1378 'LD_EXTRAS': "%s -Wl,-rpath,%s" % (dsym, lib_dir), 1379 } 1380 elif sys.platform.rstrip('0123456789') in ('freebsd', 'linux', 'netbsd') or os.environ.get('LLDB_BUILD_TYPE') == 'Makefile': 1381 d = { 1382 'CXX_SOURCES': sources, 1383 'EXE': exe_name, 1384 'CFLAGS_EXTRAS': "%s %s -I%s" % (stdflag, 1385 stdlibflag, 1386 os.path.join( 1387 os.environ["LLDB_SRC"], 1388 "include")), 1389 'LD_EXTRAS': "-L%s -llldb" % lib_dir} 1390 elif sys.platform.startswith('win'): 1391 d = { 1392 'CXX_SOURCES': sources, 1393 'EXE': exe_name, 1394 'CFLAGS_EXTRAS': "%s %s -I%s" % (stdflag, 1395 stdlibflag, 1396 os.path.join( 1397 os.environ["LLDB_SRC"], 1398 "include")), 1399 'LD_EXTRAS': "-L%s -lliblldb" % os.environ["LLDB_IMPLIB_DIR"]} 1400 if self.TraceOn(): 1401 print( 1402 "Building LLDB Driver (%s) from sources %s" % 1403 (exe_name, sources)) 1404 1405 self.buildDefault(dictionary=d) 1406 1407 def buildLibrary(self, sources, lib_name): 1408 """Platform specific way to build a default library. """ 1409 1410 stdflag = self.getstdFlag() 1411 1412 lib_dir = os.environ["LLDB_LIB_DIR"] 1413 if self.platformIsDarwin(): 1414 dsym = os.path.join(lib_dir, 'LLDB.framework', 'LLDB') 1415 d = {'DYLIB_CXX_SOURCES': sources, 1416 'DYLIB_NAME': lib_name, 1417 'CFLAGS_EXTRAS': "%s -stdlib=libc++" % stdflag, 1418 'FRAMEWORK_INCLUDES': "-F%s" % lib_dir, 1419 'LD_EXTRAS': "%s -Wl,-rpath,%s -dynamiclib" % (dsym, lib_dir), 1420 } 1421 elif self.getPlatform() in ('freebsd', 'linux', 'netbsd') or os.environ.get('LLDB_BUILD_TYPE') == 'Makefile': 1422 d = { 1423 'DYLIB_CXX_SOURCES': sources, 1424 'DYLIB_NAME': lib_name, 1425 'CFLAGS_EXTRAS': "%s -I%s -fPIC" % (stdflag, 1426 os.path.join( 1427 os.environ["LLDB_SRC"], 1428 "include")), 1429 'LD_EXTRAS': "-shared -L%s -llldb" % lib_dir} 1430 elif self.getPlatform() == 'windows': 1431 d = { 1432 'DYLIB_CXX_SOURCES': sources, 1433 'DYLIB_NAME': lib_name, 1434 'CFLAGS_EXTRAS': "%s -I%s -fPIC" % (stdflag, 1435 os.path.join( 1436 os.environ["LLDB_SRC"], 1437 "include")), 1438 'LD_EXTRAS': "-shared -l%s\liblldb.lib" % self.os.environ["LLDB_IMPLIB_DIR"]} 1439 if self.TraceOn(): 1440 print( 1441 "Building LLDB Library (%s) from sources %s" % 1442 (lib_name, sources)) 1443 1444 self.buildDefault(dictionary=d) 1445 1446 def buildProgram(self, sources, exe_name): 1447 """ Platform specific way to build an executable from C/C++ sources. """ 1448 d = {'CXX_SOURCES': sources, 1449 'EXE': exe_name} 1450 self.buildDefault(dictionary=d) 1451 1452 def buildDefault( 1453 self, 1454 architecture=None, 1455 compiler=None, 1456 dictionary=None, 1457 clean=True): 1458 """Platform specific way to build the default binaries.""" 1459 module = builder_module() 1460 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1461 if not module.buildDefault( 1462 self, 1463 architecture, 1464 compiler, 1465 dictionary, 1466 clean): 1467 raise Exception("Don't know how to build default binary") 1468 1469 def buildDsym( 1470 self, 1471 architecture=None, 1472 compiler=None, 1473 dictionary=None, 1474 clean=True): 1475 """Platform specific way to build binaries with dsym info.""" 1476 module = builder_module() 1477 if not module.buildDsym( 1478 self, 1479 architecture, 1480 compiler, 1481 dictionary, 1482 clean): 1483 raise Exception("Don't know how to build binary with dsym") 1484 1485 def buildDwarf( 1486 self, 1487 architecture=None, 1488 compiler=None, 1489 dictionary=None, 1490 clean=True): 1491 """Platform specific way to build binaries with dwarf maps.""" 1492 module = builder_module() 1493 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1494 if not module.buildDwarf( 1495 self, 1496 architecture, 1497 compiler, 1498 dictionary, 1499 clean): 1500 raise Exception("Don't know how to build binary with dwarf") 1501 1502 def buildDwo( 1503 self, 1504 architecture=None, 1505 compiler=None, 1506 dictionary=None, 1507 clean=True): 1508 """Platform specific way to build binaries with dwarf maps.""" 1509 module = builder_module() 1510 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1511 if not module.buildDwo( 1512 self, 1513 architecture, 1514 compiler, 1515 dictionary, 1516 clean): 1517 raise Exception("Don't know how to build binary with dwo") 1518 1519 def buildGModules( 1520 self, 1521 architecture=None, 1522 compiler=None, 1523 dictionary=None, 1524 clean=True): 1525 """Platform specific way to build binaries with gmodules info.""" 1526 module = builder_module() 1527 if not module.buildGModules( 1528 self, 1529 architecture, 1530 compiler, 1531 dictionary, 1532 clean): 1533 raise Exception("Don't know how to build binary with gmodules") 1534 1535 def buildGo(self): 1536 """Build the default go binary. 1537 """ 1538 system([[which('go'), 'build -gcflags "-N -l" -o a.out main.go']]) 1539 1540 def signBinary(self, binary_path): 1541 if sys.platform.startswith("darwin"): 1542 codesign_cmd = "codesign --force --sign lldb_codesign %s" % ( 1543 binary_path) 1544 call(codesign_cmd, shell=True) 1545 1546 def findBuiltClang(self): 1547 """Tries to find and use Clang from the build directory as the compiler (instead of the system compiler).""" 1548 paths_to_try = [ 1549 "llvm-build/Release+Asserts/x86_64/Release+Asserts/bin/clang", 1550 "llvm-build/Debug+Asserts/x86_64/Debug+Asserts/bin/clang", 1551 "llvm-build/Release/x86_64/Release/bin/clang", 1552 "llvm-build/Debug/x86_64/Debug/bin/clang", 1553 ] 1554 lldb_root_path = os.path.join( 1555 os.path.dirname(__file__), "..", "..", "..", "..") 1556 for p in paths_to_try: 1557 path = os.path.join(lldb_root_path, p) 1558 if os.path.exists(path): 1559 return path 1560 1561 # Tries to find clang at the same folder as the lldb 1562 path = os.path.join(os.path.dirname(lldbtest_config.lldbExec), "clang") 1563 if os.path.exists(path): 1564 return path 1565 1566 return os.environ["CC"] 1567 1568 def getBuildFlags( 1569 self, 1570 use_cpp11=True, 1571 use_libcxx=False, 1572 use_libstdcxx=False): 1573 """ Returns a dictionary (which can be provided to build* functions above) which 1574 contains OS-specific build flags. 1575 """ 1576 cflags = "" 1577 ldflags = "" 1578 1579 # On Mac OS X, unless specifically requested to use libstdc++, use 1580 # libc++ 1581 if not use_libstdcxx and self.platformIsDarwin(): 1582 use_libcxx = True 1583 1584 if use_libcxx and self.libcxxPath: 1585 cflags += "-stdlib=libc++ " 1586 if self.libcxxPath: 1587 libcxxInclude = os.path.join(self.libcxxPath, "include") 1588 libcxxLib = os.path.join(self.libcxxPath, "lib") 1589 if os.path.isdir(libcxxInclude) and os.path.isdir(libcxxLib): 1590 cflags += "-nostdinc++ -I%s -L%s -Wl,-rpath,%s " % ( 1591 libcxxInclude, libcxxLib, libcxxLib) 1592 1593 if use_cpp11: 1594 cflags += "-std=" 1595 if "gcc" in self.getCompiler() and "4.6" in self.getCompilerVersion(): 1596 cflags += "c++0x" 1597 else: 1598 cflags += "c++11" 1599 if self.platformIsDarwin() or self.getPlatform() == "freebsd": 1600 cflags += " -stdlib=libc++" 1601 elif self.getPlatform() == "netbsd": 1602 cflags += " -stdlib=libstdc++" 1603 elif "clang" in self.getCompiler(): 1604 cflags += " -stdlib=libstdc++" 1605 1606 return {'CFLAGS_EXTRAS': cflags, 1607 'LD_EXTRAS': ldflags, 1608 } 1609 1610 def cleanup(self, dictionary=None): 1611 """Platform specific way to do cleanup after build.""" 1612 module = builder_module() 1613 if not module.cleanup(self, dictionary): 1614 raise Exception( 1615 "Don't know how to do cleanup with dictionary: " + 1616 dictionary) 1617 1618 def getLLDBLibraryEnvVal(self): 1619 """ Returns the path that the OS-specific library search environment variable 1620 (self.dylibPath) should be set to in order for a program to find the LLDB 1621 library. If an environment variable named self.dylibPath is already set, 1622 the new path is appended to it and returned. 1623 """ 1624 existing_library_path = os.environ[ 1625 self.dylibPath] if self.dylibPath in os.environ else None 1626 lib_dir = os.environ["LLDB_LIB_DIR"] 1627 if existing_library_path: 1628 return "%s:%s" % (existing_library_path, lib_dir) 1629 elif sys.platform.startswith("darwin"): 1630 return os.path.join(lib_dir, 'LLDB.framework') 1631 else: 1632 return lib_dir 1633 1634 def getLibcPlusPlusLibs(self): 1635 if self.getPlatform() in ('freebsd', 'linux', 'netbsd'): 1636 return ['libc++.so.1'] 1637 else: 1638 return ['libc++.1.dylib', 'libc++abi.dylib'] 1639 1640# Metaclass for TestBase to change the list of test metods when a new TestCase is loaded. 1641# We change the test methods to create a new test method for each test for each debug info we are 1642# testing. The name of the new test method will be '<original-name>_<debug-info>' and with adding 1643# the new test method we remove the old method at the same time. This functionality can be 1644# supressed by at test case level setting the class attribute NO_DEBUG_INFO_TESTCASE or at test 1645# level by using the decorator @no_debug_info_test. 1646 1647 1648class LLDBTestCaseFactory(type): 1649 1650 def __new__(cls, name, bases, attrs): 1651 original_testcase = super( 1652 LLDBTestCaseFactory, cls).__new__( 1653 cls, name, bases, attrs) 1654 if original_testcase.NO_DEBUG_INFO_TESTCASE: 1655 return original_testcase 1656 1657 newattrs = {} 1658 for attrname, attrvalue in attrs.items(): 1659 if attrname.startswith("test") and not getattr( 1660 attrvalue, "__no_debug_info_test__", False): 1661 target_platform = lldb.DBG.GetSelectedPlatform( 1662 ).GetTriple().split('-')[2] 1663 1664 # If any debug info categories were explicitly tagged, assume that list to be 1665 # authoritative. If none were specified, try with all debug 1666 # info formats. 1667 all_dbginfo_categories = set( 1668 test_categories.debug_info_categories) 1669 categories = set( 1670 getattr( 1671 attrvalue, 1672 "categories", 1673 [])) & all_dbginfo_categories 1674 if not categories: 1675 categories = all_dbginfo_categories 1676 1677 supported_categories = [ 1678 x for x in categories if test_categories.is_supported_on_platform( 1679 x, target_platform, configuration.compilers)] 1680 if "dsym" in supported_categories: 1681 @decorators.add_test_categories(["dsym"]) 1682 @wraps(attrvalue) 1683 def dsym_test_method(self, attrvalue=attrvalue): 1684 self.debug_info = "dsym" 1685 return attrvalue(self) 1686 dsym_method_name = attrname + "_dsym" 1687 dsym_test_method.__name__ = dsym_method_name 1688 newattrs[dsym_method_name] = dsym_test_method 1689 1690 if "dwarf" in supported_categories: 1691 @decorators.add_test_categories(["dwarf"]) 1692 @wraps(attrvalue) 1693 def dwarf_test_method(self, attrvalue=attrvalue): 1694 self.debug_info = "dwarf" 1695 return attrvalue(self) 1696 dwarf_method_name = attrname + "_dwarf" 1697 dwarf_test_method.__name__ = dwarf_method_name 1698 newattrs[dwarf_method_name] = dwarf_test_method 1699 1700 if "dwo" in supported_categories: 1701 @decorators.add_test_categories(["dwo"]) 1702 @wraps(attrvalue) 1703 def dwo_test_method(self, attrvalue=attrvalue): 1704 self.debug_info = "dwo" 1705 return attrvalue(self) 1706 dwo_method_name = attrname + "_dwo" 1707 dwo_test_method.__name__ = dwo_method_name 1708 newattrs[dwo_method_name] = dwo_test_method 1709 1710 if "gmodules" in supported_categories: 1711 @decorators.add_test_categories(["gmodules"]) 1712 @wraps(attrvalue) 1713 def gmodules_test_method(self, attrvalue=attrvalue): 1714 self.debug_info = "gmodules" 1715 return attrvalue(self) 1716 gmodules_method_name = attrname + "_gmodules" 1717 gmodules_test_method.__name__ = gmodules_method_name 1718 newattrs[gmodules_method_name] = gmodules_test_method 1719 1720 else: 1721 newattrs[attrname] = attrvalue 1722 return super( 1723 LLDBTestCaseFactory, 1724 cls).__new__( 1725 cls, 1726 name, 1727 bases, 1728 newattrs) 1729 1730# Setup the metaclass for this class to change the list of the test 1731# methods when a new class is loaded 1732 1733 1734@add_metaclass(LLDBTestCaseFactory) 1735class TestBase(Base): 1736 """ 1737 This abstract base class is meant to be subclassed. It provides default 1738 implementations for setUpClass(), tearDownClass(), setUp(), and tearDown(), 1739 among other things. 1740 1741 Important things for test class writers: 1742 1743 - Overwrite the mydir class attribute, otherwise your test class won't 1744 run. It specifies the relative directory to the top level 'test' so 1745 the test harness can change to the correct working directory before 1746 running your test. 1747 1748 - The setUp method sets up things to facilitate subsequent interactions 1749 with the debugger as part of the test. These include: 1750 - populate the test method name 1751 - create/get a debugger set with synchronous mode (self.dbg) 1752 - get the command interpreter from with the debugger (self.ci) 1753 - create a result object for use with the command interpreter 1754 (self.res) 1755 - plus other stuffs 1756 1757 - The tearDown method tries to perform some necessary cleanup on behalf 1758 of the test to return the debugger to a good state for the next test. 1759 These include: 1760 - execute any tearDown hooks registered by the test method with 1761 TestBase.addTearDownHook(); examples can be found in 1762 settings/TestSettings.py 1763 - kill the inferior process associated with each target, if any, 1764 and, then delete the target from the debugger's target list 1765 - perform build cleanup before running the next test method in the 1766 same test class; examples of registering for this service can be 1767 found in types/TestIntegerTypes.py with the call: 1768 - self.setTearDownCleanup(dictionary=d) 1769 1770 - Similarly setUpClass and tearDownClass perform classwise setup and 1771 teardown fixtures. The tearDownClass method invokes a default build 1772 cleanup for the entire test class; also, subclasses can implement the 1773 classmethod classCleanup(cls) to perform special class cleanup action. 1774 1775 - The instance methods runCmd and expect are used heavily by existing 1776 test cases to send a command to the command interpreter and to perform 1777 string/pattern matching on the output of such command execution. The 1778 expect method also provides a mode to peform string/pattern matching 1779 without running a command. 1780 1781 - The build methods buildDefault, buildDsym, and buildDwarf are used to 1782 build the binaries used during a particular test scenario. A plugin 1783 should be provided for the sys.platform running the test suite. The 1784 Mac OS X implementation is located in plugins/darwin.py. 1785 """ 1786 1787 # Subclasses can set this to true (if they don't depend on debug info) to avoid running the 1788 # test multiple times with various debug info types. 1789 NO_DEBUG_INFO_TESTCASE = False 1790 1791 # Maximum allowed attempts when launching the inferior process. 1792 # Can be overridden by the LLDB_MAX_LAUNCH_COUNT environment variable. 1793 maxLaunchCount = 3 1794 1795 # Time to wait before the next launching attempt in second(s). 1796 # Can be overridden by the LLDB_TIME_WAIT_NEXT_LAUNCH environment variable. 1797 timeWaitNextLaunch = 1.0 1798 1799 # Returns the list of categories to which this test case belongs 1800 # by default, look for a ".categories" file, and read its contents 1801 # if no such file exists, traverse the hierarchy - we guarantee 1802 # a .categories to exist at the top level directory so we do not end up 1803 # looping endlessly - subclasses are free to define their own categories 1804 # in whatever way makes sense to them 1805 def getCategories(self): 1806 import inspect 1807 import os.path 1808 folder = inspect.getfile(self.__class__) 1809 folder = os.path.dirname(folder) 1810 while folder != '/': 1811 categories_file_name = os.path.join(folder, ".categories") 1812 if os.path.exists(categories_file_name): 1813 categories_file = open(categories_file_name, 'r') 1814 categories = categories_file.readline() 1815 categories_file.close() 1816 categories = str.replace(categories, '\n', '') 1817 categories = str.replace(categories, '\r', '') 1818 return categories.split(',') 1819 else: 1820 folder = os.path.dirname(folder) 1821 continue 1822 1823 def setUp(self): 1824 #import traceback 1825 # traceback.print_stack() 1826 1827 # Works with the test driver to conditionally skip tests via 1828 # decorators. 1829 Base.setUp(self) 1830 1831 if "LLDB_MAX_LAUNCH_COUNT" in os.environ: 1832 self.maxLaunchCount = int(os.environ["LLDB_MAX_LAUNCH_COUNT"]) 1833 1834 if "LLDB_TIME_WAIT_NEXT_LAUNCH" in os.environ: 1835 self.timeWaitNextLaunch = float( 1836 os.environ["LLDB_TIME_WAIT_NEXT_LAUNCH"]) 1837 1838 # We want our debugger to be synchronous. 1839 self.dbg.SetAsync(False) 1840 1841 # Retrieve the associated command interpreter instance. 1842 self.ci = self.dbg.GetCommandInterpreter() 1843 if not self.ci: 1844 raise Exception('Could not get the command interpreter') 1845 1846 # And the result object. 1847 self.res = lldb.SBCommandReturnObject() 1848 1849 def registerSharedLibrariesWithTarget(self, target, shlibs): 1850 '''If we are remotely running the test suite, register the shared libraries with the target so they get uploaded, otherwise do nothing 1851 1852 Any modules in the target that have their remote install file specification set will 1853 get uploaded to the remote host. This function registers the local copies of the 1854 shared libraries with the target and sets their remote install locations so they will 1855 be uploaded when the target is run. 1856 ''' 1857 if not shlibs or not self.platformContext: 1858 return None 1859 1860 shlib_environment_var = self.platformContext.shlib_environment_var 1861 shlib_prefix = self.platformContext.shlib_prefix 1862 shlib_extension = '.' + self.platformContext.shlib_extension 1863 1864 working_dir = self.get_process_working_directory() 1865 environment = ['%s=%s' % (shlib_environment_var, working_dir)] 1866 # Add any shared libraries to our target if remote so they get 1867 # uploaded into the working directory on the remote side 1868 for name in shlibs: 1869 # The path can be a full path to a shared library, or a make file name like "Foo" for 1870 # "libFoo.dylib" or "libFoo.so", or "Foo.so" for "Foo.so" or "libFoo.so", or just a 1871 # basename like "libFoo.so". So figure out which one it is and resolve the local copy 1872 # of the shared library accordingly 1873 if os.path.exists(name): 1874 local_shlib_path = name # name is the full path to the local shared library 1875 else: 1876 # Check relative names 1877 local_shlib_path = os.path.join( 1878 os.getcwd(), shlib_prefix + name + shlib_extension) 1879 if not os.path.exists(local_shlib_path): 1880 local_shlib_path = os.path.join( 1881 os.getcwd(), name + shlib_extension) 1882 if not os.path.exists(local_shlib_path): 1883 local_shlib_path = os.path.join(os.getcwd(), name) 1884 1885 # Make sure we found the local shared library in the above code 1886 self.assertTrue(os.path.exists(local_shlib_path)) 1887 1888 # Add the shared library to our target 1889 shlib_module = target.AddModule(local_shlib_path, None, None, None) 1890 if lldb.remote_platform: 1891 # We must set the remote install location if we want the shared library 1892 # to get uploaded to the remote target 1893 remote_shlib_path = lldbutil.append_to_process_working_directory( 1894 os.path.basename(local_shlib_path)) 1895 shlib_module.SetRemoteInstallFileSpec( 1896 lldb.SBFileSpec(remote_shlib_path, False)) 1897 1898 return environment 1899 1900 # utility methods that tests can use to access the current objects 1901 def target(self): 1902 if not self.dbg: 1903 raise Exception('Invalid debugger instance') 1904 return self.dbg.GetSelectedTarget() 1905 1906 def process(self): 1907 if not self.dbg: 1908 raise Exception('Invalid debugger instance') 1909 return self.dbg.GetSelectedTarget().GetProcess() 1910 1911 def thread(self): 1912 if not self.dbg: 1913 raise Exception('Invalid debugger instance') 1914 return self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread() 1915 1916 def frame(self): 1917 if not self.dbg: 1918 raise Exception('Invalid debugger instance') 1919 return self.dbg.GetSelectedTarget().GetProcess( 1920 ).GetSelectedThread().GetSelectedFrame() 1921 1922 def get_process_working_directory(self): 1923 '''Get the working directory that should be used when launching processes for local or remote processes.''' 1924 if lldb.remote_platform: 1925 # Remote tests set the platform working directory up in 1926 # TestBase.setUp() 1927 return lldb.remote_platform.GetWorkingDirectory() 1928 else: 1929 # local tests change directory into each test subdirectory 1930 return os.getcwd() 1931 1932 def tearDown(self): 1933 #import traceback 1934 # traceback.print_stack() 1935 1936 # Ensure all the references to SB objects have gone away so that we can 1937 # be sure that all test-specific resources have been freed before we 1938 # attempt to delete the targets. 1939 gc.collect() 1940 1941 # Delete the target(s) from the debugger as a general cleanup step. 1942 # This includes terminating the process for each target, if any. 1943 # We'd like to reuse the debugger for our next test without incurring 1944 # the initialization overhead. 1945 targets = [] 1946 for target in self.dbg: 1947 if target: 1948 targets.append(target) 1949 process = target.GetProcess() 1950 if process: 1951 rc = self.invoke(process, "Kill") 1952 self.assertTrue(rc.Success(), PROCESS_KILLED) 1953 for target in targets: 1954 self.dbg.DeleteTarget(target) 1955 1956 # Do this last, to make sure it's in reverse order from how we setup. 1957 Base.tearDown(self) 1958 1959 # This must be the last statement, otherwise teardown hooks or other 1960 # lines might depend on this still being active. 1961 del self.dbg 1962 1963 def switch_to_thread_with_stop_reason(self, stop_reason): 1964 """ 1965 Run the 'thread list' command, and select the thread with stop reason as 1966 'stop_reason'. If no such thread exists, no select action is done. 1967 """ 1968 from .lldbutil import stop_reason_to_str 1969 self.runCmd('thread list') 1970 output = self.res.GetOutput() 1971 thread_line_pattern = re.compile( 1972 "^[ *] thread #([0-9]+):.*stop reason = %s" % 1973 stop_reason_to_str(stop_reason)) 1974 for line in output.splitlines(): 1975 matched = thread_line_pattern.match(line) 1976 if matched: 1977 self.runCmd('thread select %s' % matched.group(1)) 1978 1979 def runCmd(self, cmd, msg=None, check=True, trace=False, inHistory=False): 1980 """ 1981 Ask the command interpreter to handle the command and then check its 1982 return status. 1983 """ 1984 # Fail fast if 'cmd' is not meaningful. 1985 if not cmd or len(cmd) == 0: 1986 raise Exception("Bad 'cmd' parameter encountered") 1987 1988 trace = (True if traceAlways else trace) 1989 1990 if cmd.startswith("target create "): 1991 cmd = cmd.replace("target create ", "file ") 1992 1993 running = (cmd.startswith("run") or cmd.startswith("process launch")) 1994 1995 for i in range(self.maxLaunchCount if running else 1): 1996 self.ci.HandleCommand(cmd, self.res, inHistory) 1997 1998 with recording(self, trace) as sbuf: 1999 print("runCmd:", cmd, file=sbuf) 2000 if not check: 2001 print("check of return status not required", file=sbuf) 2002 if self.res.Succeeded(): 2003 print("output:", self.res.GetOutput(), file=sbuf) 2004 else: 2005 print("runCmd failed!", file=sbuf) 2006 print(self.res.GetError(), file=sbuf) 2007 2008 if self.res.Succeeded(): 2009 break 2010 elif running: 2011 # For process launch, wait some time before possible next try. 2012 time.sleep(self.timeWaitNextLaunch) 2013 with recording(self, trace) as sbuf: 2014 print("Command '" + cmd + "' failed!", file=sbuf) 2015 2016 if check: 2017 self.assertTrue(self.res.Succeeded(), 2018 msg if msg else CMD_MSG(cmd)) 2019 2020 def match( 2021 self, 2022 str, 2023 patterns, 2024 msg=None, 2025 trace=False, 2026 error=False, 2027 matching=True, 2028 exe=True): 2029 """run command in str, and match the result against regexp in patterns returning the match object for the first matching pattern 2030 2031 Otherwise, all the arguments have the same meanings as for the expect function""" 2032 2033 trace = (True if traceAlways else trace) 2034 2035 if exe: 2036 # First run the command. If we are expecting error, set check=False. 2037 # Pass the assert message along since it provides more semantic 2038 # info. 2039 self.runCmd( 2040 str, 2041 msg=msg, 2042 trace=( 2043 True if trace else False), 2044 check=not error) 2045 2046 # Then compare the output against expected strings. 2047 output = self.res.GetError() if error else self.res.GetOutput() 2048 2049 # If error is True, the API client expects the command to fail! 2050 if error: 2051 self.assertFalse(self.res.Succeeded(), 2052 "Command '" + str + "' is expected to fail!") 2053 else: 2054 # No execution required, just compare str against the golden input. 2055 output = str 2056 with recording(self, trace) as sbuf: 2057 print("looking at:", output, file=sbuf) 2058 2059 # The heading says either "Expecting" or "Not expecting". 2060 heading = "Expecting" if matching else "Not expecting" 2061 2062 for pattern in patterns: 2063 # Match Objects always have a boolean value of True. 2064 match_object = re.search(pattern, output) 2065 matched = bool(match_object) 2066 with recording(self, trace) as sbuf: 2067 print("%s pattern: %s" % (heading, pattern), file=sbuf) 2068 print("Matched" if matched else "Not matched", file=sbuf) 2069 if matched: 2070 break 2071 2072 self.assertTrue(matched if matching else not matched, 2073 msg if msg else EXP_MSG(str, output, exe)) 2074 2075 return match_object 2076 2077 def expect( 2078 self, 2079 str, 2080 msg=None, 2081 patterns=None, 2082 startstr=None, 2083 endstr=None, 2084 substrs=None, 2085 trace=False, 2086 error=False, 2087 matching=True, 2088 exe=True, 2089 inHistory=False): 2090 """ 2091 Similar to runCmd; with additional expect style output matching ability. 2092 2093 Ask the command interpreter to handle the command and then check its 2094 return status. The 'msg' parameter specifies an informational assert 2095 message. We expect the output from running the command to start with 2096 'startstr', matches the substrings contained in 'substrs', and regexp 2097 matches the patterns contained in 'patterns'. 2098 2099 If the keyword argument error is set to True, it signifies that the API 2100 client is expecting the command to fail. In this case, the error stream 2101 from running the command is retrieved and compared against the golden 2102 input, instead. 2103 2104 If the keyword argument matching is set to False, it signifies that the API 2105 client is expecting the output of the command not to match the golden 2106 input. 2107 2108 Finally, the required argument 'str' represents the lldb command to be 2109 sent to the command interpreter. In case the keyword argument 'exe' is 2110 set to False, the 'str' is treated as a string to be matched/not-matched 2111 against the golden input. 2112 """ 2113 trace = (True if traceAlways else trace) 2114 2115 if exe: 2116 # First run the command. If we are expecting error, set check=False. 2117 # Pass the assert message along since it provides more semantic 2118 # info. 2119 self.runCmd( 2120 str, 2121 msg=msg, 2122 trace=( 2123 True if trace else False), 2124 check=not error, 2125 inHistory=inHistory) 2126 2127 # Then compare the output against expected strings. 2128 output = self.res.GetError() if error else self.res.GetOutput() 2129 2130 # If error is True, the API client expects the command to fail! 2131 if error: 2132 self.assertFalse(self.res.Succeeded(), 2133 "Command '" + str + "' is expected to fail!") 2134 else: 2135 # No execution required, just compare str against the golden input. 2136 if isinstance(str, lldb.SBCommandReturnObject): 2137 output = str.GetOutput() 2138 else: 2139 output = str 2140 with recording(self, trace) as sbuf: 2141 print("looking at:", output, file=sbuf) 2142 2143 # The heading says either "Expecting" or "Not expecting". 2144 heading = "Expecting" if matching else "Not expecting" 2145 2146 # Start from the startstr, if specified. 2147 # If there's no startstr, set the initial state appropriately. 2148 matched = output.startswith(startstr) if startstr else ( 2149 True if matching else False) 2150 2151 if startstr: 2152 with recording(self, trace) as sbuf: 2153 print("%s start string: %s" % (heading, startstr), file=sbuf) 2154 print("Matched" if matched else "Not matched", file=sbuf) 2155 2156 # Look for endstr, if specified. 2157 keepgoing = matched if matching else not matched 2158 if endstr: 2159 matched = output.endswith(endstr) 2160 with recording(self, trace) as sbuf: 2161 print("%s end string: %s" % (heading, endstr), file=sbuf) 2162 print("Matched" if matched else "Not matched", file=sbuf) 2163 2164 # Look for sub strings, if specified. 2165 keepgoing = matched if matching else not matched 2166 if substrs and keepgoing: 2167 for substr in substrs: 2168 matched = output.find(substr) != -1 2169 with recording(self, trace) as sbuf: 2170 print("%s sub string: %s" % (heading, substr), file=sbuf) 2171 print("Matched" if matched else "Not matched", file=sbuf) 2172 keepgoing = matched if matching else not matched 2173 if not keepgoing: 2174 break 2175 2176 # Search for regular expression patterns, if specified. 2177 keepgoing = matched if matching else not matched 2178 if patterns and keepgoing: 2179 for pattern in patterns: 2180 # Match Objects always have a boolean value of True. 2181 matched = bool(re.search(pattern, output)) 2182 with recording(self, trace) as sbuf: 2183 print("%s pattern: %s" % (heading, pattern), file=sbuf) 2184 print("Matched" if matched else "Not matched", file=sbuf) 2185 keepgoing = matched if matching else not matched 2186 if not keepgoing: 2187 break 2188 2189 self.assertTrue(matched if matching else not matched, 2190 msg if msg else EXP_MSG(str, output, exe)) 2191 2192 def invoke(self, obj, name, trace=False): 2193 """Use reflection to call a method dynamically with no argument.""" 2194 trace = (True if traceAlways else trace) 2195 2196 method = getattr(obj, name) 2197 import inspect 2198 self.assertTrue(inspect.ismethod(method), 2199 name + "is a method name of object: " + str(obj)) 2200 result = method() 2201 with recording(self, trace) as sbuf: 2202 print(str(method) + ":", result, file=sbuf) 2203 return result 2204 2205 def build( 2206 self, 2207 architecture=None, 2208 compiler=None, 2209 dictionary=None, 2210 clean=True): 2211 """Platform specific way to build the default binaries.""" 2212 module = builder_module() 2213 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 2214 if self.debug_info is None: 2215 return self.buildDefault(architecture, compiler, dictionary, clean) 2216 elif self.debug_info == "dsym": 2217 return self.buildDsym(architecture, compiler, dictionary, clean) 2218 elif self.debug_info == "dwarf": 2219 return self.buildDwarf(architecture, compiler, dictionary, clean) 2220 elif self.debug_info == "dwo": 2221 return self.buildDwo(architecture, compiler, dictionary, clean) 2222 elif self.debug_info == "gmodules": 2223 return self.buildGModules( 2224 architecture, compiler, dictionary, clean) 2225 else: 2226 self.fail("Can't build for debug info: %s" % self.debug_info) 2227 2228 def run_platform_command(self, cmd): 2229 platform = self.dbg.GetSelectedPlatform() 2230 shell_command = lldb.SBPlatformShellCommand(cmd) 2231 err = platform.Run(shell_command) 2232 return (err, shell_command.GetStatus(), shell_command.GetOutput()) 2233 2234 # ================================================= 2235 # Misc. helper methods for debugging test execution 2236 # ================================================= 2237 2238 def DebugSBValue(self, val): 2239 """Debug print a SBValue object, if traceAlways is True.""" 2240 from .lldbutil import value_type_to_str 2241 2242 if not traceAlways: 2243 return 2244 2245 err = sys.stderr 2246 err.write(val.GetName() + ":\n") 2247 err.write('\t' + "TypeName -> " + val.GetTypeName() + '\n') 2248 err.write('\t' + "ByteSize -> " + 2249 str(val.GetByteSize()) + '\n') 2250 err.write('\t' + "NumChildren -> " + 2251 str(val.GetNumChildren()) + '\n') 2252 err.write('\t' + "Value -> " + str(val.GetValue()) + '\n') 2253 err.write('\t' + "ValueAsUnsigned -> " + 2254 str(val.GetValueAsUnsigned()) + '\n') 2255 err.write( 2256 '\t' + 2257 "ValueType -> " + 2258 value_type_to_str( 2259 val.GetValueType()) + 2260 '\n') 2261 err.write('\t' + "Summary -> " + str(val.GetSummary()) + '\n') 2262 err.write('\t' + "IsPointerType -> " + 2263 str(val.TypeIsPointerType()) + '\n') 2264 err.write('\t' + "Location -> " + val.GetLocation() + '\n') 2265 2266 def DebugSBType(self, type): 2267 """Debug print a SBType object, if traceAlways is True.""" 2268 if not traceAlways: 2269 return 2270 2271 err = sys.stderr 2272 err.write(type.GetName() + ":\n") 2273 err.write('\t' + "ByteSize -> " + 2274 str(type.GetByteSize()) + '\n') 2275 err.write('\t' + "IsPointerType -> " + 2276 str(type.IsPointerType()) + '\n') 2277 err.write('\t' + "IsReferenceType -> " + 2278 str(type.IsReferenceType()) + '\n') 2279 2280 def DebugPExpect(self, child): 2281 """Debug the spwaned pexpect object.""" 2282 if not traceAlways: 2283 return 2284 2285 print(child) 2286 2287 @classmethod 2288 def RemoveTempFile(cls, file): 2289 if os.path.exists(file): 2290 remove_file(file) 2291 2292# On Windows, the first attempt to delete a recently-touched file can fail 2293# because of a race with antimalware scanners. This function will detect a 2294# failure and retry. 2295 2296 2297def remove_file(file, num_retries=1, sleep_duration=0.5): 2298 for i in range(num_retries + 1): 2299 try: 2300 os.remove(file) 2301 return True 2302 except: 2303 time.sleep(sleep_duration) 2304 continue 2305 return False 2306