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