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