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