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 print_function 35from __future__ import absolute_import 36 37# System modules 38import abc 39import collections 40from distutils.version import LooseVersion 41import gc 42import glob 43import inspect 44import os, sys, traceback 45import os.path 46import re 47import signal 48from subprocess import * 49import time 50import types 51 52# Third-party modules 53import unittest2 54from six import add_metaclass 55from six import StringIO as SixStringIO 56from six.moves.urllib import parse as urlparse 57import six 58 59# LLDB modules 60import lldb 61from . import lldbtest_config 62from . import lldbutil 63from . import test_categories 64 65# dosep.py starts lots and lots of dotest instances 66# This option helps you find if two (or more) dotest instances are using the same 67# directory at the same time 68# Enable it to cause test failures and stderr messages if dotest instances try to run in 69# the same directory simultaneously 70# it is disabled by default because it litters the test directories with ".dirlock" files 71debug_confirm_directory_exclusivity = False 72 73# See also dotest.parseOptionsAndInitTestdirs(), where the environment variables 74# LLDB_COMMAND_TRACE and LLDB_DO_CLEANUP are set from '-t' and '-r dir' options. 75 76# By default, traceAlways is False. 77if "LLDB_COMMAND_TRACE" in os.environ and os.environ["LLDB_COMMAND_TRACE"]=="YES": 78 traceAlways = True 79else: 80 traceAlways = False 81 82# By default, doCleanup is True. 83if "LLDB_DO_CLEANUP" in os.environ and os.environ["LLDB_DO_CLEANUP"]=="NO": 84 doCleanup = False 85else: 86 doCleanup = True 87 88 89# 90# Some commonly used assert messages. 91# 92 93COMMAND_FAILED_AS_EXPECTED = "Command has failed as expected" 94 95CURRENT_EXECUTABLE_SET = "Current executable set successfully" 96 97PROCESS_IS_VALID = "Process is valid" 98 99PROCESS_KILLED = "Process is killed successfully" 100 101PROCESS_EXITED = "Process exited successfully" 102 103PROCESS_STOPPED = "Process status should be stopped" 104 105RUN_SUCCEEDED = "Process is launched successfully" 106 107RUN_COMPLETED = "Process exited successfully" 108 109BACKTRACE_DISPLAYED_CORRECTLY = "Backtrace displayed correctly" 110 111BREAKPOINT_CREATED = "Breakpoint created successfully" 112 113BREAKPOINT_STATE_CORRECT = "Breakpoint state is correct" 114 115BREAKPOINT_PENDING_CREATED = "Pending breakpoint created successfully" 116 117BREAKPOINT_HIT_ONCE = "Breakpoint resolved with hit cout = 1" 118 119BREAKPOINT_HIT_TWICE = "Breakpoint resolved with hit cout = 2" 120 121BREAKPOINT_HIT_THRICE = "Breakpoint resolved with hit cout = 3" 122 123MISSING_EXPECTED_REGISTERS = "At least one expected register is unavailable." 124 125OBJECT_PRINTED_CORRECTLY = "Object printed correctly" 126 127SOURCE_DISPLAYED_CORRECTLY = "Source code displayed correctly" 128 129STEP_OUT_SUCCEEDED = "Thread step-out succeeded" 130 131STOPPED_DUE_TO_EXC_BAD_ACCESS = "Process should be stopped due to bad access exception" 132 133STOPPED_DUE_TO_ASSERT = "Process should be stopped due to an assertion" 134 135STOPPED_DUE_TO_BREAKPOINT = "Process should be stopped due to breakpoint" 136 137STOPPED_DUE_TO_BREAKPOINT_WITH_STOP_REASON_AS = "%s, %s" % ( 138 STOPPED_DUE_TO_BREAKPOINT, "instead, the actual stop reason is: '%s'") 139 140STOPPED_DUE_TO_BREAKPOINT_CONDITION = "Stopped due to breakpoint condition" 141 142STOPPED_DUE_TO_BREAKPOINT_IGNORE_COUNT = "Stopped due to breakpoint and ignore count" 143 144STOPPED_DUE_TO_SIGNAL = "Process state is stopped due to signal" 145 146STOPPED_DUE_TO_STEP_IN = "Process state is stopped due to step in" 147 148STOPPED_DUE_TO_WATCHPOINT = "Process should be stopped due to watchpoint" 149 150DATA_TYPES_DISPLAYED_CORRECTLY = "Data type(s) displayed correctly" 151 152VALID_BREAKPOINT = "Got a valid breakpoint" 153 154VALID_BREAKPOINT_LOCATION = "Got a valid breakpoint location" 155 156VALID_COMMAND_INTERPRETER = "Got a valid command interpreter" 157 158VALID_FILESPEC = "Got a valid filespec" 159 160VALID_MODULE = "Got a valid module" 161 162VALID_PROCESS = "Got a valid process" 163 164VALID_SYMBOL = "Got a valid symbol" 165 166VALID_TARGET = "Got a valid target" 167 168VALID_PLATFORM = "Got a valid platform" 169 170VALID_TYPE = "Got a valid type" 171 172VALID_VARIABLE = "Got a valid variable" 173 174VARIABLES_DISPLAYED_CORRECTLY = "Variable(s) displayed correctly" 175 176WATCHPOINT_CREATED = "Watchpoint created successfully" 177 178def CMD_MSG(str): 179 '''A generic "Command '%s' returns successfully" message generator.''' 180 return "Command '%s' returns successfully" % str 181 182def COMPLETION_MSG(str_before, str_after): 183 '''A generic message generator for the completion mechanism.''' 184 return "'%s' successfully completes to '%s'" % (str_before, str_after) 185 186def EXP_MSG(str, exe): 187 '''A generic "'%s' returns expected result" message generator if exe. 188 Otherwise, it generates "'%s' matches expected result" message.''' 189 return "'%s' %s expected result" % (str, 'returns' if exe else 'matches') 190 191def SETTING_MSG(setting): 192 '''A generic "Value of setting '%s' is correct" message generator.''' 193 return "Value of setting '%s' is correct" % setting 194 195def EnvArray(): 196 """Returns an env variable array from the os.environ map object.""" 197 return list(map(lambda k,v: k+"="+v, list(os.environ.keys()), list(os.environ.values()))) 198 199def line_number(filename, string_to_match): 200 """Helper function to return the line number of the first matched string.""" 201 with open(filename, 'r') as f: 202 for i, line in enumerate(f): 203 if line.find(string_to_match) != -1: 204 # Found our match. 205 return i+1 206 raise Exception("Unable to find '%s' within file %s" % (string_to_match, filename)) 207 208def pointer_size(): 209 """Return the pointer size of the host system.""" 210 import ctypes 211 a_pointer = ctypes.c_void_p(0xffff) 212 return 8 * ctypes.sizeof(a_pointer) 213 214def is_exe(fpath): 215 """Returns true if fpath is an executable.""" 216 return os.path.isfile(fpath) and os.access(fpath, os.X_OK) 217 218def which(program): 219 """Returns the full path to a program; None otherwise.""" 220 fpath, fname = os.path.split(program) 221 if fpath: 222 if is_exe(program): 223 return program 224 else: 225 for path in os.environ["PATH"].split(os.pathsep): 226 exe_file = os.path.join(path, program) 227 if is_exe(exe_file): 228 return exe_file 229 return None 230 231class recording(SixStringIO): 232 """ 233 A nice little context manager for recording the debugger interactions into 234 our session object. If trace flag is ON, it also emits the interactions 235 into the stderr. 236 """ 237 def __init__(self, test, trace): 238 """Create a SixStringIO instance; record the session obj and trace flag.""" 239 SixStringIO.__init__(self) 240 # The test might not have undergone the 'setUp(self)' phase yet, so that 241 # the attribute 'session' might not even exist yet. 242 self.session = getattr(test, "session", None) if test else None 243 self.trace = trace 244 245 def __enter__(self): 246 """ 247 Context management protocol on entry to the body of the with statement. 248 Just return the SixStringIO object. 249 """ 250 return self 251 252 def __exit__(self, type, value, tb): 253 """ 254 Context management protocol on exit from the body of the with statement. 255 If trace is ON, it emits the recordings into stderr. Always add the 256 recordings to our session object. And close the SixStringIO object, too. 257 """ 258 if self.trace: 259 print(self.getvalue(), file=sys.stderr) 260 if self.session: 261 print(self.getvalue(), file=self.session) 262 self.close() 263 264@add_metaclass(abc.ABCMeta) 265class _BaseProcess(object): 266 267 @abc.abstractproperty 268 def pid(self): 269 """Returns process PID if has been launched already.""" 270 271 @abc.abstractmethod 272 def launch(self, executable, args): 273 """Launches new process with given executable and args.""" 274 275 @abc.abstractmethod 276 def terminate(self): 277 """Terminates previously launched process..""" 278 279class _LocalProcess(_BaseProcess): 280 281 def __init__(self, trace_on): 282 self._proc = None 283 self._trace_on = trace_on 284 self._delayafterterminate = 0.1 285 286 @property 287 def pid(self): 288 return self._proc.pid 289 290 def launch(self, executable, args): 291 self._proc = Popen([executable] + args, 292 stdout = open(os.devnull) if not self._trace_on else None, 293 stdin = PIPE) 294 295 def terminate(self): 296 if self._proc.poll() == None: 297 # Terminate _proc like it does the pexpect 298 signals_to_try = [sig for sig in ['SIGHUP', 'SIGCONT', 'SIGINT'] if sig in dir(signal)] 299 for sig in signals_to_try: 300 try: 301 self._proc.send_signal(getattr(signal, sig)) 302 time.sleep(self._delayafterterminate) 303 if self._proc.poll() != None: 304 return 305 except ValueError: 306 pass # Windows says SIGINT is not a valid signal to send 307 self._proc.terminate() 308 time.sleep(self._delayafterterminate) 309 if self._proc.poll() != None: 310 return 311 self._proc.kill() 312 time.sleep(self._delayafterterminate) 313 314 def poll(self): 315 return self._proc.poll() 316 317class _RemoteProcess(_BaseProcess): 318 319 def __init__(self, install_remote): 320 self._pid = None 321 self._install_remote = install_remote 322 323 @property 324 def pid(self): 325 return self._pid 326 327 def launch(self, executable, args): 328 if self._install_remote: 329 src_path = executable 330 dst_path = lldbutil.append_to_process_working_directory(os.path.basename(executable)) 331 332 dst_file_spec = lldb.SBFileSpec(dst_path, False) 333 err = lldb.remote_platform.Install(lldb.SBFileSpec(src_path, True), dst_file_spec) 334 if err.Fail(): 335 raise Exception("remote_platform.Install('%s', '%s') failed: %s" % (src_path, dst_path, err)) 336 else: 337 dst_path = executable 338 dst_file_spec = lldb.SBFileSpec(executable, False) 339 340 launch_info = lldb.SBLaunchInfo(args) 341 launch_info.SetExecutableFile(dst_file_spec, True) 342 launch_info.SetWorkingDirectory(lldb.remote_platform.GetWorkingDirectory()) 343 344 # Redirect stdout and stderr to /dev/null 345 launch_info.AddSuppressFileAction(1, False, True) 346 launch_info.AddSuppressFileAction(2, False, True) 347 348 err = lldb.remote_platform.Launch(launch_info) 349 if err.Fail(): 350 raise Exception("remote_platform.Launch('%s', '%s') failed: %s" % (dst_path, args, err)) 351 self._pid = launch_info.GetProcessID() 352 353 def terminate(self): 354 lldb.remote_platform.Kill(self._pid) 355 356# From 2.7's subprocess.check_output() convenience function. 357# Return a tuple (stdoutdata, stderrdata). 358def system(commands, **kwargs): 359 r"""Run an os command with arguments and return its output as a byte string. 360 361 If the exit code was non-zero it raises a CalledProcessError. The 362 CalledProcessError object will have the return code in the returncode 363 attribute and output in the output attribute. 364 365 The arguments are the same as for the Popen constructor. Example: 366 367 >>> check_output(["ls", "-l", "/dev/null"]) 368 'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n' 369 370 The stdout argument is not allowed as it is used internally. 371 To capture standard error in the result, use stderr=STDOUT. 372 373 >>> check_output(["/bin/sh", "-c", 374 ... "ls -l non_existent_file ; exit 0"], 375 ... stderr=STDOUT) 376 'ls: non_existent_file: No such file or directory\n' 377 """ 378 379 # Assign the sender object to variable 'test' and remove it from kwargs. 380 test = kwargs.pop('sender', None) 381 382 # [['make', 'clean', 'foo'], ['make', 'foo']] -> ['make clean foo', 'make foo'] 383 commandList = [' '.join(x) for x in commands] 384 output = "" 385 error = "" 386 for shellCommand in commandList: 387 if 'stdout' in kwargs: 388 raise ValueError('stdout argument not allowed, it will be overridden.') 389 if 'shell' in kwargs and kwargs['shell']==False: 390 raise ValueError('shell=False not allowed') 391 process = Popen(shellCommand, stdout=PIPE, stderr=PIPE, shell=True, universal_newlines=True, **kwargs) 392 pid = process.pid 393 this_output, this_error = process.communicate() 394 retcode = process.poll() 395 396 # Enable trace on failure return while tracking down FreeBSD buildbot issues 397 trace = traceAlways 398 if not trace and retcode and sys.platform.startswith("freebsd"): 399 trace = True 400 401 with recording(test, trace) as sbuf: 402 print(file=sbuf) 403 print("os command:", shellCommand, file=sbuf) 404 print("with pid:", pid, file=sbuf) 405 print("stdout:", this_output, file=sbuf) 406 print("stderr:", this_error, file=sbuf) 407 print("retcode:", retcode, file=sbuf) 408 print(file=sbuf) 409 410 if retcode: 411 cmd = kwargs.get("args") 412 if cmd is None: 413 cmd = shellCommand 414 raise CalledProcessError(retcode, cmd) 415 output = output + this_output 416 error = error + this_error 417 return (output, error) 418 419def getsource_if_available(obj): 420 """ 421 Return the text of the source code for an object if available. Otherwise, 422 a print representation is returned. 423 """ 424 import inspect 425 try: 426 return inspect.getsource(obj) 427 except: 428 return repr(obj) 429 430def builder_module(): 431 if sys.platform.startswith("freebsd"): 432 return __import__("builder_freebsd") 433 if sys.platform.startswith("netbsd"): 434 return __import__("builder_netbsd") 435 return __import__("builder_" + sys.platform) 436 437def run_adb_command(cmd, device_id): 438 device_id_args = [] 439 if device_id: 440 device_id_args = ["-s", device_id] 441 full_cmd = ["adb"] + device_id_args + cmd 442 p = Popen(full_cmd, stdout=PIPE, stderr=PIPE) 443 stdout, stderr = p.communicate() 444 return p.returncode, stdout, stderr 445 446def append_android_envs(dictionary): 447 if dictionary is None: 448 dictionary = {} 449 dictionary["OS"] = "Android" 450 if android_device_api() >= 16: 451 dictionary["PIE"] = 1 452 return dictionary 453 454def target_is_android(): 455 if not hasattr(target_is_android, 'result'): 456 triple = lldb.DBG.GetSelectedPlatform().GetTriple() 457 match = re.match(".*-.*-.*-android", triple) 458 target_is_android.result = match is not None 459 return target_is_android.result 460 461def android_device_api(): 462 if not hasattr(android_device_api, 'result'): 463 assert lldb.platform_url is not None 464 device_id = None 465 parsed_url = urlparse.urlparse(lldb.platform_url) 466 host_name = parsed_url.netloc.split(":")[0] 467 if host_name != 'localhost': 468 device_id = host_name 469 if device_id.startswith('[') and device_id.endswith(']'): 470 device_id = device_id[1:-1] 471 retcode, stdout, stderr = run_adb_command( 472 ["shell", "getprop", "ro.build.version.sdk"], device_id) 473 if retcode == 0: 474 android_device_api.result = int(stdout) 475 else: 476 raise LookupError( 477 ">>> Unable to determine the API level of the Android device.\n" 478 ">>> stdout:\n%s\n" 479 ">>> stderr:\n%s\n" % (stdout, stderr)) 480 return android_device_api.result 481 482def check_expected_version(comparison, expected, actual): 483 def fn_leq(x,y): return x <= y 484 def fn_less(x,y): return x < y 485 def fn_geq(x,y): return x >= y 486 def fn_greater(x,y): return x > y 487 def fn_eq(x,y): return x == y 488 def fn_neq(x,y): return x != y 489 490 op_lookup = { 491 "==": fn_eq, 492 "=": fn_eq, 493 "!=": fn_neq, 494 "<>": fn_neq, 495 ">": fn_greater, 496 "<": fn_less, 497 ">=": fn_geq, 498 "<=": fn_leq 499 } 500 expected_str = '.'.join([str(x) for x in expected]) 501 actual_str = '.'.join([str(x) for x in actual]) 502 503 return op_lookup[comparison](LooseVersion(actual_str), LooseVersion(expected_str)) 504 505# 506# Decorators for categorizing test cases. 507# 508from functools import wraps 509def add_test_categories(cat): 510 """Decorate an item with test categories""" 511 cat = test_categories.validate(cat, True) 512 def impl(func): 513 func.getCategories = lambda test: cat 514 return func 515 return impl 516 517def benchmarks_test(func): 518 """Decorate the item as a benchmarks test.""" 519 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 520 raise Exception("@benchmarks_test can only be used to decorate a test method") 521 @wraps(func) 522 def wrapper(self, *args, **kwargs): 523 if not lldb.just_do_benchmarks_test: 524 self.skipTest("benchmarks tests") 525 return func(self, *args, **kwargs) 526 527 # Mark this function as such to separate them from the regular tests. 528 wrapper.__benchmarks_test__ = True 529 return wrapper 530 531def no_debug_info_test(func): 532 """Decorate the item as a test what don't use any debug info. If this annotation is specified 533 then the test runner won't generate a separate test for each debug info format. """ 534 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 535 raise Exception("@no_debug_info_test can only be used to decorate a test method") 536 @wraps(func) 537 def wrapper(self, *args, **kwargs): 538 return func(self, *args, **kwargs) 539 540 # Mark this function as such to separate them from the regular tests. 541 wrapper.__no_debug_info_test__ = True 542 return wrapper 543 544def dsym_test(func): 545 """Decorate the item as a dsym test.""" 546 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 547 raise Exception("@dsym_test can only be used to decorate a test method") 548 @wraps(func) 549 def wrapper(self, *args, **kwargs): 550 if lldb.dont_do_dsym_test: 551 self.skipTest("dsym tests") 552 return func(self, *args, **kwargs) 553 554 # Mark this function as such to separate them from the regular tests. 555 wrapper.__dsym_test__ = True 556 return wrapper 557 558def dwarf_test(func): 559 """Decorate the item as a dwarf test.""" 560 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 561 raise Exception("@dwarf_test can only be used to decorate a test method") 562 @wraps(func) 563 def wrapper(self, *args, **kwargs): 564 if lldb.dont_do_dwarf_test: 565 self.skipTest("dwarf tests") 566 return func(self, *args, **kwargs) 567 568 # Mark this function as such to separate them from the regular tests. 569 wrapper.__dwarf_test__ = True 570 return wrapper 571 572def dwo_test(func): 573 """Decorate the item as a dwo test.""" 574 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 575 raise Exception("@dwo_test can only be used to decorate a test method") 576 @wraps(func) 577 def wrapper(self, *args, **kwargs): 578 if lldb.dont_do_dwo_test: 579 self.skipTest("dwo tests") 580 return func(self, *args, **kwargs) 581 582 # Mark this function as such to separate them from the regular tests. 583 wrapper.__dwo_test__ = True 584 return wrapper 585 586def debugserver_test(func): 587 """Decorate the item as a debugserver test.""" 588 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 589 raise Exception("@debugserver_test can only be used to decorate a test method") 590 @wraps(func) 591 def wrapper(self, *args, **kwargs): 592 if lldb.dont_do_debugserver_test: 593 self.skipTest("debugserver tests") 594 return func(self, *args, **kwargs) 595 596 # Mark this function as such to separate them from the regular tests. 597 wrapper.__debugserver_test__ = True 598 return wrapper 599 600def llgs_test(func): 601 """Decorate the item as a lldb-server test.""" 602 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 603 raise Exception("@llgs_test can only be used to decorate a test method") 604 @wraps(func) 605 def wrapper(self, *args, **kwargs): 606 if lldb.dont_do_llgs_test: 607 self.skipTest("llgs tests") 608 return func(self, *args, **kwargs) 609 610 # Mark this function as such to separate them from the regular tests. 611 wrapper.__llgs_test__ = True 612 return wrapper 613 614def not_remote_testsuite_ready(func): 615 """Decorate the item as a test which is not ready yet for remote testsuite.""" 616 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 617 raise Exception("@not_remote_testsuite_ready can only be used to decorate a test method") 618 @wraps(func) 619 def wrapper(self, *args, **kwargs): 620 if lldb.lldbtest_remote_sandbox or lldb.remote_platform: 621 self.skipTest("not ready for remote testsuite") 622 return func(self, *args, **kwargs) 623 624 # Mark this function as such to separate them from the regular tests. 625 wrapper.__not_ready_for_remote_testsuite_test__ = True 626 return wrapper 627 628def expectedFailure(expected_fn, bugnumber=None): 629 def expectedFailure_impl(func): 630 @wraps(func) 631 def wrapper(*args, **kwargs): 632 from unittest2 import case 633 self = args[0] 634 if expected_fn(self): 635 xfail_func = unittest2.expectedFailure(func) 636 xfail_func(*args, **kwargs) 637 else: 638 func(*args, **kwargs) 639 return wrapper 640 # if bugnumber is not-callable(incluing None), that means decorator function is called with optional arguments 641 # return decorator in this case, so it will be used to decorating original method 642 if six.callable(bugnumber): 643 return expectedFailure_impl(bugnumber) 644 else: 645 return expectedFailure_impl 646 647# You can also pass not_in(list) to reverse the sense of the test for the arguments that 648# are simple lists, namely oslist, compiler, and debug_info. 649 650def not_in (iterable): 651 return lambda x : x not in iterable 652 653def check_list_or_lambda (list_or_lambda, value): 654 if six.callable(list_or_lambda): 655 return list_or_lambda(value) 656 else: 657 return list_or_lambda is None or value is None or value in list_or_lambda 658 659# provide a function to xfail on defined oslist, compiler version, and archs 660# if none is specified for any argument, that argument won't be checked and thus means for all 661# for example, 662# @expectedFailureAll, xfail for all platform/compiler/arch, 663# @expectedFailureAll(compiler='gcc'), xfail for gcc on all platform/architecture 664# @expectedFailureAll(bugnumber, ["linux"], "gcc", ['>=', '4.9'], ['i386']), xfail for gcc>=4.9 on linux with i386 665def expectedFailureAll(bugnumber=None, oslist=None, compiler=None, compiler_version=None, archs=None, triple=None, debug_info=None, swig_version=None, py_version=None): 666 def fn(self): 667 oslist_passes = check_list_or_lambda(oslist, self.getPlatform()) 668 compiler_passes = check_list_or_lambda(self.getCompiler(), compiler) and self.expectedCompilerVersion(compiler_version) 669 arch_passes = self.expectedArch(archs) 670 triple_passes = triple is None or re.match(triple, lldb.DBG.GetSelectedPlatform().GetTriple()) 671 debug_info_passes = check_list_or_lambda(debug_info, self.debug_info) 672 swig_version_passes = (swig_version is None) or (not hasattr(lldb, 'swig_version')) or (check_expected_version(swig_version[0], swig_version[1], lldb.swig_version)) 673 py_version_passes = (py_version is None) or check_expected_version(py_version[0], py_version[1], sys.version_info) 674 675 return (oslist_passes and 676 compiler_passes and 677 arch_passes and 678 triple_passes and 679 debug_info_passes and 680 swig_version_passes and 681 py_version_passes) 682 return expectedFailure(fn, bugnumber) 683 684def expectedFailureDwarf(bugnumber=None): 685 return expectedFailureAll(bugnumber=bugnumber, debug_info="dwarf") 686 687def expectedFailureDwo(bugnumber=None): 688 return expectedFailureAll(bugnumber=bugnumber, debug_info="dwo") 689 690def expectedFailureDsym(bugnumber=None): 691 return expectedFailureAll(bugnumber=bugnumber, debug_info="dsym") 692 693def expectedFailureCompiler(compiler, compiler_version=None, bugnumber=None): 694 if compiler_version is None: 695 compiler_version=['=', None] 696 return expectedFailureAll(bugnumber=bugnumber, compiler=compiler, compiler_version=compiler_version) 697 698# to XFAIL a specific clang versions, try this 699# @expectedFailureClang('bugnumber', ['<=', '3.4']) 700def expectedFailureClang(bugnumber=None, compiler_version=None): 701 return expectedFailureCompiler('clang', compiler_version, bugnumber) 702 703def expectedFailureGcc(bugnumber=None, compiler_version=None): 704 return expectedFailureCompiler('gcc', compiler_version, bugnumber) 705 706def expectedFailureIcc(bugnumber=None): 707 return expectedFailureCompiler('icc', None, bugnumber) 708 709def expectedFailureArch(arch, bugnumber=None): 710 def fn(self): 711 return arch in self.getArchitecture() 712 return expectedFailure(fn, bugnumber) 713 714def expectedFailurei386(bugnumber=None): 715 return expectedFailureArch('i386', bugnumber) 716 717def expectedFailurex86_64(bugnumber=None): 718 return expectedFailureArch('x86_64', bugnumber) 719 720def expectedFailureOS(oslist, bugnumber=None, compilers=None, debug_info=None): 721 def fn(self): 722 return (self.getPlatform() in oslist and 723 self.expectedCompiler(compilers) and 724 (debug_info is None or self.debug_info in debug_info)) 725 return expectedFailure(fn, bugnumber) 726 727def expectedFailureHostOS(oslist, bugnumber=None, compilers=None): 728 def fn(self): 729 return (getHostPlatform() in oslist and 730 self.expectedCompiler(compilers)) 731 return expectedFailure(fn, bugnumber) 732 733def expectedFailureDarwin(bugnumber=None, compilers=None, debug_info=None): 734 # For legacy reasons, we support both "darwin" and "macosx" as OS X triples. 735 return expectedFailureOS(getDarwinOSTriples(), bugnumber, compilers, debug_info=debug_info) 736 737def expectedFailureFreeBSD(bugnumber=None, compilers=None, debug_info=None): 738 return expectedFailureOS(['freebsd'], bugnumber, compilers, debug_info=debug_info) 739 740def expectedFailureLinux(bugnumber=None, compilers=None, debug_info=None): 741 return expectedFailureOS(['linux'], bugnumber, compilers, debug_info=debug_info) 742 743def expectedFailureWindows(bugnumber=None, compilers=None, debug_info=None): 744 return expectedFailureOS(['windows'], bugnumber, compilers, debug_info=debug_info) 745 746def expectedFailureHostWindows(bugnumber=None, compilers=None): 747 return expectedFailureHostOS(['windows'], bugnumber, compilers) 748 749def matchAndroid(api_levels=None, archs=None): 750 def match(self): 751 if not target_is_android(): 752 return False 753 if archs is not None and self.getArchitecture() not in archs: 754 return False 755 if api_levels is not None and android_device_api() not in api_levels: 756 return False 757 return True 758 return match 759 760 761def expectedFailureAndroid(bugnumber=None, api_levels=None, archs=None): 762 """ Mark a test as xfail for Android. 763 764 Arguments: 765 bugnumber - The LLVM pr associated with the problem. 766 api_levels - A sequence of numbers specifying the Android API levels 767 for which a test is expected to fail. None means all API level. 768 arch - A sequence of architecture names specifying the architectures 769 for which a test is expected to fail. None means all architectures. 770 """ 771 return expectedFailure(matchAndroid(api_levels, archs), bugnumber) 772 773# if the test passes on the first try, we're done (success) 774# if the test fails once, then passes on the second try, raise an ExpectedFailure 775# if the test fails twice in a row, re-throw the exception from the second test run 776def expectedFlakey(expected_fn, bugnumber=None): 777 def expectedFailure_impl(func): 778 @wraps(func) 779 def wrapper(*args, **kwargs): 780 from unittest2 import case 781 self = args[0] 782 try: 783 func(*args, **kwargs) 784 # don't retry if the test case is already decorated with xfail or skip 785 except (case._ExpectedFailure, case.SkipTest, case._UnexpectedSuccess): 786 raise 787 except Exception: 788 if expected_fn(self): 789 # before retry, run tearDown for previous run and setup for next 790 try: 791 self.tearDown() 792 self.setUp() 793 func(*args, **kwargs) 794 except Exception: 795 # oh snap! two failures in a row, record a failure/error 796 raise 797 # record the expected failure 798 raise case._ExpectedFailure(sys.exc_info(), bugnumber) 799 else: 800 raise 801 return wrapper 802 # if bugnumber is not-callable(incluing None), that means decorator function is called with optional arguments 803 # return decorator in this case, so it will be used to decorating original method 804 if six.callable(bugnumber): 805 return expectedFailure_impl(bugnumber) 806 else: 807 return expectedFailure_impl 808 809def expectedFlakeyDwarf(bugnumber=None): 810 def fn(self): 811 return self.debug_info == "dwarf" 812 return expectedFlakey(fn, bugnumber) 813 814def expectedFlakeyDsym(bugnumber=None): 815 def fn(self): 816 return self.debug_info == "dwarf" 817 return expectedFlakey(fn, bugnumber) 818 819def expectedFlakeyOS(oslist, bugnumber=None, compilers=None): 820 def fn(self): 821 return (self.getPlatform() in oslist and 822 self.expectedCompiler(compilers)) 823 return expectedFlakey(fn, bugnumber) 824 825def expectedFlakeyDarwin(bugnumber=None, compilers=None): 826 # For legacy reasons, we support both "darwin" and "macosx" as OS X triples. 827 return expectedFlakeyOS(getDarwinOSTriples(), bugnumber, compilers) 828 829def expectedFlakeyLinux(bugnumber=None, compilers=None): 830 return expectedFlakeyOS(['linux'], bugnumber, compilers) 831 832def expectedFlakeyFreeBSD(bugnumber=None, compilers=None): 833 return expectedFlakeyOS(['freebsd'], bugnumber, compilers) 834 835def expectedFlakeyCompiler(compiler, compiler_version=None, bugnumber=None): 836 if compiler_version is None: 837 compiler_version=['=', None] 838 def fn(self): 839 return compiler in self.getCompiler() and self.expectedCompilerVersion(compiler_version) 840 return expectedFlakey(fn, bugnumber) 841 842# @expectedFlakeyClang('bugnumber', ['<=', '3.4']) 843def expectedFlakeyClang(bugnumber=None, compiler_version=None): 844 return expectedFlakeyCompiler('clang', compiler_version, bugnumber) 845 846# @expectedFlakeyGcc('bugnumber', ['<=', '3.4']) 847def expectedFlakeyGcc(bugnumber=None, compiler_version=None): 848 return expectedFlakeyCompiler('gcc', compiler_version, bugnumber) 849 850def expectedFlakeyAndroid(bugnumber=None, api_levels=None, archs=None): 851 return expectedFlakey(matchAndroid(api_levels, archs), bugnumber) 852 853def skipIfRemote(func): 854 """Decorate the item to skip tests if testing remotely.""" 855 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 856 raise Exception("@skipIfRemote can only be used to decorate a test method") 857 @wraps(func) 858 def wrapper(*args, **kwargs): 859 from unittest2 import case 860 if lldb.remote_platform: 861 self = args[0] 862 self.skipTest("skip on remote platform") 863 else: 864 func(*args, **kwargs) 865 return wrapper 866 867def skipUnlessListedRemote(remote_list=None): 868 def myImpl(func): 869 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 870 raise Exception("@skipIfRemote can only be used to decorate a " 871 "test method") 872 873 @wraps(func) 874 def wrapper(*args, **kwargs): 875 if remote_list and lldb.remote_platform: 876 self = args[0] 877 triple = self.dbg.GetSelectedPlatform().GetTriple() 878 for r in remote_list: 879 if r in triple: 880 func(*args, **kwargs) 881 return 882 self.skipTest("skip on remote platform %s" % str(triple)) 883 else: 884 func(*args, **kwargs) 885 return wrapper 886 887 return myImpl 888 889def skipIfRemoteDueToDeadlock(func): 890 """Decorate the item to skip tests if testing remotely due to the test deadlocking.""" 891 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 892 raise Exception("@skipIfRemote can only be used to decorate a test method") 893 @wraps(func) 894 def wrapper(*args, **kwargs): 895 from unittest2 import case 896 if lldb.remote_platform: 897 self = args[0] 898 self.skipTest("skip on remote platform (deadlocks)") 899 else: 900 func(*args, **kwargs) 901 return wrapper 902 903def skipIfNoSBHeaders(func): 904 """Decorate the item to mark tests that should be skipped when LLDB is built with no SB API headers.""" 905 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 906 raise Exception("@skipIfNoSBHeaders can only be used to decorate a test method") 907 @wraps(func) 908 def wrapper(*args, **kwargs): 909 from unittest2 import case 910 self = args[0] 911 if sys.platform.startswith("darwin"): 912 header = os.path.join(os.environ["LLDB_LIB_DIR"], 'LLDB.framework', 'Versions','Current','Headers','LLDB.h') 913 else: 914 header = os.path.join(os.environ["LLDB_SRC"], "include", "lldb", "API", "LLDB.h") 915 platform = sys.platform 916 if not os.path.exists(header): 917 self.skipTest("skip because LLDB.h header not found") 918 else: 919 func(*args, **kwargs) 920 return wrapper 921 922def skipIfiOSSimulator(func): 923 """Decorate the item to skip tests that should be skipped on the iOS Simulator.""" 924 return unittest2.skipIf(hasattr(lldb, 'remote_platform_name') and lldb.remote_platform_name == 'ios-simulator', 'skip on the iOS Simulator')(func) 925 926def skipIfFreeBSD(func): 927 """Decorate the item to skip tests that should be skipped on FreeBSD.""" 928 return skipIfPlatform(["freebsd"])(func) 929 930def getDarwinOSTriples(): 931 return ['darwin', 'macosx', 'ios'] 932 933def skipIfDarwin(func): 934 """Decorate the item to skip tests that should be skipped on Darwin.""" 935 return skipIfPlatform(getDarwinOSTriples())(func) 936 937def skipIfLinux(func): 938 """Decorate the item to skip tests that should be skipped on Linux.""" 939 return skipIfPlatform(["linux"])(func) 940 941def skipUnlessHostLinux(func): 942 """Decorate the item to skip tests that should be skipped on any non Linux host.""" 943 return skipUnlessHostPlatform(["linux"])(func) 944 945def skipIfWindows(func): 946 """Decorate the item to skip tests that should be skipped on Windows.""" 947 return skipIfPlatform(["windows"])(func) 948 949def skipIfHostWindows(func): 950 """Decorate the item to skip tests that should be skipped on Windows.""" 951 return skipIfHostPlatform(["windows"])(func) 952 953def skipUnlessWindows(func): 954 """Decorate the item to skip tests that should be skipped on any non-Windows platform.""" 955 return skipUnlessPlatform(["windows"])(func) 956 957def skipUnlessDarwin(func): 958 """Decorate the item to skip tests that should be skipped on any non Darwin platform.""" 959 return skipUnlessPlatform(getDarwinOSTriples())(func) 960 961def skipUnlessGoInstalled(func): 962 """Decorate the item to skip tests when no Go compiler is available.""" 963 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 964 raise Exception("@skipIfGcc can only be used to decorate a test method") 965 @wraps(func) 966 def wrapper(*args, **kwargs): 967 from unittest2 import case 968 self = args[0] 969 compiler = self.getGoCompilerVersion() 970 if not compiler: 971 self.skipTest("skipping because go compiler not found") 972 else: 973 # Ensure the version is the minimum version supported by 974 # the LLDB go support. 975 match_version = re.search(r"(\d+\.\d+(\.\d+)?)", compiler) 976 if not match_version: 977 # Couldn't determine version. 978 self.skipTest( 979 "skipping because go version could not be parsed " 980 "out of {}".format(compiler)) 981 else: 982 from distutils.version import StrictVersion 983 min_strict_version = StrictVersion("1.4.0") 984 compiler_strict_version = StrictVersion(match_version.group(1)) 985 if compiler_strict_version < min_strict_version: 986 self.skipTest( 987 "skipping because available go version ({}) does " 988 "not meet minimum required go version ({})".format( 989 compiler_strict_version, 990 min_strict_version)) 991 func(*args, **kwargs) 992 return wrapper 993 994def getPlatform(): 995 """Returns the target platform which the tests are running on.""" 996 platform = lldb.DBG.GetSelectedPlatform().GetTriple().split('-')[2] 997 if platform.startswith('freebsd'): 998 platform = 'freebsd' 999 return platform 1000 1001def getHostPlatform(): 1002 """Returns the host platform running the test suite.""" 1003 # Attempts to return a platform name matching a target Triple platform. 1004 if sys.platform.startswith('linux'): 1005 return 'linux' 1006 elif sys.platform.startswith('win32'): 1007 return 'windows' 1008 elif sys.platform.startswith('darwin'): 1009 return 'darwin' 1010 elif sys.platform.startswith('freebsd'): 1011 return 'freebsd' 1012 else: 1013 return sys.platform 1014 1015def platformIsDarwin(): 1016 """Returns true if the OS triple for the selected platform is any valid apple OS""" 1017 return getPlatform() in getDarwinOSTriples() 1018 1019def skipIfHostIncompatibleWithRemote(func): 1020 """Decorate the item to skip tests if binaries built on this host are incompatible.""" 1021 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 1022 raise Exception("@skipIfHostIncompatibleWithRemote can only be used to decorate a test method") 1023 @wraps(func) 1024 def wrapper(*args, **kwargs): 1025 from unittest2 import case 1026 self = args[0] 1027 host_arch = self.getLldbArchitecture() 1028 host_platform = getHostPlatform() 1029 target_arch = self.getArchitecture() 1030 target_platform = 'darwin' if self.platformIsDarwin() else self.getPlatform() 1031 if not (target_arch == 'x86_64' and host_arch == 'i386') and host_arch != target_arch: 1032 self.skipTest("skipping because target %s is not compatible with host architecture %s" % (target_arch, host_arch)) 1033 elif target_platform != host_platform: 1034 self.skipTest("skipping because target is %s but host is %s" % (target_platform, host_platform)) 1035 else: 1036 func(*args, **kwargs) 1037 return wrapper 1038 1039def skipIfHostPlatform(oslist): 1040 """Decorate the item to skip tests if running on one of the listed host platforms.""" 1041 return unittest2.skipIf(getHostPlatform() in oslist, 1042 "skip on %s" % (", ".join(oslist))) 1043 1044def skipUnlessHostPlatform(oslist): 1045 """Decorate the item to skip tests unless running on one of the listed host platforms.""" 1046 return unittest2.skipUnless(getHostPlatform() in oslist, 1047 "requires on of %s" % (", ".join(oslist))) 1048 1049def skipUnlessArch(archlist): 1050 """Decorate the item to skip tests unless running on one of the listed architectures.""" 1051 def myImpl(func): 1052 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 1053 raise Exception("@skipUnlessArch can only be used to decorate a test method") 1054 1055 @wraps(func) 1056 def wrapper(*args, **kwargs): 1057 self = args[0] 1058 if self.getArchitecture() not in archlist: 1059 self.skipTest("skipping for architecture %s (requires one of %s)" % 1060 (self.getArchitecture(), ", ".join(archlist))) 1061 else: 1062 func(*args, **kwargs) 1063 return wrapper 1064 1065 return myImpl 1066 1067def skipIfPlatform(oslist): 1068 """Decorate the item to skip tests if running on one of the listed platforms.""" 1069 return unittest2.skipIf(getPlatform() in oslist, 1070 "skip on %s" % (", ".join(oslist))) 1071 1072def skipUnlessPlatform(oslist): 1073 """Decorate the item to skip tests unless running on one of the listed platforms.""" 1074 return unittest2.skipUnless(getPlatform() in oslist, 1075 "requires on of %s" % (", ".join(oslist))) 1076 1077def skipIfLinuxClang(func): 1078 """Decorate the item to skip tests that should be skipped if building on 1079 Linux with clang. 1080 """ 1081 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 1082 raise Exception("@skipIfLinuxClang can only be used to decorate a test method") 1083 @wraps(func) 1084 def wrapper(*args, **kwargs): 1085 from unittest2 import case 1086 self = args[0] 1087 compiler = self.getCompiler() 1088 platform = self.getPlatform() 1089 if "clang" in compiler and platform == "linux": 1090 self.skipTest("skipping because Clang is used on Linux") 1091 else: 1092 func(*args, **kwargs) 1093 return wrapper 1094 1095# provide a function to skip on defined oslist, compiler version, and archs 1096# if none is specified for any argument, that argument won't be checked and thus means for all 1097# for example, 1098# @skipIf, skip for all platform/compiler/arch, 1099# @skipIf(compiler='gcc'), skip for gcc on all platform/architecture 1100# @skipIf(bugnumber, ["linux"], "gcc", ['>=', '4.9'], ['i386']), skip for gcc>=4.9 on linux with i386 1101 1102# TODO: refactor current code, to make skipIfxxx functions to call this function 1103def skipIf(bugnumber=None, oslist=None, compiler=None, compiler_version=None, archs=None, debug_info=None, swig_version=None, py_version=None): 1104 def fn(self): 1105 oslist_passes = oslist is None or self.getPlatform() in oslist 1106 compiler_passes = compiler is None or (compiler in self.getCompiler() and self.expectedCompilerVersion(compiler_version)) 1107 arch_passes = self.expectedArch(archs) 1108 debug_info_passes = debug_info is None or self.debug_info in debug_info 1109 swig_version_passes = (swig_version is None) or (not hasattr(lldb, 'swig_version')) or (check_expected_version(swig_version[0], swig_version[1], lldb.swig_version)) 1110 py_version_passes = (py_version is None) or check_expected_version(py_version[0], py_version[1], sys.version_info) 1111 1112 return (oslist_passes and 1113 compiler_passes and 1114 arch_passes and 1115 debug_info_passes and 1116 swig_version_passes and 1117 py_version_passes) 1118 1119 local_vars = locals() 1120 args = [x for x in inspect.getargspec(skipIf).args] 1121 arg_vals = [eval(x, globals(), local_vars) for x in args] 1122 args = [x for x in zip(args, arg_vals) if x[1] is not None] 1123 reasons = ['%s=%s' % (x, str(y)) for (x,y) in args] 1124 return skipTestIfFn(fn, bugnumber, skipReason='skipping because ' + ' && '.join(reasons)) 1125 1126def skipIfDebugInfo(bugnumber=None, debug_info=None): 1127 return skipIf(bugnumber=bugnumber, debug_info=debug_info) 1128 1129def skipIfDWO(bugnumber=None): 1130 return skipIfDebugInfo(bugnumber, ["dwo"]) 1131 1132def skipIfDwarf(bugnumber=None): 1133 return skipIfDebugInfo(bugnumber, ["dwarf"]) 1134 1135def skipIfDsym(bugnumber=None): 1136 return skipIfDebugInfo(bugnumber, ["dsym"]) 1137 1138def skipTestIfFn(expected_fn, bugnumber=None, skipReason=None): 1139 def skipTestIfFn_impl(func): 1140 @wraps(func) 1141 def wrapper(*args, **kwargs): 1142 from unittest2 import case 1143 self = args[0] 1144 if expected_fn(self): 1145 self.skipTest(skipReason) 1146 else: 1147 func(*args, **kwargs) 1148 return wrapper 1149 if six.callable(bugnumber): 1150 return skipTestIfFn_impl(bugnumber) 1151 else: 1152 return skipTestIfFn_impl 1153 1154def skipIfGcc(func): 1155 """Decorate the item to skip tests that should be skipped if building with gcc .""" 1156 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 1157 raise Exception("@skipIfGcc can only be used to decorate a test method") 1158 @wraps(func) 1159 def wrapper(*args, **kwargs): 1160 from unittest2 import case 1161 self = args[0] 1162 compiler = self.getCompiler() 1163 if "gcc" in compiler: 1164 self.skipTest("skipping because gcc is the test compiler") 1165 else: 1166 func(*args, **kwargs) 1167 return wrapper 1168 1169def skipIfIcc(func): 1170 """Decorate the item to skip tests that should be skipped if building with icc .""" 1171 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 1172 raise Exception("@skipIfIcc can only be used to decorate a test method") 1173 @wraps(func) 1174 def wrapper(*args, **kwargs): 1175 from unittest2 import case 1176 self = args[0] 1177 compiler = self.getCompiler() 1178 if "icc" in compiler: 1179 self.skipTest("skipping because icc is the test compiler") 1180 else: 1181 func(*args, **kwargs) 1182 return wrapper 1183 1184def skipIfi386(func): 1185 """Decorate the item to skip tests that should be skipped if building 32-bit.""" 1186 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 1187 raise Exception("@skipIfi386 can only be used to decorate a test method") 1188 @wraps(func) 1189 def wrapper(*args, **kwargs): 1190 from unittest2 import case 1191 self = args[0] 1192 if "i386" == self.getArchitecture(): 1193 self.skipTest("skipping because i386 is not a supported architecture") 1194 else: 1195 func(*args, **kwargs) 1196 return wrapper 1197 1198def skipIfTargetAndroid(api_levels=None, archs=None): 1199 """Decorator to skip tests when the target is Android. 1200 1201 Arguments: 1202 api_levels - The API levels for which the test should be skipped. If 1203 it is None, then the test will be skipped for all API levels. 1204 arch - A sequence of architecture names specifying the architectures 1205 for which a test is skipped. None means all architectures. 1206 """ 1207 def myImpl(func): 1208 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 1209 raise Exception("@skipIfTargetAndroid can only be used to " 1210 "decorate a test method") 1211 @wraps(func) 1212 def wrapper(*args, **kwargs): 1213 from unittest2 import case 1214 self = args[0] 1215 if matchAndroid(api_levels, archs)(self): 1216 self.skipTest("skiped on Android target with API %d and architecture %s" % 1217 (android_device_api(), self.getArchitecture())) 1218 func(*args, **kwargs) 1219 return wrapper 1220 return myImpl 1221 1222def skipUnlessCompilerRt(func): 1223 """Decorate the item to skip tests if testing remotely.""" 1224 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 1225 raise Exception("@skipUnless can only be used to decorate a test method") 1226 @wraps(func) 1227 def wrapper(*args, **kwargs): 1228 from unittest2 import case 1229 import os.path 1230 compilerRtPath = os.path.join(os.path.dirname(__file__), "..", "..", "..", "..", "llvm","projects","compiler-rt") 1231 print(compilerRtPath) 1232 if not os.path.exists(compilerRtPath): 1233 self = args[0] 1234 self.skipTest("skip if compiler-rt not found") 1235 else: 1236 func(*args, **kwargs) 1237 return wrapper 1238 1239class _PlatformContext(object): 1240 """Value object class which contains platform-specific options.""" 1241 1242 def __init__(self, shlib_environment_var, shlib_prefix, shlib_extension): 1243 self.shlib_environment_var = shlib_environment_var 1244 self.shlib_prefix = shlib_prefix 1245 self.shlib_extension = shlib_extension 1246 1247 1248class Base(unittest2.TestCase): 1249 """ 1250 Abstract base for performing lldb (see TestBase) or other generic tests (see 1251 BenchBase for one example). lldbtest.Base works with the test driver to 1252 accomplish things. 1253 1254 """ 1255 1256 # The concrete subclass should override this attribute. 1257 mydir = None 1258 1259 # Keep track of the old current working directory. 1260 oldcwd = None 1261 1262 @staticmethod 1263 def compute_mydir(test_file): 1264 '''Subclasses should call this function to correctly calculate the required "mydir" attribute as follows: 1265 1266 mydir = TestBase.compute_mydir(__file__)''' 1267 test_dir = os.path.dirname(test_file) 1268 return test_dir[len(os.environ["LLDB_TEST"])+1:] 1269 1270 def TraceOn(self): 1271 """Returns True if we are in trace mode (tracing detailed test execution).""" 1272 return traceAlways 1273 1274 @classmethod 1275 def setUpClass(cls): 1276 """ 1277 Python unittest framework class setup fixture. 1278 Do current directory manipulation. 1279 """ 1280 # Fail fast if 'mydir' attribute is not overridden. 1281 if not cls.mydir or len(cls.mydir) == 0: 1282 raise Exception("Subclasses must override the 'mydir' attribute.") 1283 1284 # Save old working directory. 1285 cls.oldcwd = os.getcwd() 1286 1287 # Change current working directory if ${LLDB_TEST} is defined. 1288 # See also dotest.py which sets up ${LLDB_TEST}. 1289 if ("LLDB_TEST" in os.environ): 1290 full_dir = os.path.join(os.environ["LLDB_TEST"], cls.mydir) 1291 if traceAlways: 1292 print("Change dir to:", full_dir, file=sys.stderr) 1293 os.chdir(os.path.join(os.environ["LLDB_TEST"], cls.mydir)) 1294 1295 if debug_confirm_directory_exclusivity: 1296 import lock 1297 cls.dir_lock = lock.Lock(os.path.join(full_dir, ".dirlock")) 1298 try: 1299 cls.dir_lock.try_acquire() 1300 # write the class that owns the lock into the lock file 1301 cls.dir_lock.handle.write(cls.__name__) 1302 except IOError as ioerror: 1303 # nothing else should have this directory lock 1304 # wait here until we get a lock 1305 cls.dir_lock.acquire() 1306 # read the previous owner from the lock file 1307 lock_id = cls.dir_lock.handle.read() 1308 print("LOCK ERROR: {} wants to lock '{}' but it is already locked by '{}'".format(cls.__name__, full_dir, lock_id), file=sys.stderr) 1309 raise ioerror 1310 1311 # Set platform context. 1312 if platformIsDarwin(): 1313 cls.platformContext = _PlatformContext('DYLD_LIBRARY_PATH', 'lib', 'dylib') 1314 elif getPlatform() == "linux" or getPlatform() == "freebsd": 1315 cls.platformContext = _PlatformContext('LD_LIBRARY_PATH', 'lib', 'so') 1316 else: 1317 cls.platformContext = None 1318 1319 @classmethod 1320 def tearDownClass(cls): 1321 """ 1322 Python unittest framework class teardown fixture. 1323 Do class-wide cleanup. 1324 """ 1325 1326 if doCleanup and not lldb.skip_build_and_cleanup: 1327 # First, let's do the platform-specific cleanup. 1328 module = builder_module() 1329 module.cleanup() 1330 1331 # Subclass might have specific cleanup function defined. 1332 if getattr(cls, "classCleanup", None): 1333 if traceAlways: 1334 print("Call class-specific cleanup function for class:", cls, file=sys.stderr) 1335 try: 1336 cls.classCleanup() 1337 except: 1338 exc_type, exc_value, exc_tb = sys.exc_info() 1339 traceback.print_exception(exc_type, exc_value, exc_tb) 1340 1341 if debug_confirm_directory_exclusivity: 1342 cls.dir_lock.release() 1343 del cls.dir_lock 1344 1345 # Restore old working directory. 1346 if traceAlways: 1347 print("Restore dir to:", cls.oldcwd, file=sys.stderr) 1348 os.chdir(cls.oldcwd) 1349 1350 @classmethod 1351 def skipLongRunningTest(cls): 1352 """ 1353 By default, we skip long running test case. 1354 This can be overridden by passing '-l' to the test driver (dotest.py). 1355 """ 1356 if "LLDB_SKIP_LONG_RUNNING_TEST" in os.environ and "NO" == os.environ["LLDB_SKIP_LONG_RUNNING_TEST"]: 1357 return False 1358 else: 1359 return True 1360 1361 def enableLogChannelsForCurrentTest(self): 1362 if len(lldbtest_config.channels) == 0: 1363 return 1364 1365 # if debug channels are specified in lldbtest_config.channels, 1366 # create a new set of log files for every test 1367 log_basename = self.getLogBasenameForCurrentTest() 1368 1369 # confirm that the file is writeable 1370 host_log_path = "{}-host.log".format(log_basename) 1371 open(host_log_path, 'w').close() 1372 1373 log_enable = "log enable -Tpn -f {} ".format(host_log_path) 1374 for channel_with_categories in lldbtest_config.channels: 1375 channel_then_categories = channel_with_categories.split(' ', 1) 1376 channel = channel_then_categories[0] 1377 if len(channel_then_categories) > 1: 1378 categories = channel_then_categories[1] 1379 else: 1380 categories = "default" 1381 1382 if channel == "gdb-remote": 1383 # communicate gdb-remote categories to debugserver 1384 os.environ["LLDB_DEBUGSERVER_LOG_FLAGS"] = categories 1385 1386 self.ci.HandleCommand(log_enable + channel_with_categories, self.res) 1387 if not self.res.Succeeded(): 1388 raise Exception('log enable failed (check LLDB_LOG_OPTION env variable)') 1389 1390 # Communicate log path name to debugserver & lldb-server 1391 server_log_path = "{}-server.log".format(log_basename) 1392 open(server_log_path, 'w').close() 1393 os.environ["LLDB_DEBUGSERVER_LOG_FILE"] = server_log_path 1394 1395 # Communicate channels to lldb-server 1396 os.environ["LLDB_SERVER_LOG_CHANNELS"] = ":".join(lldbtest_config.channels) 1397 1398 if len(lldbtest_config.channels) == 0: 1399 return 1400 1401 def disableLogChannelsForCurrentTest(self): 1402 # close all log files that we opened 1403 for channel_and_categories in lldbtest_config.channels: 1404 # channel format - <channel-name> [<category0> [<category1> ...]] 1405 channel = channel_and_categories.split(' ', 1)[0] 1406 self.ci.HandleCommand("log disable " + channel, self.res) 1407 if not self.res.Succeeded(): 1408 raise Exception('log disable failed (check LLDB_LOG_OPTION env variable)') 1409 1410 def setUp(self): 1411 """Fixture for unittest test case setup. 1412 1413 It works with the test driver to conditionally skip tests and does other 1414 initializations.""" 1415 #import traceback 1416 #traceback.print_stack() 1417 1418 if "LIBCXX_PATH" in os.environ: 1419 self.libcxxPath = os.environ["LIBCXX_PATH"] 1420 else: 1421 self.libcxxPath = None 1422 1423 if "LLDBMI_EXEC" in os.environ: 1424 self.lldbMiExec = os.environ["LLDBMI_EXEC"] 1425 else: 1426 self.lldbMiExec = None 1427 1428 # If we spawn an lldb process for test (via pexpect), do not load the 1429 # init file unless told otherwise. 1430 if "NO_LLDBINIT" in os.environ and "NO" == os.environ["NO_LLDBINIT"]: 1431 self.lldbOption = "" 1432 else: 1433 self.lldbOption = "--no-lldbinit" 1434 1435 # Assign the test method name to self.testMethodName. 1436 # 1437 # For an example of the use of this attribute, look at test/types dir. 1438 # There are a bunch of test cases under test/types and we don't want the 1439 # module cacheing subsystem to be confused with executable name "a.out" 1440 # used for all the test cases. 1441 self.testMethodName = self._testMethodName 1442 1443 # Benchmarks test is decorated with @benchmarks_test, 1444 # which also sets the "__benchmarks_test__" attribute of the 1445 # function object to True. 1446 try: 1447 if lldb.just_do_benchmarks_test: 1448 testMethod = getattr(self, self._testMethodName) 1449 if getattr(testMethod, "__benchmarks_test__", False): 1450 pass 1451 else: 1452 self.skipTest("non benchmarks test") 1453 except AttributeError: 1454 pass 1455 1456 # This is for the case of directly spawning 'lldb'/'gdb' and interacting 1457 # with it using pexpect. 1458 self.child = None 1459 self.child_prompt = "(lldb) " 1460 # If the child is interacting with the embedded script interpreter, 1461 # there are two exits required during tear down, first to quit the 1462 # embedded script interpreter and second to quit the lldb command 1463 # interpreter. 1464 self.child_in_script_interpreter = False 1465 1466 # These are for customized teardown cleanup. 1467 self.dict = None 1468 self.doTearDownCleanup = False 1469 # And in rare cases where there are multiple teardown cleanups. 1470 self.dicts = [] 1471 self.doTearDownCleanups = False 1472 1473 # List of spawned subproces.Popen objects 1474 self.subprocesses = [] 1475 1476 # List of forked process PIDs 1477 self.forkedProcessPids = [] 1478 1479 # Create a string buffer to record the session info, to be dumped into a 1480 # test case specific file if test failure is encountered. 1481 self.log_basename = self.getLogBasenameForCurrentTest() 1482 1483 session_file = "{}.log".format(self.log_basename) 1484 # Python 3 doesn't support unbuffered I/O in text mode. Open buffered. 1485 self.session = open(session_file, "w") 1486 1487 # Optimistically set __errored__, __failed__, __expected__ to False 1488 # initially. If the test errored/failed, the session info 1489 # (self.session) is then dumped into a session specific file for 1490 # diagnosis. 1491 self.__cleanup_errored__ = False 1492 self.__errored__ = False 1493 self.__failed__ = False 1494 self.__expected__ = False 1495 # We are also interested in unexpected success. 1496 self.__unexpected__ = False 1497 # And skipped tests. 1498 self.__skipped__ = False 1499 1500 # See addTearDownHook(self, hook) which allows the client to add a hook 1501 # function to be run during tearDown() time. 1502 self.hooks = [] 1503 1504 # See HideStdout(self). 1505 self.sys_stdout_hidden = False 1506 1507 if self.platformContext: 1508 # set environment variable names for finding shared libraries 1509 self.dylibPath = self.platformContext.shlib_environment_var 1510 1511 # Create the debugger instance if necessary. 1512 try: 1513 self.dbg = lldb.DBG 1514 except AttributeError: 1515 self.dbg = lldb.SBDebugger.Create() 1516 1517 if not self.dbg: 1518 raise Exception('Invalid debugger instance') 1519 1520 # Retrieve the associated command interpreter instance. 1521 self.ci = self.dbg.GetCommandInterpreter() 1522 if not self.ci: 1523 raise Exception('Could not get the command interpreter') 1524 1525 # And the result object. 1526 self.res = lldb.SBCommandReturnObject() 1527 1528 self.enableLogChannelsForCurrentTest() 1529 1530 #Initialize debug_info 1531 self.debug_info = None 1532 1533 def runHooks(self, child=None, child_prompt=None, use_cmd_api=False): 1534 """Perform the run hooks to bring lldb debugger to the desired state. 1535 1536 By default, expect a pexpect spawned child and child prompt to be 1537 supplied (use_cmd_api=False). If use_cmd_api is true, ignore the child 1538 and child prompt and use self.runCmd() to run the hooks one by one. 1539 1540 Note that child is a process spawned by pexpect.spawn(). If not, your 1541 test case is mostly likely going to fail. 1542 1543 See also dotest.py where lldb.runHooks are processed/populated. 1544 """ 1545 if not lldb.runHooks: 1546 self.skipTest("No runhooks specified for lldb, skip the test") 1547 if use_cmd_api: 1548 for hook in lldb.runhooks: 1549 self.runCmd(hook) 1550 else: 1551 if not child or not child_prompt: 1552 self.fail("Both child and child_prompt need to be defined.") 1553 for hook in lldb.runHooks: 1554 child.sendline(hook) 1555 child.expect_exact(child_prompt) 1556 1557 def setAsync(self, value): 1558 """ Sets async mode to True/False and ensures it is reset after the testcase completes.""" 1559 old_async = self.dbg.GetAsync() 1560 self.dbg.SetAsync(value) 1561 self.addTearDownHook(lambda: self.dbg.SetAsync(old_async)) 1562 1563 def cleanupSubprocesses(self): 1564 # Ensure any subprocesses are cleaned up 1565 for p in self.subprocesses: 1566 p.terminate() 1567 del p 1568 del self.subprocesses[:] 1569 # Ensure any forked processes are cleaned up 1570 for pid in self.forkedProcessPids: 1571 if os.path.exists("/proc/" + str(pid)): 1572 os.kill(pid, signal.SIGTERM) 1573 1574 def spawnSubprocess(self, executable, args=[], install_remote=True): 1575 """ Creates a subprocess.Popen object with the specified executable and arguments, 1576 saves it in self.subprocesses, and returns the object. 1577 NOTE: if using this function, ensure you also call: 1578 1579 self.addTearDownHook(self.cleanupSubprocesses) 1580 1581 otherwise the test suite will leak processes. 1582 """ 1583 proc = _RemoteProcess(install_remote) if lldb.remote_platform else _LocalProcess(self.TraceOn()) 1584 proc.launch(executable, args) 1585 self.subprocesses.append(proc) 1586 return proc 1587 1588 def forkSubprocess(self, executable, args=[]): 1589 """ Fork a subprocess with its own group ID. 1590 NOTE: if using this function, ensure you also call: 1591 1592 self.addTearDownHook(self.cleanupSubprocesses) 1593 1594 otherwise the test suite will leak processes. 1595 """ 1596 child_pid = os.fork() 1597 if child_pid == 0: 1598 # If more I/O support is required, this can be beefed up. 1599 fd = os.open(os.devnull, os.O_RDWR) 1600 os.dup2(fd, 1) 1601 os.dup2(fd, 2) 1602 # This call causes the child to have its of group ID 1603 os.setpgid(0,0) 1604 os.execvp(executable, [executable] + args) 1605 # Give the child time to get through the execvp() call 1606 time.sleep(0.1) 1607 self.forkedProcessPids.append(child_pid) 1608 return child_pid 1609 1610 def HideStdout(self): 1611 """Hide output to stdout from the user. 1612 1613 During test execution, there might be cases where we don't want to show the 1614 standard output to the user. For example, 1615 1616 self.runCmd(r'''sc print("\n\n\tHello!\n")''') 1617 1618 tests whether command abbreviation for 'script' works or not. There is no 1619 need to show the 'Hello' output to the user as long as the 'script' command 1620 succeeds and we are not in TraceOn() mode (see the '-t' option). 1621 1622 In this case, the test method calls self.HideStdout(self) to redirect the 1623 sys.stdout to a null device, and restores the sys.stdout upon teardown. 1624 1625 Note that you should only call this method at most once during a test case 1626 execution. Any subsequent call has no effect at all.""" 1627 if self.sys_stdout_hidden: 1628 return 1629 1630 self.sys_stdout_hidden = True 1631 old_stdout = sys.stdout 1632 sys.stdout = open(os.devnull, 'w') 1633 def restore_stdout(): 1634 sys.stdout = old_stdout 1635 self.addTearDownHook(restore_stdout) 1636 1637 # ======================================================================= 1638 # Methods for customized teardown cleanups as well as execution of hooks. 1639 # ======================================================================= 1640 1641 def setTearDownCleanup(self, dictionary=None): 1642 """Register a cleanup action at tearDown() time with a dictinary""" 1643 self.dict = dictionary 1644 self.doTearDownCleanup = True 1645 1646 def addTearDownCleanup(self, dictionary): 1647 """Add a cleanup action at tearDown() time with a dictinary""" 1648 self.dicts.append(dictionary) 1649 self.doTearDownCleanups = True 1650 1651 def addTearDownHook(self, hook): 1652 """ 1653 Add a function to be run during tearDown() time. 1654 1655 Hooks are executed in a first come first serve manner. 1656 """ 1657 if six.callable(hook): 1658 with recording(self, traceAlways) as sbuf: 1659 print("Adding tearDown hook:", getsource_if_available(hook), file=sbuf) 1660 self.hooks.append(hook) 1661 1662 return self 1663 1664 def deletePexpectChild(self): 1665 # This is for the case of directly spawning 'lldb' and interacting with it 1666 # using pexpect. 1667 if self.child and self.child.isalive(): 1668 import pexpect 1669 with recording(self, traceAlways) as sbuf: 1670 print("tearing down the child process....", file=sbuf) 1671 try: 1672 if self.child_in_script_interpreter: 1673 self.child.sendline('quit()') 1674 self.child.expect_exact(self.child_prompt) 1675 self.child.sendline('settings set interpreter.prompt-on-quit false') 1676 self.child.sendline('quit') 1677 self.child.expect(pexpect.EOF) 1678 except (ValueError, pexpect.ExceptionPexpect): 1679 # child is already terminated 1680 pass 1681 except OSError as exception: 1682 import errno 1683 if exception.errno != errno.EIO: 1684 # unexpected error 1685 raise 1686 # child is already terminated 1687 pass 1688 finally: 1689 # Give it one final blow to make sure the child is terminated. 1690 self.child.close() 1691 1692 def tearDown(self): 1693 """Fixture for unittest test case teardown.""" 1694 #import traceback 1695 #traceback.print_stack() 1696 1697 self.deletePexpectChild() 1698 1699 # Check and run any hook functions. 1700 for hook in reversed(self.hooks): 1701 with recording(self, traceAlways) as sbuf: 1702 print("Executing tearDown hook:", getsource_if_available(hook), file=sbuf) 1703 import inspect 1704 hook_argc = len(inspect.getargspec(hook).args) 1705 if hook_argc == 0 or getattr(hook,'im_self',None): 1706 hook() 1707 elif hook_argc == 1: 1708 hook(self) 1709 else: 1710 hook() # try the plain call and hope it works 1711 1712 del self.hooks 1713 1714 # Perform registered teardown cleanup. 1715 if doCleanup and self.doTearDownCleanup: 1716 self.cleanup(dictionary=self.dict) 1717 1718 # In rare cases where there are multiple teardown cleanups added. 1719 if doCleanup and self.doTearDownCleanups: 1720 if self.dicts: 1721 for dict in reversed(self.dicts): 1722 self.cleanup(dictionary=dict) 1723 1724 self.disableLogChannelsForCurrentTest() 1725 1726 # ========================================================= 1727 # Various callbacks to allow introspection of test progress 1728 # ========================================================= 1729 1730 def markError(self): 1731 """Callback invoked when an error (unexpected exception) errored.""" 1732 self.__errored__ = True 1733 with recording(self, False) as sbuf: 1734 # False because there's no need to write "ERROR" to the stderr twice. 1735 # Once by the Python unittest framework, and a second time by us. 1736 print("ERROR", file=sbuf) 1737 1738 def markCleanupError(self): 1739 """Callback invoked when an error occurs while a test is cleaning up.""" 1740 self.__cleanup_errored__ = True 1741 with recording(self, False) as sbuf: 1742 # False because there's no need to write "CLEANUP_ERROR" to the stderr twice. 1743 # Once by the Python unittest framework, and a second time by us. 1744 print("CLEANUP_ERROR", file=sbuf) 1745 1746 def markFailure(self): 1747 """Callback invoked when a failure (test assertion failure) occurred.""" 1748 self.__failed__ = True 1749 with recording(self, False) as sbuf: 1750 # False because there's no need to write "FAIL" to the stderr twice. 1751 # Once by the Python unittest framework, and a second time by us. 1752 print("FAIL", file=sbuf) 1753 1754 def markExpectedFailure(self,err,bugnumber): 1755 """Callback invoked when an expected failure/error occurred.""" 1756 self.__expected__ = True 1757 with recording(self, False) as sbuf: 1758 # False because there's no need to write "expected failure" to the 1759 # stderr twice. 1760 # Once by the Python unittest framework, and a second time by us. 1761 if bugnumber == None: 1762 print("expected failure", file=sbuf) 1763 else: 1764 print("expected failure (problem id:" + str(bugnumber) + ")", file=sbuf) 1765 1766 def markSkippedTest(self): 1767 """Callback invoked when a test is skipped.""" 1768 self.__skipped__ = True 1769 with recording(self, False) as sbuf: 1770 # False because there's no need to write "skipped test" to the 1771 # stderr twice. 1772 # Once by the Python unittest framework, and a second time by us. 1773 print("skipped test", file=sbuf) 1774 1775 def markUnexpectedSuccess(self, bugnumber): 1776 """Callback invoked when an unexpected success occurred.""" 1777 self.__unexpected__ = True 1778 with recording(self, False) as sbuf: 1779 # False because there's no need to write "unexpected success" to the 1780 # stderr twice. 1781 # Once by the Python unittest framework, and a second time by us. 1782 if bugnumber == None: 1783 print("unexpected success", file=sbuf) 1784 else: 1785 print("unexpected success (problem id:" + str(bugnumber) + ")", file=sbuf) 1786 1787 def getRerunArgs(self): 1788 return " -f %s.%s" % (self.__class__.__name__, self._testMethodName) 1789 1790 def getLogBasenameForCurrentTest(self, prefix=None): 1791 """ 1792 returns a partial path that can be used as the beginning of the name of multiple 1793 log files pertaining to this test 1794 1795 <session-dir>/<arch>-<compiler>-<test-file>.<test-class>.<test-method> 1796 """ 1797 dname = os.path.join(os.environ["LLDB_TEST"], 1798 os.environ["LLDB_SESSION_DIRNAME"]) 1799 if not os.path.isdir(dname): 1800 os.mkdir(dname) 1801 1802 compiler = self.getCompiler() 1803 1804 if compiler[1] == ':': 1805 compiler = compiler[2:] 1806 if os.path.altsep is not None: 1807 compiler = compiler.replace(os.path.altsep, os.path.sep) 1808 1809 fname = "{}-{}-{}".format(self.id(), self.getArchitecture(), "_".join(compiler.split(os.path.sep))) 1810 if len(fname) > 200: 1811 fname = "{}-{}-{}".format(self.id(), self.getArchitecture(), compiler.split(os.path.sep)[-1]) 1812 1813 if prefix is not None: 1814 fname = "{}-{}".format(prefix, fname) 1815 1816 return os.path.join(dname, fname) 1817 1818 def dumpSessionInfo(self): 1819 """ 1820 Dump the debugger interactions leading to a test error/failure. This 1821 allows for more convenient postmortem analysis. 1822 1823 See also LLDBTestResult (dotest.py) which is a singlton class derived 1824 from TextTestResult and overwrites addError, addFailure, and 1825 addExpectedFailure methods to allow us to to mark the test instance as 1826 such. 1827 """ 1828 1829 # We are here because self.tearDown() detected that this test instance 1830 # either errored or failed. The lldb.test_result singleton contains 1831 # two lists (erros and failures) which get populated by the unittest 1832 # framework. Look over there for stack trace information. 1833 # 1834 # The lists contain 2-tuples of TestCase instances and strings holding 1835 # formatted tracebacks. 1836 # 1837 # See http://docs.python.org/library/unittest.html#unittest.TestResult. 1838 1839 # output tracebacks into session 1840 pairs = [] 1841 if self.__errored__: 1842 pairs = lldb.test_result.errors 1843 prefix = 'Error' 1844 elif self.__cleanup_errored__: 1845 pairs = lldb.test_result.cleanup_errors 1846 prefix = 'CleanupError' 1847 elif self.__failed__: 1848 pairs = lldb.test_result.failures 1849 prefix = 'Failure' 1850 elif self.__expected__: 1851 pairs = lldb.test_result.expectedFailures 1852 prefix = 'ExpectedFailure' 1853 elif self.__skipped__: 1854 prefix = 'SkippedTest' 1855 elif self.__unexpected__: 1856 prefix = 'UnexpectedSuccess' 1857 else: 1858 prefix = 'Success' 1859 1860 if not self.__unexpected__ and not self.__skipped__: 1861 for test, traceback in pairs: 1862 if test is self: 1863 print(traceback, file=self.session) 1864 1865 # put footer (timestamp/rerun instructions) into session 1866 testMethod = getattr(self, self._testMethodName) 1867 if getattr(testMethod, "__benchmarks_test__", False): 1868 benchmarks = True 1869 else: 1870 benchmarks = False 1871 1872 import datetime 1873 print("Session info generated @", datetime.datetime.now().ctime(), file=self.session) 1874 print("To rerun this test, issue the following command from the 'test' directory:\n", file=self.session) 1875 print("./dotest.py %s -v %s %s" % (self.getRunOptions(), 1876 ('+b' if benchmarks else '-t'), 1877 self.getRerunArgs()), file=self.session) 1878 self.session.close() 1879 del self.session 1880 1881 # process the log files 1882 log_files_for_this_test = glob.glob(self.log_basename + "*") 1883 1884 if prefix != 'Success' or lldbtest_config.log_success: 1885 # keep all log files, rename them to include prefix 1886 dst_log_basename = self.getLogBasenameForCurrentTest(prefix) 1887 for src in log_files_for_this_test: 1888 if os.path.isfile(src): 1889 dst = src.replace(self.log_basename, dst_log_basename) 1890 if os.name == "nt" and os.path.isfile(dst): 1891 # On Windows, renaming a -> b will throw an exception if b exists. On non-Windows platforms 1892 # it silently replaces the destination. Ultimately this means that atomic renames are not 1893 # guaranteed to be possible on Windows, but we need this to work anyway, so just remove the 1894 # destination first if it already exists. 1895 os.remove(dst) 1896 1897 os.rename(src, dst) 1898 else: 1899 # success! (and we don't want log files) delete log files 1900 for log_file in log_files_for_this_test: 1901 try: 1902 os.unlink(log_file) 1903 except: 1904 # We've seen consistent unlink failures on Windows, perhaps because the 1905 # just-created log file is being scanned by anti-virus. Empirically, this 1906 # sleep-and-retry approach allows tests to succeed much more reliably. 1907 # Attempts to figure out exactly what process was still holding a file handle 1908 # have failed because running instrumentation like Process Monitor seems to 1909 # slow things down enough that the problem becomes much less consistent. 1910 time.sleep(0.5) 1911 os.unlink(log_file) 1912 1913 # ==================================================== 1914 # Config. methods supported through a plugin interface 1915 # (enables reading of the current test configuration) 1916 # ==================================================== 1917 1918 def getArchitecture(self): 1919 """Returns the architecture in effect the test suite is running with.""" 1920 module = builder_module() 1921 arch = module.getArchitecture() 1922 if arch == 'amd64': 1923 arch = 'x86_64' 1924 return arch 1925 1926 def getLldbArchitecture(self): 1927 """Returns the architecture of the lldb binary.""" 1928 if not hasattr(self, 'lldbArchitecture'): 1929 1930 # spawn local process 1931 command = [ 1932 lldbtest_config.lldbExec, 1933 "-o", 1934 "file " + lldbtest_config.lldbExec, 1935 "-o", 1936 "quit" 1937 ] 1938 1939 output = check_output(command) 1940 str = output.decode("utf-8"); 1941 1942 for line in str.splitlines(): 1943 m = re.search("Current executable set to '.*' \\((.*)\\)\\.", line) 1944 if m: 1945 self.lldbArchitecture = m.group(1) 1946 break 1947 1948 return self.lldbArchitecture 1949 1950 def getCompiler(self): 1951 """Returns the compiler in effect the test suite is running with.""" 1952 module = builder_module() 1953 return module.getCompiler() 1954 1955 def getCompilerBinary(self): 1956 """Returns the compiler binary the test suite is running with.""" 1957 return self.getCompiler().split()[0] 1958 1959 def getCompilerVersion(self): 1960 """ Returns a string that represents the compiler version. 1961 Supports: llvm, clang. 1962 """ 1963 from .lldbutil import which 1964 version = 'unknown' 1965 1966 compiler = self.getCompilerBinary() 1967 version_output = system([[which(compiler), "-v"]])[1] 1968 for line in version_output.split(os.linesep): 1969 m = re.search('version ([0-9\.]+)', line) 1970 if m: 1971 version = m.group(1) 1972 return version 1973 1974 def getGoCompilerVersion(self): 1975 """ Returns a string that represents the go compiler version, or None if go is not found. 1976 """ 1977 compiler = which("go") 1978 if compiler: 1979 version_output = system([[compiler, "version"]])[0] 1980 for line in version_output.split(os.linesep): 1981 m = re.search('go version (devel|go\\S+)', line) 1982 if m: 1983 return m.group(1) 1984 return None 1985 1986 def platformIsDarwin(self): 1987 """Returns true if the OS triple for the selected platform is any valid apple OS""" 1988 return platformIsDarwin() 1989 1990 def getPlatform(self): 1991 """Returns the target platform the test suite is running on.""" 1992 return getPlatform() 1993 1994 def isIntelCompiler(self): 1995 """ Returns true if using an Intel (ICC) compiler, false otherwise. """ 1996 return any([x in self.getCompiler() for x in ["icc", "icpc", "icl"]]) 1997 1998 def expectedCompilerVersion(self, compiler_version): 1999 """Returns True iff compiler_version[1] matches the current compiler version. 2000 Use compiler_version[0] to specify the operator used to determine if a match has occurred. 2001 Any operator other than the following defaults to an equality test: 2002 '>', '>=', "=>", '<', '<=', '=<', '!=', "!" or 'not' 2003 """ 2004 if (compiler_version == None): 2005 return True 2006 operator = str(compiler_version[0]) 2007 version = compiler_version[1] 2008 2009 if (version == None): 2010 return True 2011 if (operator == '>'): 2012 return self.getCompilerVersion() > version 2013 if (operator == '>=' or operator == '=>'): 2014 return self.getCompilerVersion() >= version 2015 if (operator == '<'): 2016 return self.getCompilerVersion() < version 2017 if (operator == '<=' or operator == '=<'): 2018 return self.getCompilerVersion() <= version 2019 if (operator == '!=' or operator == '!' or operator == 'not'): 2020 return str(version) not in str(self.getCompilerVersion()) 2021 return str(version) in str(self.getCompilerVersion()) 2022 2023 def expectedCompiler(self, compilers): 2024 """Returns True iff any element of compilers is a sub-string of the current compiler.""" 2025 if (compilers == None): 2026 return True 2027 2028 for compiler in compilers: 2029 if compiler in self.getCompiler(): 2030 return True 2031 2032 return False 2033 2034 def expectedArch(self, archs): 2035 """Returns True iff any element of archs is a sub-string of the current architecture.""" 2036 if (archs == None): 2037 return True 2038 2039 for arch in archs: 2040 if arch in self.getArchitecture(): 2041 return True 2042 2043 return False 2044 2045 def getRunOptions(self): 2046 """Command line option for -A and -C to run this test again, called from 2047 self.dumpSessionInfo().""" 2048 arch = self.getArchitecture() 2049 comp = self.getCompiler() 2050 if arch: 2051 option_str = "-A " + arch 2052 else: 2053 option_str = "" 2054 if comp: 2055 option_str += " -C " + comp 2056 return option_str 2057 2058 # ================================================== 2059 # Build methods supported through a plugin interface 2060 # ================================================== 2061 2062 def getstdlibFlag(self): 2063 """ Returns the proper -stdlib flag, or empty if not required.""" 2064 if self.platformIsDarwin() or self.getPlatform() == "freebsd": 2065 stdlibflag = "-stdlib=libc++" 2066 else: 2067 stdlibflag = "" 2068 return stdlibflag 2069 2070 def getstdFlag(self): 2071 """ Returns the proper stdflag. """ 2072 if "gcc" in self.getCompiler() and "4.6" in self.getCompilerVersion(): 2073 stdflag = "-std=c++0x" 2074 else: 2075 stdflag = "-std=c++11" 2076 return stdflag 2077 2078 def buildDriver(self, sources, exe_name): 2079 """ Platform-specific way to build a program that links with LLDB (via the liblldb.so 2080 or LLDB.framework). 2081 """ 2082 2083 stdflag = self.getstdFlag() 2084 stdlibflag = self.getstdlibFlag() 2085 2086 lib_dir = os.environ["LLDB_LIB_DIR"] 2087 if sys.platform.startswith("darwin"): 2088 dsym = os.path.join(lib_dir, 'LLDB.framework', 'LLDB') 2089 d = {'CXX_SOURCES' : sources, 2090 'EXE' : exe_name, 2091 'CFLAGS_EXTRAS' : "%s %s" % (stdflag, stdlibflag), 2092 'FRAMEWORK_INCLUDES' : "-F%s" % lib_dir, 2093 'LD_EXTRAS' : "%s -Wl,-rpath,%s" % (dsym, lib_dir), 2094 } 2095 elif sys.platform.startswith('freebsd') or sys.platform.startswith("linux") or os.environ.get('LLDB_BUILD_TYPE') == 'Makefile': 2096 d = {'CXX_SOURCES' : sources, 2097 'EXE' : exe_name, 2098 'CFLAGS_EXTRAS' : "%s %s -I%s" % (stdflag, stdlibflag, os.path.join(os.environ["LLDB_SRC"], "include")), 2099 'LD_EXTRAS' : "-L%s -llldb" % lib_dir} 2100 elif sys.platform.startswith('win'): 2101 d = {'CXX_SOURCES' : sources, 2102 'EXE' : exe_name, 2103 'CFLAGS_EXTRAS' : "%s %s -I%s" % (stdflag, stdlibflag, os.path.join(os.environ["LLDB_SRC"], "include")), 2104 'LD_EXTRAS' : "-L%s -lliblldb" % os.environ["LLDB_IMPLIB_DIR"]} 2105 if self.TraceOn(): 2106 print("Building LLDB Driver (%s) from sources %s" % (exe_name, sources)) 2107 2108 self.buildDefault(dictionary=d) 2109 2110 def buildLibrary(self, sources, lib_name): 2111 """Platform specific way to build a default library. """ 2112 2113 stdflag = self.getstdFlag() 2114 2115 lib_dir = os.environ["LLDB_LIB_DIR"] 2116 if self.platformIsDarwin(): 2117 dsym = os.path.join(lib_dir, 'LLDB.framework', 'LLDB') 2118 d = {'DYLIB_CXX_SOURCES' : sources, 2119 'DYLIB_NAME' : lib_name, 2120 'CFLAGS_EXTRAS' : "%s -stdlib=libc++" % stdflag, 2121 'FRAMEWORK_INCLUDES' : "-F%s" % lib_dir, 2122 'LD_EXTRAS' : "%s -Wl,-rpath,%s -dynamiclib" % (dsym, lib_dir), 2123 } 2124 elif self.getPlatform() == 'freebsd' or self.getPlatform() == 'linux' or os.environ.get('LLDB_BUILD_TYPE') == 'Makefile': 2125 d = {'DYLIB_CXX_SOURCES' : sources, 2126 'DYLIB_NAME' : lib_name, 2127 'CFLAGS_EXTRAS' : "%s -I%s -fPIC" % (stdflag, os.path.join(os.environ["LLDB_SRC"], "include")), 2128 'LD_EXTRAS' : "-shared -L%s -llldb" % lib_dir} 2129 elif self.getPlatform() == 'windows': 2130 d = {'DYLIB_CXX_SOURCES' : sources, 2131 'DYLIB_NAME' : lib_name, 2132 'CFLAGS_EXTRAS' : "%s -I%s -fPIC" % (stdflag, os.path.join(os.environ["LLDB_SRC"], "include")), 2133 'LD_EXTRAS' : "-shared -l%s\liblldb.lib" % self.os.environ["LLDB_IMPLIB_DIR"]} 2134 if self.TraceOn(): 2135 print("Building LLDB Library (%s) from sources %s" % (lib_name, sources)) 2136 2137 self.buildDefault(dictionary=d) 2138 2139 def buildProgram(self, sources, exe_name): 2140 """ Platform specific way to build an executable from C/C++ sources. """ 2141 d = {'CXX_SOURCES' : sources, 2142 'EXE' : exe_name} 2143 self.buildDefault(dictionary=d) 2144 2145 def buildDefault(self, architecture=None, compiler=None, dictionary=None, clean=True): 2146 """Platform specific way to build the default binaries.""" 2147 if lldb.skip_build_and_cleanup: 2148 return 2149 module = builder_module() 2150 if target_is_android(): 2151 dictionary = append_android_envs(dictionary) 2152 if not module.buildDefault(self, architecture, compiler, dictionary, clean): 2153 raise Exception("Don't know how to build default binary") 2154 2155 def buildDsym(self, architecture=None, compiler=None, dictionary=None, clean=True): 2156 """Platform specific way to build binaries with dsym info.""" 2157 if lldb.skip_build_and_cleanup: 2158 return 2159 module = builder_module() 2160 if not module.buildDsym(self, architecture, compiler, dictionary, clean): 2161 raise Exception("Don't know how to build binary with dsym") 2162 2163 def buildDwarf(self, architecture=None, compiler=None, dictionary=None, clean=True): 2164 """Platform specific way to build binaries with dwarf maps.""" 2165 if lldb.skip_build_and_cleanup: 2166 return 2167 module = builder_module() 2168 if target_is_android(): 2169 dictionary = append_android_envs(dictionary) 2170 if not module.buildDwarf(self, architecture, compiler, dictionary, clean): 2171 raise Exception("Don't know how to build binary with dwarf") 2172 2173 def buildDwo(self, architecture=None, compiler=None, dictionary=None, clean=True): 2174 """Platform specific way to build binaries with dwarf maps.""" 2175 if lldb.skip_build_and_cleanup: 2176 return 2177 module = builder_module() 2178 if target_is_android(): 2179 dictionary = append_android_envs(dictionary) 2180 if not module.buildDwo(self, architecture, compiler, dictionary, clean): 2181 raise Exception("Don't know how to build binary with dwo") 2182 2183 def buildGo(self): 2184 """Build the default go binary. 2185 """ 2186 system([[which('go'), 'build -gcflags "-N -l" -o a.out main.go']]) 2187 2188 def signBinary(self, binary_path): 2189 if sys.platform.startswith("darwin"): 2190 codesign_cmd = "codesign --force --sign lldb_codesign %s" % (binary_path) 2191 call(codesign_cmd, shell=True) 2192 2193 def findBuiltClang(self): 2194 """Tries to find and use Clang from the build directory as the compiler (instead of the system compiler).""" 2195 paths_to_try = [ 2196 "llvm-build/Release+Asserts/x86_64/Release+Asserts/bin/clang", 2197 "llvm-build/Debug+Asserts/x86_64/Debug+Asserts/bin/clang", 2198 "llvm-build/Release/x86_64/Release/bin/clang", 2199 "llvm-build/Debug/x86_64/Debug/bin/clang", 2200 ] 2201 lldb_root_path = os.path.join(os.path.dirname(__file__), "..", "..", "..", "..") 2202 for p in paths_to_try: 2203 path = os.path.join(lldb_root_path, p) 2204 if os.path.exists(path): 2205 return path 2206 2207 # Tries to find clang at the same folder as the lldb 2208 path = os.path.join(os.path.dirname(lldbtest_config.lldbExec), "clang") 2209 if os.path.exists(path): 2210 return path 2211 2212 return os.environ["CC"] 2213 2214 def getBuildFlags(self, use_cpp11=True, use_libcxx=False, use_libstdcxx=False): 2215 """ Returns a dictionary (which can be provided to build* functions above) which 2216 contains OS-specific build flags. 2217 """ 2218 cflags = "" 2219 ldflags = "" 2220 2221 # On Mac OS X, unless specifically requested to use libstdc++, use libc++ 2222 if not use_libstdcxx and self.platformIsDarwin(): 2223 use_libcxx = True 2224 2225 if use_libcxx and self.libcxxPath: 2226 cflags += "-stdlib=libc++ " 2227 if self.libcxxPath: 2228 libcxxInclude = os.path.join(self.libcxxPath, "include") 2229 libcxxLib = os.path.join(self.libcxxPath, "lib") 2230 if os.path.isdir(libcxxInclude) and os.path.isdir(libcxxLib): 2231 cflags += "-nostdinc++ -I%s -L%s -Wl,-rpath,%s " % (libcxxInclude, libcxxLib, libcxxLib) 2232 2233 if use_cpp11: 2234 cflags += "-std=" 2235 if "gcc" in self.getCompiler() and "4.6" in self.getCompilerVersion(): 2236 cflags += "c++0x" 2237 else: 2238 cflags += "c++11" 2239 if self.platformIsDarwin() or self.getPlatform() == "freebsd": 2240 cflags += " -stdlib=libc++" 2241 elif "clang" in self.getCompiler(): 2242 cflags += " -stdlib=libstdc++" 2243 2244 return {'CFLAGS_EXTRAS' : cflags, 2245 'LD_EXTRAS' : ldflags, 2246 } 2247 2248 def cleanup(self, dictionary=None): 2249 """Platform specific way to do cleanup after build.""" 2250 if lldb.skip_build_and_cleanup: 2251 return 2252 module = builder_module() 2253 if not module.cleanup(self, dictionary): 2254 raise Exception("Don't know how to do cleanup with dictionary: "+dictionary) 2255 2256 def getLLDBLibraryEnvVal(self): 2257 """ Returns the path that the OS-specific library search environment variable 2258 (self.dylibPath) should be set to in order for a program to find the LLDB 2259 library. If an environment variable named self.dylibPath is already set, 2260 the new path is appended to it and returned. 2261 """ 2262 existing_library_path = os.environ[self.dylibPath] if self.dylibPath in os.environ else None 2263 lib_dir = os.environ["LLDB_LIB_DIR"] 2264 if existing_library_path: 2265 return "%s:%s" % (existing_library_path, lib_dir) 2266 elif sys.platform.startswith("darwin"): 2267 return os.path.join(lib_dir, 'LLDB.framework') 2268 else: 2269 return lib_dir 2270 2271 def getLibcPlusPlusLibs(self): 2272 if self.getPlatform() == 'freebsd' or self.getPlatform() == 'linux': 2273 return ['libc++.so.1'] 2274 else: 2275 return ['libc++.1.dylib','libc++abi.dylib'] 2276 2277# Metaclass for TestBase to change the list of test metods when a new TestCase is loaded. 2278# We change the test methods to create a new test method for each test for each debug info we are 2279# testing. The name of the new test method will be '<original-name>_<debug-info>' and with adding 2280# the new test method we remove the old method at the same time. 2281class LLDBTestCaseFactory(type): 2282 def __new__(cls, name, bases, attrs): 2283 newattrs = {} 2284 for attrname, attrvalue in attrs.items(): 2285 if attrname.startswith("test") and not getattr(attrvalue, "__no_debug_info_test__", False): 2286 @dsym_test 2287 @wraps(attrvalue) 2288 def dsym_test_method(self, attrvalue=attrvalue): 2289 self.debug_info = "dsym" 2290 return attrvalue(self) 2291 dsym_method_name = attrname + "_dsym" 2292 dsym_test_method.__name__ = dsym_method_name 2293 newattrs[dsym_method_name] = dsym_test_method 2294 2295 @dwarf_test 2296 @wraps(attrvalue) 2297 def dwarf_test_method(self, attrvalue=attrvalue): 2298 self.debug_info = "dwarf" 2299 return attrvalue(self) 2300 dwarf_method_name = attrname + "_dwarf" 2301 dwarf_test_method.__name__ = dwarf_method_name 2302 newattrs[dwarf_method_name] = dwarf_test_method 2303 2304 @dwo_test 2305 @wraps(attrvalue) 2306 def dwo_test_method(self, attrvalue=attrvalue): 2307 self.debug_info = "dwo" 2308 return attrvalue(self) 2309 dwo_method_name = attrname + "_dwo" 2310 dwo_test_method.__name__ = dwo_method_name 2311 newattrs[dwo_method_name] = dwo_test_method 2312 else: 2313 newattrs[attrname] = attrvalue 2314 return super(LLDBTestCaseFactory, cls).__new__(cls, name, bases, newattrs) 2315 2316# Setup the metaclass for this class to change the list of the test methods when a new class is loaded 2317@add_metaclass(LLDBTestCaseFactory) 2318class TestBase(Base): 2319 """ 2320 This abstract base class is meant to be subclassed. It provides default 2321 implementations for setUpClass(), tearDownClass(), setUp(), and tearDown(), 2322 among other things. 2323 2324 Important things for test class writers: 2325 2326 - Overwrite the mydir class attribute, otherwise your test class won't 2327 run. It specifies the relative directory to the top level 'test' so 2328 the test harness can change to the correct working directory before 2329 running your test. 2330 2331 - The setUp method sets up things to facilitate subsequent interactions 2332 with the debugger as part of the test. These include: 2333 - populate the test method name 2334 - create/get a debugger set with synchronous mode (self.dbg) 2335 - get the command interpreter from with the debugger (self.ci) 2336 - create a result object for use with the command interpreter 2337 (self.res) 2338 - plus other stuffs 2339 2340 - The tearDown method tries to perform some necessary cleanup on behalf 2341 of the test to return the debugger to a good state for the next test. 2342 These include: 2343 - execute any tearDown hooks registered by the test method with 2344 TestBase.addTearDownHook(); examples can be found in 2345 settings/TestSettings.py 2346 - kill the inferior process associated with each target, if any, 2347 and, then delete the target from the debugger's target list 2348 - perform build cleanup before running the next test method in the 2349 same test class; examples of registering for this service can be 2350 found in types/TestIntegerTypes.py with the call: 2351 - self.setTearDownCleanup(dictionary=d) 2352 2353 - Similarly setUpClass and tearDownClass perform classwise setup and 2354 teardown fixtures. The tearDownClass method invokes a default build 2355 cleanup for the entire test class; also, subclasses can implement the 2356 classmethod classCleanup(cls) to perform special class cleanup action. 2357 2358 - The instance methods runCmd and expect are used heavily by existing 2359 test cases to send a command to the command interpreter and to perform 2360 string/pattern matching on the output of such command execution. The 2361 expect method also provides a mode to peform string/pattern matching 2362 without running a command. 2363 2364 - The build methods buildDefault, buildDsym, and buildDwarf are used to 2365 build the binaries used during a particular test scenario. A plugin 2366 should be provided for the sys.platform running the test suite. The 2367 Mac OS X implementation is located in plugins/darwin.py. 2368 """ 2369 2370 # Maximum allowed attempts when launching the inferior process. 2371 # Can be overridden by the LLDB_MAX_LAUNCH_COUNT environment variable. 2372 maxLaunchCount = 3; 2373 2374 # Time to wait before the next launching attempt in second(s). 2375 # Can be overridden by the LLDB_TIME_WAIT_NEXT_LAUNCH environment variable. 2376 timeWaitNextLaunch = 1.0; 2377 2378 def doDelay(self): 2379 """See option -w of dotest.py.""" 2380 if ("LLDB_WAIT_BETWEEN_TEST_CASES" in os.environ and 2381 os.environ["LLDB_WAIT_BETWEEN_TEST_CASES"] == 'YES'): 2382 waitTime = 1.0 2383 if "LLDB_TIME_WAIT_BETWEEN_TEST_CASES" in os.environ: 2384 waitTime = float(os.environ["LLDB_TIME_WAIT_BETWEEN_TEST_CASES"]) 2385 time.sleep(waitTime) 2386 2387 # Returns the list of categories to which this test case belongs 2388 # by default, look for a ".categories" file, and read its contents 2389 # if no such file exists, traverse the hierarchy - we guarantee 2390 # a .categories to exist at the top level directory so we do not end up 2391 # looping endlessly - subclasses are free to define their own categories 2392 # in whatever way makes sense to them 2393 def getCategories(self): 2394 import inspect 2395 import os.path 2396 folder = inspect.getfile(self.__class__) 2397 folder = os.path.dirname(folder) 2398 while folder != '/': 2399 categories_file_name = os.path.join(folder,".categories") 2400 if os.path.exists(categories_file_name): 2401 categories_file = open(categories_file_name,'r') 2402 categories = categories_file.readline() 2403 categories_file.close() 2404 categories = str.replace(categories,'\n','') 2405 categories = str.replace(categories,'\r','') 2406 return categories.split(',') 2407 else: 2408 folder = os.path.dirname(folder) 2409 continue 2410 2411 def setUp(self): 2412 #import traceback 2413 #traceback.print_stack() 2414 2415 # Works with the test driver to conditionally skip tests via decorators. 2416 Base.setUp(self) 2417 2418 try: 2419 if lldb.blacklist: 2420 className = self.__class__.__name__ 2421 classAndMethodName = "%s.%s" % (className, self._testMethodName) 2422 if className in lldb.blacklist: 2423 self.skipTest(lldb.blacklist.get(className)) 2424 elif classAndMethodName in lldb.blacklist: 2425 self.skipTest(lldb.blacklist.get(classAndMethodName)) 2426 except AttributeError: 2427 pass 2428 2429 # Insert some delay between successive test cases if specified. 2430 self.doDelay() 2431 2432 if "LLDB_MAX_LAUNCH_COUNT" in os.environ: 2433 self.maxLaunchCount = int(os.environ["LLDB_MAX_LAUNCH_COUNT"]) 2434 2435 if "LLDB_TIME_WAIT_NEXT_LAUNCH" in os.environ: 2436 self.timeWaitNextLaunch = float(os.environ["LLDB_TIME_WAIT_NEXT_LAUNCH"]) 2437 2438 # 2439 # Warning: MAJOR HACK AHEAD! 2440 # If we are running testsuite remotely (by checking lldb.lldbtest_remote_sandbox), 2441 # redefine the self.dbg.CreateTarget(filename) method to execute a "file filename" 2442 # command, instead. See also runCmd() where it decorates the "file filename" call 2443 # with additional functionality when running testsuite remotely. 2444 # 2445 if lldb.lldbtest_remote_sandbox: 2446 def DecoratedCreateTarget(arg): 2447 self.runCmd("file %s" % arg) 2448 target = self.dbg.GetSelectedTarget() 2449 # 2450 # SBtarget.LaunchSimple () currently not working for remote platform? 2451 # johnny @ 04/23/2012 2452 # 2453 def DecoratedLaunchSimple(argv, envp, wd): 2454 self.runCmd("run") 2455 return target.GetProcess() 2456 target.LaunchSimple = DecoratedLaunchSimple 2457 2458 return target 2459 self.dbg.CreateTarget = DecoratedCreateTarget 2460 if self.TraceOn(): 2461 print("self.dbg.Create is redefined to:\n%s" % getsource_if_available(DecoratedCreateTarget)) 2462 2463 # We want our debugger to be synchronous. 2464 self.dbg.SetAsync(False) 2465 2466 # Retrieve the associated command interpreter instance. 2467 self.ci = self.dbg.GetCommandInterpreter() 2468 if not self.ci: 2469 raise Exception('Could not get the command interpreter') 2470 2471 # And the result object. 2472 self.res = lldb.SBCommandReturnObject() 2473 2474 # Run global pre-flight code, if defined via the config file. 2475 if lldb.pre_flight: 2476 lldb.pre_flight(self) 2477 2478 if lldb.remote_platform and lldb.remote_platform_working_dir: 2479 remote_test_dir = lldbutil.join_remote_paths( 2480 lldb.remote_platform_working_dir, 2481 self.getArchitecture(), 2482 str(self.test_number), 2483 self.mydir) 2484 error = lldb.remote_platform.MakeDirectory(remote_test_dir, 448) # 448 = 0o700 2485 if error.Success(): 2486 lldb.remote_platform.SetWorkingDirectory(remote_test_dir) 2487 2488 # This function removes all files from the current working directory while leaving 2489 # the directories in place. The cleaup is required to reduce the disk space required 2490 # by the test suit while leaving the directories untached is neccessary because 2491 # sub-directories might belong to an other test 2492 def clean_working_directory(): 2493 # TODO: Make it working on Windows when we need it for remote debugging support 2494 # TODO: Replace the heuristic to remove the files with a logic what collects the 2495 # list of files we have to remove during test runs. 2496 shell_cmd = lldb.SBPlatformShellCommand("rm %s/*" % remote_test_dir) 2497 lldb.remote_platform.Run(shell_cmd) 2498 self.addTearDownHook(clean_working_directory) 2499 else: 2500 print("error: making remote directory '%s': %s" % (remote_test_dir, error)) 2501 2502 def registerSharedLibrariesWithTarget(self, target, shlibs): 2503 '''If we are remotely running the test suite, register the shared libraries with the target so they get uploaded, otherwise do nothing 2504 2505 Any modules in the target that have their remote install file specification set will 2506 get uploaded to the remote host. This function registers the local copies of the 2507 shared libraries with the target and sets their remote install locations so they will 2508 be uploaded when the target is run. 2509 ''' 2510 if not shlibs or not self.platformContext: 2511 return None 2512 2513 shlib_environment_var = self.platformContext.shlib_environment_var 2514 shlib_prefix = self.platformContext.shlib_prefix 2515 shlib_extension = '.' + self.platformContext.shlib_extension 2516 2517 working_dir = self.get_process_working_directory() 2518 environment = ['%s=%s' % (shlib_environment_var, working_dir)] 2519 # Add any shared libraries to our target if remote so they get 2520 # uploaded into the working directory on the remote side 2521 for name in shlibs: 2522 # The path can be a full path to a shared library, or a make file name like "Foo" for 2523 # "libFoo.dylib" or "libFoo.so", or "Foo.so" for "Foo.so" or "libFoo.so", or just a 2524 # basename like "libFoo.so". So figure out which one it is and resolve the local copy 2525 # of the shared library accordingly 2526 if os.path.exists(name): 2527 local_shlib_path = name # name is the full path to the local shared library 2528 else: 2529 # Check relative names 2530 local_shlib_path = os.path.join(os.getcwd(), shlib_prefix + name + shlib_extension) 2531 if not os.path.exists(local_shlib_path): 2532 local_shlib_path = os.path.join(os.getcwd(), name + shlib_extension) 2533 if not os.path.exists(local_shlib_path): 2534 local_shlib_path = os.path.join(os.getcwd(), name) 2535 2536 # Make sure we found the local shared library in the above code 2537 self.assertTrue(os.path.exists(local_shlib_path)) 2538 2539 # Add the shared library to our target 2540 shlib_module = target.AddModule(local_shlib_path, None, None, None) 2541 if lldb.remote_platform: 2542 # We must set the remote install location if we want the shared library 2543 # to get uploaded to the remote target 2544 remote_shlib_path = lldbutil.append_to_process_working_directory(os.path.basename(local_shlib_path)) 2545 shlib_module.SetRemoteInstallFileSpec(lldb.SBFileSpec(remote_shlib_path, False)) 2546 2547 return environment 2548 2549 # utility methods that tests can use to access the current objects 2550 def target(self): 2551 if not self.dbg: 2552 raise Exception('Invalid debugger instance') 2553 return self.dbg.GetSelectedTarget() 2554 2555 def process(self): 2556 if not self.dbg: 2557 raise Exception('Invalid debugger instance') 2558 return self.dbg.GetSelectedTarget().GetProcess() 2559 2560 def thread(self): 2561 if not self.dbg: 2562 raise Exception('Invalid debugger instance') 2563 return self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread() 2564 2565 def frame(self): 2566 if not self.dbg: 2567 raise Exception('Invalid debugger instance') 2568 return self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() 2569 2570 def get_process_working_directory(self): 2571 '''Get the working directory that should be used when launching processes for local or remote processes.''' 2572 if lldb.remote_platform: 2573 # Remote tests set the platform working directory up in TestBase.setUp() 2574 return lldb.remote_platform.GetWorkingDirectory() 2575 else: 2576 # local tests change directory into each test subdirectory 2577 return os.getcwd() 2578 2579 def tearDown(self): 2580 #import traceback 2581 #traceback.print_stack() 2582 2583 # Ensure all the references to SB objects have gone away so that we can 2584 # be sure that all test-specific resources have been freed before we 2585 # attempt to delete the targets. 2586 gc.collect() 2587 2588 # Delete the target(s) from the debugger as a general cleanup step. 2589 # This includes terminating the process for each target, if any. 2590 # We'd like to reuse the debugger for our next test without incurring 2591 # the initialization overhead. 2592 targets = [] 2593 for target in self.dbg: 2594 if target: 2595 targets.append(target) 2596 process = target.GetProcess() 2597 if process: 2598 rc = self.invoke(process, "Kill") 2599 self.assertTrue(rc.Success(), PROCESS_KILLED) 2600 for target in targets: 2601 self.dbg.DeleteTarget(target) 2602 2603 # Run global post-flight code, if defined via the config file. 2604 if lldb.post_flight: 2605 lldb.post_flight(self) 2606 2607 # Do this last, to make sure it's in reverse order from how we setup. 2608 Base.tearDown(self) 2609 2610 # This must be the last statement, otherwise teardown hooks or other 2611 # lines might depend on this still being active. 2612 del self.dbg 2613 2614 def switch_to_thread_with_stop_reason(self, stop_reason): 2615 """ 2616 Run the 'thread list' command, and select the thread with stop reason as 2617 'stop_reason'. If no such thread exists, no select action is done. 2618 """ 2619 from .lldbutil import stop_reason_to_str 2620 self.runCmd('thread list') 2621 output = self.res.GetOutput() 2622 thread_line_pattern = re.compile("^[ *] thread #([0-9]+):.*stop reason = %s" % 2623 stop_reason_to_str(stop_reason)) 2624 for line in output.splitlines(): 2625 matched = thread_line_pattern.match(line) 2626 if matched: 2627 self.runCmd('thread select %s' % matched.group(1)) 2628 2629 def runCmd(self, cmd, msg=None, check=True, trace=False, inHistory=False): 2630 """ 2631 Ask the command interpreter to handle the command and then check its 2632 return status. 2633 """ 2634 # Fail fast if 'cmd' is not meaningful. 2635 if not cmd or len(cmd) == 0: 2636 raise Exception("Bad 'cmd' parameter encountered") 2637 2638 trace = (True if traceAlways else trace) 2639 2640 # This is an opportunity to insert the 'platform target-install' command if we are told so 2641 # via the settig of lldb.lldbtest_remote_sandbox. 2642 if cmd.startswith("target create "): 2643 cmd = cmd.replace("target create ", "file ") 2644 if cmd.startswith("file ") and lldb.lldbtest_remote_sandbox: 2645 with recording(self, trace) as sbuf: 2646 the_rest = cmd.split("file ")[1] 2647 # Split the rest of the command line. 2648 atoms = the_rest.split() 2649 # 2650 # NOTE: This assumes that the options, if any, follow the file command, 2651 # instead of follow the specified target. 2652 # 2653 target = atoms[-1] 2654 # Now let's get the absolute pathname of our target. 2655 abs_target = os.path.abspath(target) 2656 print("Found a file command, target (with absolute pathname)=%s" % abs_target, file=sbuf) 2657 fpath, fname = os.path.split(abs_target) 2658 parent_dir = os.path.split(fpath)[0] 2659 platform_target_install_command = 'platform target-install %s %s' % (fpath, lldb.lldbtest_remote_sandbox) 2660 print("Insert this command to be run first: %s" % platform_target_install_command, file=sbuf) 2661 self.ci.HandleCommand(platform_target_install_command, self.res) 2662 # And this is the file command we want to execute, instead. 2663 # 2664 # Warning: SIDE EFFECT AHEAD!!! 2665 # Populate the remote executable pathname into the lldb namespace, 2666 # so that test cases can grab this thing out of the namespace. 2667 # 2668 lldb.lldbtest_remote_sandboxed_executable = abs_target.replace(parent_dir, lldb.lldbtest_remote_sandbox) 2669 cmd = "file -P %s %s %s" % (lldb.lldbtest_remote_sandboxed_executable, the_rest.replace(target, ''), abs_target) 2670 print("And this is the replaced file command: %s" % cmd, file=sbuf) 2671 2672 running = (cmd.startswith("run") or cmd.startswith("process launch")) 2673 2674 for i in range(self.maxLaunchCount if running else 1): 2675 self.ci.HandleCommand(cmd, self.res, inHistory) 2676 2677 with recording(self, trace) as sbuf: 2678 print("runCmd:", cmd, file=sbuf) 2679 if not check: 2680 print("check of return status not required", file=sbuf) 2681 if self.res.Succeeded(): 2682 print("output:", self.res.GetOutput(), file=sbuf) 2683 else: 2684 print("runCmd failed!", file=sbuf) 2685 print(self.res.GetError(), file=sbuf) 2686 2687 if self.res.Succeeded(): 2688 break 2689 elif running: 2690 # For process launch, wait some time before possible next try. 2691 time.sleep(self.timeWaitNextLaunch) 2692 with recording(self, trace) as sbuf: 2693 print("Command '" + cmd + "' failed!", file=sbuf) 2694 2695 if check: 2696 self.assertTrue(self.res.Succeeded(), 2697 msg if msg else CMD_MSG(cmd)) 2698 2699 def match (self, str, patterns, msg=None, trace=False, error=False, matching=True, exe=True): 2700 """run command in str, and match the result against regexp in patterns returning the match object for the first matching pattern 2701 2702 Otherwise, all the arguments have the same meanings as for the expect function""" 2703 2704 trace = (True if traceAlways else trace) 2705 2706 if exe: 2707 # First run the command. If we are expecting error, set check=False. 2708 # Pass the assert message along since it provides more semantic info. 2709 self.runCmd(str, msg=msg, trace = (True if trace else False), check = not error) 2710 2711 # Then compare the output against expected strings. 2712 output = self.res.GetError() if error else self.res.GetOutput() 2713 2714 # If error is True, the API client expects the command to fail! 2715 if error: 2716 self.assertFalse(self.res.Succeeded(), 2717 "Command '" + str + "' is expected to fail!") 2718 else: 2719 # No execution required, just compare str against the golden input. 2720 output = str 2721 with recording(self, trace) as sbuf: 2722 print("looking at:", output, file=sbuf) 2723 2724 # The heading says either "Expecting" or "Not expecting". 2725 heading = "Expecting" if matching else "Not expecting" 2726 2727 for pattern in patterns: 2728 # Match Objects always have a boolean value of True. 2729 match_object = re.search(pattern, output) 2730 matched = bool(match_object) 2731 with recording(self, trace) as sbuf: 2732 print("%s pattern: %s" % (heading, pattern), file=sbuf) 2733 print("Matched" if matched else "Not matched", file=sbuf) 2734 if matched: 2735 break 2736 2737 self.assertTrue(matched if matching else not matched, 2738 msg if msg else EXP_MSG(str, exe)) 2739 2740 return match_object 2741 2742 def expect(self, str, msg=None, patterns=None, startstr=None, endstr=None, substrs=None, trace=False, error=False, matching=True, exe=True, inHistory=False): 2743 """ 2744 Similar to runCmd; with additional expect style output matching ability. 2745 2746 Ask the command interpreter to handle the command and then check its 2747 return status. The 'msg' parameter specifies an informational assert 2748 message. We expect the output from running the command to start with 2749 'startstr', matches the substrings contained in 'substrs', and regexp 2750 matches the patterns contained in 'patterns'. 2751 2752 If the keyword argument error is set to True, it signifies that the API 2753 client is expecting the command to fail. In this case, the error stream 2754 from running the command is retrieved and compared against the golden 2755 input, instead. 2756 2757 If the keyword argument matching is set to False, it signifies that the API 2758 client is expecting the output of the command not to match the golden 2759 input. 2760 2761 Finally, the required argument 'str' represents the lldb command to be 2762 sent to the command interpreter. In case the keyword argument 'exe' is 2763 set to False, the 'str' is treated as a string to be matched/not-matched 2764 against the golden input. 2765 """ 2766 trace = (True if traceAlways else trace) 2767 2768 if exe: 2769 # First run the command. If we are expecting error, set check=False. 2770 # Pass the assert message along since it provides more semantic info. 2771 self.runCmd(str, msg=msg, trace = (True if trace else False), check = not error, inHistory=inHistory) 2772 2773 # Then compare the output against expected strings. 2774 output = self.res.GetError() if error else self.res.GetOutput() 2775 2776 # If error is True, the API client expects the command to fail! 2777 if error: 2778 self.assertFalse(self.res.Succeeded(), 2779 "Command '" + str + "' is expected to fail!") 2780 else: 2781 # No execution required, just compare str against the golden input. 2782 if isinstance(str,lldb.SBCommandReturnObject): 2783 output = str.GetOutput() 2784 else: 2785 output = str 2786 with recording(self, trace) as sbuf: 2787 print("looking at:", output, file=sbuf) 2788 2789 # The heading says either "Expecting" or "Not expecting". 2790 heading = "Expecting" if matching else "Not expecting" 2791 2792 # Start from the startstr, if specified. 2793 # If there's no startstr, set the initial state appropriately. 2794 matched = output.startswith(startstr) if startstr else (True if matching else False) 2795 2796 if startstr: 2797 with recording(self, trace) as sbuf: 2798 print("%s start string: %s" % (heading, startstr), file=sbuf) 2799 print("Matched" if matched else "Not matched", file=sbuf) 2800 2801 # Look for endstr, if specified. 2802 keepgoing = matched if matching else not matched 2803 if endstr: 2804 matched = output.endswith(endstr) 2805 with recording(self, trace) as sbuf: 2806 print("%s end string: %s" % (heading, endstr), file=sbuf) 2807 print("Matched" if matched else "Not matched", file=sbuf) 2808 2809 # Look for sub strings, if specified. 2810 keepgoing = matched if matching else not matched 2811 if substrs and keepgoing: 2812 for str in substrs: 2813 matched = output.find(str) != -1 2814 with recording(self, trace) as sbuf: 2815 print("%s sub string: %s" % (heading, str), file=sbuf) 2816 print("Matched" if matched else "Not matched", file=sbuf) 2817 keepgoing = matched if matching else not matched 2818 if not keepgoing: 2819 break 2820 2821 # Search for regular expression patterns, if specified. 2822 keepgoing = matched if matching else not matched 2823 if patterns and keepgoing: 2824 for pattern in patterns: 2825 # Match Objects always have a boolean value of True. 2826 matched = bool(re.search(pattern, output)) 2827 with recording(self, trace) as sbuf: 2828 print("%s pattern: %s" % (heading, pattern), file=sbuf) 2829 print("Matched" if matched else "Not matched", file=sbuf) 2830 keepgoing = matched if matching else not matched 2831 if not keepgoing: 2832 break 2833 2834 self.assertTrue(matched if matching else not matched, 2835 msg if msg else EXP_MSG(str, exe)) 2836 2837 def invoke(self, obj, name, trace=False): 2838 """Use reflection to call a method dynamically with no argument.""" 2839 trace = (True if traceAlways else trace) 2840 2841 method = getattr(obj, name) 2842 import inspect 2843 self.assertTrue(inspect.ismethod(method), 2844 name + "is a method name of object: " + str(obj)) 2845 result = method() 2846 with recording(self, trace) as sbuf: 2847 print(str(method) + ":", result, file=sbuf) 2848 return result 2849 2850 def build(self, architecture=None, compiler=None, dictionary=None, clean=True): 2851 """Platform specific way to build the default binaries.""" 2852 if lldb.skip_build_and_cleanup: 2853 return 2854 module = builder_module() 2855 if target_is_android(): 2856 dictionary = append_android_envs(dictionary) 2857 if self.debug_info is None: 2858 return self.buildDefault(architecture, compiler, dictionary, clean) 2859 elif self.debug_info == "dsym": 2860 return self.buildDsym(architecture, compiler, dictionary, clean) 2861 elif self.debug_info == "dwarf": 2862 return self.buildDwarf(architecture, compiler, dictionary, clean) 2863 elif self.debug_info == "dwo": 2864 return self.buildDwo(architecture, compiler, dictionary, clean) 2865 else: 2866 self.fail("Can't build for debug info: %s" % self.debug_info) 2867 2868 # ================================================= 2869 # Misc. helper methods for debugging test execution 2870 # ================================================= 2871 2872 def DebugSBValue(self, val): 2873 """Debug print a SBValue object, if traceAlways is True.""" 2874 from .lldbutil import value_type_to_str 2875 2876 if not traceAlways: 2877 return 2878 2879 err = sys.stderr 2880 err.write(val.GetName() + ":\n") 2881 err.write('\t' + "TypeName -> " + val.GetTypeName() + '\n') 2882 err.write('\t' + "ByteSize -> " + str(val.GetByteSize()) + '\n') 2883 err.write('\t' + "NumChildren -> " + str(val.GetNumChildren()) + '\n') 2884 err.write('\t' + "Value -> " + str(val.GetValue()) + '\n') 2885 err.write('\t' + "ValueAsUnsigned -> " + str(val.GetValueAsUnsigned())+ '\n') 2886 err.write('\t' + "ValueType -> " + value_type_to_str(val.GetValueType()) + '\n') 2887 err.write('\t' + "Summary -> " + str(val.GetSummary()) + '\n') 2888 err.write('\t' + "IsPointerType -> " + str(val.TypeIsPointerType()) + '\n') 2889 err.write('\t' + "Location -> " + val.GetLocation() + '\n') 2890 2891 def DebugSBType(self, type): 2892 """Debug print a SBType object, if traceAlways is True.""" 2893 if not traceAlways: 2894 return 2895 2896 err = sys.stderr 2897 err.write(type.GetName() + ":\n") 2898 err.write('\t' + "ByteSize -> " + str(type.GetByteSize()) + '\n') 2899 err.write('\t' + "IsPointerType -> " + str(type.IsPointerType()) + '\n') 2900 err.write('\t' + "IsReferenceType -> " + str(type.IsReferenceType()) + '\n') 2901 2902 def DebugPExpect(self, child): 2903 """Debug the spwaned pexpect object.""" 2904 if not traceAlways: 2905 return 2906 2907 print(child) 2908 2909 @classmethod 2910 def RemoveTempFile(cls, file): 2911 if os.path.exists(file): 2912 os.remove(file) 2913