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 if args.clang_module_cache_dir: 427 configuration.clang_module_cache_dir = args.clang_module_cache_dir 428 else: 429 configuration.clang_module_cache_dir = os.path.join( 430 configuration.test_build_dir, "module-cache-clang" 431 ) 432 433 if args.lldb_libs_dir: 434 configuration.lldb_libs_dir = args.lldb_libs_dir 435 436 if args.enabled_plugins: 437 configuration.enabled_plugins = args.enabled_plugins 438 439 # Gather all the dirs passed on the command line. 440 if len(args.args) > 0: 441 configuration.testdirs = [ 442 os.path.realpath(os.path.abspath(x)) for x in args.args 443 ] 444 445 446def registerFaulthandler(): 447 try: 448 import faulthandler 449 except ImportError: 450 # faulthandler is not available until python3 451 return 452 453 faulthandler.enable() 454 # faulthandler.register is not available on Windows. 455 if getattr(faulthandler, "register", None): 456 faulthandler.register(signal.SIGTERM, chain=True) 457 458 459def setupSysPath(): 460 """ 461 Add LLDB.framework/Resources/Python to the search paths for modules. 462 As a side effect, we also discover the 'lldb' executable and export it here. 463 """ 464 465 # Get the directory containing the current script. 466 if "DOTEST_PROFILE" in os.environ and "DOTEST_SCRIPT_DIR" in os.environ: 467 scriptPath = os.environ["DOTEST_SCRIPT_DIR"] 468 else: 469 scriptPath = os.path.dirname(os.path.abspath(__file__)) 470 if not scriptPath.endswith("test"): 471 print("This script expects to reside in lldb's test directory.") 472 sys.exit(-1) 473 474 os.environ["LLDB_TEST"] = scriptPath 475 476 # Set up the root build directory. 477 if not configuration.test_build_dir: 478 raise Exception("test_build_dir is not set") 479 configuration.test_build_dir = os.path.abspath(configuration.test_build_dir) 480 481 # Set up the LLDB_SRC environment variable, so that the tests can locate 482 # the LLDB source code. 483 os.environ["LLDB_SRC"] = lldbsuite.lldb_root 484 485 pluginPath = os.path.join(scriptPath, "plugins") 486 toolsLLDBDAP = os.path.join(scriptPath, "tools", "lldb-dap") 487 toolsLLDBServerPath = os.path.join(scriptPath, "tools", "lldb-server") 488 intelpt = os.path.join(scriptPath, "tools", "intelpt") 489 490 # Insert script dir, plugin dir and lldb-server dir to the sys.path. 491 sys.path.insert(0, pluginPath) 492 # Adding test/tools/lldb-dap to the path makes it easy to 493 # "import lldb_dap_testcase" from the DAP tests 494 sys.path.insert(0, toolsLLDBDAP) 495 # Adding test/tools/lldb-server to the path makes it easy 496 # to "import lldbgdbserverutils" from the lldb-server tests 497 sys.path.insert(0, toolsLLDBServerPath) 498 # Adding test/tools/intelpt to the path makes it easy 499 # to "import intelpt_testcase" from the lldb-server tests 500 sys.path.insert(0, intelpt) 501 502 # This is the root of the lldb git/svn checkout 503 # When this changes over to a package instead of a standalone script, this 504 # will be `lldbsuite.lldb_root` 505 lldbRootDirectory = lldbsuite.lldb_root 506 507 # Some of the tests can invoke the 'lldb' command directly. 508 # We'll try to locate the appropriate executable right here. 509 510 # The lldb executable can be set from the command line 511 # if it's not set, we try to find it now 512 # first, we try the environment 513 if not lldbtest_config.lldbExec: 514 # First, you can define an environment variable LLDB_EXEC specifying the 515 # full pathname of the lldb executable. 516 if "LLDB_EXEC" in os.environ: 517 lldbtest_config.lldbExec = os.environ["LLDB_EXEC"] 518 519 if not lldbtest_config.lldbExec: 520 # Last, check the path 521 lldbtest_config.lldbExec = which("lldb") 522 523 if lldbtest_config.lldbExec and not is_exe(lldbtest_config.lldbExec): 524 print( 525 "'{}' is not a path to a valid executable".format(lldbtest_config.lldbExec) 526 ) 527 lldbtest_config.lldbExec = None 528 529 if not lldbtest_config.lldbExec: 530 print( 531 "The 'lldb' executable cannot be located. Some of the tests may not be run as a result." 532 ) 533 sys.exit(-1) 534 535 os.system("%s -v" % lldbtest_config.lldbExec) 536 537 lldbDir = os.path.dirname(lldbtest_config.lldbExec) 538 539 lldbDAPExec = os.path.join(lldbDir, "lldb-dap") 540 if is_exe(lldbDAPExec): 541 os.environ["LLDBDAP_EXEC"] = lldbDAPExec 542 else: 543 if not configuration.shouldSkipBecauseOfCategories(["lldb-dap"]): 544 print( 545 "The 'lldb-dap' executable cannot be located. The lldb-dap tests can not be run as a result." 546 ) 547 configuration.skip_categories.append("lldb-dap") 548 549 lldbPythonDir = None # The directory that contains 'lldb/__init__.py' 550 551 # If our lldb supports the -P option, use it to find the python path: 552 lldb_dash_p_result = subprocess.check_output( 553 [lldbtest_config.lldbExec, "-P"], universal_newlines=True 554 ) 555 if lldb_dash_p_result: 556 for line in lldb_dash_p_result.splitlines(): 557 if os.path.isdir(line) and os.path.exists( 558 os.path.join(line, "lldb", "__init__.py") 559 ): 560 lldbPythonDir = line 561 break 562 563 if not lldbPythonDir: 564 print( 565 "Unable to load lldb extension module. Possible reasons for this include:" 566 ) 567 print(" 1) LLDB was built with LLDB_ENABLE_PYTHON=0") 568 print( 569 " 2) PYTHONPATH and PYTHONHOME are not set correctly. PYTHONHOME should refer to" 570 ) 571 print( 572 " the version of Python that LLDB built and linked against, and PYTHONPATH" 573 ) 574 print( 575 " should contain the Lib directory for the same python distro, as well as the" 576 ) 577 print(" location of LLDB's site-packages folder.") 578 print( 579 " 3) A different version of Python than that which was built against is exported in" 580 ) 581 print(" the system's PATH environment variable, causing conflicts.") 582 print( 583 " 4) The executable '%s' could not be found. Please check " 584 % lldbtest_config.lldbExec 585 ) 586 print(" that it exists and is executable.") 587 588 if lldbPythonDir: 589 lldbPythonDir = os.path.normpath(lldbPythonDir) 590 # Some of the code that uses this path assumes it hasn't resolved the Versions... link. 591 # If the path we've constructed looks like that, then we'll strip out 592 # the Versions/A part. 593 (before, frameWithVersion, after) = lldbPythonDir.rpartition( 594 "LLDB.framework/Versions/A" 595 ) 596 if frameWithVersion != "": 597 lldbPythonDir = before + "LLDB.framework" + after 598 599 lldbPythonDir = os.path.abspath(lldbPythonDir) 600 601 if "freebsd" in sys.platform or "linux" in sys.platform: 602 os.environ["LLDB_LIB_DIR"] = os.path.join(lldbPythonDir, "..", "..") 603 604 # If tests need to find LLDB_FRAMEWORK, now they can do it 605 os.environ["LLDB_FRAMEWORK"] = os.path.dirname(os.path.dirname(lldbPythonDir)) 606 607 # This is to locate the lldb.py module. Insert it right after 608 # sys.path[0]. 609 sys.path[1:1] = [lldbPythonDir] 610 611 612def visit_file(dir, name): 613 # Try to match the regexp pattern, if specified. 614 if configuration.regexp: 615 if not re.search(configuration.regexp, name): 616 # We didn't match the regex, we're done. 617 return 618 619 if configuration.skip_tests: 620 for file_regexp in configuration.skip_tests: 621 if re.search(file_regexp, name): 622 return 623 624 # We found a match for our test. Add it to the suite. 625 626 # Update the sys.path first. 627 if not sys.path.count(dir): 628 sys.path.insert(0, dir) 629 base = os.path.splitext(name)[0] 630 631 # Thoroughly check the filterspec against the base module and admit 632 # the (base, filterspec) combination only when it makes sense. 633 634 def check(obj, parts): 635 for part in parts: 636 try: 637 parent, obj = obj, getattr(obj, part) 638 except AttributeError: 639 # The filterspec has failed. 640 return False 641 return True 642 643 module = __import__(base) 644 645 def iter_filters(): 646 for filterspec in configuration.filters: 647 parts = filterspec.split(".") 648 if check(module, parts): 649 yield filterspec 650 elif parts[0] == base and len(parts) > 1 and check(module, parts[1:]): 651 yield ".".join(parts[1:]) 652 else: 653 for key, value in module.__dict__.items(): 654 if check(value, parts): 655 yield key + "." + filterspec 656 657 filtered = False 658 for filterspec in iter_filters(): 659 filtered = True 660 print("adding filter spec %s to module %s" % (filterspec, repr(module))) 661 tests = unittest.defaultTestLoader.loadTestsFromName(filterspec, module) 662 configuration.suite.addTests(tests) 663 664 # Forgo this module if the (base, filterspec) combo is invalid 665 if configuration.filters and not filtered: 666 return 667 668 if not filtered: 669 # Add the entire file's worth of tests since we're not filtered. 670 # Also the fail-over case when the filterspec branch 671 # (base, filterspec) combo doesn't make sense. 672 configuration.suite.addTests(unittest.defaultTestLoader.loadTestsFromName(base)) 673 674 675def visit(prefix, dir, names): 676 """Visitor function for os.path.walk(path, visit, arg).""" 677 678 dir_components = set(dir.split(os.sep)) 679 excluded_components = set([".svn", ".git"]) 680 if dir_components.intersection(excluded_components): 681 return 682 683 # Gather all the Python test file names that follow the Test*.py pattern. 684 python_test_files = [ 685 name for name in names if name.endswith(".py") and name.startswith(prefix) 686 ] 687 688 # Visit all the python test files. 689 for name in python_test_files: 690 # Ensure we error out if we have multiple tests with the same 691 # base name. 692 # Future improvement: find all the places where we work with base 693 # names and convert to full paths. We have directory structure 694 # to disambiguate these, so we shouldn't need this constraint. 695 if name in configuration.all_tests: 696 raise Exception("Found multiple tests with the name %s" % name) 697 configuration.all_tests.add(name) 698 699 # Run the relevant tests in the python file. 700 visit_file(dir, name) 701 702 703# ======================================== # 704# # 705# Execution of the test driver starts here # 706# # 707# ======================================== # 708 709 710def checkDsymForUUIDIsNotOn(): 711 cmd = ["defaults", "read", "com.apple.DebugSymbols"] 712 process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 713 cmd_output = process.stdout.read() 714 output_str = cmd_output.decode("utf-8") 715 if "DBGFileMappedPaths = " in output_str: 716 print("%s =>" % " ".join(cmd)) 717 print(output_str) 718 print( 719 "Disable automatic lookup and caching of dSYMs before running the test suite!" 720 ) 721 print("Exiting...") 722 sys.exit(0) 723 724 725def exitTestSuite(exitCode=None): 726 # lldb.py does SBDebugger.Initialize(). 727 # Call SBDebugger.Terminate() on exit. 728 import lldb 729 730 lldb.SBDebugger.Terminate() 731 if exitCode: 732 sys.exit(exitCode) 733 734 735def getVersionForSDK(sdk): 736 sdk = str.lower(sdk) 737 full_path = seven.get_command_output("xcrun -sdk %s --show-sdk-path" % sdk) 738 basename = os.path.basename(full_path) 739 basename = os.path.splitext(basename)[0] 740 basename = str.lower(basename) 741 ver = basename.replace(sdk, "") 742 return ver 743 744 745def checkCompiler(): 746 # Add some intervention here to sanity check that the compiler requested is sane. 747 # If found not to be an executable program, we abort. 748 c = configuration.compiler 749 if which(c): 750 return 751 752 if not sys.platform.startswith("darwin"): 753 raise Exception(c + " is not a valid compiler") 754 755 pipe = subprocess.Popen( 756 ["xcrun", "-find", c], stdout=subprocess.PIPE, stderr=subprocess.STDOUT 757 ) 758 cmd_output = pipe.stdout.read() 759 if not cmd_output or "not found" in cmd_output: 760 raise Exception(c + " is not a valid compiler") 761 762 configuration.compiler = cmd_output.split("\n")[0] 763 print("'xcrun -find %s' returning %s" % (c, configuration.compiler)) 764 765 766def canRunLibcxxTests(): 767 from lldbsuite.test import lldbplatformutil 768 769 platform = lldbplatformutil.getPlatform() 770 771 if lldbplatformutil.target_is_android() or lldbplatformutil.platformIsDarwin(): 772 return True, "libc++ always present" 773 774 if platform == "linux": 775 with tempfile.NamedTemporaryFile() as f: 776 cmd = [configuration.compiler, "-xc++", "-stdlib=libc++", "-o", f.name, "-"] 777 p = subprocess.Popen( 778 cmd, 779 stdin=subprocess.PIPE, 780 stdout=subprocess.PIPE, 781 stderr=subprocess.PIPE, 782 universal_newlines=True, 783 ) 784 _, stderr = p.communicate("#include <cassert>\nint main() {}") 785 if not p.returncode: 786 return True, "Compiling with -stdlib=libc++ works" 787 return ( 788 False, 789 "Compiling with -stdlib=libc++ fails with the error: %s" % stderr, 790 ) 791 792 return False, "Don't know how to build with libc++ on %s" % platform 793 794 795def checkLibcxxSupport(): 796 result, reason = canRunLibcxxTests() 797 if result: 798 return # libc++ supported 799 if "libc++" in configuration.categories_list: 800 return # libc++ category explicitly requested, let it run. 801 if configuration.verbose: 802 print("libc++ tests will not be run because: " + reason) 803 configuration.skip_categories.append("libc++") 804 805 806def canRunLibstdcxxTests(): 807 from lldbsuite.test import lldbplatformutil 808 809 platform = lldbplatformutil.getPlatform() 810 if lldbplatformutil.target_is_android(): 811 platform = "android" 812 if platform == "linux": 813 return True, "libstdcxx always present" 814 return False, "Don't know how to build with libstdcxx on %s" % platform 815 816 817def checkLibstdcxxSupport(): 818 result, reason = canRunLibstdcxxTests() 819 if result: 820 return # libstdcxx supported 821 if "libstdcxx" in configuration.categories_list: 822 return # libstdcxx category explicitly requested, let it run. 823 if configuration.verbose: 824 print("libstdcxx tests will not be run because: " + reason) 825 configuration.skip_categories.append("libstdcxx") 826 827 828def canRunWatchpointTests(): 829 from lldbsuite.test import lldbplatformutil 830 831 platform = lldbplatformutil.getPlatform() 832 if platform == "netbsd": 833 if os.geteuid() == 0: 834 return True, "root can always write dbregs" 835 try: 836 output = ( 837 subprocess.check_output( 838 ["/sbin/sysctl", "-n", "security.models.extensions.user_set_dbregs"] 839 ) 840 .decode() 841 .strip() 842 ) 843 if output == "1": 844 return True, "security.models.extensions.user_set_dbregs enabled" 845 except subprocess.CalledProcessError: 846 pass 847 return False, "security.models.extensions.user_set_dbregs disabled" 848 elif platform == "freebsd" and configuration.arch == "aarch64": 849 import lldb 850 851 if lldb.SBPlatform.GetHostPlatform().GetOSMajorVersion() < 13: 852 return False, "Watchpoint support on arm64 requires FreeBSD 13.0" 853 return True, "watchpoint support available" 854 855 856def checkWatchpointSupport(): 857 result, reason = canRunWatchpointTests() 858 if result: 859 return # watchpoints supported 860 if "watchpoint" in configuration.categories_list: 861 return # watchpoint category explicitly requested, let it run. 862 if configuration.verbose: 863 print("watchpoint tests will not be run because: " + reason) 864 configuration.skip_categories.append("watchpoint") 865 866 867def checkObjcSupport(): 868 from lldbsuite.test import lldbplatformutil 869 870 if not lldbplatformutil.platformIsDarwin(): 871 if configuration.verbose: 872 print("objc tests will be skipped because of unsupported platform") 873 configuration.skip_categories.append("objc") 874 875 876def checkDebugInfoSupport(): 877 from lldbsuite.test import lldbplatformutil 878 879 platform = lldbplatformutil.getPlatform() 880 compiler = configuration.compiler 881 for cat in test_categories.debug_info_categories: 882 if cat in configuration.categories_list: 883 continue # Category explicitly requested, let it run. 884 if test_categories.is_supported_on_platform(cat, platform, compiler): 885 continue 886 configuration.skip_categories.append(cat) 887 888 889def checkDebugServerSupport(): 890 from lldbsuite.test import lldbplatformutil 891 import lldb 892 893 skip_msg = "Skipping %s tests, as they are not compatible with remote testing on this platform" 894 if lldbplatformutil.platformIsDarwin(): 895 configuration.skip_categories.append("llgs") 896 if lldb.remote_platform: 897 # <rdar://problem/34539270> 898 configuration.skip_categories.append("debugserver") 899 if configuration.verbose: 900 print(skip_msg % "debugserver") 901 else: 902 configuration.skip_categories.append("debugserver") 903 if lldb.remote_platform and lldbplatformutil.getPlatform() == "windows": 904 configuration.skip_categories.append("llgs") 905 if configuration.verbose: 906 print(skip_msg % "lldb-server") 907 908 909def checkForkVForkSupport(): 910 from lldbsuite.test import lldbplatformutil 911 912 platform = lldbplatformutil.getPlatform() 913 if platform not in ["freebsd", "linux", "netbsd"]: 914 configuration.skip_categories.append("fork") 915 916 917def checkPexpectSupport(): 918 from lldbsuite.test import lldbplatformutil 919 920 platform = lldbplatformutil.getPlatform() 921 922 # llvm.org/pr22274: need a pexpect replacement for windows 923 if platform in ["windows"]: 924 if configuration.verbose: 925 print("pexpect tests will be skipped because of unsupported platform") 926 configuration.skip_categories.append("pexpect") 927 928 929def run_suite(): 930 # On MacOS X, check to make sure that domain for com.apple.DebugSymbols defaults 931 # does not exist before proceeding to running the test suite. 932 if sys.platform.startswith("darwin"): 933 checkDsymForUUIDIsNotOn() 934 935 # Start the actions by first parsing the options while setting up the test 936 # directories, followed by setting up the search paths for lldb utilities; 937 # then, we walk the directory trees and collect the tests into our test suite. 938 # 939 parseOptionsAndInitTestdirs() 940 941 # Print a stack trace if the test hangs or is passed SIGTERM. 942 registerFaulthandler() 943 944 setupSysPath() 945 946 import lldb 947 948 lldb.SBDebugger.Initialize() 949 lldb.SBDebugger.PrintStackTraceOnError() 950 951 # Use host platform by default. 952 lldb.remote_platform = None 953 lldb.selected_platform = lldb.SBPlatform.GetHostPlatform() 954 955 # Now we can also import lldbutil 956 from lldbsuite.test import lldbutil 957 958 if configuration.lldb_platform_name: 959 print("Setting up remote platform '%s'" % (configuration.lldb_platform_name)) 960 lldb.remote_platform = lldb.SBPlatform(configuration.lldb_platform_name) 961 lldb.selected_platform = lldb.remote_platform 962 if not lldb.remote_platform.IsValid(): 963 print( 964 "error: unable to create the LLDB platform named '%s'." 965 % (configuration.lldb_platform_name) 966 ) 967 exitTestSuite(1) 968 if configuration.lldb_platform_url: 969 # We must connect to a remote platform if a LLDB platform URL was 970 # specified 971 print( 972 "Connecting to remote platform '%s' at '%s'..." 973 % (configuration.lldb_platform_name, configuration.lldb_platform_url) 974 ) 975 platform_connect_options = lldb.SBPlatformConnectOptions( 976 configuration.lldb_platform_url 977 ) 978 err = lldb.remote_platform.ConnectRemote(platform_connect_options) 979 if err.Success(): 980 print("Connected.") 981 else: 982 print( 983 "error: failed to connect to remote platform using URL '%s': %s" 984 % (configuration.lldb_platform_url, err) 985 ) 986 exitTestSuite(1) 987 else: 988 configuration.lldb_platform_url = None 989 990 if configuration.lldb_platform_working_dir: 991 print( 992 "Setting remote platform working directory to '%s'..." 993 % (configuration.lldb_platform_working_dir) 994 ) 995 error = lldb.remote_platform.MakeDirectory( 996 configuration.lldb_platform_working_dir, 448 997 ) # 448 = 0o700 998 if error.Fail(): 999 raise Exception( 1000 "making remote directory '%s': %s" 1001 % (configuration.lldb_platform_working_dir, error) 1002 ) 1003 1004 if not lldb.remote_platform.SetWorkingDirectory( 1005 configuration.lldb_platform_working_dir 1006 ): 1007 raise Exception( 1008 "failed to set working directory '%s'" 1009 % configuration.lldb_platform_working_dir 1010 ) 1011 lldb.selected_platform = lldb.remote_platform 1012 else: 1013 lldb.remote_platform = None 1014 configuration.lldb_platform_working_dir = None 1015 configuration.lldb_platform_url = None 1016 1017 # Set up the working directory. 1018 # Note that it's not dotest's job to clean this directory. 1019 lldbutil.mkdir_p(configuration.test_build_dir) 1020 1021 checkLibcxxSupport() 1022 checkLibstdcxxSupport() 1023 checkWatchpointSupport() 1024 checkDebugInfoSupport() 1025 checkDebugServerSupport() 1026 checkObjcSupport() 1027 checkForkVForkSupport() 1028 checkPexpectSupport() 1029 1030 skipped_categories_list = ", ".join(configuration.skip_categories) 1031 print( 1032 "Skipping the following test categories: {}".format( 1033 configuration.skip_categories 1034 ) 1035 ) 1036 1037 for testdir in configuration.testdirs: 1038 for dirpath, dirnames, filenames in os.walk(testdir): 1039 visit("Test", dirpath, filenames) 1040 1041 # 1042 # Now that we have loaded all the test cases, run the whole test suite. 1043 # 1044 1045 # Install the control-c handler. 1046 unittest.signals.installHandler() 1047 1048 # 1049 # Invoke the default TextTestRunner to run the test suite 1050 # 1051 checkCompiler() 1052 1053 if configuration.verbose: 1054 print("compiler=%s" % configuration.compiler) 1055 1056 # Iterating over all possible architecture and compiler combinations. 1057 configString = "arch=%s compiler=%s" % (configuration.arch, configuration.compiler) 1058 1059 # Output the configuration. 1060 if configuration.verbose: 1061 sys.stderr.write("\nConfiguration: " + configString + "\n") 1062 1063 # First, write out the number of collected test cases. 1064 if configuration.verbose: 1065 sys.stderr.write(configuration.separator + "\n") 1066 sys.stderr.write( 1067 "Collected %d test%s\n\n" 1068 % ( 1069 configuration.suite.countTestCases(), 1070 configuration.suite.countTestCases() != 1 and "s" or "", 1071 ) 1072 ) 1073 1074 if configuration.suite.countTestCases() == 0: 1075 logging.error("did not discover any matching tests") 1076 exitTestSuite(1) 1077 1078 # Invoke the test runner. 1079 if configuration.count == 1: 1080 result = unittest.TextTestRunner( 1081 stream=sys.stderr, 1082 verbosity=configuration.verbose, 1083 resultclass=test_result.LLDBTestResult, 1084 ).run(configuration.suite) 1085 else: 1086 # We are invoking the same test suite more than once. In this case, 1087 # mark __ignore_singleton__ flag as True so the signleton pattern is 1088 # not enforced. 1089 test_result.LLDBTestResult.__ignore_singleton__ = True 1090 for i in range(configuration.count): 1091 result = unittest.TextTestRunner( 1092 stream=sys.stderr, 1093 verbosity=configuration.verbose, 1094 resultclass=test_result.LLDBTestResult, 1095 ).run(configuration.suite) 1096 1097 configuration.failed = not result.wasSuccessful() 1098 1099 if configuration.sdir_has_content and configuration.verbose: 1100 sys.stderr.write( 1101 "Session logs for test failures/errors/unexpected successes" 1102 " can be found in the test build directory\n" 1103 ) 1104 1105 if configuration.use_categories and len(configuration.failures_per_category) > 0: 1106 sys.stderr.write("Failures per category:\n") 1107 for category in configuration.failures_per_category: 1108 sys.stderr.write( 1109 "%s - %d\n" % (category, configuration.failures_per_category[category]) 1110 ) 1111 1112 # Exiting. 1113 exitTestSuite(configuration.failed) 1114 1115 1116if __name__ == "__main__": 1117 print( 1118 __file__ 1119 + " is for use as a module only. It should not be run as a standalone script." 1120 ) 1121 sys.exit(-1) 1122