1""" 2A simple testing framework for lldb using python's unit testing framework. 3 4Tests for lldb are written as python scripts which take advantage of the script 5bridging provided by LLDB.framework to interact with lldb core. 6 7A specific naming pattern is followed by the .py script to be recognized as 8a module which implements a test scenario, namely, Test*.py. 9 10To specify the directories where "Test*.py" python test scripts are located, 11you need to pass in a list of directory names. By default, the current 12working directory is searched if nothing is specified on the command line. 13 14Type: 15 16./dotest.py -h 17 18for available options. 19""" 20 21from __future__ import absolute_import 22from __future__ import print_function 23 24# System modules 25import atexit 26import datetime 27import errno 28import logging 29import os 30import platform 31import re 32import shutil 33import signal 34import subprocess 35import sys 36import tempfile 37 38# Third-party modules 39import unittest2 40 41# LLDB Modules 42import lldbsuite 43from . import configuration 44from . import dotest_args 45from . import lldbtest_config 46from . import test_categories 47from . import test_result 48from ..support import seven 49 50 51def is_exe(fpath): 52 """Returns true if fpath is an executable.""" 53 if fpath == None: 54 return False 55 if sys.platform == 'win32': 56 if not fpath.endswith(".exe"): 57 fpath += ".exe" 58 return os.path.isfile(fpath) and os.access(fpath, os.X_OK) 59 60 61def which(program): 62 """Returns the full path to a program; None otherwise.""" 63 fpath, _ = os.path.split(program) 64 if fpath: 65 if is_exe(program): 66 return program 67 else: 68 for path in os.environ["PATH"].split(os.pathsep): 69 exe_file = os.path.join(path, program) 70 if is_exe(exe_file): 71 return exe_file 72 return None 73 74 75def usage(parser): 76 parser.print_help() 77 if configuration.verbose > 0: 78 print(""" 79Examples: 80 81This is an example of using the -f option to pinpoint to a specific test class 82and test method to be run: 83 84$ ./dotest.py -f ClassTypesTestCase.test_with_dsym_and_run_command 85---------------------------------------------------------------------- 86Collected 1 test 87 88test_with_dsym_and_run_command (TestClassTypes.ClassTypesTestCase) 89Test 'frame variable this' when stopped on a class constructor. ... ok 90 91---------------------------------------------------------------------- 92Ran 1 test in 1.396s 93 94OK 95 96And this is an example of using the -p option to run a single file (the filename 97matches the pattern 'ObjC' and it happens to be 'TestObjCMethods.py'): 98 99$ ./dotest.py -v -p ObjC 100---------------------------------------------------------------------- 101Collected 4 tests 102 103test_break_with_dsym (TestObjCMethods.FoundationTestCase) 104Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok 105test_break_with_dwarf (TestObjCMethods.FoundationTestCase) 106Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok 107test_data_type_and_expr_with_dsym (TestObjCMethods.FoundationTestCase) 108Lookup objective-c data types and evaluate expressions. ... ok 109test_data_type_and_expr_with_dwarf (TestObjCMethods.FoundationTestCase) 110Lookup objective-c data types and evaluate expressions. ... ok 111 112---------------------------------------------------------------------- 113Ran 4 tests in 16.661s 114 115OK 116 117Running of this script also sets up the LLDB_TEST environment variable so that 118individual test cases can locate their supporting files correctly. The script 119tries to set up Python's search paths for modules by looking at the build tree 120relative to this script. See also the '-i' option in the following example. 121 122Finally, this is an example of using the lldb.py module distributed/installed by 123Xcode4 to run against the tests under the 'forward' directory, and with the '-w' 124option to add some delay between two tests. It uses ARCH=x86_64 to specify that 125as the architecture and CC=clang to specify the compiler used for the test run: 126 127$ PYTHONPATH=/Xcode4/Library/PrivateFrameworks/LLDB.framework/Versions/A/Resources/Python ARCH=x86_64 CC=clang ./dotest.py -v -w -i forward 128 129Session logs for test failures/errors will go into directory '2010-11-11-13_56_16' 130---------------------------------------------------------------------- 131Collected 2 tests 132 133test_with_dsym_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase) 134Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok 135test_with_dwarf_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase) 136Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok 137 138---------------------------------------------------------------------- 139Ran 2 tests in 5.659s 140 141OK 142 143The 'Session ...' verbiage is recently introduced (see also the '-s' option) to 144notify the directory containing the session logs for test failures or errors. 145In case there is any test failure/error, a similar message is appended at the 146end of the stderr output for your convenience. 147 148ENABLING LOGS FROM TESTS 149 150Option 1: 151 152Writing logs into different files per test case:: 153 154$ ./dotest.py --channel "lldb all" 155 156$ ./dotest.py --channel "lldb all" --channel "gdb-remote packets" 157 158These log files are written to: 159 160<session-dir>/<test-id>-host.log (logs from lldb host process) 161<session-dir>/<test-id>-server.log (logs from debugserver/lldb-server) 162<session-dir>/<test-id>-<test-result>.log (console logs) 163 164By default, logs from successful runs are deleted. Use the --log-success flag 165to create reference logs for debugging. 166 167$ ./dotest.py --log-success 168 169""") 170 sys.exit(0) 171 172 173def parseExclusion(exclusion_file): 174 """Parse an exclusion file, of the following format, where 175 'skip files', 'skip methods', 'xfail files', and 'xfail methods' 176 are the possible list heading values: 177 178 skip files 179 <file name> 180 <file name> 181 182 xfail methods 183 <method name> 184 """ 185 excl_type = None 186 187 with open(exclusion_file) as f: 188 for line in f: 189 line = line.strip() 190 if not excl_type: 191 excl_type = line 192 continue 193 194 if not line: 195 excl_type = None 196 elif excl_type == 'skip': 197 if not configuration.skip_tests: 198 configuration.skip_tests = [] 199 configuration.skip_tests.append(line) 200 elif excl_type == 'xfail': 201 if not configuration.xfail_tests: 202 configuration.xfail_tests = [] 203 configuration.xfail_tests.append(line) 204 205 206def parseOptionsAndInitTestdirs(): 207 """Initialize the list of directories containing our unittest scripts. 208 209 '-h/--help as the first option prints out usage info and exit the program. 210 """ 211 212 do_help = False 213 214 platform_system = platform.system() 215 platform_machine = platform.machine() 216 217 try: 218 parser = dotest_args.create_parser() 219 args = parser.parse_args() 220 except: 221 raise 222 223 if args.unset_env_varnames: 224 for env_var in args.unset_env_varnames: 225 if env_var in os.environ: 226 # From Python Doc: When unsetenv() is supported, deletion of items in os.environ 227 # is automatically translated into a corresponding call to 228 # unsetenv(). 229 del os.environ[env_var] 230 # os.unsetenv(env_var) 231 232 if args.set_env_vars: 233 for env_var in args.set_env_vars: 234 parts = env_var.split('=', 1) 235 if len(parts) == 1: 236 os.environ[parts[0]] = "" 237 else: 238 os.environ[parts[0]] = parts[1] 239 240 if args.set_inferior_env_vars: 241 lldbtest_config.inferior_env = ' '.join(args.set_inferior_env_vars) 242 243 if args.h: 244 do_help = True 245 246 if args.compiler: 247 configuration.compiler = os.path.abspath(args.compiler) 248 if not is_exe(configuration.compiler): 249 configuration.compiler = which(args.compiler) 250 if not is_exe(configuration.compiler): 251 logging.error( 252 '%s is not a valid compiler executable; aborting...', 253 args.compiler) 254 sys.exit(-1) 255 else: 256 # Use a compiler appropriate appropriate for the Apple SDK if one was 257 # specified 258 if platform_system == 'Darwin' and args.apple_sdk: 259 configuration.compiler = seven.get_command_output( 260 'xcrun -sdk "%s" -find clang 2> /dev/null' % 261 (args.apple_sdk)) 262 else: 263 # 'clang' on ubuntu 14.04 is 3.4 so we try clang-3.5 first 264 candidateCompilers = ['clang-3.5', 'clang', 'gcc'] 265 for candidate in candidateCompilers: 266 if which(candidate): 267 configuration.compiler = candidate 268 break 269 270 if args.dsymutil: 271 configuration.dsymutil = args.dsymutil 272 elif platform_system == 'Darwin': 273 configuration.dsymutil = seven.get_command_output( 274 'xcrun -find -toolchain default dsymutil') 275 if args.llvm_tools_dir: 276 configuration.filecheck = shutil.which("FileCheck", path=args.llvm_tools_dir) 277 configuration.yaml2obj = shutil.which("yaml2obj", path=args.llvm_tools_dir) 278 279 if not configuration.get_filecheck_path(): 280 logging.warning('No valid FileCheck executable; some tests may fail...') 281 logging.warning('(Double-check the --llvm-tools-dir argument to dotest.py)') 282 283 configuration.hermetic_libcxx = args.hermetic_libcxx 284 if configuration.hermetic_libcxx and args.lldb_platform_name: 285 configuration.hermetic_libcxx = False 286 logging.warning('Hermetic libc++ is not supported for remote runs: ignoring --hermetic-libcxx') 287 288 if args.channels: 289 lldbtest_config.channels = args.channels 290 291 if args.log_success: 292 lldbtest_config.log_success = args.log_success 293 294 if args.out_of_tree_debugserver: 295 lldbtest_config.out_of_tree_debugserver = args.out_of_tree_debugserver 296 297 # Set SDKROOT if we are using an Apple SDK 298 if platform_system == 'Darwin' and args.apple_sdk: 299 configuration.sdkroot = seven.get_command_output( 300 'xcrun --sdk "%s" --show-sdk-path 2> /dev/null' % 301 (args.apple_sdk)) 302 if not configuration.sdkroot: 303 logging.error( 304 'No SDK found with the name %s; aborting...', 305 args.apple_sdk) 306 sys.exit(-1) 307 308 if args.arch: 309 configuration.arch = args.arch 310 else: 311 configuration.arch = platform_machine 312 313 if args.categories_list: 314 configuration.categories_list = set( 315 test_categories.validate( 316 args.categories_list, False)) 317 configuration.use_categories = True 318 else: 319 configuration.categories_list = [] 320 321 if args.skip_categories: 322 configuration.skip_categories += test_categories.validate( 323 args.skip_categories, False) 324 325 if args.xfail_categories: 326 configuration.xfail_categories += test_categories.validate( 327 args.xfail_categories, False) 328 329 if args.E: 330 os.environ['CFLAGS_EXTRAS'] = args.E 331 332 if args.dwarf_version: 333 configuration.dwarf_version = args.dwarf_version 334 # We cannot modify CFLAGS_EXTRAS because they're used in test cases 335 # that explicitly require no debug info. 336 os.environ['CFLAGS'] = '-gdwarf-{}'.format(configuration.dwarf_version) 337 338 if args.settings: 339 for setting in args.settings: 340 if not len(setting) == 1 or not setting[0].count('='): 341 logging.error('"%s" is not a setting in the form "key=value"', 342 setting[0]) 343 sys.exit(-1) 344 setting_list = setting[0].split('=', 1) 345 configuration.settings.append((setting_list[0], setting_list[1])) 346 347 if args.d: 348 sys.stdout.write( 349 "Suspending the process %d to wait for debugger to attach...\n" % 350 os.getpid()) 351 sys.stdout.flush() 352 os.kill(os.getpid(), signal.SIGSTOP) 353 354 if args.f: 355 if any([x.startswith('-') for x in args.f]): 356 usage(parser) 357 configuration.filters.extend(args.f) 358 359 if args.framework: 360 configuration.lldb_framework_path = args.framework 361 362 if args.executable: 363 # lldb executable is passed explicitly 364 lldbtest_config.lldbExec = os.path.abspath(args.executable) 365 if not is_exe(lldbtest_config.lldbExec): 366 lldbtest_config.lldbExec = which(args.executable) 367 if not is_exe(lldbtest_config.lldbExec): 368 logging.error( 369 '%s is not a valid executable to test; aborting...', 370 args.executable) 371 sys.exit(-1) 372 373 if args.excluded: 374 for excl_file in args.excluded: 375 parseExclusion(excl_file) 376 377 if args.p: 378 if args.p.startswith('-'): 379 usage(parser) 380 configuration.regexp = args.p 381 382 if args.t: 383 os.environ['LLDB_COMMAND_TRACE'] = 'YES' 384 385 if args.v: 386 configuration.verbose = 2 387 388 # argparse makes sure we have a number 389 if args.sharp: 390 configuration.count = args.sharp 391 392 if sys.platform.startswith('win32'): 393 os.environ['LLDB_DISABLE_CRASH_DIALOG'] = str( 394 args.disable_crash_dialog) 395 os.environ['LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE'] = str(True) 396 397 if do_help: 398 usage(parser) 399 400 if args.lldb_platform_name: 401 configuration.lldb_platform_name = args.lldb_platform_name 402 if args.lldb_platform_url: 403 configuration.lldb_platform_url = args.lldb_platform_url 404 if args.lldb_platform_working_dir: 405 configuration.lldb_platform_working_dir = args.lldb_platform_working_dir 406 if platform_system == 'Darwin' and args.apple_sdk: 407 configuration.apple_sdk = args.apple_sdk 408 if args.test_build_dir: 409 configuration.test_build_dir = args.test_build_dir 410 if args.lldb_module_cache_dir: 411 configuration.lldb_module_cache_dir = args.lldb_module_cache_dir 412 else: 413 configuration.lldb_module_cache_dir = os.path.join( 414 configuration.test_build_dir, 'module-cache-lldb') 415 if args.clang_module_cache_dir: 416 configuration.clang_module_cache_dir = args.clang_module_cache_dir 417 else: 418 configuration.clang_module_cache_dir = os.path.join( 419 configuration.test_build_dir, 'module-cache-clang') 420 421 if args.lldb_libs_dir: 422 configuration.lldb_libs_dir = args.lldb_libs_dir 423 424 if args.enabled_plugins: 425 configuration.enabled_plugins = args.enabled_plugins 426 427 # Gather all the dirs passed on the command line. 428 if len(args.args) > 0: 429 configuration.testdirs = [os.path.realpath(os.path.abspath(x)) for x in args.args] 430 431 lldbtest_config.codesign_identity = args.codesign_identity 432 433def registerFaulthandler(): 434 try: 435 import faulthandler 436 except ImportError: 437 # faulthandler is not available until python3 438 return 439 440 faulthandler.enable() 441 # faulthandler.register is not available on Windows. 442 if getattr(faulthandler, 'register', None): 443 faulthandler.register(signal.SIGTERM, chain=True) 444 445def setupSysPath(): 446 """ 447 Add LLDB.framework/Resources/Python to the search paths for modules. 448 As a side effect, we also discover the 'lldb' executable and export it here. 449 """ 450 451 # Get the directory containing the current script. 452 if "DOTEST_PROFILE" in os.environ and "DOTEST_SCRIPT_DIR" in os.environ: 453 scriptPath = os.environ["DOTEST_SCRIPT_DIR"] 454 else: 455 scriptPath = os.path.dirname(os.path.abspath(__file__)) 456 if not scriptPath.endswith('test'): 457 print("This script expects to reside in lldb's test directory.") 458 sys.exit(-1) 459 460 os.environ["LLDB_TEST"] = scriptPath 461 462 # Set up the root build directory. 463 if not configuration.test_build_dir: 464 raise Exception("test_build_dir is not set") 465 configuration.test_build_dir = os.path.abspath(configuration.test_build_dir) 466 467 # Set up the LLDB_SRC environment variable, so that the tests can locate 468 # the LLDB source code. 469 os.environ["LLDB_SRC"] = lldbsuite.lldb_root 470 471 pluginPath = os.path.join(scriptPath, 'plugins') 472 toolsLLDBVSCode = os.path.join(scriptPath, 'tools', 'lldb-vscode') 473 toolsLLDBServerPath = os.path.join(scriptPath, 'tools', 'lldb-server') 474 intelpt = os.path.join(scriptPath, 'tools', 'intelpt') 475 476 # Insert script dir, plugin dir and lldb-server dir to the sys.path. 477 sys.path.insert(0, pluginPath) 478 # Adding test/tools/lldb-vscode to the path makes it easy to 479 # "import lldb_vscode_testcase" from the VSCode tests 480 sys.path.insert(0, toolsLLDBVSCode) 481 # Adding test/tools/lldb-server to the path makes it easy 482 # to "import lldbgdbserverutils" from the lldb-server tests 483 sys.path.insert(0, toolsLLDBServerPath) 484 # Adding test/tools/intelpt to the path makes it easy 485 # to "import intelpt_testcase" from the lldb-server tests 486 sys.path.insert(0, intelpt) 487 488 # This is the root of the lldb git/svn checkout 489 # When this changes over to a package instead of a standalone script, this 490 # will be `lldbsuite.lldb_root` 491 lldbRootDirectory = lldbsuite.lldb_root 492 493 # Some of the tests can invoke the 'lldb' command directly. 494 # We'll try to locate the appropriate executable right here. 495 496 # The lldb executable can be set from the command line 497 # if it's not set, we try to find it now 498 # first, we try the environment 499 if not lldbtest_config.lldbExec: 500 # First, you can define an environment variable LLDB_EXEC specifying the 501 # full pathname of the lldb executable. 502 if "LLDB_EXEC" in os.environ: 503 lldbtest_config.lldbExec = os.environ["LLDB_EXEC"] 504 505 if not lldbtest_config.lldbExec: 506 # Last, check the path 507 lldbtest_config.lldbExec = which('lldb') 508 509 if lldbtest_config.lldbExec and not is_exe(lldbtest_config.lldbExec): 510 print( 511 "'{}' is not a path to a valid executable".format( 512 lldbtest_config.lldbExec)) 513 lldbtest_config.lldbExec = None 514 515 if not lldbtest_config.lldbExec: 516 print("The 'lldb' executable cannot be located. Some of the tests may not be run as a result.") 517 sys.exit(-1) 518 519 os.system('%s -v' % lldbtest_config.lldbExec) 520 521 lldbDir = os.path.dirname(lldbtest_config.lldbExec) 522 523 lldbVSCodeExec = os.path.join(lldbDir, "lldb-vscode") 524 if is_exe(lldbVSCodeExec): 525 os.environ["LLDBVSCODE_EXEC"] = lldbVSCodeExec 526 else: 527 if not configuration.shouldSkipBecauseOfCategories(["lldb-vscode"]): 528 print( 529 "The 'lldb-vscode' executable cannot be located. The lldb-vscode tests can not be run as a result.") 530 configuration.skip_categories.append("lldb-vscode") 531 532 lldbPythonDir = None # The directory that contains 'lldb/__init__.py' 533 534 # If our lldb supports the -P option, use it to find the python path: 535 lldb_dash_p_result = subprocess.check_output([lldbtest_config.lldbExec, "-P"], universal_newlines=True) 536 if lldb_dash_p_result: 537 for line in lldb_dash_p_result.splitlines(): 538 if os.path.isdir(line) and os.path.exists(os.path.join(line, 'lldb', '__init__.py')): 539 lldbPythonDir = line 540 break 541 542 if not lldbPythonDir: 543 print( 544 "Unable to load lldb extension module. Possible reasons for this include:") 545 print(" 1) LLDB was built with LLDB_ENABLE_PYTHON=0") 546 print( 547 " 2) PYTHONPATH and PYTHONHOME are not set correctly. PYTHONHOME should refer to") 548 print( 549 " the version of Python that LLDB built and linked against, and PYTHONPATH") 550 print( 551 " should contain the Lib directory for the same python distro, as well as the") 552 print(" location of LLDB\'s site-packages folder.") 553 print( 554 " 3) A different version of Python than that which was built against is exported in") 555 print(" the system\'s PATH environment variable, causing conflicts.") 556 print( 557 " 4) The executable '%s' could not be found. Please check " % 558 lldbtest_config.lldbExec) 559 print(" that it exists and is executable.") 560 561 if lldbPythonDir: 562 lldbPythonDir = os.path.normpath(lldbPythonDir) 563 # Some of the code that uses this path assumes it hasn't resolved the Versions... link. 564 # If the path we've constructed looks like that, then we'll strip out 565 # the Versions/A part. 566 (before, frameWithVersion, after) = lldbPythonDir.rpartition( 567 "LLDB.framework/Versions/A") 568 if frameWithVersion != "": 569 lldbPythonDir = before + "LLDB.framework" + after 570 571 lldbPythonDir = os.path.abspath(lldbPythonDir) 572 573 if "freebsd" in sys.platform or "linux" in sys.platform: 574 os.environ['LLDB_LIB_DIR'] = os.path.join(lldbPythonDir, '..', '..') 575 576 # If tests need to find LLDB_FRAMEWORK, now they can do it 577 os.environ["LLDB_FRAMEWORK"] = os.path.dirname( 578 os.path.dirname(lldbPythonDir)) 579 580 # This is to locate the lldb.py module. Insert it right after 581 # sys.path[0]. 582 sys.path[1:1] = [lldbPythonDir] 583 584 585def visit_file(dir, name): 586 # Try to match the regexp pattern, if specified. 587 if configuration.regexp: 588 if not re.search(configuration.regexp, name): 589 # We didn't match the regex, we're done. 590 return 591 592 if configuration.skip_tests: 593 for file_regexp in configuration.skip_tests: 594 if re.search(file_regexp, name): 595 return 596 597 # We found a match for our test. Add it to the suite. 598 599 # Update the sys.path first. 600 if not sys.path.count(dir): 601 sys.path.insert(0, dir) 602 base = os.path.splitext(name)[0] 603 604 # Thoroughly check the filterspec against the base module and admit 605 # the (base, filterspec) combination only when it makes sense. 606 607 def check(obj, parts): 608 for part in parts: 609 try: 610 parent, obj = obj, getattr(obj, part) 611 except AttributeError: 612 # The filterspec has failed. 613 return False 614 return True 615 616 module = __import__(base) 617 618 def iter_filters(): 619 for filterspec in configuration.filters: 620 parts = filterspec.split('.') 621 if check(module, parts): 622 yield filterspec 623 elif parts[0] == base and len(parts) > 1 and check(module, parts[1:]): 624 yield '.'.join(parts[1:]) 625 else: 626 for key,value in module.__dict__.items(): 627 if check(value, parts): 628 yield key + '.' + filterspec 629 630 filtered = False 631 for filterspec in iter_filters(): 632 filtered = True 633 print("adding filter spec %s to module %s" % (filterspec, repr(module))) 634 tests = unittest2.defaultTestLoader.loadTestsFromName(filterspec, module) 635 configuration.suite.addTests(tests) 636 637 # Forgo this module if the (base, filterspec) combo is invalid 638 if configuration.filters and not filtered: 639 return 640 641 if not filtered: 642 # Add the entire file's worth of tests since we're not filtered. 643 # Also the fail-over case when the filterspec branch 644 # (base, filterspec) combo doesn't make sense. 645 configuration.suite.addTests( 646 unittest2.defaultTestLoader.loadTestsFromName(base)) 647 648 649def visit(prefix, dir, names): 650 """Visitor function for os.path.walk(path, visit, arg).""" 651 652 dir_components = set(dir.split(os.sep)) 653 excluded_components = set(['.svn', '.git']) 654 if dir_components.intersection(excluded_components): 655 return 656 657 # Gather all the Python test file names that follow the Test*.py pattern. 658 python_test_files = [ 659 name 660 for name in names 661 if name.endswith('.py') and name.startswith(prefix)] 662 663 # Visit all the python test files. 664 for name in python_test_files: 665 # Ensure we error out if we have multiple tests with the same 666 # base name. 667 # Future improvement: find all the places where we work with base 668 # names and convert to full paths. We have directory structure 669 # to disambiguate these, so we shouldn't need this constraint. 670 if name in configuration.all_tests: 671 raise Exception("Found multiple tests with the name %s" % name) 672 configuration.all_tests.add(name) 673 674 # Run the relevant tests in the python file. 675 visit_file(dir, name) 676 677 678# ======================================== # 679# # 680# Execution of the test driver starts here # 681# # 682# ======================================== # 683 684 685def checkDsymForUUIDIsNotOn(): 686 cmd = ["defaults", "read", "com.apple.DebugSymbols"] 687 process = subprocess.Popen( 688 cmd, 689 stdout=subprocess.PIPE, 690 stderr=subprocess.STDOUT) 691 cmd_output = process.stdout.read() 692 output_str = cmd_output.decode("utf-8") 693 if "DBGFileMappedPaths = " in output_str: 694 print("%s =>" % ' '.join(cmd)) 695 print(output_str) 696 print( 697 "Disable automatic lookup and caching of dSYMs before running the test suite!") 698 print("Exiting...") 699 sys.exit(0) 700 701 702def exitTestSuite(exitCode=None): 703 # lldb.py does SBDebugger.Initialize(). 704 # Call SBDebugger.Terminate() on exit. 705 import lldb 706 lldb.SBDebugger.Terminate() 707 if exitCode: 708 sys.exit(exitCode) 709 710 711def getVersionForSDK(sdk): 712 sdk = str.lower(sdk) 713 full_path = seven.get_command_output('xcrun -sdk %s --show-sdk-path' % sdk) 714 basename = os.path.basename(full_path) 715 basename = os.path.splitext(basename)[0] 716 basename = str.lower(basename) 717 ver = basename.replace(sdk, '') 718 return ver 719 720 721def checkCompiler(): 722 # Add some intervention here to sanity check that the compiler requested is sane. 723 # If found not to be an executable program, we abort. 724 c = configuration.compiler 725 if which(c): 726 return 727 728 if not sys.platform.startswith("darwin"): 729 raise Exception(c + " is not a valid compiler") 730 731 pipe = subprocess.Popen( 732 ['xcrun', '-find', c], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 733 cmd_output = pipe.stdout.read() 734 if not cmd_output or "not found" in cmd_output: 735 raise Exception(c + " is not a valid compiler") 736 737 configuration.compiler = cmd_output.split('\n')[0] 738 print("'xcrun -find %s' returning %s" % (c, configuration.compiler)) 739 740def canRunLibcxxTests(): 741 from lldbsuite.test import lldbplatformutil 742 743 platform = lldbplatformutil.getPlatform() 744 745 if lldbplatformutil.target_is_android() or lldbplatformutil.platformIsDarwin(): 746 return True, "libc++ always present" 747 748 if platform == "linux": 749 with tempfile.NamedTemporaryFile() as f: 750 cmd = [configuration.compiler, "-xc++", "-stdlib=libc++", "-o", f.name, "-"] 751 p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) 752 _, stderr = p.communicate("#include <cassert>\nint main() {}") 753 if not p.returncode: 754 return True, "Compiling with -stdlib=libc++ works" 755 return False, "Compiling with -stdlib=libc++ fails with the error: %s" % stderr 756 757 return False, "Don't know how to build with libc++ on %s" % platform 758 759def checkLibcxxSupport(): 760 result, reason = canRunLibcxxTests() 761 if result: 762 return # libc++ supported 763 if "libc++" in configuration.categories_list: 764 return # libc++ category explicitly requested, let it run. 765 if configuration.verbose: 766 print("libc++ tests will not be run because: " + reason) 767 configuration.skip_categories.append("libc++") 768 769def canRunLibstdcxxTests(): 770 from lldbsuite.test import lldbplatformutil 771 772 platform = lldbplatformutil.getPlatform() 773 if lldbplatformutil.target_is_android(): 774 platform = "android" 775 if platform == "linux": 776 return True, "libstdcxx always present" 777 return False, "Don't know how to build with libstdcxx on %s" % platform 778 779def checkLibstdcxxSupport(): 780 result, reason = canRunLibstdcxxTests() 781 if result: 782 return # libstdcxx supported 783 if "libstdcxx" in configuration.categories_list: 784 return # libstdcxx category explicitly requested, let it run. 785 if configuration.verbose: 786 print("libstdcxx tests will not be run because: " + reason) 787 configuration.skip_categories.append("libstdcxx") 788 789def canRunWatchpointTests(): 790 from lldbsuite.test import lldbplatformutil 791 792 platform = lldbplatformutil.getPlatform() 793 if platform == "netbsd": 794 if os.geteuid() == 0: 795 return True, "root can always write dbregs" 796 try: 797 output = subprocess.check_output(["/sbin/sysctl", "-n", 798 "security.models.extensions.user_set_dbregs"]).decode().strip() 799 if output == "1": 800 return True, "security.models.extensions.user_set_dbregs enabled" 801 except subprocess.CalledProcessError: 802 pass 803 return False, "security.models.extensions.user_set_dbregs disabled" 804 elif platform == "freebsd" and configuration.arch == "aarch64": 805 import lldb 806 if lldb.SBPlatform.GetHostPlatform().GetOSMajorVersion() < 13: 807 return False, "Watchpoint support on arm64 requires FreeBSD 13.0" 808 return True, "watchpoint support available" 809 810def checkWatchpointSupport(): 811 result, reason = canRunWatchpointTests() 812 if result: 813 return # watchpoints supported 814 if "watchpoint" in configuration.categories_list: 815 return # watchpoint category explicitly requested, let it run. 816 if configuration.verbose: 817 print("watchpoint tests will not be run because: " + reason) 818 configuration.skip_categories.append("watchpoint") 819 820def checkObjcSupport(): 821 from lldbsuite.test import lldbplatformutil 822 823 if not lldbplatformutil.platformIsDarwin(): 824 if configuration.verbose: 825 print("objc tests will be skipped because of unsupported platform") 826 configuration.skip_categories.append("objc") 827 828def checkDebugInfoSupport(): 829 from lldbsuite.test import lldbplatformutil 830 831 platform = lldbplatformutil.getPlatform() 832 compiler = configuration.compiler 833 for cat in test_categories.debug_info_categories: 834 if cat in configuration.categories_list: 835 continue # Category explicitly requested, let it run. 836 if test_categories.is_supported_on_platform(cat, platform, compiler): 837 continue 838 configuration.skip_categories.append(cat) 839 840def checkDebugServerSupport(): 841 from lldbsuite.test import lldbplatformutil 842 import lldb 843 844 skip_msg = "Skipping %s tests, as they are not compatible with remote testing on this platform" 845 if lldbplatformutil.platformIsDarwin(): 846 configuration.skip_categories.append("llgs") 847 if configuration.lldb_platform_name: 848 # <rdar://problem/34539270> 849 configuration.skip_categories.append("debugserver") 850 if configuration.verbose: 851 print(skip_msg%"debugserver"); 852 else: 853 configuration.skip_categories.append("debugserver") 854 if configuration.lldb_platform_name and lldbplatformutil.getPlatform() == "windows": 855 configuration.skip_categories.append("llgs") 856 if configuration.verbose: 857 print(skip_msg%"lldb-server"); 858 859 860def checkForkVForkSupport(): 861 from lldbsuite.test import lldbplatformutil 862 863 platform = lldbplatformutil.getPlatform() 864 if platform not in ["freebsd", "linux", "netbsd"]: 865 configuration.skip_categories.append("fork") 866 867 868def run_suite(): 869 # On MacOS X, check to make sure that domain for com.apple.DebugSymbols defaults 870 # does not exist before proceeding to running the test suite. 871 if sys.platform.startswith("darwin"): 872 checkDsymForUUIDIsNotOn() 873 874 # Start the actions by first parsing the options while setting up the test 875 # directories, followed by setting up the search paths for lldb utilities; 876 # then, we walk the directory trees and collect the tests into our test suite. 877 # 878 parseOptionsAndInitTestdirs() 879 880 # Print a stack trace if the test hangs or is passed SIGTERM. 881 registerFaulthandler() 882 883 setupSysPath() 884 885 import lldb 886 lldb.SBDebugger.Initialize() 887 lldb.SBDebugger.PrintStackTraceOnError() 888 889 checkLibcxxSupport() 890 checkLibstdcxxSupport() 891 checkWatchpointSupport() 892 checkDebugInfoSupport() 893 checkDebugServerSupport() 894 checkObjcSupport() 895 checkForkVForkSupport() 896 897 # Use host platform by default. 898 lldb.remote_platform = None 899 lldb.selected_platform = lldb.SBPlatform.GetHostPlatform() 900 901 # Now we can also import lldbutil 902 from lldbsuite.test import lldbutil 903 904 if configuration.lldb_platform_name: 905 print("Setting up remote platform '%s'" % 906 (configuration.lldb_platform_name)) 907 lldb.remote_platform = lldb.SBPlatform( 908 configuration.lldb_platform_name) 909 lldb.selected_platform = lldb.remote_platform 910 if not lldb.remote_platform.IsValid(): 911 print( 912 "error: unable to create the LLDB platform named '%s'." % 913 (configuration.lldb_platform_name)) 914 exitTestSuite(1) 915 if configuration.lldb_platform_url: 916 # We must connect to a remote platform if a LLDB platform URL was 917 # specified 918 print( 919 "Connecting to remote platform '%s' at '%s'..." % 920 (configuration.lldb_platform_name, configuration.lldb_platform_url)) 921 platform_connect_options = lldb.SBPlatformConnectOptions( 922 configuration.lldb_platform_url) 923 err = lldb.remote_platform.ConnectRemote(platform_connect_options) 924 if err.Success(): 925 print("Connected.") 926 else: 927 print("error: failed to connect to remote platform using URL '%s': %s" % ( 928 configuration.lldb_platform_url, err)) 929 exitTestSuite(1) 930 else: 931 configuration.lldb_platform_url = None 932 933 if configuration.lldb_platform_working_dir: 934 print("Setting remote platform working directory to '%s'..." % 935 (configuration.lldb_platform_working_dir)) 936 error = lldb.remote_platform.MakeDirectory( 937 configuration.lldb_platform_working_dir, 448) # 448 = 0o700 938 if error.Fail(): 939 raise Exception("making remote directory '%s': %s" % ( 940 configuration.lldb_platform_working_dir, error)) 941 942 if not lldb.remote_platform.SetWorkingDirectory( 943 configuration.lldb_platform_working_dir): 944 raise Exception("failed to set working directory '%s'" % configuration.lldb_platform_working_dir) 945 lldb.selected_platform = lldb.remote_platform 946 else: 947 lldb.remote_platform = None 948 configuration.lldb_platform_working_dir = None 949 configuration.lldb_platform_url = None 950 951 # Set up the working directory. 952 # Note that it's not dotest's job to clean this directory. 953 lldbutil.mkdir_p(configuration.test_build_dir) 954 955 print("Skipping the following test categories: {}".format(configuration.skip_categories)) 956 957 for testdir in configuration.testdirs: 958 for (dirpath, dirnames, filenames) in os.walk(testdir): 959 visit('Test', dirpath, filenames) 960 961 # 962 # Now that we have loaded all the test cases, run the whole test suite. 963 # 964 965 # Install the control-c handler. 966 unittest2.signals.installHandler() 967 968 # 969 # Invoke the default TextTestRunner to run the test suite 970 # 971 checkCompiler() 972 973 if configuration.verbose: 974 print("compiler=%s" % configuration.compiler) 975 976 # Iterating over all possible architecture and compiler combinations. 977 configString = "arch=%s compiler=%s" % (configuration.arch, 978 configuration.compiler) 979 980 # Output the configuration. 981 if configuration.verbose: 982 sys.stderr.write("\nConfiguration: " + configString + "\n") 983 984 # First, write out the number of collected test cases. 985 if configuration.verbose: 986 sys.stderr.write(configuration.separator + "\n") 987 sys.stderr.write( 988 "Collected %d test%s\n\n" % 989 (configuration.suite.countTestCases(), 990 configuration.suite.countTestCases() != 1 and "s" or "")) 991 992 if configuration.suite.countTestCases() == 0: 993 logging.error("did not discover any matching tests") 994 exitTestSuite(1) 995 996 # Invoke the test runner. 997 if configuration.count == 1: 998 result = unittest2.TextTestRunner( 999 stream=sys.stderr, 1000 verbosity=configuration.verbose, 1001 resultclass=test_result.LLDBTestResult).run( 1002 configuration.suite) 1003 else: 1004 # We are invoking the same test suite more than once. In this case, 1005 # mark __ignore_singleton__ flag as True so the signleton pattern is 1006 # not enforced. 1007 test_result.LLDBTestResult.__ignore_singleton__ = True 1008 for i in range(configuration.count): 1009 1010 result = unittest2.TextTestRunner( 1011 stream=sys.stderr, 1012 verbosity=configuration.verbose, 1013 resultclass=test_result.LLDBTestResult).run( 1014 configuration.suite) 1015 1016 configuration.failed = not result.wasSuccessful() 1017 1018 if configuration.sdir_has_content and configuration.verbose: 1019 sys.stderr.write( 1020 "Session logs for test failures/errors/unexpected successes" 1021 " can be found in the test build directory\n") 1022 1023 if configuration.use_categories and len( 1024 configuration.failures_per_category) > 0: 1025 sys.stderr.write("Failures per category:\n") 1026 for category in configuration.failures_per_category: 1027 sys.stderr.write( 1028 "%s - %d\n" % 1029 (category, configuration.failures_per_category[category])) 1030 1031 # Exiting. 1032 exitTestSuite(configuration.failed) 1033 1034if __name__ == "__main__": 1035 print( 1036 __file__ + 1037 " is for use as a module only. It should not be run as a standalone script.") 1038 sys.exit(-1) 1039