brintos

brintos / llvm-project-archived public Read only

0
0
Text · 41.2 KiB · f280bd2 Raw
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