def test_minidump_sysroot(self): """Test that lldb can find a module referenced in an i386 linux minidump using the sysroot.""" # Copy linux-x86_64 executable to tmp_sysroot/temp/test/ (since it was compiled as # /tmp/test/linux-x86_64) tmp_sysroot = os.path.join( self.getBuildDir(), "lldb_i386_mock_sysroot") executable = os.path.join( tmp_sysroot, "tmp", "test", "linux-x86_64") exe_dir = os.path.dirname(executable) lldbutil.mkdir_p(exe_dir) shutil.copyfile("linux-x86_64", executable) # Set sysroot and load core self.runCmd("platform select remote-linux --sysroot '%s'" % tmp_sysroot) self.process_from_yaml("linux-x86_64.yaml") self.check_state() # Check that we loaded the module from the sysroot self.assertEqual(self.target.GetNumModules(), 1) module = self.target.GetModuleAtIndex(0) spec_dir_norm = os.path.normcase(module.GetFileSpec().GetDirectory()) exe_dir_norm = os.path.normcase(exe_dir) self.assertEqual(spec_dir_norm, exe_dir_norm)
def build(self): include = self.getBuildArtifact('include') lldbutil.mkdir_p(include) for f in ['Foo.h', 'Bar.h', 'module.modulemap']: shutil.copyfile(self.getSourcePath(os.path.join('Inputs', f)), os.path.join(include, f)) super(CXXModulesImportTestCase, self).build()
def test_set_breakpoint_with_absolute_path(self): self.build() hidden = self.getBuildArtifact("hidden") lldbutil.mkdir_p(hidden) # 'make -C' has resolved current directory to its realpath form. builddir_real = os.path.realpath(self.getBuildDir()) hidden_real = os.path.realpath(hidden) self.runCmd("settings set target.source-map %s %s" % (builddir_real, hidden_real)) exe = self.getBuildArtifact("a.out") main = os.path.join(builddir_real, "hidden", "main-copy.c") self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) lldbutil.run_break_set_by_file_and_line(self, main, self.line, num_expected_locations=1, loc_exact=False) self.runCmd("run", RUN_SUCCEEDED) # The stop reason of the thread should be breakpoint. self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, substrs=[ 'stopped', 'main-copy.c:%d' % self.line, 'stop reason = breakpoint' ])
def test_move_and_then_display_source(self): """Test that target.source-map settings work by moving main.c to hidden/main.c.""" self.build() exe = self.getBuildArtifact("a.out") self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) # Move main.c to hidden/main.c. hidden = self.getBuildArtifact("hidden") lldbutil.mkdir_p(hidden) main_c_hidden = os.path.join(hidden, "main-copy.c") os.rename(self.file, main_c_hidden) # Set source remapping with invalid replace path and verify we get an # error self.expect( "settings set target.source-map /a/b/c/d/e /q/r/s/t/u", error=True, substrs=[ '''error: the replacement path doesn't exist: "/q/r/s/t/u"''' ]) # 'make -C' has resolved current directory to its realpath form. builddir_real = os.path.realpath(self.getBuildDir()) hidden_real = os.path.realpath(hidden) # Set target.source-map settings. self.runCmd("settings set target.source-map %s %s" % (builddir_real, hidden_real)) # And verify that the settings work. self.expect("settings show target.source-map", substrs=[builddir_real, hidden_real]) # Display main() and verify that the source mapping has been kicked in. self.expect("source list -n main", SOURCE_DISPLAYED_CORRECTLY, substrs=['Hello world'])
def test_breakpad_hash_match_sysroot_decoy(self): """ Check that we can match the breakpad .text section hash when there is a module with the right name but wrong contents under a user-provided sysroot, and the right module is at the given search path.. """ sysroot_path = os.path.join(self.getBuildDir(), "mock_sysroot") # Create the directory under the sysroot where the minidump reports # the module. decoy_dir = os.path.join(sysroot_path, "invalid", "path", "on", "current", "system") decoy_path = os.path.join(decoy_dir, "libbreakpad.so") lldbutil.mkdir_p(decoy_dir) self.yaml2obj("libbreakpad-decoy.yaml", decoy_path) self.runCmd("platform select remote-linux --sysroot '%s'" % sysroot_path) so_dir = os.path.join(self.getBuildDir(), "searchpath_dir") so_path = os.path.join(so_dir, "libbreakpad.so") lldbutil.mkdir_p(so_dir) self.yaml2obj("libbreakpad.yaml", so_path) self.runCmd('settings set target.exec-search-paths "%s"' % so_dir) modules = self.get_minidump_modules( "linux-arm-breakpad-uuid-match.yaml") self.assertEqual(1, len(modules)) # LLDB makes up its own UUID as well when there is no build ID so we # will check that this matches. self.verify_module(modules[0], so_path, "D9C480E8")
def test_set_working_dir_existing(self): """Test that '-w dir' sets the working dir when running the inferior.""" d = {'CXX_SOURCES': 'print_cwd.cpp'} self.build(dictionary=d) self.setTearDownCleanup(d) exe = self.getBuildArtifact("a.out") self.runCmd("file " + exe) mywd = 'my_working_dir' out_file_name = "my_working_dir_test.out" err_file_name = "my_working_dir_test.err" my_working_dir_path = self.getBuildArtifact(mywd) lldbutil.mkdir_p(my_working_dir_path) out_file_path = os.path.join(my_working_dir_path, out_file_name) err_file_path = os.path.join(my_working_dir_path, err_file_name) # Make sure the output files do not exist before launching the process try: os.remove(out_file_path) os.remove(err_file_path) except OSError: pass launch_command = "process launch -w %s -o %s -e %s" % ( my_working_dir_path, out_file_path, err_file_path) self.expect(launch_command, patterns=["Process .* launched: .*a.out"]) success = True err_msg = "" # Check to see if the 'stdout' file was created try: out_f = open(out_file_path) except IOError: success = False err_msg = err_msg + "ERROR: stdout file was not created.\n" else: # Check to see if the 'stdout' file contains the right output line = out_f.readline() if self.TraceOn(): print("line:", line) if not re.search(mywd, line): success = False err_msg = err_msg + "The current working directory was not set correctly.\n" out_f.close() # Try to delete the 'stdout' and 'stderr' files try: os.remove(out_file_path) os.remove(err_file_path) pass except OSError: pass if not success: self.fail(err_msg)
def setup_test(self): lldbutil.mkdir_p(self.getBuildArtifact("hidden")) if lldb.remote_platform: path = lldb.remote_platform.GetWorkingDirectory() else: path = self.getBuildDir() if self.dylibPath in os.environ: sep = self.platformContext.shlib_path_separator path = os.environ[self.dylibPath] + sep + path self.runCmd("settings append target.env-vars '{}={}'".format(self.dylibPath, path)) self.default_path = path
def build(self): include = self.getBuildArtifact('include') inputs = self.getSourcePath('Inputs') lldbutil.mkdir_p(include) import shutil for f in ['module.modulemap', 'objc-header.h']: shutil.copyfile(os.path.join(inputs, f), os.path.join(include, f)) super(TestSwiftDWARFImporterObjC, self).build() # Remove the header files to thwart ClangImporter. self.assertTrue(os.path.isdir(include)) shutil.rmtree(include)
def build(self): include = self.getBuildArtifact('include') inputs = self.getSourcePath('Inputs') lldbutil.mkdir_p(include) import shutil for f in ['c-header.h']: shutil.copyfile(os.path.join(inputs, f), os.path.join(include, f)) super(TestSwiftDWARFImporterBridgingHeader, self).build() # Remove the header files to prevent ClangImporter loading the # bridging header from source. self.assertTrue(os.path.isdir(include)) shutil.rmtree(include)
def setup_test(self): lldbutil.mkdir_p(self.getBuildArtifact("hidden")) if not self.platformIsDarwin(): if not lldb.remote_platform and "LD_LIBRARY_PATH" in os.environ: self.runCmd("settings set target.env-vars " + self.dylibPath + "=" + os.environ["LD_LIBRARY_PATH"] + ":" + self.getBuildDir()) else: if lldb.remote_platform: wd = lldb.remote_platform.GetWorkingDirectory() else: wd = self.getBuildDir() self.runCmd("settings set target.env-vars " + self.dylibPath + "=" + wd)
def test_lldb_invocation_with_single_quote_in_filename(self): """Test that 'lldb my_file_name' works where my_file_name is a string with a single quote char in it.""" import pexpect self.buildDefault() lldbutil.mkdir_p(self.getBuildArtifact("path with '09")) system([[ "cp", self.getBuildArtifact("a.out"), "\"%s\"" % self.getBuildArtifact(self.myexe) ]]) # The default lldb prompt. prompt = "(lldb) " # So that the child gets torn down after the test. self.child = pexpect.spawn('%s %s "%s"' % (lldbtest_config.lldbExec, self.lldbOption, self.getBuildArtifact(self.myexe))) child = self.child child.setecho(True) # Turn on logging for input/output to/from the child. with open('child_send.txt', 'w') as f_send: with open('child_read.txt', 'w') as f_read: child.logfile_send = f_send child.logfile_read = f_read child.expect_exact(prompt) child.send("help watchpoint") child.sendline('') child.expect_exact(prompt) # Now that the necessary logging is done, restore logfile to None to # stop further logging. child.logfile_send = None child.logfile_read = None with open('child_send.txt', 'r') as fs: if self.TraceOn(): print("\n\nContents of child_send.txt:") print(fs.read()) with open('child_read.txt', 'r') as fr: from_child = fr.read() if self.TraceOn(): print("\n\nContents of child_read.txt:") print(from_child) self.expect(from_child, exe=False, substrs=["Current executable set to"])
def setUp(self): # Call super's setUp(). TestBase.setUp(self) # Make the hidden directory in the build hierarchy: lldbutil.mkdir_p(self.getBuildArtifact("hidden")) # Invoke the default build rule. self.build() ext = 'so' if self.platformIsDarwin(): ext = 'dylib' self.lib_name = 'libloadunload.' + ext self.wd = self.getBuildDir() self.hidden_dir = os.path.join(self.wd, 'hidden') self.hidden_lib = os.path.join(self.hidden_dir, self.lib_name)
def setUp(self): # Call super's setUp(). TestBase.setUp(self) # Make the hidden directory in the build hierarchy: lldbutil.mkdir_p(self.getBuildArtifact("hidden")) # Invoke the default build rule. self.build() ext = 'so' if self.platformIsDarwin(): ext = 'dylib' self.lib_name = 'libloadunload.' + ext self.wd = os.path.realpath(self.getBuildDir()) self.hidden_dir = os.path.join(self.wd, 'hidden') self.hidden_lib = os.path.join(self.hidden_dir, self.lib_name)
def test_breakpad_hash_match_sysroot(self): """ Check that we can match the breakpad .text section hash when the module is located under a user-provided sysroot. """ sysroot_path = os.path.join(self.getBuildDir(), "mock_sysroot") # Create the directory under the sysroot where the minidump reports # the module. so_dir = os.path.join(sysroot_path, "invalid", "path", "on", "current", "system") so_path = os.path.join(so_dir, "libbreakpad.so") lldbutil.mkdir_p(so_dir) self.yaml2obj("libbreakpad.yaml", so_path) self.runCmd("platform select remote-linux --sysroot '%s'" % sysroot_path) modules = self.get_minidump_modules("linux-arm-breakpad-uuid-match.yaml") self.assertEqual(1, len(modules)) # LLDB makes up its own UUID as well when there is no build ID so we # will check that this matches. self.verify_module(modules[0], so_path, "D9C480E8")
def test_breakpad_hash_match_exe_outside_sysroot(self): """ Check that we can match the breakpad .text section hash when the module is specified as the exe during launch, and a syroot is provided, which does not contain the exe. """ sysroot_path = os.path.join(self.getBuildDir(), "mock_sysroot") lldbutil.mkdir_p(sysroot_path) so_dir = os.path.join(self.getBuildDir(), "binary") so_path = os.path.join(so_dir, "libbreakpad.so") lldbutil.mkdir_p(so_dir) self.yaml2obj("libbreakpad.yaml", so_path) self.runCmd("platform select remote-linux --sysroot '%s'" % sysroot_path) modules = self.get_minidump_modules("linux-arm-breakpad-uuid-match.yaml", so_path) self.assertEqual(1, len(modules)) # LLDB makes up its own UUID as well when there is no build ID so we # will check that this matches. self.verify_module(modules[0], so_path, "D9C480E8")
def test_lldb_invocation_with_single_quote_in_filename(self): """Test that 'lldb my_file_name' works where my_file_name is a string with a single quote char in it.""" import pexpect self.buildDefault() lldbutil.mkdir_p(self.getBuildArtifact("path with '09")) system([[ "cp", self.getBuildArtifact("a.out"), "\"%s\"" % self.getBuildArtifact(self.myexe) ]]) # The default lldb prompt. prompt = "(lldb) " # So that the child gets torn down after the test. self.child = pexpect.spawn('%s %s "%s"' % (lldbtest_config.lldbExec, self.lldbOption, self.getBuildArtifact(self.myexe))) child = self.child child.setecho(True) child.logfile_send = send = six.StringIO() child.logfile_read = read = six.StringIO() child.expect_exact(prompt) child.send("help watchpoint") child.sendline('') child.expect_exact(prompt) # Now that the necessary logging is done, restore logfile to None to # stop further logging. child.logfile_send = None child.logfile_read = None if self.TraceOn(): print("\n\nContents of send") print(send.getvalue()) print("\n\nContents of read") print(read.getvalue()) self.expect(read.getvalue(), exe=False, substrs=["Current executable set to"])
def test_i386_sysroot(self): """Test that lldb can find the exe for an i386 linux core file using the sysroot.""" # Copy linux-i386.out to tmp_sysroot/home/labath/test/a.out (since it was compiled as # /home/labath/test/a.out) tmp_sysroot = os.path.join(self.getBuildDir(), "lldb_i386_mock_sysroot") executable = os.path.join(tmp_sysroot, "home", "labath", "test", "a.out") lldbutil.mkdir_p(os.path.dirname(executable)) shutil.copyfile("linux-i386.out", executable) # Set sysroot and load core self.runCmd("platform select remote-linux --sysroot '%s'" % tmp_sysroot) target = self.dbg.CreateTarget(None) self.assertTrue(target, VALID_TARGET) process = target.LoadCore("linux-i386.core") # Check that we found a.out from the sysroot self.check_all(process, self._i386_pid, self._i386_regions, "a.out") self.dbg.DeleteTarget(target)
def test_x86_64_sysroot(self): """Test that sysroot has more priority then local filesystem.""" # Copy wrong executable to the location outside of sysroot exe_outside = os.path.join(self.getBuildDir(), "bin", "a.out") lldbutil.mkdir_p(os.path.dirname(exe_outside)) shutil.copyfile("altmain.out", exe_outside) # Copy correct executable to the location inside sysroot tmp_sysroot = os.path.join(self.getBuildDir(), "mock_sysroot") exe_inside = os.path.join(tmp_sysroot, os.path.relpath(exe_outside, "/")) lldbutil.mkdir_p(os.path.dirname(exe_inside)) shutil.copyfile("linux-x86_64.out", exe_inside) # Prepare patched core file core_file = os.path.join(self.getBuildDir(), "patched.core") with open("linux-x86_64.core", "rb") as f: core = f.read() core = replace_path(core, "/test" * 817 + "/a.out", exe_outside) with open(core_file, "wb") as f: f.write(core) # Set sysroot and load core self.runCmd("platform select remote-linux --sysroot '%s'" % tmp_sysroot) target = self.dbg.CreateTarget(None) self.assertTrue(target, VALID_TARGET) process = target.LoadCore(core_file) # Check that we found executable from the sysroot mod_path = str(target.GetModuleAtIndex(0).GetFileSpec()) self.assertEqual(mod_path, exe_inside) self.check_all(process, self._x86_64_pid, self._x86_64_regions, "a.out") self.dbg.DeleteTarget(target)
def build(self): botdir = self.getBuildArtifact('buildbot') userdir = self.getBuildArtifact('user') inputs = self.getSourcePath('Inputs') lldbutil.mkdir_p(botdir) lldbutil.mkdir_p(userdir) import shutil for f in ['main.c', 'relative.c']: shutil.copyfile(os.path.join(inputs, f), os.path.join(botdir, f)) shutil.copyfile(os.path.join(inputs, f), os.path.join(userdir, f)) super(TestDSYMSourcePathRemapping, self).build() # Remove the build sources. self.assertTrue(os.path.isdir(botdir)) shutil.rmtree(botdir) # Create a plist. import subprocess dsym = self.getBuildArtifact('a.out.dSYM') uuid = subprocess.check_output(["/usr/bin/dwarfdump", "--uuid", dsym] ).decode("utf-8").split(" ")[1] import re self.assertTrue(re.match(r'[0-9a-fA-F-]+', uuid)) plist = os.path.join(dsym, 'Contents', 'Resources', uuid + '.plist') with open(plist, 'w') as f: f.write('<?xml version="1.0" encoding="UTF-8"?>\n') f.write('<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n') f.write('<plist version="1.0">\n') f.write('<dict>\n') f.write(' <key>DBGSourcePathRemapping</key>\n') f.write(' <dict>\n') f.write(' <key>' + os.path.realpath(botdir) + '</key>\n') f.write(' <string>' + userdir + '</string>\n') f.write(' </dict>\n') f.write('</dict>\n') f.write('</plist>\n')
def run_suite(): # On MacOS X, check to make sure that domain for com.apple.DebugSymbols defaults # does not exist before proceeding to running the test suite. if sys.platform.startswith("darwin"): checkDsymForUUIDIsNotOn() # Start the actions by first parsing the options while setting up the test # directories, followed by setting up the search paths for lldb utilities; # then, we walk the directory trees and collect the tests into our test suite. # parseOptionsAndInitTestdirs() # Print a stack trace if the test hangs or is passed SIGTERM. registerFaulthandler() setupSysPath() import lldb lldb.SBDebugger.Initialize() # Use host platform by default. lldb.selected_platform = lldb.SBPlatform.GetHostPlatform() # Now we can also import lldbutil from lldbsuite.test import lldbutil if configuration.lldb_platform_name: print("Setting up remote platform '%s'" % (configuration.lldb_platform_name)) lldb.remote_platform = lldb.SBPlatform( configuration.lldb_platform_name) if not lldb.remote_platform.IsValid(): print("error: unable to create the LLDB platform named '%s'." % (configuration.lldb_platform_name)) exitTestSuite(1) if configuration.lldb_platform_url: # We must connect to a remote platform if a LLDB platform URL was # specified print("Connecting to remote platform '%s' at '%s'..." % (configuration.lldb_platform_name, configuration.lldb_platform_url)) platform_connect_options = lldb.SBPlatformConnectOptions( configuration.lldb_platform_url) err = lldb.remote_platform.ConnectRemote(platform_connect_options) if err.Success(): print("Connected.") lldb.selected_platform = lldb.remote_platform else: print( "error: failed to connect to remote platform using URL '%s': %s" % (configuration.lldb_platform_url, err)) exitTestSuite(1) else: configuration.lldb_platform_url = None if configuration.lldb_platform_working_dir: print("Setting remote platform working directory to '%s'..." % (configuration.lldb_platform_working_dir)) error = lldb.remote_platform.MakeDirectory( configuration.lldb_platform_working_dir, 448) # 448 = 0o700 if error.Fail(): raise Exception("making remote directory '%s': %s" % (configuration.lldb_platform_working_dir, error)) if not lldb.remote_platform.SetWorkingDirectory( configuration.lldb_platform_working_dir): raise Exception("failed to set working directory '%s'" % configuration.lldb_platform_working_dir) lldb.selected_platform = lldb.remote_platform else: lldb.remote_platform = None configuration.lldb_platform_working_dir = None configuration.lldb_platform_url = None # Set up the working directory. # Note that it's not dotest's job to clean this directory. lldbutil.mkdir_p(configuration.test_build_dir) checkLibcxxSupport() checkLibstdcxxSupport() checkWatchpointSupport() checkDebugInfoSupport() checkDebugServerSupport() checkObjcSupport() checkForkVForkSupport() print("Skipping the following test categories: {}".format( configuration.skip_categories)) for testdir in configuration.testdirs: for (dirpath, dirnames, filenames) in os.walk(testdir): visit('Test', dirpath, filenames) # # Now that we have loaded all the test cases, run the whole test suite. # # Install the control-c handler. unittest2.signals.installHandler() # # Invoke the default TextTestRunner to run the test suite # checkCompiler() if configuration.verbose: print("compiler=%s" % configuration.compiler) # Iterating over all possible architecture and compiler combinations. configString = "arch=%s compiler=%s" % (configuration.arch, configuration.compiler) # Output the configuration. if configuration.verbose: sys.stderr.write("\nConfiguration: " + configString + "\n") # First, write out the number of collected test cases. if configuration.verbose: sys.stderr.write(configuration.separator + "\n") sys.stderr.write( "Collected %d test%s\n\n" % (configuration.suite.countTestCases(), configuration.suite.countTestCases() != 1 and "s" or "")) if configuration.suite.countTestCases() == 0: logging.error("did not discover any matching tests") exitTestSuite(1) # Invoke the test runner. if configuration.count == 1: result = unittest2.TextTestRunner( stream=sys.stderr, verbosity=configuration.verbose, resultclass=test_result.LLDBTestResult).run(configuration.suite) else: # We are invoking the same test suite more than once. In this case, # mark __ignore_singleton__ flag as True so the signleton pattern is # not enforced. test_result.LLDBTestResult.__ignore_singleton__ = True for i in range(configuration.count): result = unittest2.TextTestRunner( stream=sys.stderr, verbosity=configuration.verbose, resultclass=test_result.LLDBTestResult).run( configuration.suite) configuration.failed = not result.wasSuccessful() if configuration.sdir_has_content and configuration.verbose: sys.stderr.write( "Session logs for test failures/errors/unexpected successes" " can be found in the test build directory\n") if configuration.use_categories and len( configuration.failures_per_category) > 0: sys.stderr.write("Failures per category:\n") for category in configuration.failures_per_category: sys.stderr.write( "%s - %d\n" % (category, configuration.failures_per_category[category])) # Exiting. exitTestSuite(configuration.failed)
def run_suite(): # On MacOS X, check to make sure that domain for com.apple.DebugSymbols defaults # does not exist before proceeding to running the test suite. if sys.platform.startswith("darwin"): checkDsymForUUIDIsNotOn() # Start the actions by first parsing the options while setting up the test # directories, followed by setting up the search paths for lldb utilities; # then, we walk the directory trees and collect the tests into our test suite. # parseOptionsAndInitTestdirs() # Setup test results (test results formatter and output handling). setupTestResults() setupSysPath() # For the time being, let's bracket the test runner within the # lldb.SBDebugger.Initialize()/Terminate() pair. import lldb # Now we can also import lldbutil from lldbsuite.test import lldbutil # Create a singleton SBDebugger in the lldb namespace. lldb.DBG = lldb.SBDebugger.Create() if configuration.lldb_platform_name: print("Setting up remote platform '%s'" % (configuration.lldb_platform_name)) lldb.remote_platform = lldb.SBPlatform( configuration.lldb_platform_name) if not lldb.remote_platform.IsValid(): print( "error: unable to create the LLDB platform named '%s'." % (configuration.lldb_platform_name)) exitTestSuite(1) if configuration.lldb_platform_url: # We must connect to a remote platform if a LLDB platform URL was # specified print( "Connecting to remote platform '%s' at '%s'..." % (configuration.lldb_platform_name, configuration.lldb_platform_url)) platform_connect_options = lldb.SBPlatformConnectOptions( configuration.lldb_platform_url) err = lldb.remote_platform.ConnectRemote(platform_connect_options) if err.Success(): print("Connected.") else: print("error: failed to connect to remote platform using URL '%s': %s" % ( configuration.lldb_platform_url, err)) exitTestSuite(1) else: configuration.lldb_platform_url = None platform_changes = setDefaultTripleForPlatform() first = True for key in platform_changes: if first: print("Environment variables setup for platform support:") first = False print("%s = %s" % (key, platform_changes[key])) if configuration.lldb_platform_working_dir: print("Setting remote platform working directory to '%s'..." % (configuration.lldb_platform_working_dir)) error = lldb.remote_platform.MakeDirectory( configuration.lldb_platform_working_dir, 448) # 448 = 0o700 if error.Fail(): raise Exception("making remote directory '%s': %s" % ( configuration.lldb_platform_working_dir, error)) if not lldb.remote_platform.SetWorkingDirectory( configuration.lldb_platform_working_dir): raise Exception("failed to set working directory '%s'" % configuration.lldb_platform_working_dir) lldb.DBG.SetSelectedPlatform(lldb.remote_platform) else: lldb.remote_platform = None configuration.lldb_platform_working_dir = None configuration.lldb_platform_url = None # Set up the working directory. # Note that it's not dotest's job to clean this directory. build_dir = configuration.test_build_dir lldbutil.mkdir_p(build_dir) target_platform = lldb.DBG.GetSelectedPlatform().GetTriple().split('-')[2] checkLibcxxSupport() checkLibstdcxxSupport() checkWatchpointSupport() checkDebugInfoSupport() # Don't do debugserver tests on anything except OS X. configuration.dont_do_debugserver_test = ( "linux" in target_platform or "freebsd" in target_platform or "netbsd" in target_platform or "windows" in target_platform) # Don't do lldb-server (llgs) tests on anything except Linux and Windows. configuration.dont_do_llgs_test = not ( "linux" in target_platform or "netbsd" in target_platform or "windows" in target_platform) # Collect tests from the specified testing directories. If a test # subdirectory filter is explicitly specified, limit the search to that # subdirectory. exclusive_test_subdir = configuration.get_absolute_path_to_exclusive_test_subdir() if exclusive_test_subdir: dirs_to_search = [exclusive_test_subdir] else: dirs_to_search = configuration.testdirs for testdir in dirs_to_search: for (dirpath, dirnames, filenames) in os.walk(testdir): visit('Test', dirpath, filenames) # # Now that we have loaded all the test cases, run the whole test suite. # # Disable default dynamic types for testing purposes disabledynamics() # Install the control-c handler. unittest2.signals.installHandler() lldbutil.mkdir_p(configuration.sdir_name) os.environ["LLDB_SESSION_DIRNAME"] = configuration.sdir_name sys.stderr.write( "\nSession logs for test failures/errors/unexpected successes" " will go into directory '%s'\n" % configuration.sdir_name) sys.stderr.write("Command invoked: %s\n" % get_dotest_invocation()) # # Invoke the default TextTestRunner to run the test suite # checkCompiler() if configuration.verbose: print("compiler=%s" % configuration.compiler) # Iterating over all possible architecture and compiler combinations. os.environ["ARCH"] = configuration.arch os.environ["CC"] = configuration.compiler configString = "arch=%s compiler=%s" % (configuration.arch, configuration.compiler) # Output the configuration. if configuration.verbose: sys.stderr.write("\nConfiguration: " + configString + "\n") # First, write out the number of collected test cases. if configuration.verbose: sys.stderr.write(configuration.separator + "\n") sys.stderr.write( "Collected %d test%s\n\n" % (configuration.suite.countTestCases(), configuration.suite.countTestCases() != 1 and "s" or "")) # Invoke the test runner. if configuration.count == 1: result = unittest2.TextTestRunner( stream=sys.stderr, verbosity=configuration.verbose, resultclass=test_result.LLDBTestResult).run( configuration.suite) else: # We are invoking the same test suite more than once. In this case, # mark __ignore_singleton__ flag as True so the signleton pattern is # not enforced. test_result.LLDBTestResult.__ignore_singleton__ = True for i in range(configuration.count): result = unittest2.TextTestRunner( stream=sys.stderr, verbosity=configuration.verbose, resultclass=test_result.LLDBTestResult).run( configuration.suite) configuration.failed = not result.wasSuccessful() if configuration.sdir_has_content and configuration.verbose: sys.stderr.write( "Session logs for test failures/errors/unexpected successes" " can be found in directory '%s'\n" % configuration.sdir_name) if configuration.useCategories and len( configuration.failuresPerCategory) > 0: sys.stderr.write("Failures per category:\n") for category in configuration.failuresPerCategory: sys.stderr.write( "%s - %d\n" % (category, configuration.failuresPerCategory[category])) # Exiting. exitTestSuite(configuration.failed)
def test_macos_sdk(self): self.build() exe = self.getBuildArtifact('a.out') token = self.getBuildArtifact('token') # Remove the old token. try: os.remove(token) except: pass # Create a fake 'SDK' directory. test_home = os.path.join(self.getBuildDir(), 'fake_home.noindex') macos_version = platform.mac_ver()[0] sdk_dir = os.path.join(test_home, 'Library', 'Developer', 'Xcode', 'macOS DeviceSupport', macos_version) symbols_dir = os.path.join(sdk_dir, 'Symbols') lldbutil.mkdir_p(symbols_dir) # Save the current home directory and restore it afterwards. old_home = os.getenv('HOME') def cleanup(): if not old_home: del os.environ['HOME'] else: os.environ['HOME'] = old_home self.addTearDownHook(cleanup) os.environ['HOME'] = test_home # Launch our test binary. inferior = self.spawnSubprocess(exe, [token]) pid = inferior.pid # Wait for the binary to launch. lldbutil.wait_for_file_on_target(self, token) # Move the binary into the 'SDK'. rel_exe_path = os.path.relpath(exe, '/') exe_sdk_path = os.path.join(symbols_dir, rel_exe_path) lldbutil.mkdir_p(os.path.dirname(exe_sdk_path)) shutil.move(exe, exe_sdk_path) # Attach to it with debugserver. debugserver = get_debugserver_exe() debugserver_args = [ 'localhost:{}'.format(self.PORT), '--attach={}'.format(pid) ] self.spawnSubprocess(debugserver, debugserver_args) # Select the platform. self.expect('platform select remote-macosx', substrs=[sdk_dir]) # Connect to debugserver interpreter = self.dbg.GetCommandInterpreter() connected = False for i in range(self.ATTEMPTS): result = lldb.SBCommandReturnObject() interpreter.HandleCommand('gdb-remote {}'.format(self.PORT), result) connected = result.Succeeded() if connected: break time.sleep(self.TIMEOUT) self.assertTrue(connected, "could not connect to debugserver") # Make sure the image was loaded from the 'SDK'. self.expect('image list', substrs=[exe_sdk_path])
def setUp(self): TestBase.setUp(self) lldbutil.mkdir_p(self.getBuildArtifact("One")) lldbutil.mkdir_p(self.getBuildArtifact("Two"))
def test_lc_note(self): self.build() self.aout_exe = self.getBuildArtifact("a.out") self.aout_dsym = self.getBuildArtifact("a.out.dSYM") self.to_be_removed_dylib = self.getBuildArtifact("libto-be-removed.dylib") self.to_be_removed_dsym = self.getBuildArtifact("libto-be-removed.dylib.dSYM") self.corefile = self.getBuildArtifact("process.core") self.dsym_for_uuid = self.getBuildArtifact("dsym-for-uuid.sh") # After the corefile is created, we'll move a.out and a.out.dSYM # into hide.noindex and lldb will have to use the # LLDB_APPLE_DSYMFORUUID_EXECUTABLE script to find them. self.hide_dir = self.getBuildArtifact("hide.noindex") lldbutil.mkdir_p(self.hide_dir) self.hide_aout_exe = self.getBuildArtifact("hide.noindex/a.out") self.hide_aout_dsym = self.getBuildArtifact("hide.noindex/a.out.dSYM") # We can hook in our dsym-for-uuid shell script to lldb with # this env var instead of requiring a defaults write. os.environ['LLDB_APPLE_DSYMFORUUID_EXECUTABLE'] = self.dsym_for_uuid self.addTearDownHook(lambda: os.environ.pop('LLDB_APPLE_DSYMFORUUID_EXECUTABLE', None)) dwarfdump_uuid_regex = re.compile( 'UUID: ([-0-9a-fA-F]+) \(([^\(]+)\) .*') dwarfdump_cmd_output = subprocess.check_output( ('/usr/bin/dwarfdump --uuid "%s"' % self.aout_exe), shell=True).decode("utf-8") aout_uuid = None for line in dwarfdump_cmd_output.splitlines(): match = dwarfdump_uuid_regex.search(line) if match: aout_uuid = match.group(1) self.assertNotEqual(aout_uuid, None, "Could not get uuid of built a.out") ### Create our dsym-for-uuid shell script which returns self.hide_aout_exe. shell_cmds = [ '#! /bin/sh', '# the last argument is the uuid', 'while [ $# -gt 1 ]', 'do', ' shift', 'done', 'ret=0', 'echo "<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>"', 'echo "<!DOCTYPE plist PUBLIC \\"-//Apple//DTD PLIST 1.0//EN\\" \\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\\">"', 'echo "<plist version=\\"1.0\\">"', '', 'if [ "$1" = "%s" ]' % aout_uuid, 'then', ' uuid=%s' % aout_uuid, ' bin=%s' % self.hide_aout_exe, ' dsym=%s.dSYM/Contents/Resources/DWARF/%s' % (self.hide_aout_exe, os.path.basename(self.hide_aout_exe)), 'fi', 'if [ -z "$uuid" -o -z "$bin" -o ! -f "$bin" ]', 'then', ' echo "<key>DBGError</key><string>not found</string>"', ' echo "</plist>"', ' exit 1', 'fi', 'echo "<dict><key>$uuid</key><dict>"', '', 'echo "<key>DBGArchitecture</key><string>x86_64</string>"', 'echo "<key>DBGDSYMPath</key><string>$dsym</string>"', 'echo "<key>DBGSymbolRichExecutable</key><string>$bin</string>"', 'echo "</dict></dict></plist>"', 'exit $ret' ] with open(self.dsym_for_uuid, "w") as writer: for l in shell_cmds: writer.write(l + '\n') os.chmod(self.dsym_for_uuid, 0o755) # Launch a live process with a.out, libto-be-removed.dylib, # libpresent.dylib all in their original locations, create # a corefile at the breakpoint. (target, process, t, bp) = lldbutil.run_to_source_breakpoint ( self, "break here", lldb.SBFileSpec('present.c')) self.assertTrue(process.IsValid()) if self.TraceOn(): self.runCmd("bt") self.runCmd("image list") self.runCmd("process save-core " + self.corefile) process.Kill() target.Clear() # Move the main binary and its dSYM into the hide.noindex # directory. Now the only way lldb can find them is with # the LLDB_APPLE_DSYMFORUUID_EXECUTABLE shell script - # so we're testing that this dSYM discovery method works. os.rename(self.aout_exe, self.hide_aout_exe) os.rename(self.aout_dsym, self.hide_aout_dsym) # Completely remove the libto-be-removed.dylib, so we're # testing that lldb handles an unavailable binary correctly, # and non-dirty memory from this binary (e.g. the executing # instructions) are NOT included in the corefile. os.unlink(self.to_be_removed_dylib) shutil.rmtree(self.to_be_removed_dsym) # Now load the corefile self.target = self.dbg.CreateTarget('') self.process = self.target.LoadCore(self.corefile) self.assertTrue(self.process.IsValid()) if self.TraceOn(): self.runCmd("image list") self.runCmd("bt") self.assertTrue(self.process.IsValid()) self.assertTrue(self.process.GetSelectedThread().IsValid()) # f0 is present() in libpresent.dylib f0 = self.process.GetSelectedThread().GetFrameAtIndex(0) to_be_removed_dirty_data = f0.FindVariable("to_be_removed_dirty_data") self.assertEqual(to_be_removed_dirty_data.GetValueAsUnsigned(), 20) present_heap_buf = f0.FindVariable("present_heap_buf") self.assertTrue("have ints 5 20 20 5" in present_heap_buf.GetSummary()) # f1 is to_be_removed() in libto-be-removed.dylib # it has been removed since the corefile was created, # and the instructions for this frame should NOT be included # in the corefile. They were not dirty pages. f1 = self.process.GetSelectedThread().GetFrameAtIndex(1) err = lldb.SBError() uint = self.process.ReadUnsignedFromMemory(f1.GetPC(), 4, err) self.assertTrue(err.Fail())
def run_suite(): # On MacOS X, check to make sure that domain for com.apple.DebugSymbols defaults # does not exist before proceeding to running the test suite. if sys.platform.startswith("darwin"): checkDsymForUUIDIsNotOn() # # Start the actions by first parsing the options while setting up the test # directories, followed by setting up the search paths for lldb utilities; # then, we walk the directory trees and collect the tests into our test suite. # parseOptionsAndInitTestdirs() # Setup test results (test results formatter and output handling). setupTestResults() # If we are running as the multiprocess test runner, kick off the # multiprocess test runner here. if isMultiprocessTestRunner(): from . import dosep dosep.main(configuration.num_threads, configuration.multiprocess_test_subdir, configuration.test_runner_name, configuration.results_formatter_object) raise Exception("should never get here") elif configuration.is_inferior_test_runner: # Shut off Ctrl-C processing in inferiors. The parallel # test runner handles this more holistically. signal.signal(signal.SIGINT, signal.SIG_IGN) setupSysPath() # # If '-l' is specified, do not skip the long running tests. if not configuration.skip_long_running_test: os.environ["LLDB_SKIP_LONG_RUNNING_TEST"] = "NO" # For the time being, let's bracket the test runner within the # lldb.SBDebugger.Initialize()/Terminate() pair. import lldb # Create a singleton SBDebugger in the lldb namespace. lldb.DBG = lldb.SBDebugger.Create() if configuration.lldb_platform_name: print("Setting up remote platform '%s'" % (configuration.lldb_platform_name)) lldb.remote_platform = lldb.SBPlatform( configuration.lldb_platform_name) if not lldb.remote_platform.IsValid(): print("error: unable to create the LLDB platform named '%s'." % (configuration.lldb_platform_name)) exitTestSuite(1) if configuration.lldb_platform_url: # We must connect to a remote platform if a LLDB platform URL was # specified print("Connecting to remote platform '%s' at '%s'..." % (configuration.lldb_platform_name, configuration.lldb_platform_url)) platform_connect_options = lldb.SBPlatformConnectOptions( configuration.lldb_platform_url) err = lldb.remote_platform.ConnectRemote(platform_connect_options) if err.Success(): print("Connected.") else: print( "error: failed to connect to remote platform using URL '%s': %s" % (configuration.lldb_platform_url, err)) exitTestSuite(1) else: configuration.lldb_platform_url = None platform_changes = setDefaultTripleForPlatform() first = True for key in platform_changes: if first: print("Environment variables setup for platform support:") first = False print("%s = %s" % (key, platform_changes[key])) if configuration.lldb_platform_working_dir: print("Setting remote platform working directory to '%s'..." % (configuration.lldb_platform_working_dir)) error = lldb.remote_platform.MakeDirectory( configuration.lldb_platform_working_dir, 448) # 448 = 0o700 if error.Fail(): raise Exception("making remote directory '%s': %s" % (remote_test_dir, error)) if not lldb.remote_platform.SetWorkingDirectory( configuration.lldb_platform_working_dir): raise Exception("failed to set working directory '%s'" % remote_test_dir) lldb.DBG.SetSelectedPlatform(lldb.remote_platform) else: lldb.remote_platform = None configuration.lldb_platform_working_dir = None configuration.lldb_platform_url = None # Set up the working directory. # Note that it's not dotest's job to clean this directory. import lldbsuite.test.lldbutil as lldbutil build_dir = configuration.test_build_dir lldbutil.mkdir_p(build_dir) target_platform = lldb.DBG.GetSelectedPlatform().GetTriple().split('-')[2] checkLibcxxSupport() # Don't do debugserver tests on everything except OS X. configuration.dont_do_debugserver_test = "linux" in target_platform or "freebsd" in target_platform or "windows" in target_platform # Don't do lldb-server (llgs) tests on anything except Linux. configuration.dont_do_llgs_test = not ("linux" in target_platform) # # Walk through the testdirs while collecting tests. # for testdir in configuration.testdirs: for (dirpath, dirnames, filenames) in os.walk(testdir): visit('Test', dirpath, filenames) # # Now that we have loaded all the test cases, run the whole test suite. # # Turn on lldb loggings if necessary. lldbLoggings() # Disable default dynamic types for testing purposes disabledynamics() # Install the control-c handler. unittest2.signals.installHandler() # If sdir_name is not specified through the '-s sdir_name' option, get a # timestamp string and export it as LLDB_SESSION_DIR environment var. This will # be used when/if we want to dump the session info of individual test cases # later on. # # See also TestBase.dumpSessionInfo() in lldbtest.py. import datetime # The windows platforms don't like ':' in the pathname. timestamp_started = datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S") if not configuration.sdir_name: configuration.sdir_name = timestamp_started os.environ["LLDB_SESSION_DIRNAME"] = os.path.join(os.getcwd(), configuration.sdir_name) sys.stderr.write( "\nSession logs for test failures/errors/unexpected successes" " will go into directory '%s'\n" % configuration.sdir_name) sys.stderr.write("Command invoked: %s\n" % getMyCommandLine()) if not os.path.isdir(configuration.sdir_name): try: os.mkdir(configuration.sdir_name) except OSError as exception: if exception.errno != errno.EEXIST: raise # # Invoke the default TextTestRunner to run the test suite # checkCompiler() if not configuration.parsable: print("compiler=%s" % configuration.compiler) # Iterating over all possible architecture and compiler combinations. os.environ["ARCH"] = configuration.arch os.environ["CC"] = configuration.compiler configString = "arch=%s compiler=%s" % (configuration.arch, configuration.compiler) # Translate ' ' to '-' for pathname component. if six.PY2: import string tbl = string.maketrans(' ', '-') else: tbl = str.maketrans(' ', '-') configPostfix = configString.translate(tbl) # Output the configuration. if not configuration.parsable: sys.stderr.write("\nConfiguration: " + configString + "\n") # First, write out the number of collected test cases. if not configuration.parsable: sys.stderr.write(configuration.separator + "\n") sys.stderr.write( "Collected %d test%s\n\n" % (configuration.suite.countTestCases(), configuration.suite.countTestCases() != 1 and "s" or "")) if configuration.parsable: v = 0 else: v = configuration.verbose # Invoke the test runner. if configuration.count == 1: result = unittest2.TextTestRunner( stream=sys.stderr, verbosity=v, resultclass=test_result.LLDBTestResult).run(configuration.suite) else: # We are invoking the same test suite more than once. In this case, # mark __ignore_singleton__ flag as True so the signleton pattern is # not enforced. test_result.LLDBTestResult.__ignore_singleton__ = True for i in range(configuration.count): result = unittest2.TextTestRunner( stream=sys.stderr, verbosity=v, resultclass=test_result.LLDBTestResult).run( configuration.suite) configuration.failed = not result.wasSuccessful() if configuration.sdir_has_content and not configuration.parsable: sys.stderr.write( "Session logs for test failures/errors/unexpected successes" " can be found in directory '%s'\n" % configuration.sdir_name) if configuration.useCategories and len( configuration.failuresPerCategory) > 0: sys.stderr.write("Failures per category:\n") for category in configuration.failuresPerCategory: sys.stderr.write( "%s - %d\n" % (category, configuration.failuresPerCategory[category])) # Terminate the test suite if ${LLDB_TESTSUITE_FORCE_FINISH} is defined. # This should not be necessary now. if ("LLDB_TESTSUITE_FORCE_FINISH" in os.environ): print("Terminating Test suite...") subprocess.Popen(["/bin/sh", "-c", "kill %s; exit 0" % (os.getpid())]) # Exiting. exitTestSuite(configuration.failed)
def run_suite(): # On MacOS X, check to make sure that domain for com.apple.DebugSymbols defaults # does not exist before proceeding to running the test suite. if sys.platform.startswith("darwin"): checkDsymForUUIDIsNotOn() # Start the actions by first parsing the options while setting up the test # directories, followed by setting up the search paths for lldb utilities; # then, we walk the directory trees and collect the tests into our test suite. # parseOptionsAndInitTestdirs() setupSysPath() import lldbconfig if configuration.capture_path or configuration.replay_path: lldbconfig.INITIALIZE = False import lldb if configuration.capture_path: lldb.SBReproducer.Capture(configuration.capture_path) lldb.SBReproducer.SetAutoGenerate(True) elif configuration.replay_path: lldb.SBReproducer.PassiveReplay(configuration.replay_path) if not lldbconfig.INITIALIZE: lldb.SBDebugger.Initialize() # Use host platform by default. lldb.selected_platform = lldb.SBPlatform.GetHostPlatform() # Now we can also import lldbutil from lldbsuite.test import lldbutil if configuration.lldb_platform_name: print("Setting up remote platform '%s'" % (configuration.lldb_platform_name)) lldb.remote_platform = lldb.SBPlatform( configuration.lldb_platform_name) if not lldb.remote_platform.IsValid(): print( "error: unable to create the LLDB platform named '%s'." % (configuration.lldb_platform_name)) exitTestSuite(1) if configuration.lldb_platform_url: # We must connect to a remote platform if a LLDB platform URL was # specified print( "Connecting to remote platform '%s' at '%s'..." % (configuration.lldb_platform_name, configuration.lldb_platform_url)) platform_connect_options = lldb.SBPlatformConnectOptions( configuration.lldb_platform_url) err = lldb.remote_platform.ConnectRemote(platform_connect_options) if err.Success(): print("Connected.") else: print("error: failed to connect to remote platform using URL '%s': %s" % ( configuration.lldb_platform_url, err)) exitTestSuite(1) else: configuration.lldb_platform_url = None if configuration.lldb_platform_working_dir: print("Setting remote platform working directory to '%s'..." % (configuration.lldb_platform_working_dir)) error = lldb.remote_platform.MakeDirectory( configuration.lldb_platform_working_dir, 448) # 448 = 0o700 if error.Fail(): raise Exception("making remote directory '%s': %s" % ( configuration.lldb_platform_working_dir, error)) if not lldb.remote_platform.SetWorkingDirectory( configuration.lldb_platform_working_dir): raise Exception("failed to set working directory '%s'" % configuration.lldb_platform_working_dir) lldb.selected_platform = lldb.remote_platform else: lldb.remote_platform = None configuration.lldb_platform_working_dir = None configuration.lldb_platform_url = None # Set up the working directory. # Note that it's not dotest's job to clean this directory. lldbutil.mkdir_p(configuration.test_build_dir) target_platform = lldb.selected_platform.GetTriple().split('-')[2] checkLibcxxSupport() checkLibstdcxxSupport() checkWatchpointSupport() checkDebugInfoSupport() # Don't do debugserver tests on anything except OS X. configuration.dont_do_debugserver_test = ( "linux" in target_platform or "freebsd" in target_platform or "netbsd" in target_platform or "windows" in target_platform) # Don't do lldb-server (llgs) tests on anything except Linux and Windows. configuration.dont_do_llgs_test = not ( "linux" in target_platform or "netbsd" in target_platform or "windows" in target_platform) for testdir in configuration.testdirs: for (dirpath, dirnames, filenames) in os.walk(testdir): visit('Test', dirpath, filenames) # # Now that we have loaded all the test cases, run the whole test suite. # # Install the control-c handler. unittest2.signals.installHandler() lldbutil.mkdir_p(configuration.sdir_name) os.environ["LLDB_SESSION_DIRNAME"] = configuration.sdir_name sys.stderr.write( "\nSession logs for test failures/errors/unexpected successes" " will go into directory '%s'\n" % configuration.sdir_name) # # Invoke the default TextTestRunner to run the test suite # checkCompiler() if configuration.verbose: print("compiler=%s" % configuration.compiler) # Iterating over all possible architecture and compiler combinations. os.environ["ARCH"] = configuration.arch os.environ["CC"] = configuration.compiler if configuration.swiftCompiler: os.environ["SWIFTC"] = configuration.swiftCompiler configString = "arch=%s compiler=%s" % (configuration.arch, configuration.compiler) # Output the configuration. if configuration.verbose: sys.stderr.write("\nConfiguration: " + configString + "\n") # First, write out the number of collected test cases. if configuration.verbose: sys.stderr.write(configuration.separator + "\n") sys.stderr.write( "Collected %d test%s\n\n" % (configuration.suite.countTestCases(), configuration.suite.countTestCases() != 1 and "s" or "")) # Invoke the test runner. if configuration.count == 1: result = unittest2.TextTestRunner( stream=sys.stderr, verbosity=configuration.verbose, resultclass=test_result.LLDBTestResult).run( configuration.suite) else: # We are invoking the same test suite more than once. In this case, # mark __ignore_singleton__ flag as True so the signleton pattern is # not enforced. test_result.LLDBTestResult.__ignore_singleton__ = True for i in range(configuration.count): result = unittest2.TextTestRunner( stream=sys.stderr, verbosity=configuration.verbose, resultclass=test_result.LLDBTestResult).run( configuration.suite) configuration.failed = not result.wasSuccessful() if configuration.sdir_has_content and configuration.verbose: sys.stderr.write( "Session logs for test failures/errors/unexpected successes" " can be found in directory '%s'\n" % configuration.sdir_name) if configuration.use_categories and len( configuration.failures_per_category) > 0: sys.stderr.write("Failures per category:\n") for category in configuration.failures_per_category: sys.stderr.write( "%s - %d\n" % (category, configuration.failures_per_category[category])) # Exiting. exitTestSuite(configuration.failed)