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 lib_dir = os.environ["LLDB_LIB_DIR"] 833 self.dsym = None 834 self.framework_dir = None 835 self.darwinWithFramework = self.platformIsDarwin() 836 if sys.platform.startswith("darwin"): 837 # Handle the framework environment variable if it is set 838 if hasattr(lldbtest_config, 'lldbFrameworkPath'): 839 framework_path = lldbtest_config.lldbFrameworkPath 840 # Framework dir should be the directory containing the framework 841 self.framework_dir = framework_path[:framework_path.rfind('LLDB.framework')] 842 # If a framework dir was not specified assume the Xcode build 843 # directory layout where the framework is in LLDB_LIB_DIR. 844 else: 845 self.framework_dir = lib_dir 846 self.dsym = os.path.join(self.framework_dir, 'LLDB.framework', 'LLDB') 847 # If the framework binary doesn't exist, assume we didn't actually 848 # build a framework, and fallback to standard *nix behavior by 849 # setting framework_dir and dsym to None. 850 if not os.path.exists(self.dsym): 851 self.framework_dir = None 852 self.dsym = None 853 self.darwinWithFramework = False 854 855 def setAsync(self, value): 856 """ Sets async mode to True/False and ensures it is reset after the testcase completes.""" 857 old_async = self.dbg.GetAsync() 858 self.dbg.SetAsync(value) 859 self.addTearDownHook(lambda: self.dbg.SetAsync(old_async)) 860 861 def cleanupSubprocesses(self): 862 # Ensure any subprocesses are cleaned up 863 for p in self.subprocesses: 864 p.terminate() 865 del p 866 del self.subprocesses[:] 867 # Ensure any forked processes are cleaned up 868 for pid in self.forkedProcessPids: 869 if os.path.exists("/proc/" + str(pid)): 870 os.kill(pid, signal.SIGTERM) 871 872 def spawnSubprocess(self, executable, args=[], install_remote=True): 873 """ Creates a subprocess.Popen object with the specified executable and arguments, 874 saves it in self.subprocesses, and returns the object. 875 NOTE: if using this function, ensure you also call: 876 877 self.addTearDownHook(self.cleanupSubprocesses) 878 879 otherwise the test suite will leak processes. 880 """ 881 proc = _RemoteProcess( 882 install_remote) if lldb.remote_platform else _LocalProcess(self.TraceOn()) 883 proc.launch(executable, args) 884 self.subprocesses.append(proc) 885 return proc 886 887 def forkSubprocess(self, executable, args=[]): 888 """ Fork a subprocess with its own group ID. 889 NOTE: if using this function, ensure you also call: 890 891 self.addTearDownHook(self.cleanupSubprocesses) 892 893 otherwise the test suite will leak processes. 894 """ 895 child_pid = os.fork() 896 if child_pid == 0: 897 # If more I/O support is required, this can be beefed up. 898 fd = os.open(os.devnull, os.O_RDWR) 899 os.dup2(fd, 1) 900 os.dup2(fd, 2) 901 # This call causes the child to have its of group ID 902 os.setpgid(0, 0) 903 os.execvp(executable, [executable] + args) 904 # Give the child time to get through the execvp() call 905 time.sleep(0.1) 906 self.forkedProcessPids.append(child_pid) 907 return child_pid 908 909 def HideStdout(self): 910 """Hide output to stdout from the user. 911 912 During test execution, there might be cases where we don't want to show the 913 standard output to the user. For example, 914 915 self.runCmd(r'''sc print("\n\n\tHello!\n")''') 916 917 tests whether command abbreviation for 'script' works or not. There is no 918 need to show the 'Hello' output to the user as long as the 'script' command 919 succeeds and we are not in TraceOn() mode (see the '-t' option). 920 921 In this case, the test method calls self.HideStdout(self) to redirect the 922 sys.stdout to a null device, and restores the sys.stdout upon teardown. 923 924 Note that you should only call this method at most once during a test case 925 execution. Any subsequent call has no effect at all.""" 926 if self.sys_stdout_hidden: 927 return 928 929 self.sys_stdout_hidden = True 930 old_stdout = sys.stdout 931 sys.stdout = open(os.devnull, 'w') 932 933 def restore_stdout(): 934 sys.stdout = old_stdout 935 self.addTearDownHook(restore_stdout) 936 937 # ======================================================================= 938 # Methods for customized teardown cleanups as well as execution of hooks. 939 # ======================================================================= 940 941 def setTearDownCleanup(self, dictionary=None): 942 """Register a cleanup action at tearDown() time with a dictinary""" 943 self.dict = dictionary 944 self.doTearDownCleanup = True 945 946 def addTearDownCleanup(self, dictionary): 947 """Add a cleanup action at tearDown() time with a dictinary""" 948 self.dicts.append(dictionary) 949 self.doTearDownCleanups = True 950 951 def addTearDownHook(self, hook): 952 """ 953 Add a function to be run during tearDown() time. 954 955 Hooks are executed in a first come first serve manner. 956 """ 957 if six.callable(hook): 958 with recording(self, traceAlways) as sbuf: 959 print( 960 "Adding tearDown hook:", 961 getsource_if_available(hook), 962 file=sbuf) 963 self.hooks.append(hook) 964 965 return self 966 967 def deletePexpectChild(self): 968 # This is for the case of directly spawning 'lldb' and interacting with it 969 # using pexpect. 970 if self.child and self.child.isalive(): 971 import pexpect 972 with recording(self, traceAlways) as sbuf: 973 print("tearing down the child process....", file=sbuf) 974 try: 975 if self.child_in_script_interpreter: 976 self.child.sendline('quit()') 977 self.child.expect_exact(self.child_prompt) 978 self.child.sendline( 979 'settings set interpreter.prompt-on-quit false') 980 self.child.sendline('quit') 981 self.child.expect(pexpect.EOF) 982 except (ValueError, pexpect.ExceptionPexpect): 983 # child is already terminated 984 pass 985 except OSError as exception: 986 import errno 987 if exception.errno != errno.EIO: 988 # unexpected error 989 raise 990 # child is already terminated 991 pass 992 finally: 993 # Give it one final blow to make sure the child is terminated. 994 self.child.close() 995 996 def tearDown(self): 997 """Fixture for unittest test case teardown.""" 998 #import traceback 999 # traceback.print_stack() 1000 1001 self.deletePexpectChild() 1002 1003 # Check and run any hook functions. 1004 for hook in reversed(self.hooks): 1005 with recording(self, traceAlways) as sbuf: 1006 print( 1007 "Executing tearDown hook:", 1008 getsource_if_available(hook), 1009 file=sbuf) 1010 if funcutils.requires_self(hook): 1011 hook(self) 1012 else: 1013 hook() # try the plain call and hope it works 1014 1015 del self.hooks 1016 1017 # Perform registered teardown cleanup. 1018 if doCleanup and self.doTearDownCleanup: 1019 self.cleanup(dictionary=self.dict) 1020 1021 # In rare cases where there are multiple teardown cleanups added. 1022 if doCleanup and self.doTearDownCleanups: 1023 if self.dicts: 1024 for dict in reversed(self.dicts): 1025 self.cleanup(dictionary=dict) 1026 1027 # ========================================================= 1028 # Various callbacks to allow introspection of test progress 1029 # ========================================================= 1030 1031 def markError(self): 1032 """Callback invoked when an error (unexpected exception) errored.""" 1033 self.__errored__ = True 1034 with recording(self, False) as sbuf: 1035 # False because there's no need to write "ERROR" to the stderr twice. 1036 # Once by the Python unittest framework, and a second time by us. 1037 print("ERROR", file=sbuf) 1038 1039 def markCleanupError(self): 1040 """Callback invoked when an error occurs while a test is cleaning up.""" 1041 self.__cleanup_errored__ = True 1042 with recording(self, False) as sbuf: 1043 # False because there's no need to write "CLEANUP_ERROR" to the stderr twice. 1044 # Once by the Python unittest framework, and a second time by us. 1045 print("CLEANUP_ERROR", file=sbuf) 1046 1047 def markFailure(self): 1048 """Callback invoked when a failure (test assertion failure) occurred.""" 1049 self.__failed__ = True 1050 with recording(self, False) as sbuf: 1051 # False because there's no need to write "FAIL" to the stderr twice. 1052 # Once by the Python unittest framework, and a second time by us. 1053 print("FAIL", file=sbuf) 1054 1055 def markExpectedFailure(self, err, bugnumber): 1056 """Callback invoked when an expected failure/error occurred.""" 1057 self.__expected__ = True 1058 with recording(self, False) as sbuf: 1059 # False because there's no need to write "expected failure" 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("expected failure", file=sbuf) 1064 else: 1065 print( 1066 "expected failure (problem id:" + str(bugnumber) + ")", 1067 file=sbuf) 1068 1069 def markSkippedTest(self): 1070 """Callback invoked when a test is skipped.""" 1071 self.__skipped__ = True 1072 with recording(self, False) as sbuf: 1073 # False because there's no need to write "skipped test" to the 1074 # stderr twice. 1075 # Once by the Python unittest framework, and a second time by us. 1076 print("skipped test", file=sbuf) 1077 1078 def markUnexpectedSuccess(self, bugnumber): 1079 """Callback invoked when an unexpected success occurred.""" 1080 self.__unexpected__ = True 1081 with recording(self, False) as sbuf: 1082 # False because there's no need to write "unexpected success" to the 1083 # stderr twice. 1084 # Once by the Python unittest framework, and a second time by us. 1085 if bugnumber is None: 1086 print("unexpected success", file=sbuf) 1087 else: 1088 print( 1089 "unexpected success (problem id:" + str(bugnumber) + ")", 1090 file=sbuf) 1091 1092 def getRerunArgs(self): 1093 return " -f %s.%s" % (self.__class__.__name__, self._testMethodName) 1094 1095 def getLogBasenameForCurrentTest(self, prefix=None): 1096 """ 1097 returns a partial path that can be used as the beginning of the name of multiple 1098 log files pertaining to this test 1099 1100 <session-dir>/<arch>-<compiler>-<test-file>.<test-class>.<test-method> 1101 """ 1102 dname = os.path.join(os.environ["LLDB_TEST"], 1103 os.environ["LLDB_SESSION_DIRNAME"]) 1104 if not os.path.isdir(dname): 1105 os.mkdir(dname) 1106 1107 components = [] 1108 if prefix is not None: 1109 components.append(prefix) 1110 for c in configuration.session_file_format: 1111 if c == 'f': 1112 components.append(self.__class__.__module__) 1113 elif c == 'n': 1114 components.append(self.__class__.__name__) 1115 elif c == 'c': 1116 compiler = self.getCompiler() 1117 1118 if compiler[1] == ':': 1119 compiler = compiler[2:] 1120 if os.path.altsep is not None: 1121 compiler = compiler.replace(os.path.altsep, os.path.sep) 1122 components.extend( 1123 [x for x in compiler.split(os.path.sep) if x != ""]) 1124 elif c == 'a': 1125 components.append(self.getArchitecture()) 1126 elif c == 'm': 1127 components.append(self.testMethodName) 1128 fname = "-".join(components) 1129 1130 return os.path.join(dname, fname) 1131 1132 def dumpSessionInfo(self): 1133 """ 1134 Dump the debugger interactions leading to a test error/failure. This 1135 allows for more convenient postmortem analysis. 1136 1137 See also LLDBTestResult (dotest.py) which is a singlton class derived 1138 from TextTestResult and overwrites addError, addFailure, and 1139 addExpectedFailure methods to allow us to to mark the test instance as 1140 such. 1141 """ 1142 1143 # We are here because self.tearDown() detected that this test instance 1144 # either errored or failed. The lldb.test_result singleton contains 1145 # two lists (erros and failures) which get populated by the unittest 1146 # framework. Look over there for stack trace information. 1147 # 1148 # The lists contain 2-tuples of TestCase instances and strings holding 1149 # formatted tracebacks. 1150 # 1151 # See http://docs.python.org/library/unittest.html#unittest.TestResult. 1152 1153 # output tracebacks into session 1154 pairs = [] 1155 if self.__errored__: 1156 pairs = configuration.test_result.errors 1157 prefix = 'Error' 1158 elif self.__cleanup_errored__: 1159 pairs = configuration.test_result.cleanup_errors 1160 prefix = 'CleanupError' 1161 elif self.__failed__: 1162 pairs = configuration.test_result.failures 1163 prefix = 'Failure' 1164 elif self.__expected__: 1165 pairs = configuration.test_result.expectedFailures 1166 prefix = 'ExpectedFailure' 1167 elif self.__skipped__: 1168 prefix = 'SkippedTest' 1169 elif self.__unexpected__: 1170 prefix = 'UnexpectedSuccess' 1171 else: 1172 prefix = 'Success' 1173 1174 if not self.__unexpected__ and not self.__skipped__: 1175 for test, traceback in pairs: 1176 if test is self: 1177 print(traceback, file=self.session) 1178 1179 # put footer (timestamp/rerun instructions) into session 1180 testMethod = getattr(self, self._testMethodName) 1181 if getattr(testMethod, "__benchmarks_test__", False): 1182 benchmarks = True 1183 else: 1184 benchmarks = False 1185 1186 import datetime 1187 print( 1188 "Session info generated @", 1189 datetime.datetime.now().ctime(), 1190 file=self.session) 1191 print( 1192 "To rerun this test, issue the following command from the 'test' directory:\n", 1193 file=self.session) 1194 print( 1195 "./dotest.py %s -v %s %s" % 1196 (self.getRunOptions(), 1197 ('+b' if benchmarks else '-t'), 1198 self.getRerunArgs()), 1199 file=self.session) 1200 self.session.close() 1201 del self.session 1202 1203 # process the log files 1204 log_files_for_this_test = glob.glob(self.log_basename + "*") 1205 1206 if prefix != 'Success' or lldbtest_config.log_success: 1207 # keep all log files, rename them to include prefix 1208 dst_log_basename = self.getLogBasenameForCurrentTest(prefix) 1209 for src in log_files_for_this_test: 1210 if os.path.isfile(src): 1211 dst = src.replace(self.log_basename, dst_log_basename) 1212 if os.name == "nt" and os.path.isfile(dst): 1213 # On Windows, renaming a -> b will throw an exception if b exists. On non-Windows platforms 1214 # it silently replaces the destination. Ultimately this means that atomic renames are not 1215 # guaranteed to be possible on Windows, but we need this to work anyway, so just remove the 1216 # destination first if it already exists. 1217 remove_file(dst) 1218 1219 os.rename(src, dst) 1220 else: 1221 # success! (and we don't want log files) delete log files 1222 for log_file in log_files_for_this_test: 1223 remove_file(log_file) 1224 1225 # ==================================================== 1226 # Config. methods supported through a plugin interface 1227 # (enables reading of the current test configuration) 1228 # ==================================================== 1229 1230 def getArchitecture(self): 1231 """Returns the architecture in effect the test suite is running with.""" 1232 module = builder_module() 1233 arch = module.getArchitecture() 1234 if arch == 'amd64': 1235 arch = 'x86_64' 1236 return arch 1237 1238 def getLldbArchitecture(self): 1239 """Returns the architecture of the lldb binary.""" 1240 if not hasattr(self, 'lldbArchitecture'): 1241 1242 # spawn local process 1243 command = [ 1244 lldbtest_config.lldbExec, 1245 "-o", 1246 "file " + lldbtest_config.lldbExec, 1247 "-o", 1248 "quit" 1249 ] 1250 1251 output = check_output(command) 1252 str = output.decode("utf-8") 1253 1254 for line in str.splitlines(): 1255 m = re.search( 1256 "Current executable set to '.*' \\((.*)\\)\\.", line) 1257 if m: 1258 self.lldbArchitecture = m.group(1) 1259 break 1260 1261 return self.lldbArchitecture 1262 1263 def getCompiler(self): 1264 """Returns the compiler in effect the test suite is running with.""" 1265 module = builder_module() 1266 return module.getCompiler() 1267 1268 def getCompilerBinary(self): 1269 """Returns the compiler binary the test suite is running with.""" 1270 return self.getCompiler().split()[0] 1271 1272 def getCompilerVersion(self): 1273 """ Returns a string that represents the compiler version. 1274 Supports: llvm, clang. 1275 """ 1276 version = 'unknown' 1277 1278 compiler = self.getCompilerBinary() 1279 version_output = system([[compiler, "-v"]])[1] 1280 for line in version_output.split(os.linesep): 1281 m = re.search('version ([0-9\.]+)', line) 1282 if m: 1283 version = m.group(1) 1284 return version 1285 1286 def getGoCompilerVersion(self): 1287 """ Returns a string that represents the go compiler version, or None if go is not found. 1288 """ 1289 compiler = which("go") 1290 if compiler: 1291 version_output = system([[compiler, "version"]])[0] 1292 for line in version_output.split(os.linesep): 1293 m = re.search('go version (devel|go\\S+)', line) 1294 if m: 1295 return m.group(1) 1296 return None 1297 1298 def platformIsDarwin(self): 1299 """Returns true if the OS triple for the selected platform is any valid apple OS""" 1300 return lldbplatformutil.platformIsDarwin() 1301 1302 def hasDarwinFramework(self): 1303 return self.darwinWithFramework 1304 1305 def getPlatform(self): 1306 """Returns the target platform the test suite is running on.""" 1307 return lldbplatformutil.getPlatform() 1308 1309 def isIntelCompiler(self): 1310 """ Returns true if using an Intel (ICC) compiler, false otherwise. """ 1311 return any([x in self.getCompiler() for x in ["icc", "icpc", "icl"]]) 1312 1313 def expectedCompilerVersion(self, compiler_version): 1314 """Returns True iff compiler_version[1] matches the current compiler version. 1315 Use compiler_version[0] to specify the operator used to determine if a match has occurred. 1316 Any operator other than the following defaults to an equality test: 1317 '>', '>=', "=>", '<', '<=', '=<', '!=', "!" or 'not' 1318 """ 1319 if (compiler_version is None): 1320 return True 1321 operator = str(compiler_version[0]) 1322 version = compiler_version[1] 1323 1324 if (version is None): 1325 return True 1326 if (operator == '>'): 1327 return self.getCompilerVersion() > version 1328 if (operator == '>=' or operator == '=>'): 1329 return self.getCompilerVersion() >= version 1330 if (operator == '<'): 1331 return self.getCompilerVersion() < version 1332 if (operator == '<=' or operator == '=<'): 1333 return self.getCompilerVersion() <= version 1334 if (operator == '!=' or operator == '!' or operator == 'not'): 1335 return str(version) not in str(self.getCompilerVersion()) 1336 return str(version) in str(self.getCompilerVersion()) 1337 1338 def expectedCompiler(self, compilers): 1339 """Returns True iff any element of compilers is a sub-string of the current compiler.""" 1340 if (compilers is None): 1341 return True 1342 1343 for compiler in compilers: 1344 if compiler in self.getCompiler(): 1345 return True 1346 1347 return False 1348 1349 def expectedArch(self, archs): 1350 """Returns True iff any element of archs is a sub-string of the current architecture.""" 1351 if (archs is None): 1352 return True 1353 1354 for arch in archs: 1355 if arch in self.getArchitecture(): 1356 return True 1357 1358 return False 1359 1360 def getRunOptions(self): 1361 """Command line option for -A and -C to run this test again, called from 1362 self.dumpSessionInfo().""" 1363 arch = self.getArchitecture() 1364 comp = self.getCompiler() 1365 if arch: 1366 option_str = "-A " + arch 1367 else: 1368 option_str = "" 1369 if comp: 1370 option_str += " -C " + comp 1371 return option_str 1372 1373 # ================================================== 1374 # Build methods supported through a plugin interface 1375 # ================================================== 1376 1377 def getstdlibFlag(self): 1378 """ Returns the proper -stdlib flag, or empty if not required.""" 1379 if self.platformIsDarwin() or self.getPlatform() == "freebsd": 1380 stdlibflag = "-stdlib=libc++" 1381 else: # this includes NetBSD 1382 stdlibflag = "" 1383 return stdlibflag 1384 1385 def getstdFlag(self): 1386 """ Returns the proper stdflag. """ 1387 if "gcc" in self.getCompiler() and "4.6" in self.getCompilerVersion(): 1388 stdflag = "-std=c++0x" 1389 else: 1390 stdflag = "-std=c++11" 1391 return stdflag 1392 1393 def buildDriver(self, sources, exe_name): 1394 """ Platform-specific way to build a program that links with LLDB (via the liblldb.so 1395 or LLDB.framework). 1396 """ 1397 1398 stdflag = self.getstdFlag() 1399 stdlibflag = self.getstdlibFlag() 1400 1401 lib_dir = os.environ["LLDB_LIB_DIR"] 1402 if self.hasDarwinFramework(): 1403 d = {'CXX_SOURCES': sources, 1404 'EXE': exe_name, 1405 'CFLAGS_EXTRAS': "%s %s" % (stdflag, stdlibflag), 1406 'FRAMEWORK_INCLUDES': "-F%s" % self.framework_dir, 1407 'LD_EXTRAS': "%s -Wl,-rpath,%s" % (self.dsym, self.framework_dir), 1408 } 1409 elif sys.platform.rstrip('0123456789') in ('freebsd', 'linux', 'netbsd', 'darwin') or os.environ.get('LLDB_BUILD_TYPE') == 'Makefile': 1410 d = { 1411 'CXX_SOURCES': sources, 1412 'EXE': exe_name, 1413 'CFLAGS_EXTRAS': "%s %s -I%s" % (stdflag, 1414 stdlibflag, 1415 os.path.join( 1416 os.environ["LLDB_SRC"], 1417 "include")), 1418 'LD_EXTRAS': "-L%s/../lib -llldb -Wl,-rpath,%s/../lib" % (lib_dir, lib_dir)} 1419 elif sys.platform.startswith('win'): 1420 d = { 1421 'CXX_SOURCES': sources, 1422 'EXE': exe_name, 1423 'CFLAGS_EXTRAS': "%s %s -I%s" % (stdflag, 1424 stdlibflag, 1425 os.path.join( 1426 os.environ["LLDB_SRC"], 1427 "include")), 1428 'LD_EXTRAS': "-L%s -lliblldb" % os.environ["LLDB_IMPLIB_DIR"]} 1429 if self.TraceOn(): 1430 print( 1431 "Building LLDB Driver (%s) from sources %s" % 1432 (exe_name, sources)) 1433 1434 self.buildDefault(dictionary=d) 1435 1436 def buildLibrary(self, sources, lib_name): 1437 """Platform specific way to build a default library. """ 1438 1439 stdflag = self.getstdFlag() 1440 1441 lib_dir = os.environ["LLDB_LIB_DIR"] 1442 if self.hasDarwinFramework(): 1443 d = {'DYLIB_CXX_SOURCES': sources, 1444 'DYLIB_NAME': lib_name, 1445 'CFLAGS_EXTRAS': "%s -stdlib=libc++" % stdflag, 1446 'FRAMEWORK_INCLUDES': "-F%s" % self.framework_dir, 1447 'LD_EXTRAS': "%s -Wl,-rpath,%s -dynamiclib" % (self.dsym, self.framework_dir), 1448 } 1449 elif sys.platform.rstrip('0123456789') in ('freebsd', 'linux', 'netbsd', 'darwin') or os.environ.get('LLDB_BUILD_TYPE') == 'Makefile': 1450 d = { 1451 'DYLIB_CXX_SOURCES': sources, 1452 'DYLIB_NAME': lib_name, 1453 'CFLAGS_EXTRAS': "%s -I%s -fPIC" % (stdflag, 1454 os.path.join( 1455 os.environ["LLDB_SRC"], 1456 "include")), 1457 'LD_EXTRAS': "-shared -L%s/../lib -llldb -Wl,-rpath,%s/../lib" % (lib_dir, lib_dir)} 1458 elif self.getPlatform() == 'windows': 1459 d = { 1460 'DYLIB_CXX_SOURCES': sources, 1461 'DYLIB_NAME': lib_name, 1462 'CFLAGS_EXTRAS': "%s -I%s -fPIC" % (stdflag, 1463 os.path.join( 1464 os.environ["LLDB_SRC"], 1465 "include")), 1466 'LD_EXTRAS': "-shared -l%s\liblldb.lib" % self.os.environ["LLDB_IMPLIB_DIR"]} 1467 if self.TraceOn(): 1468 print( 1469 "Building LLDB Library (%s) from sources %s" % 1470 (lib_name, sources)) 1471 1472 self.buildDefault(dictionary=d) 1473 1474 def buildProgram(self, sources, exe_name): 1475 """ Platform specific way to build an executable from C/C++ sources. """ 1476 d = {'CXX_SOURCES': sources, 1477 'EXE': exe_name} 1478 self.buildDefault(dictionary=d) 1479 1480 def buildDefault( 1481 self, 1482 architecture=None, 1483 compiler=None, 1484 dictionary=None, 1485 clean=True): 1486 """Platform specific way to build the default binaries.""" 1487 module = builder_module() 1488 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1489 if not module.buildDefault( 1490 self, 1491 architecture, 1492 compiler, 1493 dictionary, 1494 clean): 1495 raise Exception("Don't know how to build default binary") 1496 1497 def buildDsym( 1498 self, 1499 architecture=None, 1500 compiler=None, 1501 dictionary=None, 1502 clean=True): 1503 """Platform specific way to build binaries with dsym info.""" 1504 module = builder_module() 1505 if not module.buildDsym( 1506 self, 1507 architecture, 1508 compiler, 1509 dictionary, 1510 clean): 1511 raise Exception("Don't know how to build binary with dsym") 1512 1513 def buildDwarf( 1514 self, 1515 architecture=None, 1516 compiler=None, 1517 dictionary=None, 1518 clean=True): 1519 """Platform specific way to build binaries with dwarf maps.""" 1520 module = builder_module() 1521 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1522 if not module.buildDwarf( 1523 self, 1524 architecture, 1525 compiler, 1526 dictionary, 1527 clean): 1528 raise Exception("Don't know how to build binary with dwarf") 1529 1530 def buildDwo( 1531 self, 1532 architecture=None, 1533 compiler=None, 1534 dictionary=None, 1535 clean=True): 1536 """Platform specific way to build binaries with dwarf maps.""" 1537 module = builder_module() 1538 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 1539 if not module.buildDwo( 1540 self, 1541 architecture, 1542 compiler, 1543 dictionary, 1544 clean): 1545 raise Exception("Don't know how to build binary with dwo") 1546 1547 def buildGModules( 1548 self, 1549 architecture=None, 1550 compiler=None, 1551 dictionary=None, 1552 clean=True): 1553 """Platform specific way to build binaries with gmodules info.""" 1554 module = builder_module() 1555 if not module.buildGModules( 1556 self, 1557 architecture, 1558 compiler, 1559 dictionary, 1560 clean): 1561 raise Exception("Don't know how to build binary with gmodules") 1562 1563 def buildGo(self): 1564 """Build the default go binary. 1565 """ 1566 system([[which('go'), 'build -gcflags "-N -l" -o a.out main.go']]) 1567 1568 def signBinary(self, binary_path): 1569 if sys.platform.startswith("darwin"): 1570 codesign_cmd = "codesign --force --sign \"%s\" %s" % ( 1571 lldbtest_config.codesign_identity, binary_path) 1572 call(codesign_cmd, shell=True) 1573 1574 def findBuiltClang(self): 1575 """Tries to find and use Clang from the build directory as the compiler (instead of the system compiler).""" 1576 paths_to_try = [ 1577 "llvm-build/Release+Asserts/x86_64/Release+Asserts/bin/clang", 1578 "llvm-build/Debug+Asserts/x86_64/Debug+Asserts/bin/clang", 1579 "llvm-build/Release/x86_64/Release/bin/clang", 1580 "llvm-build/Debug/x86_64/Debug/bin/clang", 1581 ] 1582 lldb_root_path = os.path.join( 1583 os.path.dirname(__file__), "..", "..", "..", "..") 1584 for p in paths_to_try: 1585 path = os.path.join(lldb_root_path, p) 1586 if os.path.exists(path): 1587 return path 1588 1589 # Tries to find clang at the same folder as the lldb 1590 path = os.path.join(os.path.dirname(lldbtest_config.lldbExec), "clang") 1591 if os.path.exists(path): 1592 return path 1593 1594 return os.environ["CC"] 1595 1596 def getBuildFlags( 1597 self, 1598 use_cpp11=True, 1599 use_libcxx=False, 1600 use_libstdcxx=False): 1601 """ Returns a dictionary (which can be provided to build* functions above) which 1602 contains OS-specific build flags. 1603 """ 1604 cflags = "" 1605 ldflags = "" 1606 1607 # On Mac OS X, unless specifically requested to use libstdc++, use 1608 # libc++ 1609 if not use_libstdcxx and self.platformIsDarwin(): 1610 use_libcxx = True 1611 1612 if use_libcxx and self.libcxxPath: 1613 cflags += "-stdlib=libc++ " 1614 if self.libcxxPath: 1615 libcxxInclude = os.path.join(self.libcxxPath, "include") 1616 libcxxLib = os.path.join(self.libcxxPath, "lib") 1617 if os.path.isdir(libcxxInclude) and os.path.isdir(libcxxLib): 1618 cflags += "-nostdinc++ -I%s -L%s -Wl,-rpath,%s " % ( 1619 libcxxInclude, libcxxLib, libcxxLib) 1620 1621 if use_cpp11: 1622 cflags += "-std=" 1623 if "gcc" in self.getCompiler() and "4.6" in self.getCompilerVersion(): 1624 cflags += "c++0x" 1625 else: 1626 cflags += "c++11" 1627 if self.platformIsDarwin() or self.getPlatform() == "freebsd": 1628 cflags += " -stdlib=libc++" 1629 elif self.getPlatform() == "netbsd": 1630 cflags += " -stdlib=libstdc++" 1631 elif "clang" in self.getCompiler(): 1632 cflags += " -stdlib=libstdc++" 1633 1634 return {'CFLAGS_EXTRAS': cflags, 1635 'LD_EXTRAS': ldflags, 1636 } 1637 1638 def cleanup(self, dictionary=None): 1639 """Platform specific way to do cleanup after build.""" 1640 module = builder_module() 1641 if not module.cleanup(self, dictionary): 1642 raise Exception( 1643 "Don't know how to do cleanup with dictionary: " + 1644 dictionary) 1645 1646 def getLLDBLibraryEnvVal(self): 1647 """ Returns the path that the OS-specific library search environment variable 1648 (self.dylibPath) should be set to in order for a program to find the LLDB 1649 library. If an environment variable named self.dylibPath is already set, 1650 the new path is appended to it and returned. 1651 """ 1652 existing_library_path = os.environ[ 1653 self.dylibPath] if self.dylibPath in os.environ else None 1654 lib_dir = os.environ["LLDB_LIB_DIR"] 1655 if existing_library_path: 1656 return "%s:%s" % (existing_library_path, lib_dir) 1657 elif sys.platform.startswith("darwin"): 1658 return os.path.join(lib_dir, 'LLDB.framework') 1659 else: 1660 return lib_dir 1661 1662 def getLibcPlusPlusLibs(self): 1663 if self.getPlatform() in ('freebsd', 'linux', 'netbsd'): 1664 return ['libc++.so.1'] 1665 else: 1666 return ['libc++.1.dylib', 'libc++abi.dylib'] 1667 1668# Metaclass for TestBase to change the list of test metods when a new TestCase is loaded. 1669# We change the test methods to create a new test method for each test for each debug info we are 1670# testing. The name of the new test method will be '<original-name>_<debug-info>' and with adding 1671# the new test method we remove the old method at the same time. This functionality can be 1672# supressed by at test case level setting the class attribute NO_DEBUG_INFO_TESTCASE or at test 1673# level by using the decorator @no_debug_info_test. 1674 1675 1676class LLDBTestCaseFactory(type): 1677 1678 def __new__(cls, name, bases, attrs): 1679 original_testcase = super( 1680 LLDBTestCaseFactory, cls).__new__( 1681 cls, name, bases, attrs) 1682 if original_testcase.NO_DEBUG_INFO_TESTCASE: 1683 return original_testcase 1684 1685 newattrs = {} 1686 for attrname, attrvalue in attrs.items(): 1687 if attrname.startswith("test") and not getattr( 1688 attrvalue, "__no_debug_info_test__", False): 1689 target_platform = lldb.DBG.GetSelectedPlatform( 1690 ).GetTriple().split('-')[2] 1691 1692 # If any debug info categories were explicitly tagged, assume that list to be 1693 # authoritative. If none were specified, try with all debug 1694 # info formats. 1695 all_dbginfo_categories = set( 1696 test_categories.debug_info_categories) 1697 categories = set( 1698 getattr( 1699 attrvalue, 1700 "categories", 1701 [])) & all_dbginfo_categories 1702 if not categories: 1703 categories = all_dbginfo_categories 1704 1705 supported_categories = [ 1706 x for x in categories if test_categories.is_supported_on_platform( 1707 x, target_platform, configuration.compilers)] 1708 if "dsym" in supported_categories: 1709 @decorators.add_test_categories(["dsym"]) 1710 @wraps(attrvalue) 1711 def dsym_test_method(self, attrvalue=attrvalue): 1712 self.debug_info = "dsym" 1713 return attrvalue(self) 1714 dsym_method_name = attrname + "_dsym" 1715 dsym_test_method.__name__ = dsym_method_name 1716 newattrs[dsym_method_name] = dsym_test_method 1717 1718 if "dwarf" in supported_categories: 1719 @decorators.add_test_categories(["dwarf"]) 1720 @wraps(attrvalue) 1721 def dwarf_test_method(self, attrvalue=attrvalue): 1722 self.debug_info = "dwarf" 1723 return attrvalue(self) 1724 dwarf_method_name = attrname + "_dwarf" 1725 dwarf_test_method.__name__ = dwarf_method_name 1726 newattrs[dwarf_method_name] = dwarf_test_method 1727 1728 if "dwo" in supported_categories: 1729 @decorators.add_test_categories(["dwo"]) 1730 @wraps(attrvalue) 1731 def dwo_test_method(self, attrvalue=attrvalue): 1732 self.debug_info = "dwo" 1733 return attrvalue(self) 1734 dwo_method_name = attrname + "_dwo" 1735 dwo_test_method.__name__ = dwo_method_name 1736 newattrs[dwo_method_name] = dwo_test_method 1737 1738 if "gmodules" in supported_categories: 1739 @decorators.add_test_categories(["gmodules"]) 1740 @wraps(attrvalue) 1741 def gmodules_test_method(self, attrvalue=attrvalue): 1742 self.debug_info = "gmodules" 1743 return attrvalue(self) 1744 gmodules_method_name = attrname + "_gmodules" 1745 gmodules_test_method.__name__ = gmodules_method_name 1746 newattrs[gmodules_method_name] = gmodules_test_method 1747 1748 else: 1749 newattrs[attrname] = attrvalue 1750 return super( 1751 LLDBTestCaseFactory, 1752 cls).__new__( 1753 cls, 1754 name, 1755 bases, 1756 newattrs) 1757 1758# Setup the metaclass for this class to change the list of the test 1759# methods when a new class is loaded 1760 1761 1762@add_metaclass(LLDBTestCaseFactory) 1763class TestBase(Base): 1764 """ 1765 This abstract base class is meant to be subclassed. It provides default 1766 implementations for setUpClass(), tearDownClass(), setUp(), and tearDown(), 1767 among other things. 1768 1769 Important things for test class writers: 1770 1771 - Overwrite the mydir class attribute, otherwise your test class won't 1772 run. It specifies the relative directory to the top level 'test' so 1773 the test harness can change to the correct working directory before 1774 running your test. 1775 1776 - The setUp method sets up things to facilitate subsequent interactions 1777 with the debugger as part of the test. These include: 1778 - populate the test method name 1779 - create/get a debugger set with synchronous mode (self.dbg) 1780 - get the command interpreter from with the debugger (self.ci) 1781 - create a result object for use with the command interpreter 1782 (self.res) 1783 - plus other stuffs 1784 1785 - The tearDown method tries to perform some necessary cleanup on behalf 1786 of the test to return the debugger to a good state for the next test. 1787 These include: 1788 - execute any tearDown hooks registered by the test method with 1789 TestBase.addTearDownHook(); examples can be found in 1790 settings/TestSettings.py 1791 - kill the inferior process associated with each target, if any, 1792 and, then delete the target from the debugger's target list 1793 - perform build cleanup before running the next test method in the 1794 same test class; examples of registering for this service can be 1795 found in types/TestIntegerTypes.py with the call: 1796 - self.setTearDownCleanup(dictionary=d) 1797 1798 - Similarly setUpClass and tearDownClass perform classwise setup and 1799 teardown fixtures. The tearDownClass method invokes a default build 1800 cleanup for the entire test class; also, subclasses can implement the 1801 classmethod classCleanup(cls) to perform special class cleanup action. 1802 1803 - The instance methods runCmd and expect are used heavily by existing 1804 test cases to send a command to the command interpreter and to perform 1805 string/pattern matching on the output of such command execution. The 1806 expect method also provides a mode to peform string/pattern matching 1807 without running a command. 1808 1809 - The build methods buildDefault, buildDsym, and buildDwarf are used to 1810 build the binaries used during a particular test scenario. A plugin 1811 should be provided for the sys.platform running the test suite. The 1812 Mac OS X implementation is located in plugins/darwin.py. 1813 """ 1814 1815 # Subclasses can set this to true (if they don't depend on debug info) to avoid running the 1816 # test multiple times with various debug info types. 1817 NO_DEBUG_INFO_TESTCASE = False 1818 1819 # Maximum allowed attempts when launching the inferior process. 1820 # Can be overridden by the LLDB_MAX_LAUNCH_COUNT environment variable. 1821 maxLaunchCount = 3 1822 1823 # Time to wait before the next launching attempt in second(s). 1824 # Can be overridden by the LLDB_TIME_WAIT_NEXT_LAUNCH environment variable. 1825 timeWaitNextLaunch = 1.0 1826 1827 # Returns the list of categories to which this test case belongs 1828 # by default, look for a ".categories" file, and read its contents 1829 # if no such file exists, traverse the hierarchy - we guarantee 1830 # a .categories to exist at the top level directory so we do not end up 1831 # looping endlessly - subclasses are free to define their own categories 1832 # in whatever way makes sense to them 1833 def getCategories(self): 1834 import inspect 1835 import os.path 1836 folder = inspect.getfile(self.__class__) 1837 folder = os.path.dirname(folder) 1838 while folder != '/': 1839 categories_file_name = os.path.join(folder, ".categories") 1840 if os.path.exists(categories_file_name): 1841 categories_file = open(categories_file_name, 'r') 1842 categories = categories_file.readline() 1843 categories_file.close() 1844 categories = str.replace(categories, '\n', '') 1845 categories = str.replace(categories, '\r', '') 1846 return categories.split(',') 1847 else: 1848 folder = os.path.dirname(folder) 1849 continue 1850 1851 def generateSource(self, source): 1852 template = source + '.template' 1853 temp = os.path.join(os.getcwd(), template) 1854 with open(temp, 'r') as f: 1855 content = f.read() 1856 1857 public_api_dir = os.path.join( 1858 os.environ["LLDB_SRC"], "include", "lldb", "API") 1859 1860 # Look under the include/lldb/API directory and add #include statements 1861 # for all the SB API headers. 1862 public_headers = os.listdir(public_api_dir) 1863 # For different platforms, the include statement can vary. 1864 if self.hasDarwinFramework(): 1865 include_stmt = "'#include <%s>' % os.path.join('LLDB', header)" 1866 else: 1867 include_stmt = "'#include <%s>' % os.path.join('" + public_api_dir + "', header)" 1868 list = [eval(include_stmt) for header in public_headers if ( 1869 header.startswith("SB") and header.endswith(".h"))] 1870 includes = '\n'.join(list) 1871 new_content = content.replace('%include_SB_APIs%', includes) 1872 src = os.path.join(os.getcwd(), source) 1873 with open(src, 'w') as f: 1874 f.write(new_content) 1875 1876 self.addTearDownHook(lambda: os.remove(src)) 1877 1878 def setUp(self): 1879 #import traceback 1880 # traceback.print_stack() 1881 1882 # Works with the test driver to conditionally skip tests via 1883 # decorators. 1884 Base.setUp(self) 1885 1886 if "LLDB_MAX_LAUNCH_COUNT" in os.environ: 1887 self.maxLaunchCount = int(os.environ["LLDB_MAX_LAUNCH_COUNT"]) 1888 1889 if "LLDB_TIME_WAIT_NEXT_LAUNCH" in os.environ: 1890 self.timeWaitNextLaunch = float( 1891 os.environ["LLDB_TIME_WAIT_NEXT_LAUNCH"]) 1892 1893 # We want our debugger to be synchronous. 1894 self.dbg.SetAsync(False) 1895 1896 # Retrieve the associated command interpreter instance. 1897 self.ci = self.dbg.GetCommandInterpreter() 1898 if not self.ci: 1899 raise Exception('Could not get the command interpreter') 1900 1901 # And the result object. 1902 self.res = lldb.SBCommandReturnObject() 1903 1904 def registerSharedLibrariesWithTarget(self, target, shlibs): 1905 '''If we are remotely running the test suite, register the shared libraries with the target so they get uploaded, otherwise do nothing 1906 1907 Any modules in the target that have their remote install file specification set will 1908 get uploaded to the remote host. This function registers the local copies of the 1909 shared libraries with the target and sets their remote install locations so they will 1910 be uploaded when the target is run. 1911 ''' 1912 if not shlibs or not self.platformContext: 1913 return None 1914 1915 shlib_environment_var = self.platformContext.shlib_environment_var 1916 shlib_prefix = self.platformContext.shlib_prefix 1917 shlib_extension = '.' + self.platformContext.shlib_extension 1918 1919 working_dir = self.get_process_working_directory() 1920 environment = ['%s=%s' % (shlib_environment_var, working_dir)] 1921 # Add any shared libraries to our target if remote so they get 1922 # uploaded into the working directory on the remote side 1923 for name in shlibs: 1924 # The path can be a full path to a shared library, or a make file name like "Foo" for 1925 # "libFoo.dylib" or "libFoo.so", or "Foo.so" for "Foo.so" or "libFoo.so", or just a 1926 # basename like "libFoo.so". So figure out which one it is and resolve the local copy 1927 # of the shared library accordingly 1928 if os.path.exists(name): 1929 local_shlib_path = name # name is the full path to the local shared library 1930 else: 1931 # Check relative names 1932 local_shlib_path = os.path.join( 1933 os.getcwd(), shlib_prefix + name + shlib_extension) 1934 if not os.path.exists(local_shlib_path): 1935 local_shlib_path = os.path.join( 1936 os.getcwd(), name + shlib_extension) 1937 if not os.path.exists(local_shlib_path): 1938 local_shlib_path = os.path.join(os.getcwd(), name) 1939 1940 # Make sure we found the local shared library in the above code 1941 self.assertTrue(os.path.exists(local_shlib_path)) 1942 1943 # Add the shared library to our target 1944 shlib_module = target.AddModule(local_shlib_path, None, None, None) 1945 if lldb.remote_platform: 1946 # We must set the remote install location if we want the shared library 1947 # to get uploaded to the remote target 1948 remote_shlib_path = lldbutil.append_to_process_working_directory( 1949 os.path.basename(local_shlib_path)) 1950 shlib_module.SetRemoteInstallFileSpec( 1951 lldb.SBFileSpec(remote_shlib_path, False)) 1952 1953 return environment 1954 1955 # utility methods that tests can use to access the current objects 1956 def target(self): 1957 if not self.dbg: 1958 raise Exception('Invalid debugger instance') 1959 return self.dbg.GetSelectedTarget() 1960 1961 def process(self): 1962 if not self.dbg: 1963 raise Exception('Invalid debugger instance') 1964 return self.dbg.GetSelectedTarget().GetProcess() 1965 1966 def thread(self): 1967 if not self.dbg: 1968 raise Exception('Invalid debugger instance') 1969 return self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread() 1970 1971 def frame(self): 1972 if not self.dbg: 1973 raise Exception('Invalid debugger instance') 1974 return self.dbg.GetSelectedTarget().GetProcess( 1975 ).GetSelectedThread().GetSelectedFrame() 1976 1977 def get_process_working_directory(self): 1978 '''Get the working directory that should be used when launching processes for local or remote processes.''' 1979 if lldb.remote_platform: 1980 # Remote tests set the platform working directory up in 1981 # TestBase.setUp() 1982 return lldb.remote_platform.GetWorkingDirectory() 1983 else: 1984 # local tests change directory into each test subdirectory 1985 return os.getcwd() 1986 1987 def tearDown(self): 1988 #import traceback 1989 # traceback.print_stack() 1990 1991 # Ensure all the references to SB objects have gone away so that we can 1992 # be sure that all test-specific resources have been freed before we 1993 # attempt to delete the targets. 1994 gc.collect() 1995 1996 # Delete the target(s) from the debugger as a general cleanup step. 1997 # This includes terminating the process for each target, if any. 1998 # We'd like to reuse the debugger for our next test without incurring 1999 # the initialization overhead. 2000 targets = [] 2001 for target in self.dbg: 2002 if target: 2003 targets.append(target) 2004 process = target.GetProcess() 2005 if process: 2006 rc = self.invoke(process, "Kill") 2007 self.assertTrue(rc.Success(), PROCESS_KILLED) 2008 for target in targets: 2009 self.dbg.DeleteTarget(target) 2010 2011 # Do this last, to make sure it's in reverse order from how we setup. 2012 Base.tearDown(self) 2013 2014 # This must be the last statement, otherwise teardown hooks or other 2015 # lines might depend on this still being active. 2016 del self.dbg 2017 2018 def switch_to_thread_with_stop_reason(self, stop_reason): 2019 """ 2020 Run the 'thread list' command, and select the thread with stop reason as 2021 'stop_reason'. If no such thread exists, no select action is done. 2022 """ 2023 from .lldbutil import stop_reason_to_str 2024 self.runCmd('thread list') 2025 output = self.res.GetOutput() 2026 thread_line_pattern = re.compile( 2027 "^[ *] thread #([0-9]+):.*stop reason = %s" % 2028 stop_reason_to_str(stop_reason)) 2029 for line in output.splitlines(): 2030 matched = thread_line_pattern.match(line) 2031 if matched: 2032 self.runCmd('thread select %s' % matched.group(1)) 2033 2034 def runCmd(self, cmd, msg=None, check=True, trace=False, inHistory=False): 2035 """ 2036 Ask the command interpreter to handle the command and then check its 2037 return status. 2038 """ 2039 # Fail fast if 'cmd' is not meaningful. 2040 if not cmd or len(cmd) == 0: 2041 raise Exception("Bad 'cmd' parameter encountered") 2042 2043 trace = (True if traceAlways else trace) 2044 2045 if cmd.startswith("target create "): 2046 cmd = cmd.replace("target create ", "file ") 2047 2048 running = (cmd.startswith("run") or cmd.startswith("process launch")) 2049 2050 for i in range(self.maxLaunchCount if running else 1): 2051 self.ci.HandleCommand(cmd, self.res, inHistory) 2052 2053 with recording(self, trace) as sbuf: 2054 print("runCmd:", cmd, file=sbuf) 2055 if not check: 2056 print("check of return status not required", file=sbuf) 2057 if self.res.Succeeded(): 2058 print("output:", self.res.GetOutput(), file=sbuf) 2059 else: 2060 print("runCmd failed!", file=sbuf) 2061 print(self.res.GetError(), file=sbuf) 2062 2063 if self.res.Succeeded(): 2064 break 2065 elif running: 2066 # For process launch, wait some time before possible next try. 2067 time.sleep(self.timeWaitNextLaunch) 2068 with recording(self, trace) as sbuf: 2069 print("Command '" + cmd + "' failed!", file=sbuf) 2070 2071 if check: 2072 self.assertTrue(self.res.Succeeded(), 2073 msg if msg else CMD_MSG(cmd)) 2074 2075 def match( 2076 self, 2077 str, 2078 patterns, 2079 msg=None, 2080 trace=False, 2081 error=False, 2082 matching=True, 2083 exe=True): 2084 """run command in str, and match the result against regexp in patterns returning the match object for the first matching pattern 2085 2086 Otherwise, all the arguments have the same meanings as for the expect function""" 2087 2088 trace = (True if traceAlways else trace) 2089 2090 if exe: 2091 # First run the command. If we are expecting error, set check=False. 2092 # Pass the assert message along since it provides more semantic 2093 # info. 2094 self.runCmd( 2095 str, 2096 msg=msg, 2097 trace=( 2098 True if trace else False), 2099 check=not error) 2100 2101 # Then compare the output against expected strings. 2102 output = self.res.GetError() if error else self.res.GetOutput() 2103 2104 # If error is True, the API client expects the command to fail! 2105 if error: 2106 self.assertFalse(self.res.Succeeded(), 2107 "Command '" + str + "' is expected to fail!") 2108 else: 2109 # No execution required, just compare str against the golden input. 2110 output = str 2111 with recording(self, trace) as sbuf: 2112 print("looking at:", output, file=sbuf) 2113 2114 # The heading says either "Expecting" or "Not expecting". 2115 heading = "Expecting" if matching else "Not expecting" 2116 2117 for pattern in patterns: 2118 # Match Objects always have a boolean value of True. 2119 match_object = re.search(pattern, output) 2120 matched = bool(match_object) 2121 with recording(self, trace) as sbuf: 2122 print("%s pattern: %s" % (heading, pattern), file=sbuf) 2123 print("Matched" if matched else "Not matched", file=sbuf) 2124 if matched: 2125 break 2126 2127 self.assertTrue(matched if matching else not matched, 2128 msg if msg else EXP_MSG(str, output, exe)) 2129 2130 return match_object 2131 2132 def expect( 2133 self, 2134 str, 2135 msg=None, 2136 patterns=None, 2137 startstr=None, 2138 endstr=None, 2139 substrs=None, 2140 trace=False, 2141 error=False, 2142 matching=True, 2143 exe=True, 2144 inHistory=False): 2145 """ 2146 Similar to runCmd; with additional expect style output matching ability. 2147 2148 Ask the command interpreter to handle the command and then check its 2149 return status. The 'msg' parameter specifies an informational assert 2150 message. We expect the output from running the command to start with 2151 'startstr', matches the substrings contained in 'substrs', and regexp 2152 matches the patterns contained in 'patterns'. 2153 2154 If the keyword argument error is set to True, it signifies that the API 2155 client is expecting the command to fail. In this case, the error stream 2156 from running the command is retrieved and compared against the golden 2157 input, instead. 2158 2159 If the keyword argument matching is set to False, it signifies that the API 2160 client is expecting the output of the command not to match the golden 2161 input. 2162 2163 Finally, the required argument 'str' represents the lldb command to be 2164 sent to the command interpreter. In case the keyword argument 'exe' is 2165 set to False, the 'str' is treated as a string to be matched/not-matched 2166 against the golden input. 2167 """ 2168 trace = (True if traceAlways else trace) 2169 2170 if exe: 2171 # First run the command. If we are expecting error, set check=False. 2172 # Pass the assert message along since it provides more semantic 2173 # info. 2174 self.runCmd( 2175 str, 2176 msg=msg, 2177 trace=( 2178 True if trace else False), 2179 check=not error, 2180 inHistory=inHistory) 2181 2182 # Then compare the output against expected strings. 2183 output = self.res.GetError() if error else self.res.GetOutput() 2184 2185 # If error is True, the API client expects the command to fail! 2186 if error: 2187 self.assertFalse(self.res.Succeeded(), 2188 "Command '" + str + "' is expected to fail!") 2189 else: 2190 # No execution required, just compare str against the golden input. 2191 if isinstance(str, lldb.SBCommandReturnObject): 2192 output = str.GetOutput() 2193 else: 2194 output = str 2195 with recording(self, trace) as sbuf: 2196 print("looking at:", output, file=sbuf) 2197 2198 if output is None: 2199 output = "" 2200 # The heading says either "Expecting" or "Not expecting". 2201 heading = "Expecting" if matching else "Not expecting" 2202 2203 # Start from the startstr, if specified. 2204 # If there's no startstr, set the initial state appropriately. 2205 matched = output.startswith(startstr) if startstr else ( 2206 True if matching else False) 2207 2208 if startstr: 2209 with recording(self, trace) as sbuf: 2210 print("%s start string: %s" % (heading, startstr), file=sbuf) 2211 print("Matched" if matched else "Not matched", file=sbuf) 2212 2213 # Look for endstr, if specified. 2214 keepgoing = matched if matching else not matched 2215 if endstr: 2216 matched = output.endswith(endstr) 2217 with recording(self, trace) as sbuf: 2218 print("%s end string: %s" % (heading, endstr), file=sbuf) 2219 print("Matched" if matched else "Not matched", file=sbuf) 2220 2221 # Look for sub strings, if specified. 2222 keepgoing = matched if matching else not matched 2223 if substrs and keepgoing: 2224 for substr in substrs: 2225 matched = output.find(substr) != -1 2226 with recording(self, trace) as sbuf: 2227 print("%s sub string: %s" % (heading, substr), file=sbuf) 2228 print("Matched" if matched else "Not matched", file=sbuf) 2229 keepgoing = matched if matching else not matched 2230 if not keepgoing: 2231 break 2232 2233 # Search for regular expression patterns, if specified. 2234 keepgoing = matched if matching else not matched 2235 if patterns and keepgoing: 2236 for pattern in patterns: 2237 # Match Objects always have a boolean value of True. 2238 matched = bool(re.search(pattern, output)) 2239 with recording(self, trace) as sbuf: 2240 print("%s pattern: %s" % (heading, pattern), file=sbuf) 2241 print("Matched" if matched else "Not matched", file=sbuf) 2242 keepgoing = matched if matching else not matched 2243 if not keepgoing: 2244 break 2245 2246 self.assertTrue(matched if matching else not matched, 2247 msg if msg else EXP_MSG(str, output, exe)) 2248 2249 def invoke(self, obj, name, trace=False): 2250 """Use reflection to call a method dynamically with no argument.""" 2251 trace = (True if traceAlways else trace) 2252 2253 method = getattr(obj, name) 2254 import inspect 2255 self.assertTrue(inspect.ismethod(method), 2256 name + "is a method name of object: " + str(obj)) 2257 result = method() 2258 with recording(self, trace) as sbuf: 2259 print(str(method) + ":", result, file=sbuf) 2260 return result 2261 2262 def build( 2263 self, 2264 architecture=None, 2265 compiler=None, 2266 dictionary=None, 2267 clean=True): 2268 """Platform specific way to build the default binaries.""" 2269 module = builder_module() 2270 dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) 2271 if self.debug_info is None: 2272 return self.buildDefault(architecture, compiler, dictionary, clean) 2273 elif self.debug_info == "dsym": 2274 return self.buildDsym(architecture, compiler, dictionary, clean) 2275 elif self.debug_info == "dwarf": 2276 return self.buildDwarf(architecture, compiler, dictionary, clean) 2277 elif self.debug_info == "dwo": 2278 return self.buildDwo(architecture, compiler, dictionary, clean) 2279 elif self.debug_info == "gmodules": 2280 return self.buildGModules( 2281 architecture, compiler, dictionary, clean) 2282 else: 2283 self.fail("Can't build for debug info: %s" % self.debug_info) 2284 2285 def run_platform_command(self, cmd): 2286 platform = self.dbg.GetSelectedPlatform() 2287 shell_command = lldb.SBPlatformShellCommand(cmd) 2288 err = platform.Run(shell_command) 2289 return (err, shell_command.GetStatus(), shell_command.GetOutput()) 2290 2291 # ================================================= 2292 # Misc. helper methods for debugging test execution 2293 # ================================================= 2294 2295 def DebugSBValue(self, val): 2296 """Debug print a SBValue object, if traceAlways is True.""" 2297 from .lldbutil import value_type_to_str 2298 2299 if not traceAlways: 2300 return 2301 2302 err = sys.stderr 2303 err.write(val.GetName() + ":\n") 2304 err.write('\t' + "TypeName -> " + val.GetTypeName() + '\n') 2305 err.write('\t' + "ByteSize -> " + 2306 str(val.GetByteSize()) + '\n') 2307 err.write('\t' + "NumChildren -> " + 2308 str(val.GetNumChildren()) + '\n') 2309 err.write('\t' + "Value -> " + str(val.GetValue()) + '\n') 2310 err.write('\t' + "ValueAsUnsigned -> " + 2311 str(val.GetValueAsUnsigned()) + '\n') 2312 err.write( 2313 '\t' + 2314 "ValueType -> " + 2315 value_type_to_str( 2316 val.GetValueType()) + 2317 '\n') 2318 err.write('\t' + "Summary -> " + str(val.GetSummary()) + '\n') 2319 err.write('\t' + "IsPointerType -> " + 2320 str(val.TypeIsPointerType()) + '\n') 2321 err.write('\t' + "Location -> " + val.GetLocation() + '\n') 2322 2323 def DebugSBType(self, type): 2324 """Debug print a SBType object, if traceAlways is True.""" 2325 if not traceAlways: 2326 return 2327 2328 err = sys.stderr 2329 err.write(type.GetName() + ":\n") 2330 err.write('\t' + "ByteSize -> " + 2331 str(type.GetByteSize()) + '\n') 2332 err.write('\t' + "IsPointerType -> " + 2333 str(type.IsPointerType()) + '\n') 2334 err.write('\t' + "IsReferenceType -> " + 2335 str(type.IsReferenceType()) + '\n') 2336 2337 def DebugPExpect(self, child): 2338 """Debug the spwaned pexpect object.""" 2339 if not traceAlways: 2340 return 2341 2342 print(child) 2343 2344 @classmethod 2345 def RemoveTempFile(cls, file): 2346 if os.path.exists(file): 2347 remove_file(file) 2348 2349# On Windows, the first attempt to delete a recently-touched file can fail 2350# because of a race with antimalware scanners. This function will detect a 2351# failure and retry. 2352 2353 2354def remove_file(file, num_retries=1, sleep_duration=0.5): 2355 for i in range(num_retries + 1): 2356 try: 2357 os.remove(file) 2358 return True 2359 except: 2360 time.sleep(sleep_duration) 2361 continue 2362 return False 2363