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