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