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