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