1198 lines · python
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 script5bridging provided by LLDB.framework to interact with lldb core.6 7A specific naming pattern is followed by the .py script to be recognized as8a 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 current12working directory is searched if nothing is specified on the command line.13 14Type:15 16./dotest.py -h17 18for available options.19"""20 21# System modules22import atexit23import datetime24import errno25import logging26import os27import platform28import re29import shutil30import signal31import subprocess32import sys33import tempfile34 35# Third-party modules36import unittest37 38# LLDB Modules39import lldbsuite40from . import configuration41from . import dotest_args42from . import lldbtest_config43from . import test_categories44from . import test_result45from ..support import seven46from ..support import temp_file47 48 49def is_exe(fpath):50 """Returns true if fpath is an executable."""51 if fpath is None:52 return False53 if sys.platform == "win32":54 if not fpath.endswith(".exe"):55 fpath += ".exe"56 return os.path.isfile(fpath) and os.access(fpath, os.X_OK)57 58 59def which(program):60 """Returns the full path to a program; None otherwise."""61 fpath, _ = os.path.split(program)62 if fpath:63 if is_exe(program):64 return program65 else:66 for path in os.environ["PATH"].split(os.pathsep):67 exe_file = os.path.join(path, program)68 if is_exe(exe_file):69 return exe_file70 return None71 72 73def usage(parser):74 parser.print_help()75 if configuration.verbose > 0:76 print(77 """78Examples:79 80This is an example of using the -f option to pinpoint to a specific test class81and test method to be run:82 83$ ./dotest.py -f ClassTypesTestCase.test_with_dsym_and_run_command84----------------------------------------------------------------------85Collected 1 test86 87test_with_dsym_and_run_command (TestClassTypes.ClassTypesTestCase)88Test 'frame variable this' when stopped on a class constructor. ... ok89 90----------------------------------------------------------------------91Ran 1 test in 1.396s92 93OK94 95And this is an example of using the -p option to run a single file (the filename96matches the pattern 'ObjC' and it happens to be 'TestObjCMethods.py'):97 98$ ./dotest.py -v -p ObjC99----------------------------------------------------------------------100Collected 4 tests101 102test_break_with_dsym (TestObjCMethods.FoundationTestCase)103Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok104test_break_with_dwarf (TestObjCMethods.FoundationTestCase)105Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok106test_data_type_and_expr_with_dsym (TestObjCMethods.FoundationTestCase)107Lookup objective-c data types and evaluate expressions. ... ok108test_data_type_and_expr_with_dwarf (TestObjCMethods.FoundationTestCase)109Lookup objective-c data types and evaluate expressions. ... ok110 111----------------------------------------------------------------------112Ran 4 tests in 16.661s113 114OK115 116Running of this script also sets up the LLDB_TEST environment variable so that117individual test cases can locate their supporting files correctly. The script118tries to set up Python's search paths for modules by looking at the build tree119relative to this script. See also the '-i' option in the following example.120 121Finally, this is an example of using the lldb.py module distributed/installed by122Xcode4 to run against the tests under the 'forward' directory, and with the '-w'123option to add some delay between two tests. It uses ARCH=x86_64 to specify that124as the architecture and CC=clang to specify the compiler used for the test run:125 126$ PYTHONPATH=/Xcode4/Library/PrivateFrameworks/LLDB.framework/Versions/A/Resources/Python ARCH=x86_64 CC=clang ./dotest.py -v -w -i forward127 128Session logs for test failures/errors will go into directory '2010-11-11-13_56_16'129----------------------------------------------------------------------130Collected 2 tests131 132test_with_dsym_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase)133Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok134test_with_dwarf_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase)135Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok136 137----------------------------------------------------------------------138Ran 2 tests in 5.659s139 140OK141 142The 'Session ...' verbiage is recently introduced (see also the '-s' option) to143notify the directory containing the session logs for test failures or errors.144In case there is any test failure/error, a similar message is appended at the145end of the stderr output for your convenience.146 147ENABLING LOGS FROM TESTS148 149Option 1:150 151Writing logs into different files per test case::152 153$ ./dotest.py --channel "lldb all"154 155$ ./dotest.py --channel "lldb all" --channel "gdb-remote packets"156 157These log files are written to:158 159<session-dir>/<test-id>-host.log (logs from lldb host process)160<session-dir>/<test-id>-server.log (logs from debugserver/lldb-server)161<session-dir>/<test-id>-<test-result>.log (console logs)162 163By default, logs from successful runs are deleted. Use the --log-success flag164to create reference logs for debugging.165 166$ ./dotest.py --log-success167 168"""169 )170 sys.exit(0)171 172 173def parseExclusion(exclusion_file):174 """Parse an exclusion file, of the following format, where175 'skip files', 'skip methods', 'xfail files', and 'xfail methods'176 are the possible list heading values:177 178 skip files179 <file name>180 <file name>181 182 xfail methods183 <method name>184 """185 excl_type = None186 187 with open(exclusion_file) as f:188 for line in f:189 line = line.strip()190 if not excl_type:191 excl_type = line192 continue193 194 if not line:195 excl_type = None196 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 = False213 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 raise222 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.environ227 # is automatically translated into a corresponding call to228 # 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 = True245 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...', args.compiler253 )254 sys.exit(-1)255 else:256 # Use a compiler appropriate appropriate for the Apple SDK if one was257 # specified258 if platform_system == "Darwin" and args.apple_sdk:259 configuration.compiler = seven.get_command_output(260 'xcrun -sdk "%s" -find clang 2> /dev/null' % (args.apple_sdk)261 )262 else:263 # 'clang' on ubuntu 14.04 is 3.4 so we try clang-3.5 first264 candidateCompilers = ["clang-3.5", "clang", "gcc"]265 for candidate in candidateCompilers:266 if which(candidate):267 configuration.compiler = candidate268 break269 270 if args.make:271 configuration.make_path = args.make272 273 if args.dsymutil:274 configuration.dsymutil = args.dsymutil275 elif platform_system == "Darwin":276 configuration.dsymutil = seven.get_command_output(277 "xcrun -find -toolchain default dsymutil"278 )279 if args.llvm_tools_dir:280 configuration.llvm_tools_dir = args.llvm_tools_dir281 configuration.filecheck = shutil.which("FileCheck", path=args.llvm_tools_dir)282 configuration.yaml2obj = shutil.which("yaml2obj", path=args.llvm_tools_dir)283 284 if not configuration.get_filecheck_path():285 logging.warning("No valid FileCheck executable; some tests may fail...")286 logging.warning("(Double-check the --llvm-tools-dir argument to dotest.py)")287 288 if args.libcxx_include_dir or args.libcxx_library_dir:289 if args.lldb_platform_name:290 logging.warning(291 "Custom libc++ is not supported for remote runs: ignoring --libcxx arguments"292 )293 elif not (args.libcxx_include_dir and args.libcxx_library_dir):294 logging.error(295 "Custom libc++ requires both --libcxx-include-dir and --libcxx-library-dir"296 )297 sys.exit(-1)298 else:299 configuration.libcxx_include_dir = args.libcxx_include_dir300 configuration.libcxx_include_target_dir = args.libcxx_include_target_dir301 configuration.libcxx_library_dir = args.libcxx_library_dir302 303 configuration.cmake_build_type = args.cmake_build_type.lower()304 305 if args.channels:306 lldbtest_config.channels = args.channels307 308 if args.log_success:309 lldbtest_config.log_success = args.log_success310 311 if args.out_of_tree_debugserver:312 lldbtest_config.out_of_tree_debugserver = args.out_of_tree_debugserver313 314 # Set SDKROOT if we are using an Apple SDK315 if args.sysroot is not None:316 configuration.sdkroot = args.sysroot317 elif platform_system == "Darwin" and args.apple_sdk:318 configuration.sdkroot = seven.get_command_output(319 'xcrun --sdk "%s" --show-sdk-path 2> /dev/null' % (args.apple_sdk)320 )321 if not configuration.sdkroot:322 logging.error("No SDK found with the name %s; aborting...", args.apple_sdk)323 sys.exit(-1)324 325 if args.triple:326 configuration.triple = args.triple327 328 if args.arch:329 configuration.arch = args.arch330 elif args.triple:331 configuration.arch = args.triple.split("-")[0]332 else:333 configuration.arch = platform_machine334 335 if args.categories_list:336 configuration.categories_list = set(337 test_categories.validate(args.categories_list, False)338 )339 configuration.use_categories = True340 else:341 configuration.categories_list = []342 343 if args.skip_categories:344 configuration.skip_categories += test_categories.validate(345 args.skip_categories, False346 )347 348 if args.xfail_categories:349 configuration.xfail_categories += test_categories.validate(350 args.xfail_categories, False351 )352 353 if args.E:354 os.environ["CFLAGS_EXTRAS"] = args.E355 356 if args.dwarf_version:357 configuration.dwarf_version = args.dwarf_version358 # We cannot modify CFLAGS_EXTRAS because they're used in test cases359 # that explicitly require no debug info.360 os.environ["CFLAGS"] = "-gdwarf-{}".format(configuration.dwarf_version)361 362 if args.settings:363 for setting in args.settings:364 if not len(setting) == 1 or not setting[0].count("="):365 logging.error(366 '"%s" is not a setting in the form "key=value"', setting[0]367 )368 sys.exit(-1)369 setting_list = setting[0].split("=", 1)370 configuration.settings.append((setting_list[0], setting_list[1]))371 372 if args.d:373 sys.stdout.write(374 "Suspending the process %d to wait for debugger to attach...\n"375 % os.getpid()376 )377 sys.stdout.flush()378 os.kill(os.getpid(), signal.SIGSTOP)379 380 if args.f:381 if any([x.startswith("-") for x in args.f]):382 usage(parser)383 configuration.filters.extend(args.f)384 385 if args.framework:386 configuration.lldb_framework_path = args.framework387 388 if args.executable:389 # lldb executable is passed explicitly390 lldbtest_config.lldbExec = os.path.abspath(args.executable)391 if not is_exe(lldbtest_config.lldbExec):392 lldbtest_config.lldbExec = which(args.executable)393 if not is_exe(lldbtest_config.lldbExec):394 logging.error(395 "%s is not a valid executable to test; aborting...", args.executable396 )397 sys.exit(-1)398 399 if args.excluded:400 for excl_file in args.excluded:401 parseExclusion(excl_file)402 403 if args.p:404 if args.p.startswith("-"):405 usage(parser)406 configuration.regexp = args.p407 408 if args.t:409 os.environ["LLDB_COMMAND_TRACE"] = "YES"410 411 if args.v:412 configuration.verbose = 2413 414 # argparse makes sure we have a number415 if args.sharp:416 configuration.count = args.sharp417 418 if sys.platform.startswith("win32"):419 os.environ["LLDB_DISABLE_CRASH_DIALOG"] = str(args.disable_crash_dialog)420 os.environ["LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE"] = str(True)421 422 if do_help:423 usage(parser)424 425 if args.lldb_platform_name:426 configuration.lldb_platform_name = args.lldb_platform_name427 if args.lldb_platform_url:428 configuration.lldb_platform_url = args.lldb_platform_url429 if args.lldb_platform_working_dir:430 configuration.lldb_platform_working_dir = args.lldb_platform_working_dir431 if args.lldb_platform_available_ports:432 configuration.lldb_platform_available_ports = args.lldb_platform_available_ports433 if platform_system == "Darwin" and args.apple_sdk:434 configuration.apple_sdk = args.apple_sdk435 if args.test_build_dir:436 configuration.test_build_dir = args.test_build_dir437 if args.lldb_module_cache_dir:438 configuration.lldb_module_cache_dir = args.lldb_module_cache_dir439 else:440 configuration.lldb_module_cache_dir = os.path.join(441 configuration.test_build_dir, "module-cache-lldb"442 )443 444 if args.clang_module_cache_dir:445 configuration.clang_module_cache_dir = args.clang_module_cache_dir446 else:447 configuration.clang_module_cache_dir = os.path.join(448 configuration.test_build_dir, "module-cache-clang"449 )450 451 if args.lldb_libs_dir:452 configuration.lldb_libs_dir = args.lldb_libs_dir453 if args.lldb_obj_root:454 configuration.lldb_obj_root = args.lldb_obj_root455 456 if args.enabled_plugins:457 configuration.enabled_plugins = args.enabled_plugins458 459 # Gather all the dirs passed on the command line.460 if len(args.args) > 0:461 configuration.testdirs = [462 os.path.realpath(os.path.abspath(x)) for x in args.args463 ]464 465 466def registerFaulthandler():467 try:468 import faulthandler469 except ImportError:470 # faulthandler is not available until python3471 return472 473 faulthandler.enable()474 # faulthandler.register is not available on Windows.475 if getattr(faulthandler, "register", None):476 faulthandler.register(signal.SIGTERM, chain=True)477 478 479def setupSysPath():480 """481 Add LLDB.framework/Resources/Python to the search paths for modules.482 As a side effect, we also discover the 'lldb' executable and export it here.483 """484 485 # Get the directory containing the current script.486 if "DOTEST_PROFILE" in os.environ and "DOTEST_SCRIPT_DIR" in os.environ:487 scriptPath = os.environ["DOTEST_SCRIPT_DIR"]488 else:489 scriptPath = os.path.dirname(os.path.abspath(__file__))490 if not scriptPath.endswith("test"):491 print("This script expects to reside in lldb's test directory.")492 sys.exit(-1)493 494 os.environ["LLDB_TEST"] = scriptPath495 496 # Set up the root build directory.497 if not configuration.test_build_dir:498 raise Exception("test_build_dir is not set")499 configuration.test_build_dir = os.path.abspath(configuration.test_build_dir)500 501 # Set up the LLDB_SRC environment variable, so that the tests can locate502 # the LLDB source code.503 os.environ["LLDB_SRC"] = lldbsuite.lldb_root504 505 pluginPath = os.path.join(scriptPath, "plugins")506 toolsLLDBDAP = os.path.join(scriptPath, "tools", "lldb-dap")507 toolsLLDBServerPath = os.path.join(scriptPath, "tools", "lldb-server")508 intelpt = os.path.join(scriptPath, "tools", "intelpt")509 510 # Insert script dir, plugin dir and lldb-server dir to the sys.path.511 sys.path.insert(0, pluginPath)512 # Adding test/tools/lldb-dap to the path makes it easy to513 # "import lldb_dap_testcase" from the DAP tests514 sys.path.insert(0, toolsLLDBDAP)515 # Adding test/tools/lldb-server to the path makes it easy516 # to "import lldbgdbserverutils" from the lldb-server tests517 sys.path.insert(0, toolsLLDBServerPath)518 # Adding test/tools/intelpt to the path makes it easy519 # to "import intelpt_testcase" from the lldb-server tests520 sys.path.insert(0, intelpt)521 522 # This is the root of the lldb git/svn checkout523 # When this changes over to a package instead of a standalone script, this524 # will be `lldbsuite.lldb_root`525 lldbRootDirectory = lldbsuite.lldb_root526 527 # Some of the tests can invoke the 'lldb' command directly.528 # We'll try to locate the appropriate executable right here.529 530 # The lldb executable can be set from the command line531 # if it's not set, we try to find it now532 # first, we try the environment533 if not lldbtest_config.lldbExec:534 # First, you can define an environment variable LLDB_EXEC specifying the535 # full pathname of the lldb executable.536 if "LLDB_EXEC" in os.environ:537 lldbtest_config.lldbExec = os.environ["LLDB_EXEC"]538 539 if not lldbtest_config.lldbExec:540 # Last, check the path541 lldbtest_config.lldbExec = which("lldb")542 543 if lldbtest_config.lldbExec and not is_exe(lldbtest_config.lldbExec):544 print(545 "'{}' is not a path to a valid executable".format(lldbtest_config.lldbExec)546 )547 lldbtest_config.lldbExec = None548 549 if not lldbtest_config.lldbExec:550 print(551 "The 'lldb' executable cannot be located. Some of the tests may not be run as a result."552 )553 sys.exit(-1)554 555 os.system("%s -v" % lldbtest_config.lldbExec)556 557 lldbDir = os.path.dirname(lldbtest_config.lldbExec)558 559 lldbDAPExec = os.path.join(lldbDir, "lldb-dap")560 if is_exe(lldbDAPExec):561 os.environ["LLDBDAP_EXEC"] = lldbDAPExec562 563 configuration.yaml2macho_core = shutil.which("yaml2macho-core", path=lldbDir)564 565 lldbPythonDir = None # The directory that contains 'lldb/__init__.py'566 567 # If our lldb supports the -P option, use it to find the python path:568 lldb_dash_p_result = subprocess.check_output(569 [lldbtest_config.lldbExec, "-P"], universal_newlines=True570 )571 if lldb_dash_p_result:572 for line in lldb_dash_p_result.splitlines():573 if os.path.isdir(line) and os.path.exists(574 os.path.join(line, "lldb", "__init__.py")575 ):576 lldbPythonDir = line577 break578 579 if not lldbPythonDir:580 print(581 "Unable to load lldb extension module. Possible reasons for this include:"582 )583 print(" 1) LLDB was built with LLDB_ENABLE_PYTHON=0")584 print(585 " 2) PYTHONPATH and PYTHONHOME are not set correctly. PYTHONHOME should refer to"586 )587 print(588 " the version of Python that LLDB built and linked against, and PYTHONPATH"589 )590 print(591 " should contain the Lib directory for the same python distro, as well as the"592 )593 print(" location of LLDB's site-packages folder.")594 print(595 " 3) A different version of Python than that which was built against is exported in"596 )597 print(" the system's PATH environment variable, causing conflicts.")598 print(599 " 4) The executable '%s' could not be found. Please check "600 % lldbtest_config.lldbExec601 )602 print(" that it exists and is executable.")603 604 if lldbPythonDir:605 lldbPythonDir = os.path.normpath(lldbPythonDir)606 # Some of the code that uses this path assumes it hasn't resolved the Versions... link.607 # If the path we've constructed looks like that, then we'll strip out608 # the Versions/A part.609 (before, frameWithVersion, after) = lldbPythonDir.rpartition(610 "LLDB.framework/Versions/A"611 )612 if frameWithVersion != "":613 lldbPythonDir = before + "LLDB.framework" + after614 615 lldbPythonDir = os.path.abspath(lldbPythonDir)616 617 if "freebsd" in sys.platform or "linux" in sys.platform:618 os.environ["LLDB_LIB_DIR"] = os.path.join(lldbPythonDir, "..", "..")619 620 # If tests need to find LLDB_FRAMEWORK, now they can do it621 os.environ["LLDB_FRAMEWORK"] = os.path.dirname(os.path.dirname(lldbPythonDir))622 623 # This is to locate the lldb.py module. Insert it right after624 # sys.path[0].625 sys.path[1:1] = [lldbPythonDir]626 627 628def visit_file(dir, name):629 # Try to match the regexp pattern, if specified.630 if configuration.regexp:631 if not re.search(configuration.regexp, name):632 # We didn't match the regex, we're done.633 return634 635 if configuration.skip_tests:636 for file_regexp in configuration.skip_tests:637 if re.search(file_regexp, name):638 return639 640 # We found a match for our test. Add it to the suite.641 642 # Update the sys.path first.643 if not sys.path.count(dir):644 sys.path.insert(0, dir)645 base = os.path.splitext(name)[0]646 647 # Thoroughly check the filterspec against the base module and admit648 # the (base, filterspec) combination only when it makes sense.649 650 def check(obj, parts):651 for part in parts:652 try:653 parent, obj = obj, getattr(obj, part)654 except AttributeError:655 # The filterspec has failed.656 return False657 return True658 659 module = __import__(base)660 661 def iter_filters():662 for filterspec in configuration.filters:663 parts = filterspec.split(".")664 if check(module, parts):665 yield filterspec666 elif parts[0] == base and len(parts) > 1 and check(module, parts[1:]):667 yield ".".join(parts[1:])668 else:669 for key, value in module.__dict__.items():670 if check(value, parts):671 yield key + "." + filterspec672 673 filtered = False674 for filterspec in iter_filters():675 filtered = True676 print("adding filter spec %s to module %s" % (filterspec, repr(module)))677 tests = unittest.defaultTestLoader.loadTestsFromName(filterspec, module)678 configuration.suite.addTests(tests)679 680 # Forgo this module if the (base, filterspec) combo is invalid681 if configuration.filters and not filtered:682 return683 684 if not filtered:685 # Add the entire file's worth of tests since we're not filtered.686 # Also the fail-over case when the filterspec branch687 # (base, filterspec) combo doesn't make sense.688 configuration.suite.addTests(unittest.defaultTestLoader.loadTestsFromName(base))689 690 691def visit(prefix, dir, names):692 """Visitor function for os.path.walk(path, visit, arg)."""693 694 dir_components = set(dir.split(os.sep))695 excluded_components = set([".svn", ".git"])696 if dir_components.intersection(excluded_components):697 return698 699 # Gather all the Python test file names that follow the Test*.py pattern.700 python_test_files = [701 name for name in names if name.endswith(".py") and name.startswith(prefix)702 ]703 704 # Visit all the python test files.705 for name in python_test_files:706 # Ensure we error out if we have multiple tests with the same707 # base name.708 # Future improvement: find all the places where we work with base709 # names and convert to full paths. We have directory structure710 # to disambiguate these, so we shouldn't need this constraint.711 if name in configuration.all_tests:712 raise Exception("Found multiple tests with the name %s" % name)713 configuration.all_tests.add(name)714 715 # Run the relevant tests in the python file.716 visit_file(dir, name)717 718 719# ======================================== #720# #721# Execution of the test driver starts here #722# #723# ======================================== #724 725 726def checkDsymForUUIDIsNotOn():727 cmd = ["defaults", "read", "com.apple.DebugSymbols"]728 process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)729 cmd_output = process.stdout.read()730 output_str = cmd_output.decode("utf-8")731 if "DBGFileMappedPaths = " in output_str:732 print("%s =>" % " ".join(cmd))733 print(output_str)734 print(735 "Disable automatic lookup and caching of dSYMs before running the test suite!"736 )737 print("Exiting...")738 sys.exit(0)739 740 741def exitTestSuite(exitCode=None):742 # lldb.py does SBDebugger.Initialize().743 # Call SBDebugger.Terminate() on exit.744 import lldb745 746 lldb.SBDebugger.Terminate()747 if exitCode:748 sys.exit(exitCode)749 750 751def getVersionForSDK(sdk):752 sdk = str.lower(sdk)753 full_path = seven.get_command_output("xcrun -sdk %s --show-sdk-path" % sdk)754 basename = os.path.basename(full_path)755 basename = os.path.splitext(basename)[0]756 basename = str.lower(basename)757 ver = basename.replace(sdk, "")758 return ver759 760 761def checkCompiler():762 # Add some intervention here to sanity check that the compiler requested is sane.763 # If found not to be an executable program, we abort.764 c = configuration.compiler765 if which(c):766 return767 768 if not sys.platform.startswith("darwin"):769 raise Exception(c + " is not a valid compiler")770 771 pipe = subprocess.Popen(772 ["xcrun", "-find", c], stdout=subprocess.PIPE, stderr=subprocess.STDOUT773 )774 cmd_output = pipe.stdout.read()775 if not cmd_output or "not found" in cmd_output:776 raise Exception(c + " is not a valid compiler")777 778 configuration.compiler = cmd_output.split("\n")[0]779 print("'xcrun -find %s' returning %s" % (c, configuration.compiler))780 781 782def canRunLibcxxTests():783 from lldbsuite.test import lldbplatformutil784 785 platform = lldbplatformutil.getPlatform()786 787 if lldbplatformutil.target_is_android() or lldbplatformutil.platformIsDarwin():788 return True, "libc++ always present"789 790 if platform == "linux":791 if not configuration.libcxx_include_dir or not configuration.libcxx_library_dir:792 return False, "API tests require a locally built libc++."793 794 # Make sure -stdlib=libc++ works since that's how the tests will be built.795 with temp_file.OnDiskTempFile() as f:796 cmd = [configuration.compiler, "-xc++", "-stdlib=libc++", "-o", f.path, "-"]797 p = subprocess.Popen(798 cmd,799 stdin=subprocess.PIPE,800 stdout=subprocess.PIPE,801 stderr=subprocess.PIPE,802 universal_newlines=True,803 )804 _, stderr = p.communicate("#include <cassert>\nint main() {}")805 if not p.returncode:806 return True, "Compiling with -stdlib=libc++ works"807 return (808 False,809 "Compiling with -stdlib=libc++ fails with the error: %s" % stderr,810 )811 812 return False, "Don't know how to build with libc++ on %s" % platform813 814 815def checkLibcxxSupport():816 result, reason = canRunLibcxxTests()817 if result:818 return # libc++ supported819 if "libc++" in configuration.categories_list:820 return # libc++ category explicitly requested, let it run.821 if configuration.verbose:822 print("libc++ tests will not be run because: " + reason)823 configuration.skip_categories.append("libc++")824 825 826def canRunLibstdcxxTests():827 from lldbsuite.test import lldbplatformutil828 829 platform = lldbplatformutil.getPlatform()830 if lldbplatformutil.target_is_android():831 platform = "android"832 if platform == "linux":833 return True, "libstdcxx always present"834 return False, "Don't know how to build with libstdcxx on %s" % platform835 836 837def checkLibstdcxxSupport():838 result, reason = canRunLibstdcxxTests()839 if result:840 return # libstdcxx supported841 if "libstdcxx" in configuration.categories_list:842 return # libstdcxx category explicitly requested, let it run.843 if configuration.verbose:844 print("libstdcxx tests will not be run because: " + reason)845 configuration.skip_categories.append("libstdcxx")846 847 848def canRunMsvcStlTests():849 from lldbsuite.test import lldbplatformutil850 851 platform = lldbplatformutil.getPlatform()852 if platform != "windows":853 return False, f"Don't know how to build with MSVC's STL on {platform}"854 855 with temp_file.OnDiskTempFile() as f:856 cmd = [configuration.compiler, "-xc++", "-o", f.path, "-E", "-"]857 p = subprocess.Popen(858 cmd,859 stdin=subprocess.PIPE,860 stdout=subprocess.PIPE,861 stderr=subprocess.PIPE,862 universal_newlines=True,863 )864 _, stderr = p.communicate(865 """866 #include <yvals_core.h>867 #ifndef _MSVC_STL_VERSION868 #error _MSVC_STL_VERSION not defined869 #endif870 """871 )872 if not p.returncode:873 return True, "Compiling with MSVC STL"874 return (False, f"Not compiling with MSVC STL: {stderr}")875 876 877def checkMsvcStlSupport():878 result, reason = canRunMsvcStlTests()879 if result:880 return # msvcstl supported881 if "msvcstl" in configuration.categories_list:882 return # msvcstl category explicitly requested, let it run.883 if configuration.verbose:884 print(f"msvcstl tests will not be run because: {reason}")885 configuration.skip_categories.append("msvcstl")886 887 888def canRunWatchpointTests():889 from lldbsuite.test import lldbplatformutil890 891 platform = lldbplatformutil.getPlatform()892 if platform == "netbsd":893 if os.geteuid() == 0:894 return True, "root can always write dbregs"895 try:896 output = (897 subprocess.check_output(898 ["/sbin/sysctl", "-n", "security.models.extensions.user_set_dbregs"]899 )900 .decode()901 .strip()902 )903 if output == "1":904 return True, "security.models.extensions.user_set_dbregs enabled"905 except subprocess.CalledProcessError:906 pass907 return False, "security.models.extensions.user_set_dbregs disabled"908 elif platform == "freebsd" and configuration.arch == "aarch64":909 import lldb910 911 if lldb.SBPlatform.GetHostPlatform().GetOSMajorVersion() < 13:912 return False, "Watchpoint support on arm64 requires FreeBSD 13.0"913 return True, "watchpoint support available"914 915 916def checkWatchpointSupport():917 result, reason = canRunWatchpointTests()918 if result:919 return # watchpoints supported920 if "watchpoint" in configuration.categories_list:921 return # watchpoint category explicitly requested, let it run.922 if configuration.verbose:923 print("watchpoint tests will not be run because: " + reason)924 configuration.skip_categories.append("watchpoint")925 926 927def checkObjcSupport():928 from lldbsuite.test import lldbplatformutil929 930 if not lldbplatformutil.platformIsDarwin():931 if configuration.verbose:932 print("objc tests will be skipped because of unsupported platform")933 configuration.skip_categories.append("objc")934 935 936def checkDebugInfoSupport():937 from lldbsuite.test import lldbplatformutil938 939 platform = lldbplatformutil.getPlatform()940 compiler = configuration.compiler941 for cat in test_categories.debug_info_categories:942 if cat in configuration.categories_list:943 continue # Category explicitly requested, let it run.944 if test_categories.is_supported_on_platform(cat, platform, compiler):945 continue946 configuration.skip_categories.append(cat)947 948 949def checkDebugServerSupport():950 from lldbsuite.test import lldbplatformutil951 import lldb952 953 skip_msg = "Skipping %s tests, as they are not compatible with remote testing on this platform"954 if lldbplatformutil.platformIsDarwin():955 configuration.skip_categories.append("llgs")956 if lldb.remote_platform:957 # <rdar://problem/34539270>958 configuration.skip_categories.append("debugserver")959 if configuration.verbose:960 print(skip_msg % "debugserver")961 else:962 configuration.skip_categories.append("debugserver")963 if lldb.remote_platform and lldbplatformutil.getPlatform() == "windows":964 configuration.skip_categories.append("llgs")965 if configuration.verbose:966 print(skip_msg % "lldb-server")967 968 969def checkForkVForkSupport():970 from lldbsuite.test import lldbplatformutil971 972 platform = lldbplatformutil.getPlatform()973 if platform not in ["freebsd", "linux", "netbsd"]:974 configuration.skip_categories.append("fork")975 976 977def checkPexpectSupport():978 from lldbsuite.test import lldbplatformutil979 980 platform = lldbplatformutil.getPlatform()981 982 # llvm.org/pr22274: need a pexpect replacement for windows983 if platform in ["windows"]:984 if configuration.verbose:985 print("pexpect tests will be skipped because of unsupported platform")986 configuration.skip_categories.append("pexpect")987 988 989def checkDAPSupport():990 import lldb991 992 if "LLDBDAP_EXEC" not in os.environ:993 msg = (994 "The 'lldb-dap' executable cannot be located and its tests will not be run."995 )996 elif lldb.remote_platform:997 msg = "lldb-dap tests are not compatible with remote platforms and will not be run."998 else:999 msg = None1000 1001 if msg:1002 if configuration.verbose:1003 print(msg)1004 configuration.skip_categories.append("lldb-dap")1005 1006 1007def run_suite():1008 # On MacOS X, check to make sure that domain for com.apple.DebugSymbols defaults1009 # does not exist before proceeding to running the test suite.1010 if sys.platform.startswith("darwin"):1011 checkDsymForUUIDIsNotOn()1012 1013 # Start the actions by first parsing the options while setting up the test1014 # directories, followed by setting up the search paths for lldb utilities;1015 # then, we walk the directory trees and collect the tests into our test suite.1016 #1017 parseOptionsAndInitTestdirs()1018 1019 # Print a stack trace if the test hangs or is passed SIGTERM.1020 registerFaulthandler()1021 1022 setupSysPath()1023 1024 import lldb1025 1026 lldb.SBDebugger.Initialize()1027 lldb.SBDebugger.PrintStackTraceOnError()1028 1029 # Use host platform by default.1030 lldb.remote_platform = None1031 lldb.selected_platform = lldb.SBPlatform.GetHostPlatform()1032 1033 # Now we can also import lldbutil1034 from lldbsuite.test import lldbutil1035 1036 if configuration.lldb_platform_name:1037 print("Setting up remote platform '%s'" % (configuration.lldb_platform_name))1038 lldb.remote_platform = lldb.SBPlatform(configuration.lldb_platform_name)1039 lldb.selected_platform = lldb.remote_platform1040 if not lldb.remote_platform.IsValid():1041 print(1042 "error: unable to create the LLDB platform named '%s'."1043 % (configuration.lldb_platform_name)1044 )1045 exitTestSuite(1)1046 if configuration.lldb_platform_url:1047 # We must connect to a remote platform if a LLDB platform URL was1048 # specified1049 print(1050 "Connecting to remote platform '%s' at '%s'..."1051 % (configuration.lldb_platform_name, configuration.lldb_platform_url)1052 )1053 platform_connect_options = lldb.SBPlatformConnectOptions(1054 configuration.lldb_platform_url1055 )1056 err = lldb.remote_platform.ConnectRemote(platform_connect_options)1057 if err.Success():1058 print("Connected.")1059 else:1060 print(1061 "error: failed to connect to remote platform using URL '%s': %s"1062 % (configuration.lldb_platform_url, err)1063 )1064 exitTestSuite(1)1065 else:1066 configuration.lldb_platform_url = None1067 1068 if configuration.lldb_platform_working_dir:1069 print(1070 "Setting remote platform working directory to '%s'..."1071 % (configuration.lldb_platform_working_dir)1072 )1073 error = lldb.remote_platform.MakeDirectory(1074 configuration.lldb_platform_working_dir, 4481075 ) # 448 = 0o7001076 if error.Fail():1077 raise Exception(1078 "making remote directory '%s': %s"1079 % (configuration.lldb_platform_working_dir, error)1080 )1081 1082 if not lldb.remote_platform.SetWorkingDirectory(1083 configuration.lldb_platform_working_dir1084 ):1085 raise Exception(1086 "failed to set working directory '%s'"1087 % configuration.lldb_platform_working_dir1088 )1089 lldb.selected_platform = lldb.remote_platform1090 else:1091 lldb.remote_platform = None1092 configuration.lldb_platform_working_dir = None1093 configuration.lldb_platform_url = None1094 1095 # Set up the working directory.1096 # Note that it's not dotest's job to clean this directory.1097 lldbutil.mkdir_p(configuration.test_build_dir)1098 1099 checkLibcxxSupport()1100 checkLibstdcxxSupport()1101 checkMsvcStlSupport()1102 checkWatchpointSupport()1103 checkDebugInfoSupport()1104 checkDebugServerSupport()1105 checkObjcSupport()1106 checkForkVForkSupport()1107 checkPexpectSupport()1108 checkDAPSupport()1109 1110 skipped_categories_list = ", ".join(configuration.skip_categories)1111 print(f"Skipping the following test categories: {skipped_categories_list}")1112 1113 for testdir in configuration.testdirs:1114 for dirpath, dirnames, filenames in os.walk(testdir):1115 visit("Test", dirpath, filenames)1116 1117 #1118 # Now that we have loaded all the test cases, run the whole test suite.1119 #1120 1121 # Install the control-c handler.1122 unittest.signals.installHandler()1123 1124 #1125 # Invoke the default TextTestRunner to run the test suite1126 #1127 checkCompiler()1128 1129 if configuration.verbose:1130 print("compiler=%s" % configuration.compiler)1131 1132 # Iterating over all possible architecture and compiler combinations.1133 configString = "arch=%s compiler=%s" % (configuration.arch, configuration.compiler)1134 1135 # Output the configuration.1136 if configuration.verbose:1137 sys.stderr.write("\nConfiguration: " + configString + "\n")1138 1139 # First, write out the number of collected test cases.1140 if configuration.verbose:1141 sys.stderr.write(configuration.separator + "\n")1142 sys.stderr.write(1143 "Collected %d test%s\n\n"1144 % (1145 configuration.suite.countTestCases(),1146 configuration.suite.countTestCases() != 1 and "s" or "",1147 )1148 )1149 1150 if configuration.suite.countTestCases() == 0:1151 logging.error("did not discover any matching tests")1152 exitTestSuite(1)1153 1154 # Invoke the test runner.1155 if configuration.count == 1:1156 result = unittest.TextTestRunner(1157 stream=sys.stderr,1158 verbosity=configuration.verbose,1159 resultclass=test_result.LLDBTestResult,1160 ).run(configuration.suite)1161 else:1162 # We are invoking the same test suite more than once. In this case,1163 # mark __ignore_singleton__ flag as True so the signleton pattern is1164 # not enforced.1165 test_result.LLDBTestResult.__ignore_singleton__ = True1166 for i in range(configuration.count):1167 result = unittest.TextTestRunner(1168 stream=sys.stderr,1169 verbosity=configuration.verbose,1170 resultclass=test_result.LLDBTestResult,1171 ).run(configuration.suite)1172 1173 configuration.failed = not result.wasSuccessful()1174 1175 if configuration.sdir_has_content and configuration.verbose:1176 sys.stderr.write(1177 "Session logs for test failures/errors/unexpected successes"1178 " can be found in the test build directory\n"1179 )1180 1181 if configuration.use_categories and len(configuration.failures_per_category) > 0:1182 sys.stderr.write("Failures per category:\n")1183 for category in configuration.failures_per_category:1184 sys.stderr.write(1185 "%s - %d\n" % (category, configuration.failures_per_category[category])1186 )1187 1188 # Exiting.1189 exitTestSuite(configuration.failed)1190 1191 1192if __name__ == "__main__":1193 print(1194 __file__1195 + " is for use as a module only. It should not be run as a standalone script."1196 )1197 sys.exit(-1)1198