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