diff options
Diffstat (limited to 'lldb/packages/Python/lldbsuite/test')
29 files changed, 4391 insertions, 3320 deletions
diff --git a/lldb/packages/Python/lldbsuite/test/bench.py b/lldb/packages/Python/lldbsuite/test/bench.py index a9661b6..3fe301f 100644 --- a/lldb/packages/Python/lldbsuite/test/bench.py +++ b/lldb/packages/Python/lldbsuite/test/bench.py @@ -23,36 +23,42 @@ from optparse import OptionParser benches = [ # Measure startup delays creating a target, setting a breakpoint, and run # to breakpoint stop. - './dotest.py -v +b %E %X -n -p TestStartupDelays.py', - + "./dotest.py -v +b %E %X -n -p TestStartupDelays.py", # Measure 'frame variable' response after stopping at a breakpoint. - './dotest.py -v +b %E %X -n -p TestFrameVariableResponse.py', - + "./dotest.py -v +b %E %X -n -p TestFrameVariableResponse.py", # Measure stepping speed after stopping at a breakpoint. - './dotest.py -v +b %E %X -n -p TestSteppingSpeed.py', - + "./dotest.py -v +b %E %X -n -p TestSteppingSpeed.py", # Measure expression cmd response with a simple custom executable program. - './dotest.py +b -n -p TestExpressionCmd.py', - + "./dotest.py +b -n -p TestExpressionCmd.py", # Attach to a spawned process then run disassembly benchmarks. - './dotest.py -v +b -n %E -p TestDoAttachThenDisassembly.py' + "./dotest.py -v +b -n %E -p TestDoAttachThenDisassembly.py", ] def main(): """Read the items from 'benches' and run the command line one by one.""" - parser = OptionParser(usage="""\ + parser = OptionParser( + usage="""\ %prog [options] Run the standard benchmarks defined in the list named 'benches'.\ -""") - parser.add_option('-e', '--executable', - type='string', action='store', - dest='exe', - help='The target program launched by lldb.') - parser.add_option('-x', '--breakpoint-spec', - type='string', action='store', - dest='break_spec', - help='The lldb breakpoint spec for the target program.') +""" + ) + parser.add_option( + "-e", + "--executable", + type="string", + action="store", + dest="exe", + help="The target program launched by lldb.", + ) + parser.add_option( + "-x", + "--breakpoint-spec", + type="string", + action="store", + dest="break_spec", + help="The lldb breakpoint spec for the target program.", + ) # Parses the options, if any. opts, args = parser.parse_args() @@ -60,14 +66,15 @@ Run the standard benchmarks defined in the list named 'benches'.\ print("Starting bench runner....") for item in benches: - command = item.replace('%E', - '-e "%s"' % opts.exe if opts.exe else '') - command = command.replace('%X', '-x "%s"' % - opts.break_spec if opts.break_spec else '') + command = item.replace("%E", '-e "%s"' % opts.exe if opts.exe else "") + command = command.replace( + "%X", '-x "%s"' % opts.break_spec if opts.break_spec else "" + ) print("Running %s" % (command)) os.system(command) print("Bench runner done.") -if __name__ == '__main__': + +if __name__ == "__main__": main() diff --git a/lldb/packages/Python/lldbsuite/test/builders/__init__.py b/lldb/packages/Python/lldbsuite/test/builders/__init__.py index 84024f2..9dd82cb 100644 --- a/lldb/packages/Python/lldbsuite/test/builders/__init__.py +++ b/lldb/packages/Python/lldbsuite/test/builders/__init__.py @@ -7,10 +7,12 @@ factory method below hands out builders based on the given platform. def get_builder(platform): - """Returns a Builder instance for the given platform.""" - if platform == 'darwin': - from .darwin import BuilderDarwin - return BuilderDarwin() + """Returns a Builder instance for the given platform.""" + if platform == "darwin": + from .darwin import BuilderDarwin - from .builder import Builder - return Builder() + return BuilderDarwin() + + from .builder import Builder + + return Builder() diff --git a/lldb/packages/Python/lldbsuite/test/builders/builder.py b/lldb/packages/Python/lldbsuite/test/builders/builder.py index 4817dae..823a982 100644 --- a/lldb/packages/Python/lldbsuite/test/builders/builder.py +++ b/lldb/packages/Python/lldbsuite/test/builders/builder.py @@ -47,19 +47,31 @@ class Builder: # Construct the base make invocation. lldb_test = os.environ["LLDB_TEST"] - if not (lldb_test and configuration.test_build_dir and test_subdir - and test_name and (not os.path.isabs(test_subdir))): + if not ( + lldb_test + and configuration.test_build_dir + and test_subdir + and test_name + and (not os.path.isabs(test_subdir)) + ): raise Exception("Could not derive test directories") - build_dir = os.path.join(configuration.test_build_dir, test_subdir, - test_name) + build_dir = os.path.join(configuration.test_build_dir, test_subdir, test_name) src_dir = os.path.join(configuration.test_src_root, test_subdir) # This is a bit of a hack to make inline testcases work. makefile = os.path.join(src_dir, "Makefile") if not os.path.isfile(makefile): makefile = os.path.join(build_dir, "Makefile") return [ - make, "VPATH=" + src_dir, "-C", build_dir, "-I", src_dir, "-I", - os.path.join(lldb_test, "make"), "-f", makefile + make, + "VPATH=" + src_dir, + "-C", + build_dir, + "-I", + src_dir, + "-I", + os.path.join(lldb_test, "make"), + "-f", + makefile, ] def getCmdLine(self, d): @@ -76,7 +88,7 @@ class Builder: append_vars = ["CFLAGS", "CFLAGS_EXTRAS", "LD_EXTRAS"] if k in append_vars and k in os.environ: v = os.environ[k] + " " + v - return '%s=%s' % (k, v) + return "%s=%s" % (k, v) cmdline = [setOrAppendVariable(k, v) for k, v in list(d.items())] @@ -98,7 +110,7 @@ class Builder: if not cc and configuration.compiler: cc = configuration.compiler if cc: - return ["CC=\"%s\"" % cc] + return ['CC="%s"' % cc] return [] def getSDKRootSpec(self): @@ -116,17 +128,23 @@ class Builder: module cache used for the make system. """ if configuration.clang_module_cache_dir: - return ["CLANG_MODULE_CACHE_DIR={}".format( - configuration.clang_module_cache_dir)] + return [ + "CLANG_MODULE_CACHE_DIR={}".format(configuration.clang_module_cache_dir) + ] return [] def getLibCxxArgs(self): if configuration.libcxx_include_dir and configuration.libcxx_library_dir: - libcpp_args = ["LIBCPP_INCLUDE_DIR={}".format(configuration.libcxx_include_dir), - "LIBCPP_LIBRARY_DIR={}".format(configuration.libcxx_library_dir)] + libcpp_args = [ + "LIBCPP_INCLUDE_DIR={}".format(configuration.libcxx_include_dir), + "LIBCPP_LIBRARY_DIR={}".format(configuration.libcxx_library_dir), + ] if configuration.libcxx_include_target_dir: - libcpp_args.append("LIBCPP_INCLUDE_TARGET_DIR={}".format( - configuration.libcxx_include_target_dir)) + libcpp_args.append( + "LIBCPP_INCLUDE_TARGET_DIR={}".format( + configuration.libcxx_include_target_dir + ) + ) return libcpp_args return [] @@ -141,19 +159,34 @@ class Builder: return ["MAKE_DSYM=NO", "MAKE_GMODULES=YES"] return None - def getBuildCommand(self, debug_info, architecture=None, compiler=None, - dictionary=None, testdir=None, testname=None, make_targets=None): + def getBuildCommand( + self, + debug_info, + architecture=None, + compiler=None, + dictionary=None, + testdir=None, + testname=None, + make_targets=None, + ): debug_info_args = self._getDebugInfoArgs(debug_info) if debug_info_args is None: return None if make_targets is None: make_targets = ["all"] command_parts = [ - self.getMake(testdir, testname), debug_info_args, make_targets, - self.getArchCFlags(architecture), self.getArchSpec(architecture), - self.getCCSpec(compiler), self.getExtraMakeArgs(), - self.getSDKRootSpec(), self.getModuleCacheSpec(), - self.getLibCxxArgs(), self.getCmdLine(dictionary)] + self.getMake(testdir, testname), + debug_info_args, + make_targets, + self.getArchCFlags(architecture), + self.getArchSpec(architecture), + self.getCCSpec(compiler), + self.getExtraMakeArgs(), + self.getSDKRootSpec(), + self.getModuleCacheSpec(), + self.getLibCxxArgs(), + self.getCmdLine(dictionary), + ] command = list(itertools.chain(*command_parts)) return command diff --git a/lldb/packages/Python/lldbsuite/test/builders/darwin.py b/lldb/packages/Python/lldbsuite/test/builders/darwin.py index fd97ef8..40dd13b 100644 --- a/lldb/packages/Python/lldbsuite/test/builders/darwin.py +++ b/lldb/packages/Python/lldbsuite/test/builders/darwin.py @@ -21,7 +21,7 @@ def get_os_env_from_platform(platform): def get_os_from_sdk(sdk): - return sdk[:sdk.find('.')], "" + return sdk[: sdk.find(".")], "" def get_os_and_env(): @@ -61,7 +61,7 @@ def get_triple_str(arch, vendor, os, version, env): component = [arch, vendor, os + version] if env: components.append(env) - return '-'.join(component) + return "-".join(component) class BuilderDarwin(Builder): @@ -77,32 +77,31 @@ class BuilderDarwin(Builder): args = dict() if configuration.dsymutil: - args['DSYMUTIL'] = configuration.dsymutil + args["DSYMUTIL"] = configuration.dsymutil - if configuration.apple_sdk and 'internal' in configuration.apple_sdk: + if configuration.apple_sdk and "internal" in configuration.apple_sdk: sdk_root = lldbutil.get_xcode_sdk_root(configuration.apple_sdk) if sdk_root: - private_frameworks = os.path.join(sdk_root, 'System', - 'Library', - 'PrivateFrameworks') - args['FRAMEWORK_INCLUDES'] = '-F{}'.format(private_frameworks) + private_frameworks = os.path.join( + sdk_root, "System", "Library", "PrivateFrameworks" + ) + args["FRAMEWORK_INCLUDES"] = "-F{}".format(private_frameworks) operating_system, env = get_os_and_env() if operating_system and operating_system != "macosx": builder_dir = os.path.dirname(os.path.abspath(__file__)) test_dir = os.path.dirname(builder_dir) if env == "simulator": - entitlements_file = 'entitlements-simulator.plist' + entitlements_file = "entitlements-simulator.plist" else: - entitlements_file = 'entitlements.plist' - entitlements = os.path.join(test_dir, 'make', entitlements_file) - args['CODESIGN'] = 'codesign --entitlements {}'.format( - entitlements) + entitlements_file = "entitlements.plist" + entitlements = os.path.join(test_dir, "make", entitlements_file) + args["CODESIGN"] = "codesign --entitlements {}".format(entitlements) else: - args['CODESIGN'] = 'codesign' + args["CODESIGN"] = "codesign" # Return extra args as a formatted string. - return ['{}={}'.format(key, value) for key, value in args.items()] + return ["{}={}".format(key, value) for key, value in args.items()] def getArchCFlags(self, arch): """Returns the ARCH_CFLAGS for the make system.""" diff --git a/lldb/packages/Python/lldbsuite/test/concurrent_base.py b/lldb/packages/Python/lldbsuite/test/concurrent_base.py index b695b3a..72e04bb 100644 --- a/lldb/packages/Python/lldbsuite/test/concurrent_base.py +++ b/lldb/packages/Python/lldbsuite/test/concurrent_base.py @@ -18,7 +18,6 @@ from lldbsuite.test import lldbutil class ConcurrentEventsBase(TestBase): - # Concurrency is the primary test factor here, not debug info variants. NO_DEBUG_INFO_TESTCASE = True @@ -26,13 +25,16 @@ class ConcurrentEventsBase(TestBase): # Call super's setUp(). super(ConcurrentEventsBase, self).setUp() # Find the line number for our breakpoint. - self.filename = 'main.cpp' + self.filename = "main.cpp" self.thread_breakpoint_line = line_number( - self.filename, '// Set breakpoint here') + self.filename, "// Set breakpoint here" + ) self.setup_breakpoint_line = line_number( - self.filename, '// Break here and adjust num') + self.filename, "// Break here and adjust num" + ) self.finish_breakpoint_line = line_number( - self.filename, '// Break here and verify one thread is active') + self.filename, "// Break here and verify one thread is active" + ) def describe_threads(self): ret = [] @@ -45,66 +47,83 @@ class ConcurrentEventsBase(TestBase): bpid = x.GetStopReasonDataAtIndex(0) bp = self.inferior_target.FindBreakpointByID(bpid) reason_str = "%s hit %d times" % ( - lldbutil.get_description(bp), bp.GetHitCount()) + lldbutil.get_description(bp), + bp.GetHitCount(), + ) elif reason == lldb.eStopReasonWatchpoint: watchid = x.GetStopReasonDataAtIndex(0) watch = self.inferior_target.FindWatchpointByID(watchid) reason_str = "%s hit %d times" % ( - lldbutil.get_description(watch), watch.GetHitCount()) + lldbutil.get_description(watch), + watch.GetHitCount(), + ) elif reason == lldb.eStopReasonSignal: signals = self.inferior_process.GetUnixSignals() - signal_name = signals.GetSignalAsCString( - x.GetStopReasonDataAtIndex(0)) + signal_name = signals.GetSignalAsCString(x.GetStopReasonDataAtIndex(0)) reason_str = "signal %s" % signal_name - location = "\t".join([lldbutil.get_description( - x.GetFrameAtIndex(i)) for i in range(x.GetNumFrames())]) + location = "\t".join( + [ + lldbutil.get_description(x.GetFrameAtIndex(i)) + for i in range(x.GetNumFrames()) + ] + ) ret.append( - "thread %d %s due to %s at\n\t%s" % - (id, status, reason_str, location)) + "thread %d %s due to %s at\n\t%s" % (id, status, reason_str, location) + ) return ret def add_breakpoint(self, line, descriptions): - """ Adds a breakpoint at self.filename:line and appends its description to descriptions, and - returns the LLDB SBBreakpoint object. + """Adds a breakpoint at self.filename:line and appends its description to descriptions, and + returns the LLDB SBBreakpoint object. """ bpno = lldbutil.run_break_set_by_file_and_line( - self, self.filename, line, num_expected_locations=-1) + self, self.filename, line, num_expected_locations=-1 + ) bp = self.inferior_target.FindBreakpointByID(bpno) descriptions.append(": file = 'main.cpp', line = %d" % line) return bp def inferior_done(self): - """ Returns true if the inferior is done executing all the event threads (and is stopped at self.finish_breakpoint, - or has terminated execution. + """Returns true if the inferior is done executing all the event threads (and is stopped at self.finish_breakpoint, + or has terminated execution. """ - return self.finish_breakpoint.GetHitCount() > 0 or \ - self.crash_count > 0 or \ - self.inferior_process.GetState() == lldb.eStateExited + return ( + self.finish_breakpoint.GetHitCount() > 0 + or self.crash_count > 0 + or self.inferior_process.GetState() == lldb.eStateExited + ) def count_signaled_threads(self): count = 0 for thread in self.inferior_process: - if thread.GetStopReason() == lldb.eStopReasonSignal and thread.GetStopReasonDataAtIndex( - 0) == self.inferior_process.GetUnixSignals().GetSignalNumberFromName('SIGUSR1'): + if ( + thread.GetStopReason() == lldb.eStopReasonSignal + and thread.GetStopReasonDataAtIndex(0) + == self.inferior_process.GetUnixSignals().GetSignalNumberFromName( + "SIGUSR1" + ) + ): count += 1 return count - def do_thread_actions(self, - num_breakpoint_threads=0, - num_signal_threads=0, - num_watchpoint_threads=0, - num_crash_threads=0, - num_delay_breakpoint_threads=0, - num_delay_signal_threads=0, - num_delay_watchpoint_threads=0, - num_delay_crash_threads=0): - """ Sets a breakpoint in the main thread where test parameters (numbers of threads) can be adjusted, runs the inferior - to that point, and modifies the locals that control the event thread counts. Also sets a breakpoint in - breakpoint_func (the function executed by each 'breakpoint' thread) and a watchpoint on a global modified in - watchpoint_func. The inferior is continued until exit or a crash takes place, and the number of events seen by LLDB - is verified to match the expected number of events. + def do_thread_actions( + self, + num_breakpoint_threads=0, + num_signal_threads=0, + num_watchpoint_threads=0, + num_crash_threads=0, + num_delay_breakpoint_threads=0, + num_delay_signal_threads=0, + num_delay_watchpoint_threads=0, + num_delay_crash_threads=0, + ): + """Sets a breakpoint in the main thread where test parameters (numbers of threads) can be adjusted, runs the inferior + to that point, and modifies the locals that control the event thread counts. Also sets a breakpoint in + breakpoint_func (the function executed by each 'breakpoint' thread) and a watchpoint on a global modified in + watchpoint_func. The inferior is continued until exit or a crash takes place, and the number of events seen by LLDB + is verified to match the expected number of events. """ exe = self.getBuildArtifact("a.out") self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) @@ -116,27 +135,34 @@ class ConcurrentEventsBase(TestBase): # Initialize all the breakpoints (main thread/aux thread) self.setup_breakpoint = self.add_breakpoint( - self.setup_breakpoint_line, expected_bps) + self.setup_breakpoint_line, expected_bps + ) self.finish_breakpoint = self.add_breakpoint( - self.finish_breakpoint_line, expected_bps) + self.finish_breakpoint_line, expected_bps + ) # Set the thread breakpoint if num_breakpoint_threads + num_delay_breakpoint_threads > 0: self.thread_breakpoint = self.add_breakpoint( - self.thread_breakpoint_line, expected_bps) + self.thread_breakpoint_line, expected_bps + ) # Verify breakpoints self.expect( "breakpoint list -f", "Breakpoint locations shown correctly", - substrs=expected_bps) + substrs=expected_bps, + ) # Run the program. self.runCmd("run", RUN_SUCCEEDED) # Check we are at line self.setup_breakpoint - self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT, - substrs=["stop reason = breakpoint 1."]) + self.expect( + "thread backtrace", + STOPPED_DUE_TO_BREAKPOINT, + substrs=["stop reason = breakpoint 1."], + ) # Initialize the (single) watchpoint on the global variable (g_watchme) if num_watchpoint_threads + num_delay_watchpoint_threads > 0: @@ -144,9 +170,9 @@ class ConcurrentEventsBase(TestBase): for w in self.inferior_target.watchpoint_iter(): self.thread_watchpoint = w self.assertTrue( - "g_watchme" in str( - self.thread_watchpoint), - "Watchpoint location not shown correctly") + "g_watchme" in str(self.thread_watchpoint), + "Watchpoint location not shown correctly", + ) # Get the process self.inferior_process = self.inferior_target.GetProcess() @@ -156,7 +182,8 @@ class ConcurrentEventsBase(TestBase): self.assertEqual( self.inferior_process.GetNumThreads(), 1, - 'Expected to stop before any additional threads are spawned.') + "Expected to stop before any additional threads are spawned.", + ) self.runCmd("expr num_breakpoint_threads=%d" % num_breakpoint_threads) self.runCmd("expr num_crash_threads=%d" % num_crash_threads) @@ -164,17 +191,13 @@ class ConcurrentEventsBase(TestBase): self.runCmd("expr num_watchpoint_threads=%d" % num_watchpoint_threads) self.runCmd( - "expr num_delay_breakpoint_threads=%d" % - num_delay_breakpoint_threads) - self.runCmd( - "expr num_delay_crash_threads=%d" % - num_delay_crash_threads) + "expr num_delay_breakpoint_threads=%d" % num_delay_breakpoint_threads + ) + self.runCmd("expr num_delay_crash_threads=%d" % num_delay_crash_threads) + self.runCmd("expr num_delay_signal_threads=%d" % num_delay_signal_threads) self.runCmd( - "expr num_delay_signal_threads=%d" % - num_delay_signal_threads) - self.runCmd( - "expr num_delay_watchpoint_threads=%d" % - num_delay_watchpoint_threads) + "expr num_delay_watchpoint_threads=%d" % num_delay_watchpoint_threads + ) # Continue the inferior so threads are spawned self.runCmd("continue") @@ -183,23 +206,28 @@ class ConcurrentEventsBase(TestBase): # the inferior program ensures all threads are started and running # before any thread triggers its 'event'. num_threads = self.inferior_process.GetNumThreads() - expected_num_threads = num_breakpoint_threads + num_delay_breakpoint_threads \ - + num_signal_threads + num_delay_signal_threads \ - + num_watchpoint_threads + num_delay_watchpoint_threads \ - + num_crash_threads + num_delay_crash_threads + 1 + expected_num_threads = ( + num_breakpoint_threads + + num_delay_breakpoint_threads + + num_signal_threads + + num_delay_signal_threads + + num_watchpoint_threads + + num_delay_watchpoint_threads + + num_crash_threads + + num_delay_crash_threads + + 1 + ) self.assertEqual( num_threads, expected_num_threads, - 'Expected to see %d threads, but seeing %d. Details:\n%s' % - (expected_num_threads, - num_threads, - "\n\t".join( - self.describe_threads()))) + "Expected to see %d threads, but seeing %d. Details:\n%s" + % (expected_num_threads, num_threads, "\n\t".join(self.describe_threads())), + ) self.signal_count = self.count_signaled_threads() self.crash_count = len( - lldbutil.get_crashed_threads( - self, self.inferior_process)) + lldbutil.get_crashed_threads(self, self.inferior_process) + ) # Run to completion (or crash) while not self.inferior_done(): @@ -208,16 +236,16 @@ class ConcurrentEventsBase(TestBase): self.runCmd("continue") self.signal_count += self.count_signaled_threads() self.crash_count += len( - lldbutil.get_crashed_threads( - self, self.inferior_process)) + lldbutil.get_crashed_threads(self, self.inferior_process) + ) if num_crash_threads > 0 or num_delay_crash_threads > 0: # Expecting a crash self.assertTrue( self.crash_count > 0, - "Expecting at least one thread to crash. Details: %s" % - "\t\n".join( - self.describe_threads())) + "Expecting at least one thread to crash. Details: %s" + % "\t\n".join(self.describe_threads()), + ) # Ensure the zombie process is reaped self.runCmd("process kill") @@ -228,53 +256,61 @@ class ConcurrentEventsBase(TestBase): self.assertEqual( 1, self.finish_breakpoint.GetHitCount(), - "Expected main thread (finish) breakpoint to be hit once") + "Expected main thread (finish) breakpoint to be hit once", + ) num_threads = self.inferior_process.GetNumThreads() self.assertEqual( 1, num_threads, - "Expecting 1 thread but seeing %d. Details:%s" % - (num_threads, - "\n\t".join( - self.describe_threads()))) + "Expecting 1 thread but seeing %d. Details:%s" + % (num_threads, "\n\t".join(self.describe_threads())), + ) self.runCmd("continue") # The inferior process should have exited without crashing self.assertEqual( - 0, - self.crash_count, - "Unexpected thread(s) in crashed state") + 0, self.crash_count, "Unexpected thread(s) in crashed state" + ) self.assertEqual( - self.inferior_process.GetState(), - lldb.eStateExited, - PROCESS_EXITED) + self.inferior_process.GetState(), lldb.eStateExited, PROCESS_EXITED + ) # Verify the number of actions took place matches expected numbers - expected_breakpoint_threads = num_delay_breakpoint_threads + num_breakpoint_threads - breakpoint_hit_count = self.thread_breakpoint.GetHitCount( - ) if expected_breakpoint_threads > 0 else 0 + expected_breakpoint_threads = ( + num_delay_breakpoint_threads + num_breakpoint_threads + ) + breakpoint_hit_count = ( + self.thread_breakpoint.GetHitCount() + if expected_breakpoint_threads > 0 + else 0 + ) self.assertEqual( expected_breakpoint_threads, breakpoint_hit_count, - "Expected %d breakpoint hits, but got %d" % - (expected_breakpoint_threads, - breakpoint_hit_count)) + "Expected %d breakpoint hits, but got %d" + % (expected_breakpoint_threads, breakpoint_hit_count), + ) expected_signal_threads = num_delay_signal_threads + num_signal_threads self.assertEqual( expected_signal_threads, self.signal_count, - "Expected %d stops due to signal delivery, but got %d" % - (expected_signal_threads, - self.signal_count)) - - expected_watchpoint_threads = num_delay_watchpoint_threads + num_watchpoint_threads - watchpoint_hit_count = self.thread_watchpoint.GetHitCount( - ) if expected_watchpoint_threads > 0 else 0 + "Expected %d stops due to signal delivery, but got %d" + % (expected_signal_threads, self.signal_count), + ) + + expected_watchpoint_threads = ( + num_delay_watchpoint_threads + num_watchpoint_threads + ) + watchpoint_hit_count = ( + self.thread_watchpoint.GetHitCount() + if expected_watchpoint_threads > 0 + else 0 + ) self.assertEqual( expected_watchpoint_threads, watchpoint_hit_count, - "Expected %d watchpoint hits, got %d" % - (expected_watchpoint_threads, - watchpoint_hit_count)) + "Expected %d watchpoint hits, got %d" + % (expected_watchpoint_threads, watchpoint_hit_count), + ) diff --git a/lldb/packages/Python/lldbsuite/test/configuration.py b/lldb/packages/Python/lldbsuite/test/configuration.py index 266d785..0085117 100644 --- a/lldb/packages/Python/lldbsuite/test/configuration.py +++ b/lldb/packages/Python/lldbsuite/test/configuration.py @@ -62,7 +62,7 @@ yaml2obj = None # The arch might dictate some specific CFLAGS to be passed to the toolchain to build # the inferior programs. The global variable cflags_extras provides a hook to do # just that. -cflags_extras = '' +cflags_extras = "" # The filters (testclass.testmethod) used to admit tests into our test suite. filters = [] @@ -78,7 +78,7 @@ xfail_tests = None # Set this flag if there is any session info dumped during the test run. sdir_has_content = False # svn_info stores the output from 'svn info lldb.base.dir'. -svn_info = '' +svn_info = "" # Default verbosity is 0. verbose = 0 @@ -93,7 +93,7 @@ testdirs = [lldbsuite.lldb_test_root] test_src_root = lldbsuite.lldb_test_root # Separator string. -separator = '-' * 70 +separator = "-" * 70 failed = False @@ -133,8 +133,10 @@ enabled_plugins = [] def shouldSkipBecauseOfCategories(test_categories): if use_categories: - if len(test_categories) == 0 or len( - categories_list & set(test_categories)) == 0: + if ( + len(test_categories) == 0 + or len(categories_list & set(test_categories)) == 0 + ): return True for category in skip_categories: @@ -151,6 +153,7 @@ def get_filecheck_path(): if filecheck and os.path.lexists(filecheck): return filecheck + def get_yaml2obj_path(): """ Get the path to the yaml2obj tool. diff --git a/lldb/packages/Python/lldbsuite/test/decorators.py b/lldb/packages/Python/lldbsuite/test/decorators.py index 0c5f55f..b9ac170 100644 --- a/lldb/packages/Python/lldbsuite/test/decorators.py +++ b/lldb/packages/Python/lldbsuite/test/decorators.py @@ -34,23 +34,28 @@ class DecorateMode: # and linux, oslist=no_match(["windows", "linux"]) skips *unless* windows # or linux. class no_match: - def __init__(self, item): self.item = item def _check_expected_version(comparison, expected, actual): - def fn_leq(x, y): return x <= y + def fn_leq(x, y): + return x <= y - def fn_less(x, y): return x < y + def fn_less(x, y): + return x < y - def fn_geq(x, y): return x >= y + def fn_geq(x, y): + return x >= y - def fn_greater(x, y): return x > y + def fn_greater(x, y): + return x > y - def fn_eq(x, y): return x == y + def fn_eq(x, y): + return x == y - def fn_neq(x, y): return x != y + def fn_neq(x, y): + return x != y op_lookup = { "==": fn_eq, @@ -60,48 +65,50 @@ def _check_expected_version(comparison, expected, actual): ">": fn_greater, "<": fn_less, ">=": fn_geq, - "<=": fn_leq + "<=": fn_leq, } - expected_str = '.'.join([str(x) for x in expected]) - actual_str = '.'.join([str(x) for x in actual]) + expected_str = ".".join([str(x) for x in expected]) + actual_str = ".".join([str(x) for x in actual]) - return op_lookup[comparison]( - LooseVersion(actual_str), - LooseVersion(expected_str)) + return op_lookup[comparison](LooseVersion(actual_str), LooseVersion(expected_str)) def _match_decorator_property(expected, actual): if expected is None: return True - if actual is None : + if actual is None: return False if isinstance(expected, no_match): return not _match_decorator_property(expected.item, actual) # Python 3.6 doesn't declare a `re.Pattern` type, get the dynamic type. - pattern_type = type(re.compile('')) + pattern_type = type(re.compile("")) if isinstance(expected, (pattern_type, str)): return re.search(expected, actual) is not None if hasattr(expected, "__iter__"): - return any([x is not None and _match_decorator_property(x, actual) - for x in expected]) + return any( + [x is not None and _match_decorator_property(x, actual) for x in expected] + ) return expected == actual -def _compiler_supports(compiler, - flag, - source='int main() {}', - output_file=tempfile.NamedTemporaryFile()): +def _compiler_supports( + compiler, flag, source="int main() {}", output_file=tempfile.NamedTemporaryFile() +): """Test whether the compiler supports the given flag.""" - if platform.system() == 'Darwin': + if platform.system() == "Darwin": compiler = "xcrun " + compiler try: - cmd = "echo '%s' | %s %s -x c -o %s -" % (source, compiler, flag, - output_file.name) + cmd = "echo '%s' | %s %s -x c -o %s -" % ( + source, + compiler, + flag, + output_file.name, + ) subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError: return False @@ -111,11 +118,11 @@ def _compiler_supports(compiler, def expectedFailure(func): return unittest2.expectedFailure(func) + def expectedFailureIfFn(expected_fn, bugnumber=None): def expectedFailure_impl(func): if isinstance(func, type) and issubclass(func, unittest2.TestCase): - raise Exception( - "Decorator can only be used to decorate a test method") + raise Exception("Decorator can only be used to decorate a test method") @wraps(func) def wrapper(*args, **kwargs): @@ -125,7 +132,9 @@ def expectedFailureIfFn(expected_fn, bugnumber=None): xfail_func(*args, **kwargs) else: func(*args, **kwargs) + return wrapper + # Some decorators can be called both with no arguments (e.g. @expectedFailureWindows) # or with arguments (e.g. @expectedFailureWindows(compilers=['gcc'])). When called # the first way, the first argument will be the actual function because decorators are @@ -157,6 +166,7 @@ def skipTestIfFn(expected_fn, bugnumber=None): self.skipTest(reason) else: return func(*args, **kwargs) + return wrapper # Some decorators can be called both with no arguments (e.g. @expectedFailureWindows) @@ -170,70 +180,86 @@ def skipTestIfFn(expected_fn, bugnumber=None): return skipTestIfFn_impl -def _decorateTest(mode, - bugnumber=None, oslist=None, hostoslist=None, - compiler=None, compiler_version=None, - archs=None, triple=None, - debug_info=None, - swig_version=None, py_version=None, - macos_version=None, - remote=None, dwarf_version=None, - setting=None): +def _decorateTest( + mode, + bugnumber=None, + oslist=None, + hostoslist=None, + compiler=None, + compiler_version=None, + archs=None, + triple=None, + debug_info=None, + swig_version=None, + py_version=None, + macos_version=None, + remote=None, + dwarf_version=None, + setting=None, +): def fn(self): skip_for_os = _match_decorator_property( - lldbplatform.translate(oslist), self.getPlatform()) + lldbplatform.translate(oslist), self.getPlatform() + ) skip_for_hostos = _match_decorator_property( - lldbplatform.translate(hostoslist), - lldbplatformutil.getHostPlatform()) + lldbplatform.translate(hostoslist), lldbplatformutil.getHostPlatform() + ) skip_for_compiler = _match_decorator_property( - compiler, self.getCompiler()) and self.expectedCompilerVersion(compiler_version) - skip_for_arch = _match_decorator_property( - archs, self.getArchitecture()) - skip_for_debug_info = _match_decorator_property( - debug_info, self.getDebugInfo()) + compiler, self.getCompiler() + ) and self.expectedCompilerVersion(compiler_version) + skip_for_arch = _match_decorator_property(archs, self.getArchitecture()) + skip_for_debug_info = _match_decorator_property(debug_info, self.getDebugInfo()) skip_for_triple = _match_decorator_property( - triple, lldb.selected_platform.GetTriple()) + triple, lldb.selected_platform.GetTriple() + ) skip_for_remote = _match_decorator_property( - remote, lldb.remote_platform is not None) + remote, lldb.remote_platform is not None + ) skip_for_swig_version = ( - swig_version is None) or ( - not hasattr( - lldb, - 'swig_version')) or ( + (swig_version is None) + or (not hasattr(lldb, "swig_version")) + or ( _check_expected_version( - swig_version[0], - swig_version[1], - lldb.swig_version)) - skip_for_py_version = ( - py_version is None) or _check_expected_version( - py_version[0], py_version[1], sys.version_info) + swig_version[0], swig_version[1], lldb.swig_version + ) + ) + ) + skip_for_py_version = (py_version is None) or _check_expected_version( + py_version[0], py_version[1], sys.version_info + ) skip_for_macos_version = (macos_version is None) or ( - (platform.mac_ver()[0] != "") and (_check_expected_version( - macos_version[0], - macos_version[1], - platform.mac_ver()[0]))) + (platform.mac_ver()[0] != "") + and ( + _check_expected_version( + macos_version[0], macos_version[1], platform.mac_ver()[0] + ) + ) + ) skip_for_dwarf_version = (dwarf_version is None) or ( - _check_expected_version(dwarf_version[0], dwarf_version[1], - self.getDwarfVersion())) - skip_for_setting = (setting is None) or ( - setting in configuration.settings) + _check_expected_version( + dwarf_version[0], dwarf_version[1], self.getDwarfVersion() + ) + ) + skip_for_setting = (setting is None) or (setting in configuration.settings) # For the test to be skipped, all specified (e.g. not None) parameters must be True. # An unspecified parameter means "any", so those are marked skip by default. And we skip # the final test if all conditions are True. - conditions = [(oslist, skip_for_os, "target o/s"), - (hostoslist, skip_for_hostos, "host o/s"), - (compiler, skip_for_compiler, "compiler or version"), - (archs, skip_for_arch, "architecture"), - (debug_info, skip_for_debug_info, "debug info format"), - (triple, skip_for_triple, "target triple"), - (swig_version, skip_for_swig_version, "swig version"), - (py_version, skip_for_py_version, "python version"), - (macos_version, skip_for_macos_version, "macOS version"), - (remote, skip_for_remote, "platform locality (remote/local)"), - (dwarf_version, skip_for_dwarf_version, "dwarf version"), - (setting, skip_for_setting, "setting")] + conditions = [ + (oslist, skip_for_os, "target o/s"), + (hostoslist, skip_for_hostos, "host o/s"), + (compiler, skip_for_compiler, "compiler or version"), + (archs, skip_for_arch, "architecture"), + (debug_info, skip_for_debug_info, "debug info format"), + (triple, skip_for_triple, "target triple"), + (swig_version, skip_for_swig_version, "swig version"), + (py_version, skip_for_py_version, "python version"), + (macos_version, skip_for_macos_version, "macOS version"), + (remote, skip_for_remote, "platform locality (remote/local)"), + (dwarf_version, skip_for_dwarf_version, "dwarf version"), + (setting, skip_for_setting, "setting"), + ] reasons = [] final_skip_result = True for this_condition in conditions: @@ -242,13 +268,14 @@ def _decorateTest(mode, reasons.append(this_condition[2]) reason_str = None if final_skip_result: - mode_str = { - DecorateMode.Skip: "skipping", - DecorateMode.Xfail: "xfailing"}[mode] + mode_str = {DecorateMode.Skip: "skipping", DecorateMode.Xfail: "xfailing"}[ + mode + ] if len(reasons) > 0: reason_str = ",".join(reasons) reason_str = "{} due to the following parameter(s): {}".format( - mode_str, reason_str) + mode_str, reason_str + ) else: reason_str = "{} unconditionally".format(mode_str) if bugnumber is not None and not callable(bugnumber): @@ -262,6 +289,7 @@ def _decorateTest(mode, else: return None + # provide a function to xfail on defined oslist, compiler version, and archs # if none is specified for any argument, that argument won't be checked and thus means for all # for example, @@ -270,25 +298,39 @@ def _decorateTest(mode, # @expectedFailureAll(bugnumber, ["linux"], "gcc", ['>=', '4.9'], ['i386']), xfail for gcc>=4.9 on linux with i386 -def expectedFailureAll(bugnumber=None, - oslist=None, hostoslist=None, - compiler=None, compiler_version=None, - archs=None, triple=None, - debug_info=None, - swig_version=None, py_version=None, - macos_version=None, - remote=None, dwarf_version=None, - setting=None): - return _decorateTest(DecorateMode.Xfail, - bugnumber=bugnumber, - oslist=oslist, hostoslist=hostoslist, - compiler=compiler, compiler_version=compiler_version, - archs=archs, triple=triple, - debug_info=debug_info, - swig_version=swig_version, py_version=py_version, - macos_version=macos_version, - remote=remote,dwarf_version=dwarf_version, - setting=setting) +def expectedFailureAll( + bugnumber=None, + oslist=None, + hostoslist=None, + compiler=None, + compiler_version=None, + archs=None, + triple=None, + debug_info=None, + swig_version=None, + py_version=None, + macos_version=None, + remote=None, + dwarf_version=None, + setting=None, +): + return _decorateTest( + DecorateMode.Xfail, + bugnumber=bugnumber, + oslist=oslist, + hostoslist=hostoslist, + compiler=compiler, + compiler_version=compiler_version, + archs=archs, + triple=triple, + debug_info=debug_info, + swig_version=swig_version, + py_version=py_version, + macos_version=macos_version, + remote=remote, + dwarf_version=dwarf_version, + setting=setting, + ) # provide a function to skip on defined oslist, compiler version, and archs @@ -297,32 +339,48 @@ def expectedFailureAll(bugnumber=None, # @skipIf, skip for all platform/compiler/arch, # @skipIf(compiler='gcc'), skip for gcc on all platform/architecture # @skipIf(bugnumber, ["linux"], "gcc", ['>=', '4.9'], ['i386']), skip for gcc>=4.9 on linux with i386 -def skipIf(bugnumber=None, - oslist=None, hostoslist=None, - compiler=None, compiler_version=None, - archs=None, triple=None, - debug_info=None, - swig_version=None, py_version=None, - macos_version=None, - remote=None, dwarf_version=None, - setting=None): - return _decorateTest(DecorateMode.Skip, - bugnumber=bugnumber, - oslist=oslist, hostoslist=hostoslist, - compiler=compiler, compiler_version=compiler_version, - archs=archs, triple=triple, - debug_info=debug_info, - swig_version=swig_version, py_version=py_version, - macos_version=macos_version, - remote=remote, dwarf_version=dwarf_version, - setting=setting) +def skipIf( + bugnumber=None, + oslist=None, + hostoslist=None, + compiler=None, + compiler_version=None, + archs=None, + triple=None, + debug_info=None, + swig_version=None, + py_version=None, + macos_version=None, + remote=None, + dwarf_version=None, + setting=None, +): + return _decorateTest( + DecorateMode.Skip, + bugnumber=bugnumber, + oslist=oslist, + hostoslist=hostoslist, + compiler=compiler, + compiler_version=compiler_version, + archs=archs, + triple=triple, + debug_info=debug_info, + swig_version=swig_version, + py_version=py_version, + macos_version=macos_version, + remote=remote, + dwarf_version=dwarf_version, + setting=setting, + ) def _skip_for_android(reason, api_levels, archs): def impl(obj): result = lldbplatformutil.match_android_device( - obj.getArchitecture(), valid_archs=archs, valid_api_levels=api_levels) + obj.getArchitecture(), valid_archs=archs, valid_api_levels=api_levels + ) return reason if result else None + return impl @@ -333,13 +391,14 @@ def add_test_categories(cat): def impl(func): if isinstance(func, type) and issubclass(func, unittest2.TestCase): raise Exception( - "@add_test_categories can only be used to decorate a test method") + "@add_test_categories can only be used to decorate a test method" + ) try: if hasattr(func, "categories"): cat.extend(func.categories) setattr(func, "categories", cat) except AttributeError: - raise Exception('Cannot assign categories to inline tests.') + raise Exception("Cannot assign categories to inline tests.") return func @@ -348,6 +407,7 @@ def add_test_categories(cat): def benchmarks_test(func): """Decorate the item as a benchmarks test.""" + def should_skip_benchmarks_test(): return "benchmarks test" @@ -359,10 +419,11 @@ def benchmarks_test(func): def no_debug_info_test(func): """Decorate the item as a test what don't use any debug info. If this annotation is specified - then the test runner won't generate a separate test for each debug info format. """ + then the test runner won't generate a separate test for each debug info format.""" if isinstance(func, type) and issubclass(func, unittest2.TestCase): raise Exception( - "@no_debug_info_test can only be used to decorate a test method") + "@no_debug_info_test can only be used to decorate a test method" + ) @wraps(func) def wrapper(self, *args, **kwargs): @@ -372,6 +433,7 @@ def no_debug_info_test(func): wrapper.__no_debug_info_test__ = True return wrapper + def apple_simulator_test(platform): """ Decorate the test as a test requiring a simulator for a specific platform. @@ -379,13 +441,16 @@ def apple_simulator_test(platform): Consider that a simulator is available if you have the corresponding SDK installed. The SDK identifiers for simulators are iphonesimulator, appletvsimulator, watchsimulator """ + def should_skip_simulator_test(): - if lldbplatformutil.getHostPlatform() not in ['darwin', 'macosx']: + if lldbplatformutil.getHostPlatform() not in ["darwin", "macosx"]: return "simulator tests are run only on darwin hosts." try: - DEVNULL = open(os.devnull, 'w') - output = subprocess.check_output(["xcodebuild", "-showsdks"], stderr=DEVNULL).decode("utf-8") - if re.search('%ssimulator' % platform, output): + DEVNULL = open(os.devnull, "w") + output = subprocess.check_output( + ["xcodebuild", "-showsdks"], stderr=DEVNULL + ).decode("utf-8") + if re.search("%ssimulator" % platform, output): return None else: return "%s simulator is not supported on this system." % platform @@ -406,17 +471,15 @@ def llgs_test(func): def expectedFailureOS( - oslist, - bugnumber=None, - compilers=None, - debug_info=None, - archs=None): + oslist, bugnumber=None, compilers=None, debug_info=None, archs=None +): return expectedFailureAll( oslist=oslist, bugnumber=bugnumber, compiler=compilers, archs=archs, - debug_info=debug_info) + debug_info=debug_info, + ) def expectedFailureDarwin(bugnumber=None, compilers=None, debug_info=None, archs=None): @@ -427,11 +490,12 @@ def expectedFailureDarwin(bugnumber=None, compilers=None, debug_info=None, archs bugnumber, compilers, debug_info=debug_info, - archs=archs) + archs=archs, + ) def expectedFailureAndroid(bugnumber=None, api_levels=None, archs=None): - """ Mark a test as xfail for Android. + """Mark a test as xfail for Android. Arguments: bugnumber - The LLVM pr associated with the problem. @@ -441,17 +505,13 @@ def expectedFailureAndroid(bugnumber=None, api_levels=None, archs=None): for which a test is expected to fail. None means all architectures. """ return expectedFailureIfFn( - _skip_for_android( - "xfailing on android", - api_levels, - archs), - bugnumber) + _skip_for_android("xfailing on android", api_levels, archs), bugnumber + ) def expectedFailureNetBSD(bugnumber=None): - return expectedFailureOS( - ['netbsd'], - bugnumber) + return expectedFailureOS(["netbsd"], bugnumber) + # TODO: This decorator does not do anything. Remove it. def expectedFlakey(expected_fn, bugnumber=None): @@ -459,7 +519,9 @@ def expectedFlakey(expected_fn, bugnumber=None): @wraps(func) def wrapper(*args, **kwargs): func(*args, **kwargs) + return wrapper + # Some decorators can be called both with no arguments (e.g. @expectedFailureWindows) # or with arguments (e.g. @expectedFailureWindows(compilers=['gcc'])). When called # the first way, the first argument will be the actual function because decorators are @@ -473,46 +535,48 @@ def expectedFlakey(expected_fn, bugnumber=None): def expectedFlakeyOS(oslist, bugnumber=None, compilers=None): def fn(self): - return (self.getPlatform() in oslist and - self.expectedCompiler(compilers)) + return self.getPlatform() in oslist and self.expectedCompiler(compilers) + return expectedFlakey(fn, bugnumber) def expectedFlakeyDarwin(bugnumber=None, compilers=None): # For legacy reasons, we support both "darwin" and "macosx" as OS X # triples. - return expectedFlakeyOS( - lldbplatformutil.getDarwinOSTriples(), - bugnumber, - compilers) + return expectedFlakeyOS(lldbplatformutil.getDarwinOSTriples(), bugnumber, compilers) def expectedFlakeyFreeBSD(bugnumber=None, compilers=None): - return expectedFlakeyOS(['freebsd'], bugnumber, compilers) + return expectedFlakeyOS(["freebsd"], bugnumber, compilers) def expectedFlakeyLinux(bugnumber=None, compilers=None): - return expectedFlakeyOS(['linux'], bugnumber, compilers) + return expectedFlakeyOS(["linux"], bugnumber, compilers) def expectedFlakeyNetBSD(bugnumber=None, compilers=None): - return expectedFlakeyOS(['netbsd'], bugnumber, compilers) + return expectedFlakeyOS(["netbsd"], bugnumber, compilers) def expectedFlakeyAndroid(bugnumber=None, api_levels=None, archs=None): return expectedFlakey( - _skip_for_android( - "flakey on android", - api_levels, - archs), - bugnumber) + _skip_for_android("flakey on android", api_levels, archs), bugnumber + ) + def skipIfOutOfTreeDebugserver(func): """Decorate the item to skip tests if using an out-of-tree debugserver.""" + def is_out_of_tree_debugserver(): - return "out-of-tree debugserver" if lldbtest_config.out_of_tree_debugserver else None + return ( + "out-of-tree debugserver" + if lldbtest_config.out_of_tree_debugserver + else None + ) + return skipTestIfFn(is_out_of_tree_debugserver)(func) + def skipIfRemote(func): """Decorate the item to skip tests if testing remotely.""" return unittest2.skipIf(lldb.remote_platform, "skip on remote platform")(func) @@ -520,26 +584,28 @@ def skipIfRemote(func): def skipIfNoSBHeaders(func): """Decorate the item to mark tests that should be skipped when LLDB is built with no SB API headers.""" + def are_sb_headers_missing(): if lldb.remote_platform: return "skip because SBHeaders tests make no sense remotely" - if lldbplatformutil.getHostPlatform() == 'darwin' and configuration.lldb_framework_path: + if ( + lldbplatformutil.getHostPlatform() == "darwin" + and configuration.lldb_framework_path + ): header = os.path.join( configuration.lldb_framework_path, - 'Versions', - 'Current', - 'Headers', - 'LLDB.h') + "Versions", + "Current", + "Headers", + "LLDB.h", + ) if os.path.exists(header): return None header = os.path.join( - os.environ["LLDB_SRC"], - "include", - "lldb", - "API", - "LLDB.h") + os.environ["LLDB_SRC"], "include", "lldb", "API", "LLDB.h" + ) if not os.path.exists(header): return "skip because LLDB.h header not found" return None @@ -549,42 +615,54 @@ def skipIfNoSBHeaders(func): def skipIfRosetta(bugnumber): """Skip a test when running the testsuite on macOS under the Rosetta translation layer.""" + def is_running_rosetta(self): - if lldbplatformutil.getPlatform() in ['darwin', 'macosx']: + if lldbplatformutil.getPlatform() in ["darwin", "macosx"]: if (platform.uname()[5] == "arm") and (self.getArchitecture() == "x86_64"): return "skipped under Rosetta" return None + return skipTestIfFn(is_running_rosetta) + def skipIfiOSSimulator(func): """Decorate the item to skip tests that should be skipped on the iOS Simulator.""" + def is_ios_simulator(): - return "skip on the iOS Simulator" if configuration.lldb_platform_name == 'ios-simulator' else None + return ( + "skip on the iOS Simulator" + if configuration.lldb_platform_name == "ios-simulator" + else None + ) + return skipTestIfFn(is_ios_simulator)(func) + def skipIfiOS(func): return skipIfPlatform(lldbplatform.translate(lldbplatform.ios))(func) + def skipIftvOS(func): return skipIfPlatform(lldbplatform.translate(lldbplatform.tvos))(func) + def skipIfwatchOS(func): return skipIfPlatform(lldbplatform.translate(lldbplatform.watchos))(func) + def skipIfbridgeOS(func): return skipIfPlatform(lldbplatform.translate(lldbplatform.bridgeos))(func) + def skipIfDarwinEmbedded(func): """Decorate the item to skip tests that should be skipped on Darwin armv7/arm64 targets.""" - return skipIfPlatform( - lldbplatform.translate( - lldbplatform.darwin_embedded))(func) + return skipIfPlatform(lldbplatform.translate(lldbplatform.darwin_embedded))(func) + def skipIfDarwinSimulator(func): """Decorate the item to skip tests that should be skipped on Darwin simulator targets.""" - return skipIfPlatform( - lldbplatform.translate( - lldbplatform.darwin_simulator))(func) + return skipIfPlatform(lldbplatform.translate(lldbplatform.darwin_simulator))(func) + def skipIfFreeBSD(func): """Decorate the item to skip tests that should be skipped on FreeBSD.""" @@ -598,9 +676,7 @@ def skipIfNetBSD(func): def skipIfDarwin(func): """Decorate the item to skip tests that should be skipped on Darwin.""" - return skipIfPlatform( - lldbplatform.translate( - lldbplatform.darwin_all))(func) + return skipIfPlatform(lldbplatform.translate(lldbplatform.darwin_all))(func) def skipIfLinux(func): @@ -612,17 +688,21 @@ def skipIfWindows(func): """Decorate the item to skip tests that should be skipped on Windows.""" return skipIfPlatform(["windows"])(func) + def skipIfWindowsAndNonEnglish(func): """Decorate the item to skip tests that should be skipped on non-English locales on Windows.""" + def is_Windows_NonEnglish(self): if sys.platform != "win32": return None kernel = ctypes.windll.kernel32 - if locale.windows_locale[ kernel.GetUserDefaultUILanguage() ] == "en_US": + if locale.windows_locale[kernel.GetUserDefaultUILanguage()] == "en_US": return None return "skipping non-English Windows locale" + return skipTestIfFn(is_Windows_NonEnglish)(func) + def skipUnlessWindows(func): """Decorate the item to skip tests that should be skipped on any non-Windows platform.""" return skipUnlessPlatform(["windows"])(func) @@ -632,9 +712,11 @@ def skipUnlessDarwin(func): """Decorate the item to skip tests that should be skipped on any non Darwin platform.""" return skipUnlessPlatform(lldbplatformutil.getDarwinOSTriples())(func) + def skipUnlessTargetAndroid(func): - return unittest2.skipUnless(lldbplatformutil.target_is_android(), - "requires target to be Android")(func) + return unittest2.skipUnless( + lldbplatformutil.target_is_android(), "requires target to be Android" + )(func) def skipIfHostIncompatibleWithRemote(func): @@ -644,17 +726,24 @@ def skipIfHostIncompatibleWithRemote(func): host_arch = self.getLldbArchitecture() host_platform = lldbplatformutil.getHostPlatform() target_arch = self.getArchitecture() - target_platform = 'darwin' if self.platformIsDarwin() else self.getPlatform() - if not (target_arch == 'x86_64' and host_arch == - 'i386') and host_arch != target_arch: - return "skipping because target %s is not compatible with host architecture %s" % ( - target_arch, host_arch) + target_platform = "darwin" if self.platformIsDarwin() else self.getPlatform() + if ( + not (target_arch == "x86_64" and host_arch == "i386") + and host_arch != target_arch + ): + return ( + "skipping because target %s is not compatible with host architecture %s" + % (target_arch, host_arch) + ) if target_platform != host_platform: return "skipping because target is %s but host is %s" % ( - target_platform, host_platform) + target_platform, + host_platform, + ) if lldbplatformutil.match_android_device(target_arch): return "skipping because target is android" return None + return skipTestIfFn(is_host_incompatible_with_remote)(func) @@ -662,16 +751,20 @@ def skipIfPlatform(oslist): """Decorate the item to skip tests if running on one of the listed platforms.""" # This decorator cannot be ported to `skipIf` yet because it is used on entire # classes, which `skipIf` explicitly forbids. - return unittest2.skipIf(lldbplatformutil.getPlatform() in oslist, - "skip on %s" % (", ".join(oslist))) + return unittest2.skipIf( + lldbplatformutil.getPlatform() in oslist, "skip on %s" % (", ".join(oslist)) + ) def skipUnlessPlatform(oslist): """Decorate the item to skip tests unless running on one of the listed platforms.""" # This decorator cannot be ported to `skipIf` yet because it is used on entire # classes, which `skipIf` explicitly forbids. - return unittest2.skipUnless(lldbplatformutil.getPlatform() in oslist, - "requires one of %s" % (", ".join(oslist))) + return unittest2.skipUnless( + lldbplatformutil.getPlatform() in oslist, + "requires one of %s" % (", ".join(oslist)), + ) + def skipUnlessArch(arch): """Decorate the item to skip tests unless running on the specified architecture.""" @@ -684,6 +777,7 @@ def skipUnlessArch(arch): return skipTestIfFn(arch_doesnt_match) + def skipIfTargetAndroid(bugnumber=None, api_levels=None, archs=None): """Decorator to skip tests when the target is Android. @@ -694,36 +788,46 @@ def skipIfTargetAndroid(bugnumber=None, api_levels=None, archs=None): for which a test is skipped. None means all architectures. """ return skipTestIfFn( - _skip_for_android( - "skipping for android", - api_levels, - archs), - bugnumber) + _skip_for_android("skipping for android", api_levels, archs), bugnumber + ) + def skipUnlessAppleSilicon(func): """Decorate the item to skip tests unless running on Apple Silicon.""" + def not_apple_silicon(test): - if platform.system() != 'Darwin' or test.getArchitecture() not in [ - 'arm64', 'arm64e' + if platform.system() != "Darwin" or test.getArchitecture() not in [ + "arm64", + "arm64e", ]: return "Test only runs on Apple Silicon" return None return skipTestIfFn(not_apple_silicon)(func) + def skipUnlessSupportedTypeAttribute(attr): """Decorate the item to skip test unless Clang supports type __attribute__(attr).""" + def compiler_doesnt_support_struct_attribute(self): compiler_path = self.getCompiler() f = tempfile.NamedTemporaryFile() cmd = [self.getCompiler(), "-x", "c++", "-c", "-o", f.name, "-"] - p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) - stdout, stderr = p.communicate('struct __attribute__((%s)) Test {};'%attr) + p = subprocess.Popen( + cmd, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True, + ) + stdout, stderr = p.communicate("struct __attribute__((%s)) Test {};" % attr) if attr in stderr: - return "Compiler does not support attribute %s"%(attr) + return "Compiler does not support attribute %s" % (attr) return None + return skipTestIfFn(compiler_doesnt_support_struct_attribute) + def skipUnlessHasCallSiteInfo(func): """Decorate the function to skip testing unless call site info from clang is available.""" @@ -734,20 +838,24 @@ def skipUnlessHasCallSiteInfo(func): return "Test requires clang as compiler" f = tempfile.NamedTemporaryFile() - cmd = "echo 'int main() {}' | " \ - "%s -g -glldb -O1 -S -emit-llvm -x c -o %s -" % (compiler_path, f.name) + cmd = ( + "echo 'int main() {}' | " + "%s -g -glldb -O1 -S -emit-llvm -x c -o %s -" % (compiler_path, f.name) + ) if os.popen(cmd).close() is not None: return "Compiler can't compile with call site info enabled" - with open(f.name, 'r') as ir_output_file: + with open(f.name, "r") as ir_output_file: buf = ir_output_file.read() - if 'DIFlagAllCallsDescribed' not in buf: + if "DIFlagAllCallsDescribed" not in buf: return "Compiler did not introduce DIFlagAllCallsDescribed IR flag" return None + return skipTestIfFn(is_compiler_clang_with_call_site_info)(func) + def skipUnlessThreadSanitizer(func): """Decorate the item to skip test unless Clang -fsanitize=thread is supported.""" @@ -759,41 +867,48 @@ def skipUnlessThreadSanitizer(func): compiler = os.path.basename(compiler_path) if not compiler.startswith("clang"): return "Test requires clang as compiler" - if lldbplatformutil.getPlatform() == 'windows': + if lldbplatformutil.getPlatform() == "windows": return "TSAN tests not compatible with 'windows'" # rdar://28659145 - TSAN tests don't look like they're supported on i386 - if self.getArchitecture() == 'i386' and platform.system() == 'Darwin': + if self.getArchitecture() == "i386" and platform.system() == "Darwin": return "TSAN tests not compatible with i386 targets" - if not _compiler_supports(compiler_path, '-fsanitize=thread'): + if not _compiler_supports(compiler_path, "-fsanitize=thread"): return "Compiler cannot compile with -fsanitize=thread" return None + return skipTestIfFn(is_compiler_clang_with_thread_sanitizer)(func) + def skipUnlessUndefinedBehaviorSanitizer(func): """Decorate the item to skip test unless -fsanitize=undefined is supported.""" def is_compiler_clang_with_ubsan(self): if is_running_under_asan(): - return "Undefined behavior sanitizer tests are disabled when runing under ASAN" + return ( + "Undefined behavior sanitizer tests are disabled when runing under ASAN" + ) # We need to write out the object into a named temp file for inspection. outputf = tempfile.NamedTemporaryFile() # Try to compile with ubsan turned on. - if not _compiler_supports(self.getCompiler(), '-fsanitize=undefined', - 'int main() { int x = 0; return x / x; }', - outputf): + if not _compiler_supports( + self.getCompiler(), + "-fsanitize=undefined", + "int main() { int x = 0; return x / x; }", + outputf, + ): return "Compiler cannot compile with -fsanitize=undefined" # Check that we actually see ubsan instrumentation in the binary. - cmd = 'nm %s' % outputf.name + cmd = "nm %s" % outputf.name with os.popen(cmd) as nm_output: - if '___ubsan_handle_divrem_overflow' not in nm_output.read(): + if "___ubsan_handle_divrem_overflow" not in nm_output.read(): return "Division by zero instrumentation is missing" # Find the ubsan dylib. # FIXME: This check should go away once compiler-rt gains support for __ubsan_on_report. - cmd = '%s -fsanitize=undefined -x c - -o - -### 2>&1' % self.getCompiler() + cmd = "%s -fsanitize=undefined -x c - -o - -### 2>&1" % self.getCompiler() with os.popen(cmd) as cc_output: driver_jobs = cc_output.read() m = re.search(r'"([^"]+libclang_rt.ubsan_osx_dynamic.dylib)"', driver_jobs) @@ -802,12 +917,12 @@ def skipUnlessUndefinedBehaviorSanitizer(func): ubsan_dylib = m.group(1) # Check that the ubsan dylib has special monitor hooks. - cmd = 'nm -gU %s' % ubsan_dylib + cmd = "nm -gU %s" % ubsan_dylib with os.popen(cmd) as nm_output: syms = nm_output.read() - if '___ubsan_on_report' not in syms: + if "___ubsan_on_report" not in syms: return "Missing ___ubsan_on_report" - if '___ubsan_get_current_report_data' not in syms: + if "___ubsan_get_current_report_data" not in syms: return "Missing ___ubsan_get_current_report_data" # OK, this dylib + compiler works for us. @@ -815,11 +930,13 @@ def skipUnlessUndefinedBehaviorSanitizer(func): return skipTestIfFn(is_compiler_clang_with_ubsan)(func) + def is_running_under_asan(): - if ('ASAN_OPTIONS' in os.environ): + if "ASAN_OPTIONS" in os.environ: return "ASAN unsupported" return None + def skipUnlessAddressSanitizer(func): """Decorate the item to skip test unless Clang -fsanitize=thread is supported.""" @@ -830,17 +947,20 @@ def skipUnlessAddressSanitizer(func): if is_running_under_asan(): return "Address sanitizer tests are disabled when runing under ASAN" - if lldbplatformutil.getPlatform() == 'windows': + if lldbplatformutil.getPlatform() == "windows": return "ASAN tests not compatible with 'windows'" - if not _compiler_supports(self.getCompiler(), '-fsanitize=address'): + if not _compiler_supports(self.getCompiler(), "-fsanitize=address"): return "Compiler cannot compile with -fsanitize=address" return None + return skipTestIfFn(is_compiler_with_address_sanitizer)(func) + def skipIfAsan(func): """Skip this test if the environment is set up to run LLDB *itself* under ASAN.""" return skipTestIfFn(is_running_under_asan)(func) + def skipUnlessAArch64MTELinuxCompiler(func): """Decorate the item to skip test unless MTE is supported by the test compiler.""" @@ -848,7 +968,7 @@ def skipUnlessAArch64MTELinuxCompiler(func): compiler_path = self.getCompiler() compiler = os.path.basename(compiler_path) f = tempfile.NamedTemporaryFile() - if lldbplatformutil.getPlatform() == 'windows': + if lldbplatformutil.getPlatform() == "windows": return "MTE tests are not compatible with 'windows'" cmd = "echo 'int main() {}' | %s -x c -o %s -" % (compiler_path, f.name) @@ -867,14 +987,19 @@ def skipUnlessAArch64MTELinuxCompiler(func): int main() { void* ptr = __arm_mte_create_random_tag((void*)(0), 0); }""" - cmd = "echo '%s' | %s -march=armv8.5-a+memtag -x c -o %s -" % (test_src, compiler_path, f.name) + cmd = "echo '%s' | %s -march=armv8.5-a+memtag -x c -o %s -" % ( + test_src, + compiler_path, + f.name, + ) if os.popen(cmd).close() is not None: return "Toolchain does not support MTE" return None return skipTestIfFn(is_toolchain_with_mte)(func) -def _get_bool_config(key, fail_value = True): + +def _get_bool_config(key, fail_value=True): """ Returns the current LLDB's build config value. :param key The key to lookup in LLDB's build configuration. @@ -886,22 +1011,28 @@ def _get_bool_config(key, fail_value = True): value_node = config.GetValueForKey(key) return value_node.GetValueForKey("value").GetBooleanValue(fail_value) + def _get_bool_config_skip_if_decorator(key): have = _get_bool_config(key) return unittest2.skipIf(not have, "requires " + key) + def skipIfCursesSupportMissing(func): return _get_bool_config_skip_if_decorator("curses")(func) + def skipIfXmlSupportMissing(func): return _get_bool_config_skip_if_decorator("xml")(func) + def skipIfEditlineSupportMissing(func): return _get_bool_config_skip_if_decorator("editline")(func) + def skipIfFBSDVMCoreSupportMissing(func): return _get_bool_config_skip_if_decorator("fbsdvmcore")(func) + def skipIfLLVMTargetMissing(target): config = lldb.SBDebugger.GetBuildConfiguration() targets = config.GetValueForKey("targets").GetValueForKey("value") @@ -913,19 +1044,23 @@ def skipIfLLVMTargetMissing(target): return unittest2.skipIf(not found, "requires " + target) + # Call sysctl on darwin to see if a specified hardware feature is available on this machine. def skipUnlessFeature(feature): def is_feature_enabled(self): - if platform.system() == 'Darwin': + if platform.system() == "Darwin": try: - DEVNULL = open(os.devnull, 'w') - output = subprocess.check_output(["/usr/sbin/sysctl", feature], stderr=DEVNULL).decode("utf-8") + DEVNULL = open(os.devnull, "w") + output = subprocess.check_output( + ["/usr/sbin/sysctl", feature], stderr=DEVNULL + ).decode("utf-8") # If 'feature: 1' was output, then this feature is available and # the test should not be skipped. - if re.match('%s: 1\s*' % feature, output): + if re.match("%s: 1\s*" % feature, output): return None else: return "%s is not supported on this system." % feature except subprocess.CalledProcessError: return "%s is not supported on this system." % feature + return skipTestIfFn(is_feature_enabled) diff --git a/lldb/packages/Python/lldbsuite/test/dotest.py b/lldb/packages/Python/lldbsuite/test/dotest.py index db7a345..1b2076f5 100644 --- a/lldb/packages/Python/lldbsuite/test/dotest.py +++ b/lldb/packages/Python/lldbsuite/test/dotest.py @@ -52,7 +52,7 @@ def is_exe(fpath): """Returns true if fpath is an executable.""" if fpath == None: return False - if sys.platform == 'win32': + if sys.platform == "win32": if not fpath.endswith(".exe"): fpath += ".exe" return os.path.isfile(fpath) and os.access(fpath, os.X_OK) @@ -75,7 +75,8 @@ def which(program): def usage(parser): parser.print_help() if configuration.verbose > 0: - print(""" + print( + """ Examples: This is an example of using the -f option to pinpoint to a specific test class @@ -166,21 +167,22 @@ to create reference logs for debugging. $ ./dotest.py --log-success -""") +""" + ) sys.exit(0) def parseExclusion(exclusion_file): """Parse an exclusion file, of the following format, where - 'skip files', 'skip methods', 'xfail files', and 'xfail methods' - are the possible list heading values: + 'skip files', 'skip methods', 'xfail files', and 'xfail methods' + are the possible list heading values: - skip files - <file name> - <file name> + skip files + <file name> + <file name> - xfail methods - <method name> + xfail methods + <method name> """ excl_type = None @@ -193,11 +195,11 @@ def parseExclusion(exclusion_file): if not line: excl_type = None - elif excl_type == 'skip': + elif excl_type == "skip": if not configuration.skip_tests: configuration.skip_tests = [] configuration.skip_tests.append(line) - elif excl_type == 'xfail': + elif excl_type == "xfail": if not configuration.xfail_tests: configuration.xfail_tests = [] configuration.xfail_tests.append(line) @@ -231,14 +233,14 @@ def parseOptionsAndInitTestdirs(): if args.set_env_vars: for env_var in args.set_env_vars: - parts = env_var.split('=', 1) + parts = env_var.split("=", 1) if len(parts) == 1: os.environ[parts[0]] = "" else: os.environ[parts[0]] = parts[1] if args.set_inferior_env_vars: - lldbtest_config.inferior_env = ' '.join(args.set_inferior_env_vars) + lldbtest_config.inferior_env = " ".join(args.set_inferior_env_vars) if args.h: do_help = True @@ -249,19 +251,19 @@ def parseOptionsAndInitTestdirs(): configuration.compiler = which(args.compiler) if not is_exe(configuration.compiler): logging.error( - '%s is not a valid compiler executable; aborting...', - args.compiler) + "%s is not a valid compiler executable; aborting...", args.compiler + ) sys.exit(-1) else: # Use a compiler appropriate appropriate for the Apple SDK if one was # specified - if platform_system == 'Darwin' and args.apple_sdk: + if platform_system == "Darwin" and args.apple_sdk: configuration.compiler = seven.get_command_output( - 'xcrun -sdk "%s" -find clang 2> /dev/null' % - (args.apple_sdk)) + 'xcrun -sdk "%s" -find clang 2> /dev/null' % (args.apple_sdk) + ) else: # 'clang' on ubuntu 14.04 is 3.4 so we try clang-3.5 first - candidateCompilers = ['clang-3.5', 'clang', 'gcc'] + candidateCompilers = ["clang-3.5", "clang", "gcc"] for candidate in candidateCompilers: if which(candidate): configuration.compiler = candidate @@ -269,22 +271,27 @@ def parseOptionsAndInitTestdirs(): if args.dsymutil: configuration.dsymutil = args.dsymutil - elif platform_system == 'Darwin': + elif platform_system == "Darwin": configuration.dsymutil = seven.get_command_output( - 'xcrun -find -toolchain default dsymutil') + "xcrun -find -toolchain default dsymutil" + ) if args.llvm_tools_dir: configuration.filecheck = shutil.which("FileCheck", path=args.llvm_tools_dir) configuration.yaml2obj = shutil.which("yaml2obj", path=args.llvm_tools_dir) if not configuration.get_filecheck_path(): - logging.warning('No valid FileCheck executable; some tests may fail...') - logging.warning('(Double-check the --llvm-tools-dir argument to dotest.py)') + logging.warning("No valid FileCheck executable; some tests may fail...") + logging.warning("(Double-check the --llvm-tools-dir argument to dotest.py)") if args.libcxx_include_dir or args.libcxx_library_dir: if args.lldb_platform_name: - logging.warning('Custom libc++ is not supported for remote runs: ignoring --libcxx arguments') + logging.warning( + "Custom libc++ is not supported for remote runs: ignoring --libcxx arguments" + ) elif not (args.libcxx_include_dir and args.libcxx_library_dir): - logging.error('Custom libc++ requires both --libcxx-include-dir and --libcxx-library-dir') + logging.error( + "Custom libc++ requires both --libcxx-include-dir and --libcxx-library-dir" + ) sys.exit(-1) configuration.libcxx_include_dir = args.libcxx_include_dir configuration.libcxx_include_target_dir = args.libcxx_include_target_dir @@ -300,14 +307,12 @@ def parseOptionsAndInitTestdirs(): lldbtest_config.out_of_tree_debugserver = args.out_of_tree_debugserver # Set SDKROOT if we are using an Apple SDK - if platform_system == 'Darwin' and args.apple_sdk: + if platform_system == "Darwin" and args.apple_sdk: configuration.sdkroot = seven.get_command_output( - 'xcrun --sdk "%s" --show-sdk-path 2> /dev/null' % - (args.apple_sdk)) + 'xcrun --sdk "%s" --show-sdk-path 2> /dev/null' % (args.apple_sdk) + ) if not configuration.sdkroot: - logging.error( - 'No SDK found with the name %s; aborting...', - args.apple_sdk) + logging.error("No SDK found with the name %s; aborting...", args.apple_sdk) sys.exit(-1) if args.arch: @@ -317,47 +322,51 @@ def parseOptionsAndInitTestdirs(): if args.categories_list: configuration.categories_list = set( - test_categories.validate( - args.categories_list, False)) + test_categories.validate(args.categories_list, False) + ) configuration.use_categories = True else: configuration.categories_list = [] if args.skip_categories: configuration.skip_categories += test_categories.validate( - args.skip_categories, False) + args.skip_categories, False + ) if args.xfail_categories: configuration.xfail_categories += test_categories.validate( - args.xfail_categories, False) + args.xfail_categories, False + ) if args.E: - os.environ['CFLAGS_EXTRAS'] = args.E + os.environ["CFLAGS_EXTRAS"] = args.E if args.dwarf_version: configuration.dwarf_version = args.dwarf_version # We cannot modify CFLAGS_EXTRAS because they're used in test cases # that explicitly require no debug info. - os.environ['CFLAGS'] = '-gdwarf-{}'.format(configuration.dwarf_version) + os.environ["CFLAGS"] = "-gdwarf-{}".format(configuration.dwarf_version) if args.settings: for setting in args.settings: - if not len(setting) == 1 or not setting[0].count('='): - logging.error('"%s" is not a setting in the form "key=value"', - setting[0]) + if not len(setting) == 1 or not setting[0].count("="): + logging.error( + '"%s" is not a setting in the form "key=value"', setting[0] + ) sys.exit(-1) - setting_list = setting[0].split('=', 1) + setting_list = setting[0].split("=", 1) configuration.settings.append((setting_list[0], setting_list[1])) if args.d: sys.stdout.write( - "Suspending the process %d to wait for debugger to attach...\n" % - os.getpid()) + "Suspending the process %d to wait for debugger to attach...\n" + % os.getpid() + ) sys.stdout.flush() os.kill(os.getpid(), signal.SIGSTOP) if args.f: - if any([x.startswith('-') for x in args.f]): + if any([x.startswith("-") for x in args.f]): usage(parser) configuration.filters.extend(args.f) @@ -371,8 +380,8 @@ def parseOptionsAndInitTestdirs(): lldbtest_config.lldbExec = which(args.executable) if not is_exe(lldbtest_config.lldbExec): logging.error( - '%s is not a valid executable to test; aborting...', - args.executable) + "%s is not a valid executable to test; aborting...", args.executable + ) sys.exit(-1) if args.excluded: @@ -380,12 +389,12 @@ def parseOptionsAndInitTestdirs(): parseExclusion(excl_file) if args.p: - if args.p.startswith('-'): + if args.p.startswith("-"): usage(parser) configuration.regexp = args.p if args.t: - os.environ['LLDB_COMMAND_TRACE'] = 'YES' + os.environ["LLDB_COMMAND_TRACE"] = "YES" if args.v: configuration.verbose = 2 @@ -394,10 +403,9 @@ def parseOptionsAndInitTestdirs(): if args.sharp: configuration.count = args.sharp - if sys.platform.startswith('win32'): - os.environ['LLDB_DISABLE_CRASH_DIALOG'] = str( - args.disable_crash_dialog) - os.environ['LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE'] = str(True) + if sys.platform.startswith("win32"): + os.environ["LLDB_DISABLE_CRASH_DIALOG"] = str(args.disable_crash_dialog) + os.environ["LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE"] = str(True) if do_help: usage(parser) @@ -408,7 +416,7 @@ def parseOptionsAndInitTestdirs(): configuration.lldb_platform_url = args.lldb_platform_url if args.lldb_platform_working_dir: configuration.lldb_platform_working_dir = args.lldb_platform_working_dir - if platform_system == 'Darwin' and args.apple_sdk: + if platform_system == "Darwin" and args.apple_sdk: configuration.apple_sdk = args.apple_sdk if args.test_build_dir: configuration.test_build_dir = args.test_build_dir @@ -416,12 +424,14 @@ def parseOptionsAndInitTestdirs(): configuration.lldb_module_cache_dir = args.lldb_module_cache_dir else: configuration.lldb_module_cache_dir = os.path.join( - configuration.test_build_dir, 'module-cache-lldb') + configuration.test_build_dir, "module-cache-lldb" + ) if args.clang_module_cache_dir: configuration.clang_module_cache_dir = args.clang_module_cache_dir else: configuration.clang_module_cache_dir = os.path.join( - configuration.test_build_dir, 'module-cache-clang') + configuration.test_build_dir, "module-cache-clang" + ) if args.lldb_libs_dir: configuration.lldb_libs_dir = args.lldb_libs_dir @@ -431,10 +441,13 @@ def parseOptionsAndInitTestdirs(): # Gather all the dirs passed on the command line. if len(args.args) > 0: - configuration.testdirs = [os.path.realpath(os.path.abspath(x)) for x in args.args] + configuration.testdirs = [ + os.path.realpath(os.path.abspath(x)) for x in args.args + ] lldbtest_config.codesign_identity = args.codesign_identity + def registerFaulthandler(): try: import faulthandler @@ -444,9 +457,10 @@ def registerFaulthandler(): faulthandler.enable() # faulthandler.register is not available on Windows. - if getattr(faulthandler, 'register', None): + if getattr(faulthandler, "register", None): faulthandler.register(signal.SIGTERM, chain=True) + def setupSysPath(): """ Add LLDB.framework/Resources/Python to the search paths for modules. @@ -458,7 +472,7 @@ def setupSysPath(): scriptPath = os.environ["DOTEST_SCRIPT_DIR"] else: scriptPath = os.path.dirname(os.path.abspath(__file__)) - if not scriptPath.endswith('test'): + if not scriptPath.endswith("test"): print("This script expects to reside in lldb's test directory.") sys.exit(-1) @@ -473,10 +487,10 @@ def setupSysPath(): # the LLDB source code. os.environ["LLDB_SRC"] = lldbsuite.lldb_root - pluginPath = os.path.join(scriptPath, 'plugins') - toolsLLDBVSCode = os.path.join(scriptPath, 'tools', 'lldb-vscode') - toolsLLDBServerPath = os.path.join(scriptPath, 'tools', 'lldb-server') - intelpt = os.path.join(scriptPath, 'tools', 'intelpt') + pluginPath = os.path.join(scriptPath, "plugins") + toolsLLDBVSCode = os.path.join(scriptPath, "tools", "lldb-vscode") + toolsLLDBServerPath = os.path.join(scriptPath, "tools", "lldb-server") + intelpt = os.path.join(scriptPath, "tools", "intelpt") # Insert script dir, plugin dir and lldb-server dir to the sys.path. sys.path.insert(0, pluginPath) @@ -509,19 +523,21 @@ def setupSysPath(): if not lldbtest_config.lldbExec: # Last, check the path - lldbtest_config.lldbExec = which('lldb') + lldbtest_config.lldbExec = which("lldb") if lldbtest_config.lldbExec and not is_exe(lldbtest_config.lldbExec): print( - "'{}' is not a path to a valid executable".format( - lldbtest_config.lldbExec)) + "'{}' is not a path to a valid executable".format(lldbtest_config.lldbExec) + ) lldbtest_config.lldbExec = None if not lldbtest_config.lldbExec: - print("The 'lldb' executable cannot be located. Some of the tests may not be run as a result.") + print( + "The 'lldb' executable cannot be located. Some of the tests may not be run as a result." + ) sys.exit(-1) - os.system('%s -v' % lldbtest_config.lldbExec) + os.system("%s -v" % lldbtest_config.lldbExec) lldbDir = os.path.dirname(lldbtest_config.lldbExec) @@ -531,36 +547,47 @@ def setupSysPath(): else: if not configuration.shouldSkipBecauseOfCategories(["lldb-vscode"]): print( - "The 'lldb-vscode' executable cannot be located. The lldb-vscode tests can not be run as a result.") + "The 'lldb-vscode' executable cannot be located. The lldb-vscode tests can not be run as a result." + ) configuration.skip_categories.append("lldb-vscode") lldbPythonDir = None # The directory that contains 'lldb/__init__.py' # If our lldb supports the -P option, use it to find the python path: - lldb_dash_p_result = subprocess.check_output([lldbtest_config.lldbExec, "-P"], universal_newlines=True) + lldb_dash_p_result = subprocess.check_output( + [lldbtest_config.lldbExec, "-P"], universal_newlines=True + ) if lldb_dash_p_result: for line in lldb_dash_p_result.splitlines(): - if os.path.isdir(line) and os.path.exists(os.path.join(line, 'lldb', '__init__.py')): + if os.path.isdir(line) and os.path.exists( + os.path.join(line, "lldb", "__init__.py") + ): lldbPythonDir = line break if not lldbPythonDir: print( - "Unable to load lldb extension module. Possible reasons for this include:") + "Unable to load lldb extension module. Possible reasons for this include:" + ) print(" 1) LLDB was built with LLDB_ENABLE_PYTHON=0") print( - " 2) PYTHONPATH and PYTHONHOME are not set correctly. PYTHONHOME should refer to") + " 2) PYTHONPATH and PYTHONHOME are not set correctly. PYTHONHOME should refer to" + ) print( - " the version of Python that LLDB built and linked against, and PYTHONPATH") + " the version of Python that LLDB built and linked against, and PYTHONPATH" + ) print( - " should contain the Lib directory for the same python distro, as well as the") - print(" location of LLDB\'s site-packages folder.") + " should contain the Lib directory for the same python distro, as well as the" + ) + print(" location of LLDB's site-packages folder.") print( - " 3) A different version of Python than that which was built against is exported in") - print(" the system\'s PATH environment variable, causing conflicts.") + " 3) A different version of Python than that which was built against is exported in" + ) + print(" the system's PATH environment variable, causing conflicts.") print( - " 4) The executable '%s' could not be found. Please check " % - lldbtest_config.lldbExec) + " 4) The executable '%s' could not be found. Please check " + % lldbtest_config.lldbExec + ) print(" that it exists and is executable.") if lldbPythonDir: @@ -569,18 +596,18 @@ def setupSysPath(): # If the path we've constructed looks like that, then we'll strip out # the Versions/A part. (before, frameWithVersion, after) = lldbPythonDir.rpartition( - "LLDB.framework/Versions/A") + "LLDB.framework/Versions/A" + ) if frameWithVersion != "": lldbPythonDir = before + "LLDB.framework" + after lldbPythonDir = os.path.abspath(lldbPythonDir) if "freebsd" in sys.platform or "linux" in sys.platform: - os.environ['LLDB_LIB_DIR'] = os.path.join(lldbPythonDir, '..', '..') + os.environ["LLDB_LIB_DIR"] = os.path.join(lldbPythonDir, "..", "..") # If tests need to find LLDB_FRAMEWORK, now they can do it - os.environ["LLDB_FRAMEWORK"] = os.path.dirname( - os.path.dirname(lldbPythonDir)) + os.environ["LLDB_FRAMEWORK"] = os.path.dirname(os.path.dirname(lldbPythonDir)) # This is to locate the lldb.py module. Insert it right after # sys.path[0]. @@ -622,15 +649,15 @@ def visit_file(dir, name): def iter_filters(): for filterspec in configuration.filters: - parts = filterspec.split('.') + parts = filterspec.split(".") if check(module, parts): yield filterspec elif parts[0] == base and len(parts) > 1 and check(module, parts[1:]): - yield '.'.join(parts[1:]) + yield ".".join(parts[1:]) else: - for key,value in module.__dict__.items(): + for key, value in module.__dict__.items(): if check(value, parts): - yield key + '.' + filterspec + yield key + "." + filterspec filtered = False for filterspec in iter_filters(): @@ -648,22 +675,22 @@ def visit_file(dir, name): # Also the fail-over case when the filterspec branch # (base, filterspec) combo doesn't make sense. configuration.suite.addTests( - unittest2.defaultTestLoader.loadTestsFromName(base)) + unittest2.defaultTestLoader.loadTestsFromName(base) + ) def visit(prefix, dir, names): """Visitor function for os.path.walk(path, visit, arg).""" dir_components = set(dir.split(os.sep)) - excluded_components = set(['.svn', '.git']) + excluded_components = set([".svn", ".git"]) if dir_components.intersection(excluded_components): return # Gather all the Python test file names that follow the Test*.py pattern. python_test_files = [ - name - for name in names - if name.endswith('.py') and name.startswith(prefix)] + name for name in names if name.endswith(".py") and name.startswith(prefix) + ] # Visit all the python test files. for name in python_test_files: @@ -689,17 +716,15 @@ def visit(prefix, dir, names): def checkDsymForUUIDIsNotOn(): cmd = ["defaults", "read", "com.apple.DebugSymbols"] - process = subprocess.Popen( - cmd, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) + process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) cmd_output = process.stdout.read() output_str = cmd_output.decode("utf-8") if "DBGFileMappedPaths = " in output_str: - print("%s =>" % ' '.join(cmd)) + print("%s =>" % " ".join(cmd)) print(output_str) print( - "Disable automatic lookup and caching of dSYMs before running the test suite!") + "Disable automatic lookup and caching of dSYMs before running the test suite!" + ) print("Exiting...") sys.exit(0) @@ -708,6 +733,7 @@ def exitTestSuite(exitCode=None): # lldb.py does SBDebugger.Initialize(). # Call SBDebugger.Terminate() on exit. import lldb + lldb.SBDebugger.Terminate() if exitCode: sys.exit(exitCode) @@ -715,11 +741,11 @@ def exitTestSuite(exitCode=None): def getVersionForSDK(sdk): sdk = str.lower(sdk) - full_path = seven.get_command_output('xcrun -sdk %s --show-sdk-path' % sdk) + full_path = seven.get_command_output("xcrun -sdk %s --show-sdk-path" % sdk) basename = os.path.basename(full_path) basename = os.path.splitext(basename)[0] basename = str.lower(basename) - ver = basename.replace(sdk, '') + ver = basename.replace(sdk, "") return ver @@ -734,14 +760,16 @@ def checkCompiler(): raise Exception(c + " is not a valid compiler") pipe = subprocess.Popen( - ['xcrun', '-find', c], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + ["xcrun", "-find", c], stdout=subprocess.PIPE, stderr=subprocess.STDOUT + ) cmd_output = pipe.stdout.read() if not cmd_output or "not found" in cmd_output: raise Exception(c + " is not a valid compiler") - configuration.compiler = cmd_output.split('\n')[0] + configuration.compiler = cmd_output.split("\n")[0] print("'xcrun -find %s' returning %s" % (c, configuration.compiler)) + def canRunLibcxxTests(): from lldbsuite.test import lldbplatformutil @@ -753,24 +781,35 @@ def canRunLibcxxTests(): if platform == "linux": with tempfile.NamedTemporaryFile() as f: cmd = [configuration.compiler, "-xc++", "-stdlib=libc++", "-o", f.name, "-"] - p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) + p = subprocess.Popen( + cmd, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True, + ) _, stderr = p.communicate("#include <cassert>\nint main() {}") if not p.returncode: return True, "Compiling with -stdlib=libc++ works" - return False, "Compiling with -stdlib=libc++ fails with the error: %s" % stderr + return ( + False, + "Compiling with -stdlib=libc++ fails with the error: %s" % stderr, + ) return False, "Don't know how to build with libc++ on %s" % platform + def checkLibcxxSupport(): result, reason = canRunLibcxxTests() if result: - return # libc++ supported + return # libc++ supported if "libc++" in configuration.categories_list: - return # libc++ category explicitly requested, let it run. + return # libc++ category explicitly requested, let it run. if configuration.verbose: print("libc++ tests will not be run because: " + reason) configuration.skip_categories.append("libc++") + def canRunLibstdcxxTests(): from lldbsuite.test import lldbplatformutil @@ -781,16 +820,18 @@ def canRunLibstdcxxTests(): return True, "libstdcxx always present" return False, "Don't know how to build with libstdcxx on %s" % platform + def checkLibstdcxxSupport(): result, reason = canRunLibstdcxxTests() if result: - return # libstdcxx supported + return # libstdcxx supported if "libstdcxx" in configuration.categories_list: - return # libstdcxx category explicitly requested, let it run. + return # libstdcxx category explicitly requested, let it run. if configuration.verbose: print("libstdcxx tests will not be run because: " + reason) configuration.skip_categories.append("libstdcxx") + def canRunWatchpointTests(): from lldbsuite.test import lldbplatformutil @@ -799,8 +840,13 @@ def canRunWatchpointTests(): if os.geteuid() == 0: return True, "root can always write dbregs" try: - output = subprocess.check_output(["/sbin/sysctl", "-n", - "security.models.extensions.user_set_dbregs"]).decode().strip() + output = ( + subprocess.check_output( + ["/sbin/sysctl", "-n", "security.models.extensions.user_set_dbregs"] + ) + .decode() + .strip() + ) if output == "1": return True, "security.models.extensions.user_set_dbregs enabled" except subprocess.CalledProcessError: @@ -808,20 +854,23 @@ def canRunWatchpointTests(): return False, "security.models.extensions.user_set_dbregs disabled" elif platform == "freebsd" and configuration.arch == "aarch64": import lldb + if lldb.SBPlatform.GetHostPlatform().GetOSMajorVersion() < 13: return False, "Watchpoint support on arm64 requires FreeBSD 13.0" return True, "watchpoint support available" + def checkWatchpointSupport(): result, reason = canRunWatchpointTests() if result: - return # watchpoints supported + return # watchpoints supported if "watchpoint" in configuration.categories_list: - return # watchpoint category explicitly requested, let it run. + return # watchpoint category explicitly requested, let it run. if configuration.verbose: print("watchpoint tests will not be run because: " + reason) configuration.skip_categories.append("watchpoint") + def checkObjcSupport(): from lldbsuite.test import lldbplatformutil @@ -830,6 +879,7 @@ def checkObjcSupport(): print("objc tests will be skipped because of unsupported platform") configuration.skip_categories.append("objc") + def checkDebugInfoSupport(): from lldbsuite.test import lldbplatformutil @@ -837,11 +887,12 @@ def checkDebugInfoSupport(): compiler = configuration.compiler for cat in test_categories.debug_info_categories: if cat in configuration.categories_list: - continue # Category explicitly requested, let it run. + continue # Category explicitly requested, let it run. if test_categories.is_supported_on_platform(cat, platform, compiler): continue configuration.skip_categories.append(cat) + def checkDebugServerSupport(): from lldbsuite.test import lldbplatformutil import lldb @@ -853,13 +904,13 @@ def checkDebugServerSupport(): # <rdar://problem/34539270> configuration.skip_categories.append("debugserver") if configuration.verbose: - print(skip_msg%"debugserver"); + print(skip_msg % "debugserver") else: configuration.skip_categories.append("debugserver") if lldb.remote_platform and lldbplatformutil.getPlatform() == "windows": configuration.skip_categories.append("llgs") if configuration.verbose: - print(skip_msg%"lldb-server"); + print(skip_msg % "lldb-server") def checkForkVForkSupport(): @@ -888,6 +939,7 @@ def run_suite(): setupSysPath() import lldb + lldb.SBDebugger.Initialize() lldb.SBDebugger.PrintStackTraceOnError() @@ -899,46 +951,58 @@ def run_suite(): 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) + print("Setting up remote platform '%s'" % (configuration.lldb_platform_name)) + lldb.remote_platform = lldb.SBPlatform(configuration.lldb_platform_name) lldb.selected_platform = lldb.remote_platform if not lldb.remote_platform.IsValid(): print( - "error: unable to create the LLDB platform named '%s'." % - (configuration.lldb_platform_name)) + "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)) + "Connecting to remote platform '%s' at '%s'..." + % (configuration.lldb_platform_name, configuration.lldb_platform_url) + ) platform_connect_options = lldb.SBPlatformConnectOptions( - configuration.lldb_platform_url) + 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)) + 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)) + 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 + configuration.lldb_platform_working_dir, 448 + ) # 448 = 0o700 if error.Fail(): - raise Exception("making remote directory '%s': %s" % ( - configuration.lldb_platform_working_dir, error)) + 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) + 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 @@ -958,11 +1022,15 @@ def run_suite(): checkForkVForkSupport() skipped_categories_list = ", ".join(configuration.skip_categories) - print("Skipping the following test categories: {}".format(configuration.skip_categories)) + 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) + 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. @@ -980,8 +1048,7 @@ def run_suite(): print("compiler=%s" % configuration.compiler) # Iterating over all possible architecture and compiler combinations. - configString = "arch=%s compiler=%s" % (configuration.arch, - configuration.compiler) + configString = "arch=%s compiler=%s" % (configuration.arch, configuration.compiler) # Output the configuration. if configuration.verbose: @@ -991,9 +1058,12 @@ def run_suite(): 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 "")) + "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") @@ -1004,41 +1074,42 @@ def run_suite(): result = unittest2.TextTestRunner( stream=sys.stderr, verbosity=configuration.verbose, - resultclass=test_result.LLDBTestResult).run( - configuration.suite) + 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) + 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") + " can be found in the test build directory\n" + ) - if configuration.use_categories and len( - configuration.failures_per_category) > 0: + 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])) + "%s - %d\n" % (category, configuration.failures_per_category[category]) + ) # Exiting. exitTestSuite(configuration.failed) + if __name__ == "__main__": print( - __file__ + - " is for use as a module only. It should not be run as a standalone script.") + __file__ + + " is for use as a module only. It should not be run as a standalone script." + ) sys.exit(-1) diff --git a/lldb/packages/Python/lldbsuite/test/dotest_args.py b/lldb/packages/Python/lldbsuite/test/dotest_args.py index 31c0c0e..ae02285 100644 --- a/lldb/packages/Python/lldbsuite/test/dotest_args.py +++ b/lldb/packages/Python/lldbsuite/test/dotest_args.py @@ -12,227 +12,323 @@ from . import configuration def create_parser(): parser = argparse.ArgumentParser( - description='description', - prefix_chars='+-', - add_help=False) + description="description", prefix_chars="+-", add_help=False + ) group = None # Helper function for boolean options (group will point to the current # group when executing X) X = lambda optstr, helpstr, **kwargs: group.add_argument( - optstr, help=helpstr, action='store_true', **kwargs) + optstr, help=helpstr, action="store_true", **kwargs + ) - group = parser.add_argument_group('Help') + group = parser.add_argument_group("Help") group.add_argument( - '-h', - '--help', - dest='h', - action='store_true', - help="Print this help message and exit. Add '-v' for more detailed help.") + "-h", + "--help", + dest="h", + action="store_true", + help="Print this help message and exit. Add '-v' for more detailed help.", + ) # C and Python toolchain options - group = parser.add_argument_group('Toolchain options') - group.add_argument( - '-A', - '--arch', - metavar='arch', - dest='arch', - help=textwrap.dedent('''Specify the architecture(s) to test. This option can be specified more than once''')) - group.add_argument('-C', '--compiler', metavar='compiler', dest='compiler', help=textwrap.dedent( - '''Specify the compiler(s) used to build the inferior executables. The compiler path can be an executable basename or a full path to a compiler executable. This option can be specified multiple times.''')) - if sys.platform == 'darwin': - group.add_argument('--apple-sdk', metavar='apple_sdk', dest='apple_sdk', default="", help=textwrap.dedent( - '''Specify the name of the Apple SDK (macosx, macosx.internal, iphoneos, iphoneos.internal, or path to SDK) and use the appropriate tools from that SDK's toolchain.''')) - group.add_argument('--libcxx-include-dir', help=textwrap.dedent( - 'Specify the path to a custom libc++ include directory. Must be used in conjunction with --libcxx-library-dir.')) - group.add_argument('--libcxx-include-target-dir', help=textwrap.dedent( - 'Specify the path to a custom libc++ include target directory to use in addition to --libcxx-include-dir. Optional.')) - group.add_argument('--libcxx-library-dir', help=textwrap.dedent( - 'Specify the path to a custom libc++ library directory. Must be used in conjunction with --libcxx-include-dir.')) + group = parser.add_argument_group("Toolchain options") + group.add_argument( + "-A", + "--arch", + metavar="arch", + dest="arch", + help=textwrap.dedent( + """Specify the architecture(s) to test. This option can be specified more than once""" + ), + ) + group.add_argument( + "-C", + "--compiler", + metavar="compiler", + dest="compiler", + help=textwrap.dedent( + """Specify the compiler(s) used to build the inferior executables. The compiler path can be an executable basename or a full path to a compiler executable. This option can be specified multiple times.""" + ), + ) + if sys.platform == "darwin": + group.add_argument( + "--apple-sdk", + metavar="apple_sdk", + dest="apple_sdk", + default="", + help=textwrap.dedent( + """Specify the name of the Apple SDK (macosx, macosx.internal, iphoneos, iphoneos.internal, or path to SDK) and use the appropriate tools from that SDK's toolchain.""" + ), + ) + group.add_argument( + "--libcxx-include-dir", + help=textwrap.dedent( + "Specify the path to a custom libc++ include directory. Must be used in conjunction with --libcxx-library-dir." + ), + ) + group.add_argument( + "--libcxx-include-target-dir", + help=textwrap.dedent( + "Specify the path to a custom libc++ include target directory to use in addition to --libcxx-include-dir. Optional." + ), + ) + group.add_argument( + "--libcxx-library-dir", + help=textwrap.dedent( + "Specify the path to a custom libc++ library directory. Must be used in conjunction with --libcxx-include-dir." + ), + ) # FIXME? This won't work for different extra flags according to each arch. group.add_argument( - '-E', - metavar='extra-flags', - help=textwrap.dedent('''Specify the extra flags to be passed to the toolchain when building the inferior programs to be debugged - suggestions: do not lump the "-A arch1 -A arch2" together such that the -E option applies to only one of the architectures''')) + "-E", + metavar="extra-flags", + help=textwrap.dedent( + """Specify the extra flags to be passed to the toolchain when building the inferior programs to be debugged + suggestions: do not lump the "-A arch1 -A arch2" together such that the -E option applies to only one of the architectures""" + ), + ) - group.add_argument('--dsymutil', metavar='dsymutil', dest='dsymutil', help=textwrap.dedent('Specify which dsymutil to use.')) - group.add_argument('--llvm-tools-dir', metavar='dir', dest='llvm_tools_dir', - help=textwrap.dedent('The location of llvm tools used for testing (yaml2obj, FileCheck, etc.).')) + group.add_argument( + "--dsymutil", + metavar="dsymutil", + dest="dsymutil", + help=textwrap.dedent("Specify which dsymutil to use."), + ) + group.add_argument( + "--llvm-tools-dir", + metavar="dir", + dest="llvm_tools_dir", + help=textwrap.dedent( + "The location of llvm tools used for testing (yaml2obj, FileCheck, etc.)." + ), + ) # Test filtering options - group = parser.add_argument_group('Test filtering options') - group.add_argument( - '-f', - metavar='filterspec', - action='append', - help=('Specify a filter, which looks like "TestModule.TestClass.test_name". '+ - 'You may also use shortened filters, such as '+ - '"TestModule.TestClass", "TestClass.test_name", or just "test_name".')) - group.add_argument( - '-p', - metavar='pattern', - help='Specify a regexp filename pattern for inclusion in the test suite') - group.add_argument('--excluded', metavar='exclusion-file', action='append', help=textwrap.dedent( - '''Specify a file for tests to exclude. File should contain lists of regular expressions for test files or methods, - with each list under a matching header (xfail files, xfail methods, skip files, skip methods)''')) - group.add_argument( - '-G', - '--category', - metavar='category', - action='append', - dest='categories_list', - help=textwrap.dedent('''Specify categories of test cases of interest. Can be specified more than once.''')) - group.add_argument( - '--skip-category', - metavar='category', - action='append', - dest='skip_categories', - help=textwrap.dedent('''Specify categories of test cases to skip. Takes precedence over -G. Can be specified more than once.''')) - group.add_argument( - '--xfail-category', - metavar='category', - action='append', - dest='xfail_categories', - help=textwrap.dedent('''Specify categories of test cases that are expected to fail. Can be specified more than once.''')) + group = parser.add_argument_group("Test filtering options") + group.add_argument( + "-f", + metavar="filterspec", + action="append", + help=( + 'Specify a filter, which looks like "TestModule.TestClass.test_name". ' + + "You may also use shortened filters, such as " + + '"TestModule.TestClass", "TestClass.test_name", or just "test_name".' + ), + ) + group.add_argument( + "-p", + metavar="pattern", + help="Specify a regexp filename pattern for inclusion in the test suite", + ) + group.add_argument( + "--excluded", + metavar="exclusion-file", + action="append", + help=textwrap.dedent( + """Specify a file for tests to exclude. File should contain lists of regular expressions for test files or methods, + with each list under a matching header (xfail files, xfail methods, skip files, skip methods)""" + ), + ) + group.add_argument( + "-G", + "--category", + metavar="category", + action="append", + dest="categories_list", + help=textwrap.dedent( + """Specify categories of test cases of interest. Can be specified more than once.""" + ), + ) + group.add_argument( + "--skip-category", + metavar="category", + action="append", + dest="skip_categories", + help=textwrap.dedent( + """Specify categories of test cases to skip. Takes precedence over -G. Can be specified more than once.""" + ), + ) + group.add_argument( + "--xfail-category", + metavar="category", + action="append", + dest="xfail_categories", + help=textwrap.dedent( + """Specify categories of test cases that are expected to fail. Can be specified more than once.""" + ), + ) # Configuration options - group = parser.add_argument_group('Configuration options') + group = parser.add_argument_group("Configuration options") group.add_argument( - '--framework', - metavar='framework-path', - help='The path to LLDB.framework') + "--framework", metavar="framework-path", help="The path to LLDB.framework" + ) group.add_argument( - '--executable', - metavar='executable-path', - help='The path to the lldb executable') + "--executable", + metavar="executable-path", + help="The path to the lldb executable", + ) group.add_argument( - '--out-of-tree-debugserver', - dest='out_of_tree_debugserver', - action='store_true', - help='A flag to indicate an out-of-tree debug server is being used') + "--out-of-tree-debugserver", + dest="out_of_tree_debugserver", + action="store_true", + help="A flag to indicate an out-of-tree debug server is being used", + ) group.add_argument( - '--dwarf-version', - metavar='dwarf_version', - dest='dwarf_version', + "--dwarf-version", + metavar="dwarf_version", + dest="dwarf_version", type=int, - help='Override the DWARF version.') + help="Override the DWARF version.", + ) group.add_argument( - '--setting', - metavar='SETTING=VALUE', - dest='settings', + "--setting", + metavar="SETTING=VALUE", + dest="settings", type=str, nargs=1, - action='append', - help='Run "setting set SETTING VALUE" before executing any test.') + action="append", + help='Run "setting set SETTING VALUE" before executing any test.', + ) group.add_argument( - '-y', + "-y", type=int, - metavar='count', - help="Specify the iteration count used to collect our benchmarks. An example is the number of times to do 'thread step-over' to measure stepping speed.") + metavar="count", + help="Specify the iteration count used to collect our benchmarks. An example is the number of times to do 'thread step-over' to measure stepping speed.", + ) group.add_argument( - '-#', + "-#", type=int, - metavar='sharp', - dest='sharp', - help='Repeat the test suite for a specified number of times') - group.add_argument('--channel', metavar='channel', dest='channels', action='append', help=textwrap.dedent( - "Specify the log channels (and optional categories) e.g. 'lldb all' or 'gdb-remote packets' if no categories are specified, 'default' is used")) - group.add_argument( - '--log-success', - dest='log_success', - action='store_true', - help="Leave logs/traces even for successful test runs (useful for creating reference log files during debugging.)") - group.add_argument( - '--codesign-identity', - metavar='Codesigning identity', - default='lldb_codesign', - help='The codesigning identity to use') - group.add_argument( - '--build-dir', - dest='test_build_dir', - metavar='Test build directory', - default='lldb-test-build.noindex', - help='The root build directory for the tests. It will be removed before running.') - group.add_argument( - '--lldb-module-cache-dir', - dest='lldb_module_cache_dir', - metavar='The clang module cache directory used by LLDB', - help='The clang module cache directory used by LLDB. Defaults to <test build directory>/module-cache-lldb.') - group.add_argument( - '--clang-module-cache-dir', - dest='clang_module_cache_dir', - metavar='The clang module cache directory used by Clang', - help='The clang module cache directory used in the Make files by Clang while building tests. Defaults to <test build directory>/module-cache-clang.') - group.add_argument( - '--lldb-libs-dir', - dest='lldb_libs_dir', - metavar='path', - help='The path to LLDB library directory (containing liblldb)') - group.add_argument( - '--enable-plugin', - dest='enabled_plugins', - action='append', + metavar="sharp", + dest="sharp", + help="Repeat the test suite for a specified number of times", + ) + group.add_argument( + "--channel", + metavar="channel", + dest="channels", + action="append", + help=textwrap.dedent( + "Specify the log channels (and optional categories) e.g. 'lldb all' or 'gdb-remote packets' if no categories are specified, 'default' is used" + ), + ) + group.add_argument( + "--log-success", + dest="log_success", + action="store_true", + help="Leave logs/traces even for successful test runs (useful for creating reference log files during debugging.)", + ) + group.add_argument( + "--codesign-identity", + metavar="Codesigning identity", + default="lldb_codesign", + help="The codesigning identity to use", + ) + group.add_argument( + "--build-dir", + dest="test_build_dir", + metavar="Test build directory", + default="lldb-test-build.noindex", + help="The root build directory for the tests. It will be removed before running.", + ) + group.add_argument( + "--lldb-module-cache-dir", + dest="lldb_module_cache_dir", + metavar="The clang module cache directory used by LLDB", + help="The clang module cache directory used by LLDB. Defaults to <test build directory>/module-cache-lldb.", + ) + group.add_argument( + "--clang-module-cache-dir", + dest="clang_module_cache_dir", + metavar="The clang module cache directory used by Clang", + help="The clang module cache directory used in the Make files by Clang while building tests. Defaults to <test build directory>/module-cache-clang.", + ) + group.add_argument( + "--lldb-libs-dir", + dest="lldb_libs_dir", + metavar="path", + help="The path to LLDB library directory (containing liblldb)", + ) + group.add_argument( + "--enable-plugin", + dest="enabled_plugins", + action="append", type=str, - metavar='A plugin whose tests will be enabled', - help='A plugin whose tests will be enabled. The only currently supported plugin is intel-pt.') + metavar="A plugin whose tests will be enabled", + help="A plugin whose tests will be enabled. The only currently supported plugin is intel-pt.", + ) # Configuration options - group = parser.add_argument_group('Remote platform options') - group.add_argument( - '--platform-name', - dest='lldb_platform_name', - metavar='platform-name', - help='The name of a remote platform to use') - group.add_argument( - '--platform-url', - dest='lldb_platform_url', - metavar='platform-url', - help='A LLDB platform URL to use when connecting to a remote platform to run the test suite') - group.add_argument( - '--platform-working-dir', - dest='lldb_platform_working_dir', - metavar='platform-working-dir', - help='The directory to use on the remote platform.') + group = parser.add_argument_group("Remote platform options") + group.add_argument( + "--platform-name", + dest="lldb_platform_name", + metavar="platform-name", + help="The name of a remote platform to use", + ) + group.add_argument( + "--platform-url", + dest="lldb_platform_url", + metavar="platform-url", + help="A LLDB platform URL to use when connecting to a remote platform to run the test suite", + ) + group.add_argument( + "--platform-working-dir", + dest="lldb_platform_working_dir", + metavar="platform-working-dir", + help="The directory to use on the remote platform.", + ) # Test-suite behaviour - group = parser.add_argument_group('Runtime behaviour options') - X('-d', 'Suspend the process after launch to wait indefinitely for a debugger to attach') - X('-t', 'Turn on tracing of lldb command and other detailed test executions') - group.add_argument( - '-u', - dest='unset_env_varnames', - metavar='variable', - action='append', - help='Specify an environment variable to unset before running the test cases. e.g., -u DYLD_INSERT_LIBRARIES -u MallocScribble') - group.add_argument( - '--env', - dest='set_env_vars', - metavar='variable', - action='append', - help='Specify an environment variable to set to the given value before running the test cases e.g.: --env CXXFLAGS=-O3 --env DYLD_INSERT_LIBRARIES') - group.add_argument( - '--inferior-env', - dest='set_inferior_env_vars', - metavar='variable', - action='append', - help='Specify an environment variable to set to the given value for the inferior.') - X('-v', 'Do verbose mode of unittest framework (print out each test case invocation)') - group.add_argument( - '--enable-crash-dialog', - dest='disable_crash_dialog', - action='store_false', - help='(Windows only) When LLDB crashes, display the Windows crash dialog.') + group = parser.add_argument_group("Runtime behaviour options") + X( + "-d", + "Suspend the process after launch to wait indefinitely for a debugger to attach", + ) + X("-t", "Turn on tracing of lldb command and other detailed test executions") + group.add_argument( + "-u", + dest="unset_env_varnames", + metavar="variable", + action="append", + help="Specify an environment variable to unset before running the test cases. e.g., -u DYLD_INSERT_LIBRARIES -u MallocScribble", + ) + group.add_argument( + "--env", + dest="set_env_vars", + metavar="variable", + action="append", + help="Specify an environment variable to set to the given value before running the test cases e.g.: --env CXXFLAGS=-O3 --env DYLD_INSERT_LIBRARIES", + ) + group.add_argument( + "--inferior-env", + dest="set_inferior_env_vars", + metavar="variable", + action="append", + help="Specify an environment variable to set to the given value for the inferior.", + ) + X( + "-v", + "Do verbose mode of unittest framework (print out each test case invocation)", + ) + group.add_argument( + "--enable-crash-dialog", + dest="disable_crash_dialog", + action="store_false", + help="(Windows only) When LLDB crashes, display the Windows crash dialog.", + ) group.set_defaults(disable_crash_dialog=True) # Remove the reference to our helper function del X - group = parser.add_argument_group('Test directories') + group = parser.add_argument_group("Test directories") group.add_argument( - 'args', - metavar='test-dir', - nargs='*', - help='Specify a list of directory names to search for test modules named after Test*.py (test discovery). If empty, search from the current working directory instead.') + "args", + metavar="test-dir", + nargs="*", + help="Specify a list of directory names to search for test modules named after Test*.py (test discovery). If empty, search from the current working directory instead.", + ) return parser diff --git a/lldb/packages/Python/lldbsuite/test/gdbclientutils.py b/lldb/packages/Python/lldbsuite/test/gdbclientutils.py index 7e78963..a0104d3 100644 --- a/lldb/packages/Python/lldbsuite/test/gdbclientutils.py +++ b/lldb/packages/Python/lldbsuite/test/gdbclientutils.py @@ -6,6 +6,7 @@ import socket import traceback from lldbsuite.support import seven + def checksum(message): """ Calculate the GDB server protocol checksum of the message. @@ -40,8 +41,8 @@ def escape_binary(message): out = "" for c in message: d = ord(c) - if d in (0x23, 0x24, 0x7d): - out += chr(0x7d) + if d in (0x23, 0x24, 0x7D): + out += chr(0x7D) out += chr(d ^ 0x20) else: out += c @@ -68,7 +69,7 @@ def hex_decode_bytes(hex_bytes): hex_len = len(hex_bytes) i = 0 while i < hex_len - 1: - out += chr(int(hex_bytes[i:i + 2], 16)) + out += chr(int(hex_bytes[i : i + 2], 16)) i += 2 return out @@ -87,7 +88,9 @@ class MockGDBServerResponder: registerCount = 40 packetLog = None - class RESPONSE_DISCONNECT: pass + + class RESPONSE_DISCONNECT: + pass def __init__(self): self.packetLog = [] @@ -113,19 +116,19 @@ class MockGDBServerResponder: if packet[0] == "G": # Gxxxxxxxxxxx # Gxxxxxxxxxxx;thread:1234; - return self.writeRegisters(packet[1:].split(';')[0]) + return self.writeRegisters(packet[1:].split(";")[0]) if packet[0] == "p": - regnum = packet[1:].split(';')[0] + regnum = packet[1:].split(";")[0] return self.readRegister(int(regnum, 16)) if packet[0] == "P": register, value = packet[1:].split("=") return self.writeRegister(int(register, 16), value) if packet[0] == "m": - addr, length = [int(x, 16) for x in packet[1:].split(',')] + addr, length = [int(x, 16) for x in packet[1:].split(",")] return self.readMemory(addr, length) if packet[0] == "M": location, encoded_data = packet[1:].split(":") - addr, length = [int(x, 16) for x in location.split(',')] + addr, length = [int(x, 16) for x in location.split(",")] return self.writeMemory(addr, encoded_data) if packet[0:7] == "qSymbol": return self.qSymbol(packet[8:]) @@ -152,25 +155,25 @@ class MockGDBServerResponder: return self.selectThread(packet[1], int(tid, 16)) if packet[0:6] == "qXfer:": obj, read, annex, location = packet[6:].split(":") - offset, length = [int(x, 16) for x in location.split(',')] + offset, length = [int(x, 16) for x in location.split(",")] data, has_more = self.qXferRead(obj, annex, offset, length) if data is not None: return self._qXferResponse(data, has_more) return "" if packet.startswith("vAttach;"): - pid = packet.partition(';')[2] + pid = packet.partition(";")[2] return self.vAttach(int(pid, 16)) if packet[0] == "Z": return self.setBreakpoint(packet) if packet.startswith("qThreadStopInfo"): - threadnum = int (packet[15:], 16) + threadnum = int(packet[15:], 16) return self.threadStopInfo(threadnum) if packet == "QThreadSuffixSupported": return self.QThreadSuffixSupported() if packet == "QListThreadsInStopReply": return self.QListThreadsInStopReply() if packet.startswith("qMemoryRegionInfo:"): - return self.qMemoryRegionInfo(int(packet.split(':')[1], 16)) + return self.qMemoryRegionInfo(int(packet.split(":")[1], 16)) if packet == "qQueryGDBServer": return self.qQueryGDBServer() if packet == "qHostInfo": @@ -178,7 +181,7 @@ class MockGDBServerResponder: if packet == "qGetWorkingDir": return self.qGetWorkingDir() if packet == "qOffsets": - return self.qOffsets(); + return self.qOffsets() if packet == "qProcessInfo": return self.qProcessInfo() if packet == "qsProcessInfo": @@ -200,7 +203,7 @@ class MockGDBServerResponder: if packet.startswith("QEnvironmentHexEncoded:"): return self.QEnvironmentHexEncoded(packet) if packet.startswith("qRegisterInfo"): - regnum = int(packet[len("qRegisterInfo"):], 16) + regnum = int(packet[len("qRegisterInfo") :], 16) return self.qRegisterInfo(regnum) if packet == "k": return self.k() @@ -346,6 +349,7 @@ class MockGDBServerResponder: Override the responder class to implement behavior suitable for the test at hand. """ + class UnexpectedPacketException(Exception): pass @@ -416,7 +420,8 @@ class ServerSocket(ServerChannel): class TCPServerSocket(ServerSocket): def __init__(self): family, type, proto, _, addr = socket.getaddrinfo( - "localhost", 0, proto=socket.IPPROTO_TCP)[0] + "localhost", 0, proto=socket.IPPROTO_TCP + )[0] super().__init__(family, type, proto, addr) def get_connect_address(self): @@ -441,10 +446,11 @@ class PtyServerSocket(ServerChannel): def __init__(self): import pty import tty + primary, secondary = pty.openpty() tty.setraw(primary) - self._primary = io.FileIO(primary, 'r+b') - self._secondary = io.FileIO(secondary, 'r+b') + self._primary = io.FileIO(primary, "r+b") + self._secondary = io.FileIO(secondary, "r+b") def get_connect_address(self): libc = ctypes.CDLL(None) @@ -465,7 +471,7 @@ class PtyServerSocket(ServerChannel): except OSError as e: # closing the pty results in EIO on Linux, convert it to EOF if e.errno == errno.EIO: - return b'' + return b"" raise def sendall(self, data): @@ -528,7 +534,9 @@ class MockGDBServer: except self.TerminateConnectionException: pass except Exception as e: - print("An exception happened when receiving the response from the gdb server. Closing the client...") + print( + "An exception happened when receiving the response from the gdb server. Closing the client..." + ) traceback.print_exc() finally: self._socket.close_connection() @@ -567,22 +575,23 @@ class MockGDBServer: # If we're looking at the start of the received data, that means # we're looking for the start of a new packet, denoted by a $. # It's also possible we'll see an ACK here, denoted by a + - if data[0] == '+': + if data[0] == "+": self._receivedData = data[1:] return self.PACKET_ACK if ord(data[0]) == 3: self._receivedData = data[1:] return self.PACKET_INTERRUPT - if data[0] == '$': + if data[0] == "$": i += 1 else: raise self.InvalidPacketException( - "Unexpected leading byte: %s" % data[0]) + "Unexpected leading byte: %s" % data[0] + ) # If we're looking beyond the start of the received data, then we're # looking for the end of the packet content, denoted by a #. # Note that we pick up searching from where we left off last time - while i < data_len and data[i] != '#': + while i < data_len and data[i] != "#": i += 1 # If there isn't enough data left for a checksum, just remember where @@ -596,14 +605,14 @@ class MockGDBServer: packet = data[1:i] i += 1 try: - check = int(data[i:i + 2], 16) + check = int(data[i : i + 2], 16) except ValueError: raise self.InvalidPacketException("Checksum is not valid hex") i += 2 if check != checksum(packet): raise self.InvalidPacketException( - "Checksum %02x does not match content %02x" % - (check, checksum(packet))) + "Checksum %02x does not match content %02x" % (check, checksum(packet)) + ) # remove parsed bytes from _receivedData and reset offset so parsing # can start on the next packet the next time around self._receivedData = data[i:] @@ -623,7 +632,7 @@ class MockGDBServer: # We'll handle the ack stuff here since it's not something any of the # tests will be concerned about, and it'll get turned off quickly anyway. if self._shouldSendAck: - self._socket.sendall(seven.bitcast_to_bytes('+')) + self._socket.sendall(seven.bitcast_to_bytes("+")) if packet == "QStartNoAckMode": self._shouldSendAck = False response = "OK" diff --git a/lldb/packages/Python/lldbsuite/test/lldb_pylint_helper.py b/lldb/packages/Python/lldbsuite/test/lldb_pylint_helper.py index c8b25df..b4b120b 100644 --- a/lldb/packages/Python/lldbsuite/test/lldb_pylint_helper.py +++ b/lldb/packages/Python/lldbsuite/test/lldb_pylint_helper.py @@ -113,16 +113,14 @@ def add_lldb_module_directory(): try: lldb_module_path = None - if platform.system() == 'Darwin': + if platform.system() == "Darwin": # Use xcrun to find the selected lldb. lldb_module_path = subprocess.check_output(["xcrun", "lldb", "-P"]) - elif platform.system() == 'Windows': - lldb_module_path = subprocess.check_output( - ["lldb.exe", "-P"], shell=True) + elif platform.system() == "Windows": + lldb_module_path = subprocess.check_output(["lldb.exe", "-P"], shell=True) else: # Use the shell to run lldb from the path. - lldb_module_path = subprocess.check_output( - ["lldb", "-P"], shell=True) + lldb_module_path = subprocess.check_output(["lldb", "-P"], shell=True) # Trim the result. if lldb_module_path is not None: @@ -145,24 +143,27 @@ def add_lldb_test_package_paths(check_dir): """ def child_dirs(parent_dir): - return [os.path.join(parent_dir, child) - for child in os.listdir(parent_dir) - if os.path.isdir(os.path.join(parent_dir, child))] + return [ + os.path.join(parent_dir, child) + for child in os.listdir(parent_dir) + if os.path.isdir(os.path.join(parent_dir, child)) + ] check_dir = os.path.realpath(check_dir) while check_dir and len(check_dir) > 0: # If the current directory contains a packages/Python # directory, add that directory to the path. - packages_python_child_dir = os.path.join( - check_dir, "packages", "Python") + packages_python_child_dir = os.path.join(check_dir, "packages", "Python") if os.path.exists(packages_python_child_dir): sys.path.insert(0, packages_python_child_dir) - sys.path.insert(0, os.path.join( - packages_python_child_dir, "test_runner", "lib")) + sys.path.insert( + 0, os.path.join(packages_python_child_dir, "test_runner", "lib") + ) # Handle third_party module/package directory. third_party_module_dir = os.path.join( - check_dir, "third_party", "Python", "module") + check_dir, "third_party", "Python", "module" + ) for child_dir in child_dirs(third_party_module_dir): # Yes, we embed the module in the module parent dir sys.path.insert(0, child_dir) diff --git a/lldb/packages/Python/lldbsuite/test/lldbbench.py b/lldb/packages/Python/lldbsuite/test/lldbbench.py index 4771044..139f5f1 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbbench.py +++ b/lldb/packages/Python/lldbsuite/test/lldbbench.py @@ -65,8 +65,7 @@ class Stopwatch(object): if self.__start__ is None: self.__start__ = time.time() else: - raise Exception( - "start() already called, did you forget to stop() first?") + raise Exception("start() already called, did you forget to stop() first?") # Return self to facilitate the context manager __enter__ protocol. return self @@ -96,8 +95,13 @@ class Stopwatch(object): # return numpy.std(self.__nums__) def __str__(self): - return "Avg: %f (Laps: %d, Total Elapsed Time: %f, min=%f, max=%f)" % (self.avg( - ), self.__laps__, self.__total_elapsed__, min(self.__nums__), max(self.__nums__)) + return "Avg: %f (Laps: %d, Total Elapsed Time: %f, min=%f, max=%f)" % ( + self.avg(), + self.__laps__, + self.__total_elapsed__, + min(self.__nums__), + max(self.__nums__), + ) class BenchBase(TestBase): diff --git a/lldb/packages/Python/lldbsuite/test/lldbdwarf.py b/lldb/packages/Python/lldbsuite/test/lldbdwarf.py index 5492960..1e421ce 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbdwarf.py +++ b/lldb/packages/Python/lldbsuite/test/lldbdwarf.py @@ -3,187 +3,185 @@ import lldb # DWARF Expression operators. -DW_OP_addr = 0x03 -DW_OP_deref = 0x06 -DW_OP_const1u = 0x08 -DW_OP_const1s = 0x09 -DW_OP_const2u = 0x0A -DW_OP_const2s = 0x0B -DW_OP_const4u = 0x0C -DW_OP_const4s = 0x0D -DW_OP_const8u = 0x0E -DW_OP_const8s = 0x0F -DW_OP_constu = 0x10 -DW_OP_consts = 0x11 -DW_OP_dup = 0x12 -DW_OP_drop = 0x13 -DW_OP_over = 0x14 -DW_OP_pick = 0x15 -DW_OP_swap = 0x16 -DW_OP_rot = 0x17 -DW_OP_xderef = 0x18 -DW_OP_abs = 0x19 -DW_OP_and = 0x1A -DW_OP_div = 0x1B -DW_OP_minus = 0x1C -DW_OP_mod = 0x1D -DW_OP_mul = 0x1E -DW_OP_neg = 0x1F -DW_OP_not = 0x20 -DW_OP_or = 0x21 -DW_OP_plus = 0x22 -DW_OP_plus_uconst = 0x23 -DW_OP_shl = 0x24 -DW_OP_shr = 0x25 -DW_OP_shra = 0x26 -DW_OP_xor = 0x27 -DW_OP_skip = 0x2F -DW_OP_bra = 0x28 -DW_OP_eq = 0x29 -DW_OP_ge = 0x2A -DW_OP_gt = 0x2B -DW_OP_le = 0x2C -DW_OP_lt = 0x2D -DW_OP_ne = 0x2E -DW_OP_lit0 = 0x30 -DW_OP_lit1 = 0x31 -DW_OP_lit2 = 0x32 -DW_OP_lit3 = 0x33 -DW_OP_lit4 = 0x34 -DW_OP_lit5 = 0x35 -DW_OP_lit6 = 0x36 -DW_OP_lit7 = 0x37 -DW_OP_lit8 = 0x38 -DW_OP_lit9 = 0x39 -DW_OP_lit10 = 0x3A -DW_OP_lit11 = 0x3B -DW_OP_lit12 = 0x3C -DW_OP_lit13 = 0x3D -DW_OP_lit14 = 0x3E -DW_OP_lit15 = 0x3F -DW_OP_lit16 = 0x40 -DW_OP_lit17 = 0x41 -DW_OP_lit18 = 0x42 -DW_OP_lit19 = 0x43 -DW_OP_lit20 = 0x44 -DW_OP_lit21 = 0x45 -DW_OP_lit22 = 0x46 -DW_OP_lit23 = 0x47 -DW_OP_lit24 = 0x48 -DW_OP_lit25 = 0x49 -DW_OP_lit26 = 0x4A -DW_OP_lit27 = 0x4B -DW_OP_lit28 = 0x4C -DW_OP_lit29 = 0x4D -DW_OP_lit30 = 0x4E -DW_OP_lit31 = 0x4F -DW_OP_reg0 = 0x50 -DW_OP_reg1 = 0x51 -DW_OP_reg2 = 0x52 -DW_OP_reg3 = 0x53 -DW_OP_reg4 = 0x54 -DW_OP_reg5 = 0x55 -DW_OP_reg6 = 0x56 -DW_OP_reg7 = 0x57 -DW_OP_reg8 = 0x58 -DW_OP_reg9 = 0x59 -DW_OP_reg10 = 0x5A -DW_OP_reg11 = 0x5B -DW_OP_reg12 = 0x5C -DW_OP_reg13 = 0x5D -DW_OP_reg14 = 0x5E -DW_OP_reg15 = 0x5F -DW_OP_reg16 = 0x60 -DW_OP_reg17 = 0x61 -DW_OP_reg18 = 0x62 -DW_OP_reg19 = 0x63 -DW_OP_reg20 = 0x64 -DW_OP_reg21 = 0x65 -DW_OP_reg22 = 0x66 -DW_OP_reg23 = 0x67 -DW_OP_reg24 = 0x68 -DW_OP_reg25 = 0x69 -DW_OP_reg26 = 0x6A -DW_OP_reg27 = 0x6B -DW_OP_reg28 = 0x6C -DW_OP_reg29 = 0x6D -DW_OP_reg30 = 0x6E -DW_OP_reg31 = 0x6F -DW_OP_breg0 = 0x70 -DW_OP_breg1 = 0x71 -DW_OP_breg2 = 0x72 -DW_OP_breg3 = 0x73 -DW_OP_breg4 = 0x74 -DW_OP_breg5 = 0x75 -DW_OP_breg6 = 0x76 -DW_OP_breg7 = 0x77 -DW_OP_breg8 = 0x78 -DW_OP_breg9 = 0x79 -DW_OP_breg10 = 0x7A -DW_OP_breg11 = 0x7B -DW_OP_breg12 = 0x7C -DW_OP_breg13 = 0x7D -DW_OP_breg14 = 0x7E -DW_OP_breg15 = 0x7F -DW_OP_breg16 = 0x80 -DW_OP_breg17 = 0x81 -DW_OP_breg18 = 0x82 -DW_OP_breg19 = 0x83 -DW_OP_breg20 = 0x84 -DW_OP_breg21 = 0x85 -DW_OP_breg22 = 0x86 -DW_OP_breg23 = 0x87 -DW_OP_breg24 = 0x88 -DW_OP_breg25 = 0x89 -DW_OP_breg26 = 0x8A -DW_OP_breg27 = 0x8B -DW_OP_breg28 = 0x8C -DW_OP_breg29 = 0x8D -DW_OP_breg30 = 0x8E -DW_OP_breg31 = 0x8F -DW_OP_regx = 0x90 -DW_OP_fbreg = 0x91 -DW_OP_bregx = 0x92 -DW_OP_piece = 0x93 -DW_OP_deref_size = 0x94 -DW_OP_xderef_size = 0x95 -DW_OP_nop = 0x96 -DW_OP_push_object_address = 0x97 -DW_OP_call2 = 0x98 -DW_OP_call4 = 0x99 -DW_OP_call_ref = 0x9A -DW_OP_form_tls_address = 0x9B -DW_OP_call_frame_cfa = 0x9C -DW_OP_bit_piece = 0x9D -DW_OP_implicit_value = 0x9E -DW_OP_stack_value = 0x9F -DW_OP_lo_user = 0xE0 -DW_OP_GNU_push_tls_address = 0xE0 -DW_OP_hi_user = 0xFF +DW_OP_addr = 0x03 +DW_OP_deref = 0x06 +DW_OP_const1u = 0x08 +DW_OP_const1s = 0x09 +DW_OP_const2u = 0x0A +DW_OP_const2s = 0x0B +DW_OP_const4u = 0x0C +DW_OP_const4s = 0x0D +DW_OP_const8u = 0x0E +DW_OP_const8s = 0x0F +DW_OP_constu = 0x10 +DW_OP_consts = 0x11 +DW_OP_dup = 0x12 +DW_OP_drop = 0x13 +DW_OP_over = 0x14 +DW_OP_pick = 0x15 +DW_OP_swap = 0x16 +DW_OP_rot = 0x17 +DW_OP_xderef = 0x18 +DW_OP_abs = 0x19 +DW_OP_and = 0x1A +DW_OP_div = 0x1B +DW_OP_minus = 0x1C +DW_OP_mod = 0x1D +DW_OP_mul = 0x1E +DW_OP_neg = 0x1F +DW_OP_not = 0x20 +DW_OP_or = 0x21 +DW_OP_plus = 0x22 +DW_OP_plus_uconst = 0x23 +DW_OP_shl = 0x24 +DW_OP_shr = 0x25 +DW_OP_shra = 0x26 +DW_OP_xor = 0x27 +DW_OP_skip = 0x2F +DW_OP_bra = 0x28 +DW_OP_eq = 0x29 +DW_OP_ge = 0x2A +DW_OP_gt = 0x2B +DW_OP_le = 0x2C +DW_OP_lt = 0x2D +DW_OP_ne = 0x2E +DW_OP_lit0 = 0x30 +DW_OP_lit1 = 0x31 +DW_OP_lit2 = 0x32 +DW_OP_lit3 = 0x33 +DW_OP_lit4 = 0x34 +DW_OP_lit5 = 0x35 +DW_OP_lit6 = 0x36 +DW_OP_lit7 = 0x37 +DW_OP_lit8 = 0x38 +DW_OP_lit9 = 0x39 +DW_OP_lit10 = 0x3A +DW_OP_lit11 = 0x3B +DW_OP_lit12 = 0x3C +DW_OP_lit13 = 0x3D +DW_OP_lit14 = 0x3E +DW_OP_lit15 = 0x3F +DW_OP_lit16 = 0x40 +DW_OP_lit17 = 0x41 +DW_OP_lit18 = 0x42 +DW_OP_lit19 = 0x43 +DW_OP_lit20 = 0x44 +DW_OP_lit21 = 0x45 +DW_OP_lit22 = 0x46 +DW_OP_lit23 = 0x47 +DW_OP_lit24 = 0x48 +DW_OP_lit25 = 0x49 +DW_OP_lit26 = 0x4A +DW_OP_lit27 = 0x4B +DW_OP_lit28 = 0x4C +DW_OP_lit29 = 0x4D +DW_OP_lit30 = 0x4E +DW_OP_lit31 = 0x4F +DW_OP_reg0 = 0x50 +DW_OP_reg1 = 0x51 +DW_OP_reg2 = 0x52 +DW_OP_reg3 = 0x53 +DW_OP_reg4 = 0x54 +DW_OP_reg5 = 0x55 +DW_OP_reg6 = 0x56 +DW_OP_reg7 = 0x57 +DW_OP_reg8 = 0x58 +DW_OP_reg9 = 0x59 +DW_OP_reg10 = 0x5A +DW_OP_reg11 = 0x5B +DW_OP_reg12 = 0x5C +DW_OP_reg13 = 0x5D +DW_OP_reg14 = 0x5E +DW_OP_reg15 = 0x5F +DW_OP_reg16 = 0x60 +DW_OP_reg17 = 0x61 +DW_OP_reg18 = 0x62 +DW_OP_reg19 = 0x63 +DW_OP_reg20 = 0x64 +DW_OP_reg21 = 0x65 +DW_OP_reg22 = 0x66 +DW_OP_reg23 = 0x67 +DW_OP_reg24 = 0x68 +DW_OP_reg25 = 0x69 +DW_OP_reg26 = 0x6A +DW_OP_reg27 = 0x6B +DW_OP_reg28 = 0x6C +DW_OP_reg29 = 0x6D +DW_OP_reg30 = 0x6E +DW_OP_reg31 = 0x6F +DW_OP_breg0 = 0x70 +DW_OP_breg1 = 0x71 +DW_OP_breg2 = 0x72 +DW_OP_breg3 = 0x73 +DW_OP_breg4 = 0x74 +DW_OP_breg5 = 0x75 +DW_OP_breg6 = 0x76 +DW_OP_breg7 = 0x77 +DW_OP_breg8 = 0x78 +DW_OP_breg9 = 0x79 +DW_OP_breg10 = 0x7A +DW_OP_breg11 = 0x7B +DW_OP_breg12 = 0x7C +DW_OP_breg13 = 0x7D +DW_OP_breg14 = 0x7E +DW_OP_breg15 = 0x7F +DW_OP_breg16 = 0x80 +DW_OP_breg17 = 0x81 +DW_OP_breg18 = 0x82 +DW_OP_breg19 = 0x83 +DW_OP_breg20 = 0x84 +DW_OP_breg21 = 0x85 +DW_OP_breg22 = 0x86 +DW_OP_breg23 = 0x87 +DW_OP_breg24 = 0x88 +DW_OP_breg25 = 0x89 +DW_OP_breg26 = 0x8A +DW_OP_breg27 = 0x8B +DW_OP_breg28 = 0x8C +DW_OP_breg29 = 0x8D +DW_OP_breg30 = 0x8E +DW_OP_breg31 = 0x8F +DW_OP_regx = 0x90 +DW_OP_fbreg = 0x91 +DW_OP_bregx = 0x92 +DW_OP_piece = 0x93 +DW_OP_deref_size = 0x94 +DW_OP_xderef_size = 0x95 +DW_OP_nop = 0x96 +DW_OP_push_object_address = 0x97 +DW_OP_call2 = 0x98 +DW_OP_call4 = 0x99 +DW_OP_call_ref = 0x9A +DW_OP_form_tls_address = 0x9B +DW_OP_call_frame_cfa = 0x9C +DW_OP_bit_piece = 0x9D +DW_OP_implicit_value = 0x9E +DW_OP_stack_value = 0x9F +DW_OP_lo_user = 0xE0 +DW_OP_GNU_push_tls_address = 0xE0 +DW_OP_hi_user = 0xFF class DwarfOpcodeParser(object): - def updateRegInfoBitsize(self, reg_info, byte_order): - """ Update the regInfo bit size. """ + """Update the regInfo bit size.""" # Evaluate Dwarf Expression - expr_result = self.evaluateDwarfExpression(reg_info["dynamic_size_dwarf_expr_bytes"], - byte_order) + expr_result = self.evaluateDwarfExpression( + reg_info["dynamic_size_dwarf_expr_bytes"], byte_order + ) if expr_result == 0: reg_info["bitsize"] = 32 elif expr_result == 1: reg_info["bitsize"] = 64 - def evaluateDwarfExpression(self, dwarf_opcode, byte_order): - """Evaluate Dwarf Expression. """ + """Evaluate Dwarf Expression.""" - dwarf_opcode = [dwarf_opcode[i:i+2] for i in range(0,len(dwarf_opcode),2)] + dwarf_opcode = [dwarf_opcode[i : i + 2] for i in range(0, len(dwarf_opcode), 2)] dwarf_data = [] for index in range(len(dwarf_opcode)): - if index < len(dwarf_opcode): val = int(dwarf_opcode[index], 16) else: @@ -197,9 +195,16 @@ class DwarfOpcodeParser(object): self.reset_test_sequence() # Read register value self.test_sequence.add_log_lines( - ["read packet: $p{0:x}#00".format(reg_no), - {"direction": "send", "regex": r"^\$([0-9a-fA-F]+)#", - "capture": {1: "p_response"}}],True) + [ + "read packet: $p{0:x}#00".format(reg_no), + { + "direction": "send", + "regex": r"^\$([0-9a-fA-F]+)#", + "capture": {1: "p_response"}, + }, + ], + True, + ) Context = self.expect_gdbremote_sequence() self.assertIsNotNone(Context) @@ -207,13 +212,19 @@ class DwarfOpcodeParser(object): self.assertIsNotNone(p_response) if byte_order == lldb.eByteOrderLittle: - # In case of little endian - # first decode the HEX ASCII bytes and then reverse it - # to get actual value of SR register - p_response = "".join(reversed([p_response[i:i+2] for i in range(0, - len(p_response),2)])) + # In case of little endian + # first decode the HEX ASCII bytes and then reverse it + # to get actual value of SR register + p_response = "".join( + reversed( + [ + p_response[i : i + 2] + for i in range(0, len(p_response), 2) + ] + ) + ) # Push register value - dwarf_data.append(int(p_response,16)) + dwarf_data.append(int(p_response, 16)) elif val == DW_OP_lit1: # Push literal 1 @@ -252,4 +263,3 @@ class DwarfOpcodeParser(object): self.assertTrue(len(dwarf_data) == 1) expr_result = dwarf_data.pop() return expr_result - diff --git a/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py b/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py index 320ae0d..459460b 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py +++ b/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py @@ -4,6 +4,7 @@ import lldb from lldbsuite.test.lldbtest import * from lldbsuite.test.gdbclientutils import * + class GDBRemoteTestBase(TestBase): """ Base class for GDB client tests. @@ -52,8 +53,9 @@ class GDBRemoteTestBase(TestBase): """ listener = self.dbg.GetListener() error = lldb.SBError() - process = target.ConnectRemote(listener, - self.server.get_connect_url(), "gdb-remote", error) + process = target.ConnectRemote( + listener, self.server.get_connect_url(), "gdb-remote", error + ) self.assertTrue(error.Success(), error.description) self.assertTrue(process, PROCESS_IS_VALID) return process @@ -79,8 +81,10 @@ class GDBRemoteTestBase(TestBase): i += 1 j += 1 if i < len(packets): - self.fail(u"Did not receive: %s\nLast 10 packets:\n\t%s" % - (packets[i], u'\n\t'.join(log))) + self.fail( + "Did not receive: %s\nLast 10 packets:\n\t%s" + % (packets[i], "\n\t".join(log)) + ) class GDBPlatformClientTestBase(GDBRemoteTestBase): diff --git a/lldb/packages/Python/lldbsuite/test/lldbinline.py b/lldb/packages/Python/lldbsuite/test/lldbinline.py index e8d4d4d..6fb23ee 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbinline.py +++ b/lldb/packages/Python/lldbsuite/test/lldbinline.py @@ -15,25 +15,25 @@ from . import configuration from . import lldbutil from .decorators import * + def source_type(filename): _, extension = os.path.splitext(filename) return { - '.c': 'C_SOURCES', - '.cpp': 'CXX_SOURCES', - '.cxx': 'CXX_SOURCES', - '.cc': 'CXX_SOURCES', - '.m': 'OBJC_SOURCES', - '.mm': 'OBJCXX_SOURCES' + ".c": "C_SOURCES", + ".cpp": "CXX_SOURCES", + ".cxx": "CXX_SOURCES", + ".cc": "CXX_SOURCES", + ".m": "OBJC_SOURCES", + ".mm": "OBJCXX_SOURCES", }.get(extension, None) class CommandParser: - def __init__(self): self.breakpoints = [] def parse_one_command(self, line): - parts = line.split('//%') + parts = line.split("//%") command = None new_breakpoint = True @@ -46,7 +46,7 @@ class CommandParser: def parse_source_files(self, source_files): for source_file in source_files: - file_handle = io.open(source_file, encoding='utf-8') + file_handle = io.open(source_file, encoding="utf-8") lines = file_handle.readlines() line_number = 0 # non-NULL means we're looking through whitespace to find @@ -62,30 +62,31 @@ class CommandParser: if command is not None: if current_breakpoint is None: current_breakpoint = {} - current_breakpoint['file_name'] = source_file - current_breakpoint['line_number'] = line_number - current_breakpoint['command'] = command + current_breakpoint["file_name"] = source_file + current_breakpoint["line_number"] = line_number + current_breakpoint["command"] = command self.breakpoints.append(current_breakpoint) else: - current_breakpoint['command'] = current_breakpoint[ - 'command'] + "\n" + command + current_breakpoint["command"] = ( + current_breakpoint["command"] + "\n" + command + ) for bkpt in self.breakpoints: - bkpt['command'] = textwrap.dedent(bkpt['command']) + bkpt["command"] = textwrap.dedent(bkpt["command"]) def set_breakpoints(self, target): for breakpoint in self.breakpoints: - breakpoint['breakpoint'] = target.BreakpointCreateByLocation( - breakpoint['file_name'], breakpoint['line_number']) + breakpoint["breakpoint"] = target.BreakpointCreateByLocation( + breakpoint["file_name"], breakpoint["line_number"] + ) def handle_breakpoint(self, test, breakpoint_id): for breakpoint in self.breakpoints: - if breakpoint['breakpoint'].GetID() == breakpoint_id: - test.execute_user_command(breakpoint['command']) + if breakpoint["breakpoint"].GetID() == breakpoint_id: + test.execute_user_command(breakpoint["command"]) return class InlineTest(TestBase): - def getBuildDirBasename(self): return self.__class__.__name__ + "." + self.testMethodName @@ -103,17 +104,17 @@ class InlineTest(TestBase): else: categories[t] = [f] - with open(makefilePath, 'w+') as makefile: + with open(makefilePath, "w+") as makefile: for t in list(categories.keys()): line = t + " := " + " ".join(categories[t]) makefile.write(line + "\n") - if ('OBJCXX_SOURCES' in list(categories.keys())) or \ - ('OBJC_SOURCES' in list(categories.keys())): - makefile.write( - "LDFLAGS = $(CFLAGS) -lobjc -framework Foundation\n") + if ("OBJCXX_SOURCES" in list(categories.keys())) or ( + "OBJC_SOURCES" in list(categories.keys()) + ): + makefile.write("LDFLAGS = $(CFLAGS) -lobjc -framework Foundation\n") - if ('CXX_SOURCES' in list(categories.keys())): + if "CXX_SOURCES" in list(categories.keys()): makefile.write("CXXFLAGS += -std=c++11\n") makefile.write("include Makefile.rules\n") @@ -135,8 +136,7 @@ class InlineTest(TestBase): def do_test(self): exe = self.getBuildArtifact("a.out") - source_files = [f for f in os.listdir(self.getSourceDir()) - if source_type(f)] + source_files = [f for f in os.listdir(self.getSourceDir()) if source_type(f)] target = self.dbg.CreateTarget(exe) parser = CommandParser() @@ -150,18 +150,19 @@ class InlineTest(TestBase): while lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint): hit_breakpoints += 1 - thread = lldbutil.get_stopped_thread( - process, lldb.eStopReasonBreakpoint) + thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint) for bp_id in self._get_breakpoint_ids(thread): parser.handle_breakpoint(self, bp_id) process.Continue() - self.assertTrue(hit_breakpoints > 0, - "inline test did not hit a single breakpoint") + self.assertTrue( + hit_breakpoints > 0, "inline test did not hit a single breakpoint" + ) # Either the process exited or the stepping plan is complete. - self.assertTrue(process.GetState() in [lldb.eStateStopped, - lldb.eStateExited], - PROCESS_EXITED) + self.assertTrue( + process.GetState() in [lldb.eStateStopped, lldb.eStateExited], + PROCESS_EXITED, + ) def check_expression(self, expression, expected_result, use_summary=True): value = self.frame().EvaluateExpression(expression) @@ -173,8 +174,7 @@ class InlineTest(TestBase): answer = value.GetSummary() else: answer = value.GetValue() - report_str = "%s expected: %s got: %s" % ( - expression, expected_result, answer) + report_str = "%s expected: %s got: %s" % (expression, expected_result, answer) self.assertTrue(answer == expected_result, report_str) @@ -183,13 +183,12 @@ def ApplyDecoratorsToFunction(func, decorators): if isinstance(decorators, list): for decorator in decorators: tmp = decorator(tmp) - elif hasattr(decorators, '__call__'): + elif hasattr(decorators, "__call__"): tmp = decorators(tmp) return tmp -def MakeInlineTest(__file, __globals, decorators=None, name=None, - build_dict=None): +def MakeInlineTest(__file, __globals, decorators=None, name=None, build_dict=None): # Adjust the filename if it ends in .pyc. We want filenames to # reflect the source python file, not the compiled variant. if __file is not None and __file.endswith(".pyc"): @@ -203,8 +202,9 @@ def MakeInlineTest(__file, __globals, decorators=None, name=None, test_func = ApplyDecoratorsToFunction(InlineTest._test, decorators) # Build the test case - test_class = type(name, (InlineTest,), dict(test=test_func, - name=name, _build_dict=build_dict)) + test_class = type( + name, (InlineTest,), dict(test=test_func, name=name, _build_dict=build_dict) + ) # Add the test case to the globals, and hide InlineTest __globals.update({name: test_class}) diff --git a/lldb/packages/Python/lldbsuite/test/lldbpexpect.py b/lldb/packages/Python/lldbsuite/test/lldbpexpect.py index f298cc5..b95b0e8 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbpexpect.py +++ b/lldb/packages/Python/lldbsuite/test/lldbpexpect.py @@ -10,34 +10,40 @@ from .lldbtest import * from . import lldbutil from lldbsuite.test.decorators import * + @skipIfRemote @skipIfWindows # llvm.org/pr22274: need a pexpect replacement for windows class PExpectTest(TestBase): - NO_DEBUG_INFO_TESTCASE = True PROMPT = "(lldb) " def expect_prompt(self): self.child.expect_exact(self.PROMPT) - def launch(self, executable=None, extra_args=None, timeout=60, - dimensions=None, run_under=None, post_spawn=None, - use_colors=False): - logfile = getattr(sys.stdout, 'buffer', - sys.stdout) if self.TraceOn() else None + def launch( + self, + executable=None, + extra_args=None, + timeout=60, + dimensions=None, + run_under=None, + post_spawn=None, + use_colors=False, + ): + logfile = getattr(sys.stdout, "buffer", sys.stdout) if self.TraceOn() else None args = [] if run_under is not None: args += run_under - args += [lldbtest_config.lldbExec, '--no-lldbinit'] + args += [lldbtest_config.lldbExec, "--no-lldbinit"] if not use_colors: - args.append('--no-use-colors') + args.append("--no-use-colors") for cmd in self.setUpCommands(): if "use-color false" in cmd and use_colors: continue - args += ['-O', cmd] + args += ["-O", cmd] if executable is not None: - args += ['--file', executable] + args += ["--file", executable] if extra_args is not None: args.extend(extra_args) @@ -46,11 +52,17 @@ class PExpectTest(TestBase): env["HOME"] = self.getBuildDir() import pexpect + self.child = pexpect.spawn( - args[0], args=args[1:], logfile=logfile, - timeout=timeout, dimensions=dimensions, env=env) - self.child.ptyproc.delayafterclose = timeout/10 - self.child.ptyproc.delayafterterminate = timeout/10 + args[0], + args=args[1:], + logfile=logfile, + timeout=timeout, + dimensions=dimensions, + env=env, + ) + self.child.ptyproc.delayafterclose = timeout / 10 + self.child.ptyproc.delayafterterminate = timeout / 10 if post_spawn is not None: post_spawn() @@ -66,11 +78,10 @@ class PExpectTest(TestBase): self.expect_prompt() def expect(self, cmd, substrs=None): - self.assertNotIn('\n', cmd) + self.assertNotIn("\n", cmd) # If 'substrs' is a string then this code would just check that every # character of the string is in the output. - assert not isinstance(substrs, str), \ - "substrs must be a collection of strings" + assert not isinstance(substrs, str), "substrs must be a collection of strings" self.child.sendline(cmd) if substrs is not None: diff --git a/lldb/packages/Python/lldbsuite/test/lldbplatform.py b/lldb/packages/Python/lldbsuite/test/lldbplatform.py index 4418942..fdf5030 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbplatform.py +++ b/lldb/packages/Python/lldbsuite/test/lldbplatform.py @@ -8,9 +8,23 @@ import itertools # LLDB modules import lldb -windows, linux, macosx, darwin, ios, tvos, watchos, bridgeos, darwin_all, \ - darwin_embedded, darwin_simulator, freebsd, netbsd, bsd_all, android \ - = range(15) +( + windows, + linux, + macosx, + darwin, + ios, + tvos, + watchos, + bridgeos, + darwin_all, + darwin_embedded, + darwin_simulator, + freebsd, + netbsd, + bsd_all, + android, +) = range(15) __darwin_embedded = ["ios", "tvos", "watchos", "bridgeos"] __darwin_simulators = ["iphonesimulator", "watchsimulator", "appletvsimulator"] @@ -30,12 +44,11 @@ __name_lookup = { freebsd: ["freebsd"], netbsd: ["netbsd"], bsd_all: ["freebsd", "netbsd"], - android: ["android"] + android: ["android"], } def translate(values): - if isinstance(values, int): # This is a value from the platform enumeration, translate it. return __name_lookup[values] diff --git a/lldb/packages/Python/lldbsuite/test/lldbplatformutil.py b/lldb/packages/Python/lldbsuite/test/lldbplatformutil.py index 56d4024..4570c51 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbplatformutil.py +++ b/lldb/packages/Python/lldbsuite/test/lldbplatformutil.py @@ -20,23 +20,24 @@ import lldbsuite.test.lldbplatform as lldbplatform def check_first_register_readable(test_case): arch = test_case.getArchitecture() - if arch in ['x86_64', 'i386']: - test_case.expect("register read eax", substrs=['eax = 0x']) - elif arch in ['arm', 'armv7', 'armv7k', 'armv8l', 'armv7l']: - test_case.expect("register read r0", substrs=['r0 = 0x']) - elif arch in ['aarch64', 'arm64', 'arm64e', 'arm64_32']: - test_case.expect("register read x0", substrs=['x0 = 0x']) + if arch in ["x86_64", "i386"]: + test_case.expect("register read eax", substrs=["eax = 0x"]) + elif arch in ["arm", "armv7", "armv7k", "armv8l", "armv7l"]: + test_case.expect("register read r0", substrs=["r0 = 0x"]) + elif arch in ["aarch64", "arm64", "arm64e", "arm64_32"]: + test_case.expect("register read x0", substrs=["x0 = 0x"]) elif re.match("mips", arch): - test_case.expect("register read zero", substrs=['zero = 0x']) - elif arch in ['s390x']: - test_case.expect("register read r0", substrs=['r0 = 0x']) - elif arch in ['powerpc64le']: - test_case.expect("register read r0", substrs=['r0 = 0x']) + test_case.expect("register read zero", substrs=["zero = 0x"]) + elif arch in ["s390x"]: + test_case.expect("register read r0", substrs=["r0 = 0x"]) + elif arch in ["powerpc64le"]: + test_case.expect("register read r0", substrs=["r0 = 0x"]) else: # TODO: Add check for other architectures test_case.fail( - "Unsupported architecture for test case (arch: %s)" % - test_case.getArchitecture()) + "Unsupported architecture for test case (arch: %s)" + % test_case.getArchitecture() + ) def _run_adb_command(cmd, device_id): @@ -44,10 +45,7 @@ def _run_adb_command(cmd, device_id): if device_id: device_id_args = ["-s", device_id] full_cmd = ["adb"] + device_id_args + cmd - p = subprocess.Popen( - full_cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + p = subprocess.Popen(full_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate() return p.returncode, stdout, stderr @@ -55,26 +53,28 @@ def _run_adb_command(cmd, device_id): def target_is_android(): return configuration.lldb_platform_name == "remote-android" + def android_device_api(): - if not hasattr(android_device_api, 'result'): + if not hasattr(android_device_api, "result"): assert configuration.lldb_platform_url is not None device_id = None parsed_url = urlparse(configuration.lldb_platform_url) host_name = parsed_url.netloc.split(":")[0] - if host_name != 'localhost': + if host_name != "localhost": device_id = host_name - if device_id.startswith('[') and device_id.endswith(']'): + if device_id.startswith("[") and device_id.endswith("]"): device_id = device_id[1:-1] retcode, stdout, stderr = _run_adb_command( - ["shell", "getprop", "ro.build.version.sdk"], device_id) + ["shell", "getprop", "ro.build.version.sdk"], device_id + ) if retcode == 0: android_device_api.result = int(stdout) else: raise LookupError( ">>> Unable to determine the API level of the Android device.\n" ">>> stdout:\n%s\n" - ">>> stderr:\n%s\n" % - (stdout, stderr)) + ">>> stderr:\n%s\n" % (stdout, stderr) + ) return android_device_api.result @@ -102,14 +102,14 @@ def _get_platform_os(p): # Use the triple to determine the platform if set. triple = p.GetTriple() if triple: - platform = triple.split('-')[2] - if platform.startswith('freebsd'): - platform = 'freebsd' - elif platform.startswith('netbsd'): - platform = 'netbsd' + platform = triple.split("-")[2] + if platform.startswith("freebsd"): + platform = "freebsd" + elif platform.startswith("netbsd"): + platform = "netbsd" return platform - return '' + return "" def getHostPlatform(): @@ -120,16 +120,17 @@ def getHostPlatform(): def getDarwinOSTriples(): return lldbplatform.translate(lldbplatform.darwin_all) + def getPlatform(): """Returns the target platform which the tests are running on.""" # Use the Apple SDK to determine the platform if set. if configuration.apple_sdk: platform = configuration.apple_sdk - dot = platform.find('.') + dot = platform.find(".") if dot != -1: platform = platform[:dot] - if platform == 'iphoneos': - platform = 'ios' + if platform == "iphoneos": + platform = "ios" return platform return _get_platform_os(lldb.selected_platform) @@ -147,9 +148,9 @@ def findMainThreadCheckerDylib(): if getPlatform() in lldbplatform.translate(lldbplatform.darwin_embedded): return "/Developer/usr/lib/libMainThreadChecker.dylib" - with os.popen('xcode-select -p') as output: + with os.popen("xcode-select -p") as output: xcode_developer_path = output.read().strip() - mtc_dylib_path = '%s/usr/lib/libMainThreadChecker.dylib' % xcode_developer_path + mtc_dylib_path = "%s/usr/lib/libMainThreadChecker.dylib" % xcode_developer_path if os.path.isfile(mtc_dylib_path): return mtc_dylib_path @@ -159,7 +160,9 @@ def findMainThreadCheckerDylib(): class _PlatformContext(object): """Value object class which contains platform-specific options.""" - def __init__(self, shlib_environment_var, shlib_path_separator, shlib_prefix, shlib_extension): + def __init__( + self, shlib_environment_var, shlib_path_separator, shlib_prefix, shlib_extension + ): self.shlib_environment_var = shlib_environment_var self.shlib_path_separator = shlib_path_separator self.shlib_prefix = shlib_prefix @@ -168,16 +171,18 @@ class _PlatformContext(object): def createPlatformContext(): if platformIsDarwin(): - return _PlatformContext('DYLD_LIBRARY_PATH', ':', 'lib', 'dylib') + return _PlatformContext("DYLD_LIBRARY_PATH", ":", "lib", "dylib") elif getPlatform() in ("freebsd", "linux", "netbsd"): - return _PlatformContext('LD_LIBRARY_PATH', ':', 'lib', 'so') + return _PlatformContext("LD_LIBRARY_PATH", ":", "lib", "so") else: - return _PlatformContext('PATH', ';', '', 'dll') + return _PlatformContext("PATH", ";", "", "dll") def hasChattyStderr(test_case): """Some targets produce garbage on the standard error output. This utility function determines whether the tests can be strict about the expected stderr contents.""" - if match_android_device(test_case.getArchitecture(), ['aarch64'], range(22, 25+1)): + if match_android_device( + test_case.getArchitecture(), ["aarch64"], range(22, 25 + 1) + ): return True # The dynamic linker on the device will complain about unknown DT entries return False diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py index 0ca0fac..a712f6b 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbtest.py +++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py @@ -68,8 +68,7 @@ from lldbsuite.test_event import build_exception # LLDB_COMMAND_TRACE is set from '-t' option. # By default, traceAlways is False. -if "LLDB_COMMAND_TRACE" in os.environ and os.environ[ - "LLDB_COMMAND_TRACE"] == "YES": +if "LLDB_COMMAND_TRACE" in os.environ and os.environ["LLDB_COMMAND_TRACE"] == "YES": traceAlways = True else: traceAlways = False @@ -132,13 +131,17 @@ STOPPED_DUE_TO_ASSERT = "Process should be stopped due to an assertion" STOPPED_DUE_TO_BREAKPOINT = "Process should be stopped due to breakpoint" STOPPED_DUE_TO_BREAKPOINT_WITH_STOP_REASON_AS = "%s, %s" % ( - STOPPED_DUE_TO_BREAKPOINT, "instead, the actual stop reason is: '%s'") + STOPPED_DUE_TO_BREAKPOINT, + "instead, the actual stop reason is: '%s'", +) STOPPED_DUE_TO_BREAKPOINT_CONDITION = "Stopped due to breakpoint condition" STOPPED_DUE_TO_BREAKPOINT_IGNORE_COUNT = "Stopped due to breakpoint and ignore count" -STOPPED_DUE_TO_BREAKPOINT_JITTED_CONDITION = "Stopped due to breakpoint jitted condition" +STOPPED_DUE_TO_BREAKPOINT_JITTED_CONDITION = ( + "Stopped due to breakpoint jitted condition" +) STOPPED_DUE_TO_SIGNAL = "Process state is stopped due to signal" @@ -176,49 +179,56 @@ WATCHPOINT_CREATED = "Watchpoint created successfully" def CMD_MSG(str): - '''A generic "Command '%s' did not return successfully" message generator.''' + """A generic "Command '%s' did not return successfully" message generator.""" return "Command '%s' did not return successfully" % str def COMPLETION_MSG(str_before, str_after, completions): - '''A generic assertion failed message generator for the completion mechanism.''' - return ("'%s' successfully completes to '%s', but completions were:\n%s" - % (str_before, str_after, "\n".join(completions))) + """A generic assertion failed message generator for the completion mechanism.""" + return "'%s' successfully completes to '%s', but completions were:\n%s" % ( + str_before, + str_after, + "\n".join(completions), + ) def EXP_MSG(str, actual, exe): - '''A generic "'%s' returned unexpected result" message generator if exe. - Otherwise, it generates "'%s' does not match expected result" message.''' + """A generic "'%s' returned unexpected result" message generator if exe. + Otherwise, it generates "'%s' does not match expected result" message.""" return "'%s' %s result, got '%s'" % ( - str, 'returned unexpected' if exe else 'does not match expected', actual.strip()) + str, + "returned unexpected" if exe else "does not match expected", + actual.strip(), + ) def SETTING_MSG(setting): - '''A generic "Value of setting '%s' is not correct" message generator.''' + """A generic "Value of setting '%s' is not correct" message generator.""" return "Value of setting '%s' is not correct" % setting def line_number(filename, string_to_match): """Helper function to return the line number of the first matched string.""" - with io.open(filename, mode='r', encoding="utf-8") as f: + with io.open(filename, mode="r", encoding="utf-8") as f: for i, line in enumerate(f): if line.find(string_to_match) != -1: # Found our match. return i + 1 - raise Exception( - "Unable to find '%s' within file %s" % - (string_to_match, filename)) + raise Exception("Unable to find '%s' within file %s" % (string_to_match, filename)) + def get_line(filename, line_number): """Return the text of the line at the 1-based line number.""" - with io.open(filename, mode='r', encoding="utf-8") as f: + with io.open(filename, mode="r", encoding="utf-8") as f: return f.readlines()[line_number - 1] + def pointer_size(): """Return the pointer size of the host system.""" import ctypes - a_pointer = ctypes.c_void_p(0xffff) + + a_pointer = ctypes.c_void_p(0xFFFF) return 8 * ctypes.sizeof(a_pointer) @@ -226,7 +236,7 @@ def is_exe(fpath): """Returns true if fpath is an executable.""" if fpath == None: return False - if sys.platform == 'win32': + if sys.platform == "win32": if not fpath.endswith(".exe"): fpath += ".exe" return os.path.isfile(fpath) and os.access(fpath, os.X_OK) @@ -245,9 +255,17 @@ def which(program): return exe_file return None + class ValueCheck: - def __init__(self, name=None, value=None, type=None, summary=None, - children=None, dereference=None): + def __init__( + self, + name=None, + value=None, + type=None, + summary=None, + children=None, + dereference=None, + ): """ :param name: The name that the SBValue should have. None if the summary should not be checked. @@ -287,28 +305,28 @@ class ValueCheck: test_base.assertSuccess(val.GetError()) # Python 3.6 doesn't declare a `re.Pattern` type, get the dynamic type. - pattern_type = type(re.compile('')) + pattern_type = type(re.compile("")) if self.expect_name: - test_base.assertEqual(self.expect_name, val.GetName(), - this_error_msg) + test_base.assertEqual(self.expect_name, val.GetName(), this_error_msg) if self.expect_value: if isinstance(self.expect_value, pattern_type): - test_base.assertRegex(val.GetValue(), self.expect_value, - this_error_msg) + test_base.assertRegex(val.GetValue(), self.expect_value, this_error_msg) else: - test_base.assertEqual(self.expect_value, val.GetValue(), - this_error_msg) + test_base.assertEqual(self.expect_value, val.GetValue(), this_error_msg) if self.expect_type: - test_base.assertEqual(self.expect_type, val.GetDisplayTypeName(), - this_error_msg) + test_base.assertEqual( + self.expect_type, val.GetDisplayTypeName(), this_error_msg + ) if self.expect_summary: if isinstance(self.expect_summary, pattern_type): - test_base.assertRegex(val.GetSummary(), self.expect_summary, - this_error_msg) + test_base.assertRegex( + val.GetSummary(), self.expect_summary, this_error_msg + ) else: - test_base.assertEqual(self.expect_summary, val.GetSummary(), - this_error_msg) + test_base.assertEqual( + self.expect_summary, val.GetSummary(), this_error_msg + ) if self.children is not None: self.check_value_children(test_base, val, error_msg) @@ -335,6 +353,7 @@ class ValueCheck: child_error = "Checking child with index " + str(i) + ":\n" + error_msg expected_child.check_value(test_base, actual_child, child_error) + class recording(io.StringIO): """ A nice little context manager for recording the debugger interactions into @@ -371,7 +390,6 @@ class recording(io.StringIO): class _BaseProcess(object, metaclass=abc.ABCMeta): - @abc.abstractproperty def pid(self): """Returns process PID if has been launched already.""" @@ -386,7 +404,6 @@ class _BaseProcess(object, metaclass=abc.ABCMeta): class _LocalProcess(_BaseProcess): - def __init__(self, trace_on): self._proc = None self._trace_on = trace_on @@ -397,26 +414,24 @@ class _LocalProcess(_BaseProcess): return self._proc.pid def launch(self, executable, args, extra_env): - env=None + env = None if extra_env: env = dict(os.environ) env.update([kv.split("=", 1) for kv in extra_env]) self._proc = Popen( [executable] + args, - stdout=open( - os.devnull) if not self._trace_on else None, + stdout=open(os.devnull) if not self._trace_on else None, stdin=PIPE, - env=env) + env=env, + ) def terminate(self): if self._proc.poll() is None: # Terminate _proc like it does the pexpect signals_to_try = [ - sig for sig in [ - 'SIGHUP', - 'SIGCONT', - 'SIGINT'] if sig in dir(signal)] + sig for sig in ["SIGHUP", "SIGCONT", "SIGINT"] if sig in dir(signal) + ] for sig in signals_to_try: try: self._proc.send_signal(getattr(signal, sig)) @@ -440,7 +455,6 @@ class _LocalProcess(_BaseProcess): class _RemoteProcess(_BaseProcess): - def __init__(self, install_remote): self._pid = None self._install_remote = install_remote @@ -453,23 +467,25 @@ class _RemoteProcess(_BaseProcess): if self._install_remote: src_path = executable dst_path = lldbutil.join_remote_paths( - lldb.remote_platform.GetWorkingDirectory(), os.path.basename(executable)) + lldb.remote_platform.GetWorkingDirectory(), os.path.basename(executable) + ) dst_file_spec = lldb.SBFileSpec(dst_path, False) err = lldb.remote_platform.Install( - lldb.SBFileSpec(src_path, True), dst_file_spec) + lldb.SBFileSpec(src_path, True), dst_file_spec + ) if err.Fail(): raise Exception( - "remote_platform.Install('%s', '%s') failed: %s" % - (src_path, dst_path, err)) + "remote_platform.Install('%s', '%s') failed: %s" + % (src_path, dst_path, err) + ) else: dst_path = executable dst_file_spec = lldb.SBFileSpec(executable, False) launch_info = lldb.SBLaunchInfo(args) launch_info.SetExecutableFile(dst_file_spec, True) - launch_info.SetWorkingDirectory( - lldb.remote_platform.GetWorkingDirectory()) + launch_info.SetWorkingDirectory(lldb.remote_platform.GetWorkingDirectory()) # Redirect stdout and stderr to /dev/null launch_info.AddSuppressFileAction(1, False, True) @@ -481,19 +497,21 @@ class _RemoteProcess(_BaseProcess): err = lldb.remote_platform.Launch(launch_info) if err.Fail(): raise Exception( - "remote_platform.Launch('%s', '%s') failed: %s" % - (dst_path, args, err)) + "remote_platform.Launch('%s', '%s') failed: %s" % (dst_path, args, err) + ) self._pid = launch_info.GetProcessID() def terminate(self): lldb.remote_platform.Kill(self._pid) + def getsource_if_available(obj): """ Return the text of the source code for an object if available. Otherwise, a print representation is returned. """ import inspect + try: return inspect.getsource(obj) except: @@ -520,24 +538,25 @@ class Base(unittest2.TestCase): @staticmethod def compute_mydir(test_file): - '''Subclasses should call this function to correctly calculate the - required "mydir" attribute as follows: + """Subclasses should call this function to correctly calculate the + required "mydir" attribute as follows: - mydir = TestBase.compute_mydir(__file__) - ''' + mydir = TestBase.compute_mydir(__file__) + """ # /abs/path/to/packages/group/subdir/mytest.py -> group/subdir lldb_test_src = configuration.test_src_root if not test_file.startswith(lldb_test_src): raise Exception( "Test file '%s' must reside within lldb_test_src " - "(which is '%s')." % (test_file, lldb_test_src)) + "(which is '%s')." % (test_file, lldb_test_src) + ) return os.path.dirname(os.path.relpath(test_file, start=lldb_test_src)) def TraceOn(self): """Returns True if we are in trace mode (tracing detailed test execution).""" return traceAlways - def trace(self, *args,**kwargs): + def trace(self, *args, **kwargs): with recording(self, self.TraceOn()) as sbuf: print(*args, file=sbuf, **kwargs) @@ -582,7 +601,8 @@ class Base(unittest2.TestCase): print( "Call class-specific cleanup function for class:", cls, - file=sys.stderr) + file=sys.stderr, + ) try: cls.classCleanup() except: @@ -604,12 +624,12 @@ class Base(unittest2.TestCase): # confirm that the file is writeable host_log_path = "{}-host.log".format(log_basename) - open(host_log_path, 'w').close() + open(host_log_path, "w").close() self.log_files.append(host_log_path) log_enable = "log enable -Tpn -f {} ".format(host_log_path) for channel_with_categories in lldbtest_config.channels: - channel_then_categories = channel_with_categories.split(' ', 1) + channel_then_categories = channel_with_categories.split(" ", 1) channel = channel_then_categories[0] if len(channel_then_categories) > 1: categories = channel_then_categories[1] @@ -620,24 +640,23 @@ class Base(unittest2.TestCase): # communicate gdb-remote categories to debugserver os.environ["LLDB_DEBUGSERVER_LOG_FLAGS"] = categories - self.ci.HandleCommand( - log_enable + channel_with_categories, self.res) + self.ci.HandleCommand(log_enable + channel_with_categories, self.res) if not self.res.Succeeded(): raise Exception( - 'log enable failed (check LLDB_LOG_OPTION env variable)') + "log enable failed (check LLDB_LOG_OPTION env variable)" + ) # Communicate log path name to debugserver & lldb-server # For remote debugging, these variables need to be set when starting the platform # instance. if lldb.remote_platform is None: server_log_path = "{}-server.log".format(log_basename) - open(server_log_path, 'w').close() + open(server_log_path, "w").close() self.log_files.append(server_log_path) os.environ["LLDB_DEBUGSERVER_LOG_FILE"] = server_log_path # Communicate channels to lldb-server - os.environ["LLDB_SERVER_LOG_CHANNELS"] = ":".join( - lldbtest_config.channels) + os.environ["LLDB_SERVER_LOG_CHANNELS"] = ":".join(lldbtest_config.channels) self.addTearDownHook(self.disableLogChannelsForCurrentTest) @@ -645,11 +664,12 @@ class Base(unittest2.TestCase): # close all log files that we opened for channel_and_categories in lldbtest_config.channels: # channel format - <channel-name> [<category0> [<category1> ...]] - channel = channel_and_categories.split(' ', 1)[0] + channel = channel_and_categories.split(" ", 1)[0] self.ci.HandleCommand("log disable " + channel, self.res) if not self.res.Succeeded(): raise Exception( - 'log disable failed (check LLDB_LOG_OPTION env variable)') + "log disable failed (check LLDB_LOG_OPTION env variable)" + ) # Retrieve the server log (if any) from the remote system. It is assumed the server log # is writing to the "server.log" file in the current test directory. This can be @@ -658,23 +678,28 @@ class Base(unittest2.TestCase): if lldb.remote_platform: server_log_path = self.getLogBasenameForCurrentTest() + "-server.log" if lldb.remote_platform.Get( - lldb.SBFileSpec("server.log"), - lldb.SBFileSpec(server_log_path)).Success(): + lldb.SBFileSpec("server.log"), lldb.SBFileSpec(server_log_path) + ).Success(): self.log_files.append(server_log_path) def setPlatformWorkingDir(self): if not lldb.remote_platform or not configuration.lldb_platform_working_dir: return - components = self.mydir.split(os.path.sep) + [str(self.test_number), self.getBuildDirBasename()] + components = self.mydir.split(os.path.sep) + [ + str(self.test_number), + self.getBuildDirBasename(), + ] remote_test_dir = configuration.lldb_platform_working_dir for c in components: remote_test_dir = lldbutil.join_remote_paths(remote_test_dir, c) error = lldb.remote_platform.MakeDirectory( - remote_test_dir, 448) # 448 = 0o700 + remote_test_dir, 448 + ) # 448 = 0o700 if error.Fail(): - raise Exception("making remote directory '%s': %s" % ( - remote_test_dir, error)) + raise Exception( + "making remote directory '%s': %s" % (remote_test_dir, error) + ) lldb.remote_platform.SetWorkingDirectory(remote_test_dir) @@ -686,9 +711,9 @@ class Base(unittest2.TestCase): # TODO: Make it working on Windows when we need it for remote debugging support # TODO: Replace the heuristic to remove the files with a logic what collects the # list of files we have to remove during test runs. - shell_cmd = lldb.SBPlatformShellCommand( - "rm %s/*" % remote_test_dir) + shell_cmd = lldb.SBPlatformShellCommand("rm %s/*" % remote_test_dir) lldb.remote_platform.Run(shell_cmd) + self.addTearDownHook(clean_working_directory) def getSourceDir(self): @@ -700,8 +725,9 @@ class Base(unittest2.TestCase): def getBuildDir(self): """Return the full path to the current test.""" - return os.path.join(configuration.test_build_dir, self.mydir, - self.getBuildDirBasename()) + return os.path.join( + configuration.test_build_dir, self.mydir, self.getBuildDirBasename() + ) def makeBuildDir(self): """Create the test-specific working directory, deleting any previous @@ -724,43 +750,45 @@ class Base(unittest2.TestCase): commands = [ # First of all, clear all settings to have clean state of global properties. "settings clear -all", - # Disable Spotlight lookup. The testsuite creates # different binaries with the same UUID, because they only # differ in the debug info, which is not being hashed. "settings set symbols.enable-external-lookup false", - # Inherit the TCC permissions from the inferior's parent. "settings set target.inherit-tcc true", - # Kill rather than detach from the inferior if something goes wrong. "settings set target.detach-on-error false", - # Disable fix-its by default so that incorrect expressions in tests don't # pass just because Clang thinks it has a fix-it. "settings set target.auto-apply-fixits false", - # Testsuite runs in parallel and the host can have also other load. "settings set plugin.process.gdb-remote.packet-timeout 60", - 'settings set symbols.clang-modules-cache-path "{}"'.format( - configuration.lldb_module_cache_dir), + configuration.lldb_module_cache_dir + ), "settings set use-color false", ] # Set any user-overridden settings. for setting, value in configuration.settings: - commands.append('setting set %s %s'%(setting, value)) + commands.append("setting set %s %s" % (setting, value)) # Make sure that a sanitizer LLDB's environment doesn't get passed on. - if cls.platformContext and cls.platformContext.shlib_environment_var in os.environ: - commands.append('settings set target.env-vars {}='.format( - cls.platformContext.shlib_environment_var)) + if ( + cls.platformContext + and cls.platformContext.shlib_environment_var in os.environ + ): + commands.append( + "settings set target.env-vars {}=".format( + cls.platformContext.shlib_environment_var + ) + ) # Set environment variables for the inferior. if lldbtest_config.inferior_env: - commands.append('settings set target.env-vars {}'.format( - lldbtest_config.inferior_env)) + commands.append( + "settings set target.env-vars {}".format(lldbtest_config.inferior_env) + ) return commands def setUp(self): @@ -768,7 +796,7 @@ class Base(unittest2.TestCase): It works with the test driver to conditionally skip tests and does other initializations.""" - #import traceback + # import traceback # traceback.print_stack() if "LIBCXX_PATH" in os.environ: @@ -781,8 +809,7 @@ class Base(unittest2.TestCase): else: self.lldbVSCodeExec = None - self.lldbOption = " ".join( - "-o '" + s + "'" for s in self.setUpCommands()) + self.lldbOption = " ".join("-o '" + s + "'" for s in self.setUpCommands()) # If we spawn an lldb process for test (via pexpect), do not load the # init file unless told otherwise. @@ -825,7 +852,7 @@ class Base(unittest2.TestCase): # before creating the first log file. self.makeBuildDir() - session_file = self.getLogBasenameForCurrentTest()+".log" + session_file = self.getLogBasenameForCurrentTest() + ".log" self.log_files.append(session_file) # Python 3 doesn't support unbuffered I/O in text mode. Open buffered. @@ -862,12 +889,12 @@ class Base(unittest2.TestCase): self.dbg.SetSelectedPlatform(lldb.selected_platform) if not self.dbg: - raise Exception('Invalid debugger instance') + raise Exception("Invalid debugger instance") # Retrieve the associated command interpreter instance. self.ci = self.dbg.GetCommandInterpreter() if not self.ci: - raise Exception('Could not get the command interpreter') + raise Exception("Could not get the command interpreter") # And the result object. self.res = lldb.SBCommandReturnObject() @@ -881,14 +908,14 @@ class Base(unittest2.TestCase): if sys.platform.startswith("darwin") and configuration.lldb_framework_path: framework = configuration.lldb_framework_path - lib = os.path.join(framework, 'LLDB') + lib = os.path.join(framework, "LLDB") if os.path.exists(lib): self.framework_dir = os.path.dirname(framework) self.lib_lldb = lib self.darwinWithFramework = self.platformIsDarwin() def setAsync(self, value): - """ Sets async mode to True/False and ensures it is reset after the testcase completes.""" + """Sets async mode to True/False and ensures it is reset after the testcase completes.""" old_async = self.dbg.GetAsync() self.dbg.SetAsync(value) self.addTearDownHook(lambda: self.dbg.SetAsync(old_async)) @@ -901,11 +928,14 @@ class Base(unittest2.TestCase): del self.subprocesses[:] def spawnSubprocess(self, executable, args=[], extra_env=None, install_remote=True): - """ Creates a subprocess.Popen object with the specified executable and arguments, - saves it in self.subprocesses, and returns the object. + """Creates a subprocess.Popen object with the specified executable and arguments, + saves it in self.subprocesses, and returns the object. """ - proc = _RemoteProcess( - install_remote) if lldb.remote_platform else _LocalProcess(self.TraceOn()) + proc = ( + _RemoteProcess(install_remote) + if lldb.remote_platform + else _LocalProcess(self.TraceOn()) + ) proc.launch(executable, args, extra_env=extra_env) self.subprocesses.append(proc) return proc @@ -932,10 +962,11 @@ class Base(unittest2.TestCase): self.sys_stdout_hidden = True old_stdout = sys.stdout - sys.stdout = open(os.devnull, 'w') + sys.stdout = open(os.devnull, "w") def restore_stdout(): sys.stdout = old_stdout + self.addTearDownHook(restore_stdout) # ======================================================================= @@ -960,10 +991,7 @@ class Base(unittest2.TestCase): """ if callable(hook): with recording(self, traceAlways) as sbuf: - print( - "Adding tearDown hook:", - getsource_if_available(hook), - file=sbuf) + print("Adding tearDown hook:", getsource_if_available(hook), file=sbuf) self.hooks.append(hook) return self @@ -973,21 +1001,22 @@ class Base(unittest2.TestCase): # using pexpect. if self.child and self.child.isalive(): import pexpect + with recording(self, traceAlways) as sbuf: print("tearing down the child process....", file=sbuf) try: if self.child_in_script_interpreter: - self.child.sendline('quit()') + self.child.sendline("quit()") self.child.expect_exact(self.child_prompt) - self.child.sendline( - 'settings set interpreter.prompt-on-quit false') - self.child.sendline('quit') + self.child.sendline("settings set interpreter.prompt-on-quit false") + self.child.sendline("quit") self.child.expect(pexpect.EOF) except (ValueError, pexpect.ExceptionPexpect): # child is already terminated pass except OSError as exception: import errno + if exception.errno != errno.EIO: # unexpected error raise @@ -1004,9 +1033,8 @@ class Base(unittest2.TestCase): for hook in reversed(self.hooks): with recording(self, traceAlways) as sbuf: print( - "Executing tearDown hook:", - getsource_if_available(hook), - file=sbuf) + "Executing tearDown hook:", getsource_if_available(hook), file=sbuf + ) if funcutils.requires_self(hook): hook(self) else: @@ -1039,7 +1067,6 @@ class Base(unittest2.TestCase): # Assert that the global module cache is empty. self.assertEqual(lldb.SBModule.GetNumberAllocatedModules(), 0) - # ========================================================= # Various callbacks to allow introspection of test progress # ========================================================= @@ -1078,9 +1105,7 @@ class Base(unittest2.TestCase): if bugnumber is None: print("expected failure", file=sbuf) else: - print( - "expected failure (problem id:" + str(bugnumber) + ")", - file=sbuf) + print("expected failure (problem id:" + str(bugnumber) + ")", file=sbuf) def markSkippedTest(self): """Callback invoked when a test is skipped.""" @@ -1102,8 +1127,8 @@ class Base(unittest2.TestCase): print("unexpected success", file=sbuf) else: print( - "unexpected success (problem id:" + str(bugnumber) + ")", - file=sbuf) + "unexpected success (problem id:" + str(bugnumber) + ")", file=sbuf + ) def getRerunArgs(self): return " -f %s.%s" % (self.__class__.__name__, self._testMethodName) @@ -1140,22 +1165,22 @@ class Base(unittest2.TestCase): pairs = [] if self.__errored__: pairs = configuration.test_result.errors - prefix = 'Error' + prefix = "Error" elif self.__cleanup_errored__: pairs = configuration.test_result.cleanup_errors - prefix = 'CleanupError' + prefix = "CleanupError" elif self.__failed__: pairs = configuration.test_result.failures - prefix = 'Failure' + prefix = "Failure" elif self.__expected__: pairs = configuration.test_result.expectedFailures - prefix = 'ExpectedFailure' + prefix = "ExpectedFailure" elif self.__skipped__: - prefix = 'SkippedTest' + prefix = "SkippedTest" elif self.__unexpected__: - prefix = 'UnexpectedSuccess' + prefix = "UnexpectedSuccess" else: - prefix = 'Success' + prefix = "Success" if not self.__unexpected__ and not self.__skipped__: for test, traceback in pairs: @@ -1163,15 +1188,17 @@ class Base(unittest2.TestCase): print(traceback, file=self.session) import datetime + print( "Session info generated @", datetime.datetime.now().ctime(), - file=self.session) + file=self.session, + ) self.session.close() del self.session # process the log files - if prefix != 'Success' or lldbtest_config.log_success: + if prefix != "Success" or lldbtest_config.log_success: # keep all log files, rename them to include prefix src_log_basename = self.getLogBasenameForCurrentTest() dst_log_basename = self.getLogBasenameForCurrentTest(prefix) @@ -1229,7 +1256,7 @@ class Base(unittest2.TestCase): cpuinfo_path = "/proc/cpuinfo" try: - with open(cpuinfo_path, 'r') as f: + with open(cpuinfo_path, "r") as f: cpuinfo = f.read() except: return "" @@ -1254,7 +1281,7 @@ class Base(unittest2.TestCase): def isAArch64Windows(self): """Returns true if the architecture is AArch64 and platform windows.""" - if self.getPlatform() == 'windows': + if self.getPlatform() == "windows": arch = self.getArchitecture().lower() return arch in ["aarch64", "arm64", "arm64e"] return False @@ -1263,33 +1290,34 @@ class Base(unittest2.TestCase): """Returns the architecture in effect the test suite is running with.""" module = builder_module() arch = module.getArchitecture() - if arch == 'amd64': - arch = 'x86_64' - if arch in ['armv7l', 'armv8l'] : - arch = 'arm' + if arch == "amd64": + arch = "x86_64" + if arch in ["armv7l", "armv8l"]: + arch = "arm" return arch def getLldbArchitecture(self): """Returns the architecture of the lldb binary.""" - if not hasattr(self, 'lldbArchitecture'): - + if not hasattr(self, "lldbArchitecture"): # These two target settings prevent lldb from doing setup that does # nothing but slow down the end goal of printing the architecture. command = [ lldbtest_config.lldbExec, "-x", "-b", - "-o", "settings set target.preload-symbols false", - "-o", "settings set target.load-script-from-symbol-file false", - "-o", "file " + lldbtest_config.lldbExec, + "-o", + "settings set target.preload-symbols false", + "-o", + "settings set target.load-script-from-symbol-file false", + "-o", + "file " + lldbtest_config.lldbExec, ] output = check_output(command) str = output.decode() for line in str.splitlines(): - m = re.search( - r"Current executable set to '.*' \((.*)\)\.", line) + m = re.search(r"Current executable set to '.*' \((.*)\)\.", line) if m: self.lldbArchitecture = m.group(1) break @@ -1306,35 +1334,36 @@ class Base(unittest2.TestCase): return self.getCompiler().split()[0] def getCompilerVersion(self): - """ Returns a string that represents the compiler version. - Supports: llvm, clang. + """Returns a string that represents the compiler version. + Supports: llvm, clang. """ compiler = self.getCompilerBinary() version_output = check_output([compiler, "--version"], errors="replace") - m = re.search('version ([0-9.]+)', version_output) + m = re.search("version ([0-9.]+)", version_output) if m: return m.group(1) - return 'unknown' + return "unknown" def getDwarfVersion(self): - """ Returns the dwarf version generated by clang or '0'. """ + """Returns the dwarf version generated by clang or '0'.""" if configuration.dwarf_version: return str(configuration.dwarf_version) - if 'clang' in self.getCompiler(): + if "clang" in self.getCompiler(): try: triple = builder_module().getTriple(self.getArchitecture()) - target = ['-target', triple] if triple else [] + target = ["-target", triple] if triple else [] driver_output = check_output( - [self.getCompiler()] + target + '-g -c -x c - -o - -###'.split(), - stderr=STDOUT) + [self.getCompiler()] + target + "-g -c -x c - -o - -###".split(), + stderr=STDOUT, + ) driver_output = driver_output.decode("utf-8") for line in driver_output.split(os.linesep): - m = re.search('dwarf-version=([0-9])', line) + m = re.search("dwarf-version=([0-9])", line) if m: return m.group(1) except CalledProcessError: pass - return '0' + return "0" def platformIsDarwin(self): """Returns true if the OS triple for the selected platform is any valid apple OS""" @@ -1348,18 +1377,18 @@ class Base(unittest2.TestCase): return lldbplatformutil.getPlatform() def isIntelCompiler(self): - """ Returns true if using an Intel (ICC) compiler, false otherwise. """ + """Returns true if using an Intel (ICC) compiler, false otherwise.""" return any([x in self.getCompiler() for x in ["icc", "icpc", "icl"]]) def expectedCompilerVersion(self, compiler_version): """Returns True iff compiler_version[1] matches the current compiler version. - Use compiler_version[0] to specify the operator used to determine if a match has occurred. - Any operator other than the following defaults to an equality test: - '>', '>=', "=>", '<', '<=', '=<', '!=', "!" or 'not' + Use compiler_version[0] to specify the operator used to determine if a match has occurred. + Any operator other than the following defaults to an equality test: + '>', '>=', "=>", '<', '<=', '=<', '!=', "!" or 'not' - If the current compiler version cannot be determined, we assume it is close to the top - of trunk, so any less-than or equal-to comparisons will return False, and any - greater-than or not-equal-to comparisons will return True. + If the current compiler version cannot be determined, we assume it is close to the top + of trunk, so any less-than or equal-to comparisons will return False, and any + greater-than or not-equal-to comparisons will return True. """ if compiler_version is None: return True @@ -1370,25 +1399,25 @@ class Base(unittest2.TestCase): return True test_compiler_version = self.getCompilerVersion() - if test_compiler_version == 'unknown': + if test_compiler_version == "unknown": # Assume the compiler version is at or near the top of trunk. - return operator in ['>', '>=', '!', '!=', 'not'] + return operator in [">", ">=", "!", "!=", "not"] - if operator == '>': + if operator == ">": return LooseVersion(test_compiler_version) > LooseVersion(version) - if operator == '>=' or operator == '=>': + if operator == ">=" or operator == "=>": return LooseVersion(test_compiler_version) >= LooseVersion(version) - if operator == '<': + if operator == "<": return LooseVersion(test_compiler_version) < LooseVersion(version) - if operator == '<=' or operator == '=<': + if operator == "<=" or operator == "=<": return LooseVersion(test_compiler_version) <= LooseVersion(version) - if operator == '!=' or operator == '!' or operator == 'not': + if operator == "!=" or operator == "!" or operator == "not": return str(version) not in str(test_compiler_version) return str(version) in str(test_compiler_version) def expectedCompiler(self, compilers): """Returns True iff any element of compilers is a sub-string of the current compiler.""" - if (compilers is None): + if compilers is None: return True for compiler in compilers: @@ -1399,7 +1428,7 @@ class Base(unittest2.TestCase): def expectedArch(self, archs): """Returns True iff any element of archs is a sub-string of the current architecture.""" - if (archs is None): + if archs is None: return True for arch in archs: @@ -1425,12 +1454,13 @@ class Base(unittest2.TestCase): return getattr(method, "debug_info", None) def build( - self, - debug_info=None, - architecture=None, - compiler=None, - dictionary=None, - make_targets=None): + self, + debug_info=None, + architecture=None, + compiler=None, + dictionary=None, + make_targets=None, + ): """Platform specific way to build binaries.""" if not architecture and configuration.arch: architecture = configuration.arch @@ -1444,8 +1474,15 @@ class Base(unittest2.TestCase): testname = self.getBuildDirBasename() module = builder_module() - command = builder_module().getBuildCommand(debug_info, architecture, - compiler, dictionary, testdir, testname, make_targets) + command = builder_module().getBuildCommand( + debug_info, + architecture, + compiler, + dictionary, + testdir, + testname, + make_targets, + ) if command is None: raise Exception("Don't know how to build binary") @@ -1459,21 +1496,24 @@ class Base(unittest2.TestCase): raise build_exception.BuildError(cpe) self.trace(output) - # ================================================== # Build methods supported through a plugin interface # ================================================== def getstdlibFlag(self): - """ Returns the proper -stdlib flag, or empty if not required.""" - if self.platformIsDarwin() or self.getPlatform() == "freebsd" or self.getPlatform() == "openbsd": + """Returns the proper -stdlib flag, or empty if not required.""" + if ( + self.platformIsDarwin() + or self.getPlatform() == "freebsd" + or self.getPlatform() == "openbsd" + ): stdlibflag = "-stdlib=libc++" else: # this includes NetBSD stdlibflag = "" return stdlibflag def getstdFlag(self): - """ Returns the proper stdflag. """ + """Returns the proper stdflag.""" if "gcc" in self.getCompiler() and "4.6" in self.getCompilerVersion(): stdflag = "-std=c++0x" else: @@ -1481,95 +1521,97 @@ class Base(unittest2.TestCase): return stdflag def buildDriver(self, sources, exe_name): - """ Platform-specific way to build a program that links with LLDB (via the liblldb.so - or LLDB.framework). + """Platform-specific way to build a program that links with LLDB (via the liblldb.so + or LLDB.framework). """ stdflag = self.getstdFlag() stdlibflag = self.getstdlibFlag() lib_dir = configuration.lldb_libs_dir if self.hasDarwinFramework(): - d = {'CXX_SOURCES': sources, - 'EXE': exe_name, - 'CFLAGS_EXTRAS': "%s %s" % (stdflag, stdlibflag), - 'FRAMEWORK_INCLUDES': "-F%s" % self.framework_dir, - 'LD_EXTRAS': "%s -Wl,-rpath,%s" % (self.lib_lldb, self.framework_dir), - } - elif sys.platform.startswith('win'): d = { - 'CXX_SOURCES': sources, - 'EXE': exe_name, - 'CFLAGS_EXTRAS': "%s %s -I%s" % (stdflag, - stdlibflag, - os.path.join( - os.environ["LLDB_SRC"], - "include")), - 'LD_EXTRAS': "-L%s -lliblldb" % lib_dir} + "CXX_SOURCES": sources, + "EXE": exe_name, + "CFLAGS_EXTRAS": "%s %s" % (stdflag, stdlibflag), + "FRAMEWORK_INCLUDES": "-F%s" % self.framework_dir, + "LD_EXTRAS": "%s -Wl,-rpath,%s" % (self.lib_lldb, self.framework_dir), + } + elif sys.platform.startswith("win"): + d = { + "CXX_SOURCES": sources, + "EXE": exe_name, + "CFLAGS_EXTRAS": "%s %s -I%s" + % ( + stdflag, + stdlibflag, + os.path.join(os.environ["LLDB_SRC"], "include"), + ), + "LD_EXTRAS": "-L%s -lliblldb" % lib_dir, + } else: d = { - 'CXX_SOURCES': sources, - 'EXE': exe_name, - 'CFLAGS_EXTRAS': "%s %s -I%s" % (stdflag, - stdlibflag, - os.path.join( - os.environ["LLDB_SRC"], - "include")), - 'LD_EXTRAS': "-L%s -llldb -Wl,-rpath,%s" % (lib_dir, lib_dir)} + "CXX_SOURCES": sources, + "EXE": exe_name, + "CFLAGS_EXTRAS": "%s %s -I%s" + % ( + stdflag, + stdlibflag, + os.path.join(os.environ["LLDB_SRC"], "include"), + ), + "LD_EXTRAS": "-L%s -llldb -Wl,-rpath,%s" % (lib_dir, lib_dir), + } if self.TraceOn(): - print( - "Building LLDB Driver (%s) from sources %s" % - (exe_name, sources)) + print("Building LLDB Driver (%s) from sources %s" % (exe_name, sources)) self.build(dictionary=d) def buildLibrary(self, sources, lib_name): - """Platform specific way to build a default library. """ + """Platform specific way to build a default library.""" stdflag = self.getstdFlag() lib_dir = configuration.lldb_libs_dir if self.hasDarwinFramework(): - d = {'DYLIB_CXX_SOURCES': sources, - 'DYLIB_NAME': lib_name, - 'CFLAGS_EXTRAS': "%s -stdlib=libc++" % stdflag, - 'FRAMEWORK_INCLUDES': "-F%s" % self.framework_dir, - 'LD_EXTRAS': "%s -Wl,-rpath,%s -dynamiclib" % (self.lib_lldb, self.framework_dir), - } - elif self.getPlatform() == 'windows': d = { - 'DYLIB_CXX_SOURCES': sources, - 'DYLIB_NAME': lib_name, - 'CFLAGS_EXTRAS': "%s -I%s " % (stdflag, - os.path.join( - os.environ["LLDB_SRC"], - "include")), - 'LD_EXTRAS': "-shared -l%s\liblldb.lib" % lib_dir} + "DYLIB_CXX_SOURCES": sources, + "DYLIB_NAME": lib_name, + "CFLAGS_EXTRAS": "%s -stdlib=libc++" % stdflag, + "FRAMEWORK_INCLUDES": "-F%s" % self.framework_dir, + "LD_EXTRAS": "%s -Wl,-rpath,%s -dynamiclib" + % (self.lib_lldb, self.framework_dir), + } + elif self.getPlatform() == "windows": + d = { + "DYLIB_CXX_SOURCES": sources, + "DYLIB_NAME": lib_name, + "CFLAGS_EXTRAS": "%s -I%s " + % (stdflag, os.path.join(os.environ["LLDB_SRC"], "include")), + "LD_EXTRAS": "-shared -l%s\liblldb.lib" % lib_dir, + } else: d = { - 'DYLIB_CXX_SOURCES': sources, - 'DYLIB_NAME': lib_name, - 'CFLAGS_EXTRAS': "%s -I%s -fPIC" % (stdflag, - os.path.join( - os.environ["LLDB_SRC"], - "include")), - 'LD_EXTRAS': "-shared -L%s -llldb -Wl,-rpath,%s" % (lib_dir, lib_dir)} + "DYLIB_CXX_SOURCES": sources, + "DYLIB_NAME": lib_name, + "CFLAGS_EXTRAS": "%s -I%s -fPIC" + % (stdflag, os.path.join(os.environ["LLDB_SRC"], "include")), + "LD_EXTRAS": "-shared -L%s -llldb -Wl,-rpath,%s" % (lib_dir, lib_dir), + } if self.TraceOn(): - print( - "Building LLDB Library (%s) from sources %s" % - (lib_name, sources)) + print("Building LLDB Library (%s) from sources %s" % (lib_name, sources)) self.build(dictionary=d) def buildProgram(self, sources, exe_name): - """ Platform specific way to build an executable from C/C++ sources. """ - d = {'CXX_SOURCES': sources, - 'EXE': exe_name} + """Platform specific way to build an executable from C/C++ sources.""" + d = {"CXX_SOURCES": sources, "EXE": exe_name} self.build(dictionary=d) def signBinary(self, binary_path): if sys.platform.startswith("darwin"): - codesign_cmd = "codesign --force --sign \"%s\" %s" % ( - lldbtest_config.codesign_identity, binary_path) + codesign_cmd = 'codesign --force --sign "%s" %s' % ( + lldbtest_config.codesign_identity, + binary_path, + ) call(codesign_cmd, shell=True) def findBuiltClang(self): @@ -1580,8 +1622,7 @@ class Base(unittest2.TestCase): "llvm-build/Release/x86_64/bin/clang", "llvm-build/Debug/x86_64/bin/clang", ] - lldb_root_path = os.path.join( - os.path.dirname(__file__), "..", "..", "..", "..") + lldb_root_path = os.path.join(os.path.dirname(__file__), "..", "..", "..", "..") for p in paths_to_try: path = os.path.join(lldb_root_path, p) if os.path.exists(path): @@ -1595,7 +1636,6 @@ class Base(unittest2.TestCase): return os.environ["CC"] - def yaml2obj(self, yaml_path, obj_path, max_size=None): """ Create an object file at the given path from a yaml file. @@ -1615,30 +1655,33 @@ class Base(unittest2.TestCase): module = builder_module() if not module.cleanup(dictionary): raise Exception( - "Don't know how to do cleanup with dictionary: " + - dictionary) + "Don't know how to do cleanup with dictionary: " + dictionary + ) def invoke(self, obj, name, trace=False): """Use reflection to call a method dynamically with no argument.""" - trace = (True if traceAlways else trace) + trace = True if traceAlways else trace method = getattr(obj, name) import inspect - self.assertTrue(inspect.ismethod(method), - name + "is a method name of object: " + str(obj)) + + self.assertTrue( + inspect.ismethod(method), name + "is a method name of object: " + str(obj) + ) result = method() with recording(self, trace) as sbuf: print(str(method) + ":", result, file=sbuf) return result def getLLDBLibraryEnvVal(self): - """ Returns the path that the OS-specific library search environment variable - (self.dylibPath) should be set to in order for a program to find the LLDB - library. If an environment variable named self.dylibPath is already set, - the new path is appended to it and returned. + """Returns the path that the OS-specific library search environment variable + (self.dylibPath) should be set to in order for a program to find the LLDB + library. If an environment variable named self.dylibPath is already set, + the new path is appended to it and returned. """ - existing_library_path = os.environ[ - self.dylibPath] if self.dylibPath in os.environ else None + existing_library_path = ( + os.environ[self.dylibPath] if self.dylibPath in os.environ else None + ) if existing_library_path: return "%s:%s" % (existing_library_path, configuration.lldb_libs_dir) if sys.platform.startswith("darwin") and configuration.lldb_framework_path: @@ -1646,10 +1689,10 @@ class Base(unittest2.TestCase): return configuration.lldb_libs_dir def getLibcPlusPlusLibs(self): - if self.getPlatform() in ('freebsd', 'linux', 'netbsd', 'openbsd'): - return ['libc++.so.1'] + if self.getPlatform() in ("freebsd", "linux", "netbsd", "openbsd"): + return ["libc++.so.1"] else: - return ['libc++.1.dylib', 'libc++abi.'] + return ["libc++.1.dylib", "libc++abi."] def run_platform_command(self, cmd): platform = self.dbg.GetSelectedPlatform() @@ -1659,8 +1702,8 @@ class Base(unittest2.TestCase): def get_stats(self, options=None): """ - Get the output of the "statistics dump" with optional extra options - and return the JSON as a python dictionary. + Get the output of the "statistics dump" with optional extra options + and return the JSON as a python dictionary. """ return_obj = lldb.SBCommandReturnObject() command = "statistics dump " @@ -1670,6 +1713,7 @@ class Base(unittest2.TestCase): metrics_json = return_obj.GetOutput() return json.loads(metrics_json) + # Metaclass for TestBase to change the list of test metods when a new TestCase is loaded. # We change the test methods to create a new test method for each test for each debug info we are # testing. The name of the new test method will be '<original-name>_<debug-info>' and with adding @@ -1679,34 +1723,36 @@ class Base(unittest2.TestCase): class LLDBTestCaseFactory(type): - def __new__(cls, name, bases, attrs): - original_testcase = super( - LLDBTestCaseFactory, cls).__new__( - cls, name, bases, attrs) + original_testcase = super(LLDBTestCaseFactory, cls).__new__( + cls, name, bases, attrs + ) if original_testcase.NO_DEBUG_INFO_TESTCASE: return original_testcase newattrs = {} for attrname, attrvalue in attrs.items(): if attrname.startswith("test") and not getattr( - attrvalue, "__no_debug_info_test__", False): - + attrvalue, "__no_debug_info_test__", False + ): # If any debug info categories were explicitly tagged, assume that list to be # authoritative. If none were specified, try with all debug # info formats. - all_dbginfo_categories = set(test_categories.debug_info_categories.keys()) - categories = set( - getattr( - attrvalue, - "categories", - [])) & all_dbginfo_categories + all_dbginfo_categories = set( + test_categories.debug_info_categories.keys() + ) + categories = ( + set(getattr(attrvalue, "categories", [])) & all_dbginfo_categories + ) if not categories: - categories = [category for category, can_replicate \ - in test_categories.debug_info_categories.items() \ - if can_replicate] + categories = [ + category + for category, can_replicate in test_categories.debug_info_categories.items() + if can_replicate + ] for cat in categories: + @decorators.add_test_categories([cat]) @wraps(attrvalue) def test_method(self, attrvalue=attrvalue): @@ -1719,13 +1765,8 @@ class LLDBTestCaseFactory(type): else: newattrs[attrname] = attrvalue - return super( - LLDBTestCaseFactory, - cls).__new__( - cls, - name, - bases, - newattrs) + return super(LLDBTestCaseFactory, cls).__new__(cls, name, bases, newattrs) + # Setup the metaclass for this class to change the list of the test # methods when a new class is loaded @@ -1791,13 +1832,12 @@ class TestBase(Base, metaclass=LLDBTestCaseFactory): timeWaitNextLaunch = 1.0 def generateSource(self, source): - template = source + '.template' + template = source + ".template" temp = os.path.join(self.getSourceDir(), template) - with open(temp, 'r') as f: + with open(temp, "r") as f: content = f.read() - public_api_dir = os.path.join( - os.environ["LLDB_SRC"], "include", "lldb", "API") + public_api_dir = os.path.join(os.environ["LLDB_SRC"], "include", "lldb", "API") # Look under the include/lldb/API directory and add #include statements # for all the SB API headers. @@ -1806,14 +1846,19 @@ class TestBase(Base, metaclass=LLDBTestCaseFactory): if self.hasDarwinFramework(): include_stmt = "'#include <%s>' % os.path.join('LLDB', header)" else: - include_stmt = "'#include <%s>' % os.path.join(r'" + public_api_dir + "', header)" - list = [eval(include_stmt) for header in public_headers if ( - header.startswith("SB") and header.endswith(".h"))] - includes = '\n'.join(list) - new_content = content.replace('%include_SB_APIs%', includes) - new_content = new_content.replace('%SOURCE_DIR%', self.getSourceDir()) + include_stmt = ( + "'#include <%s>' % os.path.join(r'" + public_api_dir + "', header)" + ) + list = [ + eval(include_stmt) + for header in public_headers + if (header.startswith("SB") and header.endswith(".h")) + ] + includes = "\n".join(list) + new_content = content.replace("%include_SB_APIs%", includes) + new_content = new_content.replace("%SOURCE_DIR%", self.getSourceDir()) src = os.path.join(self.getBuildDir(), source) - with open(src, 'w') as f: + with open(src, "w") as f: f.write(new_content) self.addTearDownHook(lambda: os.remove(src)) @@ -1830,8 +1875,7 @@ class TestBase(Base, metaclass=LLDBTestCaseFactory): self.maxLaunchCount = int(os.environ["LLDB_MAX_LAUNCH_COUNT"]) if "LLDB_TIME_WAIT_NEXT_LAUNCH" in os.environ: - self.timeWaitNextLaunch = float( - os.environ["LLDB_TIME_WAIT_NEXT_LAUNCH"]) + self.timeWaitNextLaunch = float(os.environ["LLDB_TIME_WAIT_NEXT_LAUNCH"]) # We want our debugger to be synchronous. self.dbg.SetAsync(False) @@ -1839,25 +1883,25 @@ class TestBase(Base, metaclass=LLDBTestCaseFactory): # Retrieve the associated command interpreter instance. self.ci = self.dbg.GetCommandInterpreter() if not self.ci: - raise Exception('Could not get the command interpreter') + raise Exception("Could not get the command interpreter") # And the result object. self.res = lldb.SBCommandReturnObject() def registerSharedLibrariesWithTarget(self, target, shlibs): - '''If we are remotely running the test suite, register the shared libraries with the target so they get uploaded, otherwise do nothing + """If we are remotely running the test suite, register the shared libraries with the target so they get uploaded, otherwise do nothing Any modules in the target that have their remote install file specification set will get uploaded to the remote host. This function registers the local copies of the shared libraries with the target and sets their remote install locations so they will be uploaded when the target is run. - ''' + """ if not shlibs or not self.platformContext: return None shlib_environment_var = self.platformContext.shlib_environment_var shlib_prefix = self.platformContext.shlib_prefix - shlib_extension = '.' + self.platformContext.shlib_extension + shlib_extension = "." + self.platformContext.shlib_extension dirs = [] # Add any shared libraries to our target if remote so they get @@ -1868,30 +1912,35 @@ class TestBase(Base, metaclass=LLDBTestCaseFactory): # basename like "libFoo.so". So figure out which one it is and resolve the local copy # of the shared library accordingly if os.path.isfile(name): - local_shlib_path = name # name is the full path to the local shared library + local_shlib_path = ( + name # name is the full path to the local shared library + ) else: # Check relative names local_shlib_path = os.path.join( - self.getBuildDir(), shlib_prefix + name + shlib_extension) + self.getBuildDir(), shlib_prefix + name + shlib_extension + ) if not os.path.exists(local_shlib_path): local_shlib_path = os.path.join( - self.getBuildDir(), name + shlib_extension) + self.getBuildDir(), name + shlib_extension + ) if not os.path.exists(local_shlib_path): local_shlib_path = os.path.join(self.getBuildDir(), name) # Make sure we found the local shared library in the above code self.assertTrue(os.path.exists(local_shlib_path)) - # Add the shared library to our target shlib_module = target.AddModule(local_shlib_path, None, None, None) if lldb.remote_platform: # We must set the remote install location if we want the shared library # to get uploaded to the remote target - remote_shlib_path = lldbutil.append_to_process_working_directory(self, - os.path.basename(local_shlib_path)) + remote_shlib_path = lldbutil.append_to_process_working_directory( + self, os.path.basename(local_shlib_path) + ) shlib_module.SetRemoteInstallFileSpec( - lldb.SBFileSpec(remote_shlib_path, False)) + lldb.SBFileSpec(remote_shlib_path, False) + ) dir_to_add = self.get_process_working_directory() else: dir_to_add = os.path.dirname(local_shlib_path) @@ -1900,41 +1949,46 @@ class TestBase(Base, metaclass=LLDBTestCaseFactory): dirs.append(dir_to_add) env_value = self.platformContext.shlib_path_separator.join(dirs) - return ['%s=%s' % (shlib_environment_var, env_value)] + return ["%s=%s" % (shlib_environment_var, env_value)] def registerSanitizerLibrariesWithTarget(self, target): runtimes = [] for m in target.module_iter(): libspec = m.GetFileSpec() if "clang_rt" in libspec.GetFilename(): - runtimes.append(os.path.join(libspec.GetDirectory(), - libspec.GetFilename())) + runtimes.append( + os.path.join(libspec.GetDirectory(), libspec.GetFilename()) + ) return self.registerSharedLibrariesWithTarget(target, runtimes) # utility methods that tests can use to access the current objects def target(self): if not self.dbg: - raise Exception('Invalid debugger instance') + raise Exception("Invalid debugger instance") return self.dbg.GetSelectedTarget() def process(self): if not self.dbg: - raise Exception('Invalid debugger instance') + raise Exception("Invalid debugger instance") return self.dbg.GetSelectedTarget().GetProcess() def thread(self): if not self.dbg: - raise Exception('Invalid debugger instance') + raise Exception("Invalid debugger instance") return self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread() def frame(self): if not self.dbg: - raise Exception('Invalid debugger instance') - return self.dbg.GetSelectedTarget().GetProcess( - ).GetSelectedThread().GetSelectedFrame() + raise Exception("Invalid debugger instance") + return ( + self.dbg.GetSelectedTarget() + .GetProcess() + .GetSelectedThread() + .GetSelectedFrame() + ) def get_process_working_directory(self): - '''Get the working directory that should be used when launching processes for local or remote processes.''' + """Get the working directory that should be used when launching processes for local or remote processes.""" if lldb.remote_platform: # Remote tests set the platform working directory up in # TestBase.setUp() @@ -1976,15 +2030,17 @@ class TestBase(Base, metaclass=LLDBTestCaseFactory): 'stop_reason'. If no such thread exists, no select action is done. """ from .lldbutil import stop_reason_to_str - self.runCmd('thread list') + + self.runCmd("thread list") output = self.res.GetOutput() thread_line_pattern = re.compile( - "^[ *] thread #([0-9]+):.*stop reason = %s" % - stop_reason_to_str(stop_reason)) + "^[ *] thread #([0-9]+):.*stop reason = %s" + % stop_reason_to_str(stop_reason) + ) for line in output.splitlines(): matched = thread_line_pattern.match(line) if matched: - self.runCmd('thread select %s' % matched.group(1)) + self.runCmd("thread select %s" % matched.group(1)) def runCmd(self, cmd, msg=None, check=True, trace=False, inHistory=False): """ @@ -1995,12 +2051,12 @@ class TestBase(Base, metaclass=LLDBTestCaseFactory): if cmd is None: raise Exception("Bad 'cmd' parameter encountered") - trace = (True if traceAlways else trace) + trace = True if traceAlways else trace if cmd.startswith("target create "): cmd = cmd.replace("target create ", "file ") - running = (cmd.startswith("run") or cmd.startswith("process launch")) + running = cmd.startswith("run") or cmd.startswith("process launch") for i in range(self.maxLaunchCount if running else 1): self.ci.HandleCommand(cmd, self.res, inHistory) @@ -2033,42 +2089,32 @@ class TestBase(Base, metaclass=LLDBTestCaseFactory): msg += output if cmd: cmd += output - self.assertTrue(self.res.Succeeded(), - msg if (msg) else CMD_MSG(cmd)) + self.assertTrue(self.res.Succeeded(), msg if (msg) else CMD_MSG(cmd)) def match( - self, - str, - patterns, - msg=None, - trace=False, - error=False, - matching=True, - exe=True): + self, str, patterns, msg=None, trace=False, error=False, matching=True, exe=True + ): """run command in str, and match the result against regexp in patterns returning the match object for the first matching pattern - Otherwise, all the arguments have the same meanings as for the expect function""" + Otherwise, all the arguments have the same meanings as for the expect function + """ - trace = (True if traceAlways else trace) + trace = True if traceAlways else trace if exe: # First run the command. If we are expecting error, set check=False. # Pass the assert message along since it provides more semantic # info. - self.runCmd( - str, - msg=msg, - trace=( - True if trace else False), - check=not error) + self.runCmd(str, msg=msg, trace=(True if trace else False), check=not error) # Then compare the output against expected strings. output = self.res.GetError() if error else self.res.GetOutput() # If error is True, the API client expects the command to fail! if error: - self.assertFalse(self.res.Succeeded(), - "Command '" + str + "' is expected to fail!") + self.assertFalse( + self.res.Succeeded(), "Command '" + str + "' is expected to fail!" + ) else: # No execution required, just compare str against the golden input. output = str @@ -2088,12 +2134,16 @@ class TestBase(Base, metaclass=LLDBTestCaseFactory): if matched: break - self.assertTrue(matched if matching else not matched, - msg if msg else EXP_MSG(str, output, exe)) + self.assertTrue( + matched if matching else not matched, + msg if msg else EXP_MSG(str, output, exe), + ) return match_object - def check_completion_with_desc(self, str_input, match_desc_pairs, enforce_order=False): + def check_completion_with_desc( + self, str_input, match_desc_pairs, enforce_order=False + ): """ Checks that when the given input is completed at the given list of completions and descriptions is returned. @@ -2107,7 +2157,9 @@ class TestBase(Base, metaclass=LLDBTestCaseFactory): interp = self.dbg.GetCommandInterpreter() match_strings = lldb.SBStringList() description_strings = lldb.SBStringList() - num_matches = interp.HandleCompletionWithDescriptions(str_input, len(str_input), 0, -1, match_strings, description_strings) + num_matches = interp.HandleCompletionWithDescriptions( + str_input, len(str_input), 0, -1, match_strings, description_strings + ) self.assertEqual(len(description_strings), len(match_strings)) # The index of the last matched description in description_strings or @@ -2123,11 +2175,18 @@ class TestBase(Base, metaclass=LLDBTestCaseFactory): if match_candidate == pair[0] and description_candidate == pair[1]: found_pair = True if enforce_order and last_found_index > i: - new_err = ("Found completion " + pair[0] + " at index " + - str(i) + " in returned completion list but " + - "should have been after completion " + - match_strings.GetStringAtIndex(last_found_index) + - " (index:" + str(last_found_index) + ")\n") + new_err = ( + "Found completion " + + pair[0] + + " at index " + + str(i) + + " in returned completion list but " + + "should have been after completion " + + match_strings.GetStringAtIndex(last_found_index) + + " (index:" + + str(last_found_index) + + ")\n" + ) out_of_order_errors += new_err last_found_index = i break @@ -2145,11 +2204,21 @@ class TestBase(Base, metaclass=LLDBTestCaseFactory): got_failure = True error_msg += out_of_order_errors if got_failure: - error_msg += "Got the following " + str(num_matches) + " completions back:\n" + error_msg += ( + "Got the following " + str(num_matches) + " completions back:\n" + ) for i in range(num_matches + 1): match_candidate = match_strings.GetStringAtIndex(i) description_candidate = description_strings.GetStringAtIndex(i) - error_msg += "[" + match_candidate + ":" + description_candidate + "] index " + str(i) + "\n" + error_msg += ( + "[" + + match_candidate + + ":" + + description_candidate + + "] index " + + str(i) + + "\n" + ) self.assertFalse(got_failure, error_msg) def complete_exactly(self, str_input, patterns): @@ -2169,7 +2238,9 @@ class TestBase(Base, metaclass=LLDBTestCaseFactory): interp = self.dbg.GetCommandInterpreter() match_strings = lldb.SBStringList() - num_matches = interp.HandleCompletion(str_input, len(str_input), 0, -1, match_strings) + num_matches = interp.HandleCompletion( + str_input, len(str_input), 0, -1, match_strings + ) common_match = match_strings.GetStringAtIndex(0) if num_matches == 0: compare_string = str_input @@ -2178,18 +2249,24 @@ class TestBase(Base, metaclass=LLDBTestCaseFactory): compare_string = str_input + common_match else: compare_string = "" - for idx in range(1, num_matches+1): + for idx in range(1, num_matches + 1): compare_string += match_strings.GetStringAtIndex(idx) + "\n" for p in patterns: if turn_off_re_match: self.expect( - compare_string, msg=COMPLETION_MSG( - str_input, p, match_strings), exe=False, substrs=[p]) + compare_string, + msg=COMPLETION_MSG(str_input, p, match_strings), + exe=False, + substrs=[p], + ) else: self.expect( - compare_string, msg=COMPLETION_MSG( - str_input, p, match_strings), exe=False, patterns=[p]) + compare_string, + msg=COMPLETION_MSG(str_input, p, match_strings), + exe=False, + patterns=[p], + ) def completions_match(self, command, completions): """Checks that the completions for the given command are equal to the @@ -2198,8 +2275,9 @@ class TestBase(Base, metaclass=LLDBTestCaseFactory): match_strings = lldb.SBStringList() interp.HandleCompletion(command, len(command), 0, -1, match_strings) # match_strings is a 1-indexed list, so we have to slice... - self.assertItemsEqual(completions, list(match_strings)[1:], - "List of returned completion is wrong") + self.assertItemsEqual( + completions, list(match_strings)[1:], "List of returned completion is wrong" + ) def completions_contain(self, command, completions): """Checks that the completions for the given command contain the given @@ -2209,31 +2287,29 @@ class TestBase(Base, metaclass=LLDBTestCaseFactory): interp.HandleCompletion(command, len(command), 0, -1, match_strings) for completion in completions: # match_strings is a 1-indexed list, so we have to slice... - self.assertIn(completion, list(match_strings)[1:], - "Couldn't find expected completion") + self.assertIn( + completion, list(match_strings)[1:], "Couldn't find expected completion" + ) def filecheck( - self, - command, - check_file, - filecheck_options = '', - expect_cmd_failure = False): + self, command, check_file, filecheck_options="", expect_cmd_failure=False + ): # Run the command. self.runCmd( - command, - check=(not expect_cmd_failure), - msg="FileCheck'ing result of `{0}`".format(command)) + command, + check=(not expect_cmd_failure), + msg="FileCheck'ing result of `{0}`".format(command), + ) self.assertTrue((not expect_cmd_failure) == self.res.Succeeded()) # Get the error text if there was an error, and the regular text if not. - output = self.res.GetOutput() if self.res.Succeeded() \ - else self.res.GetError() + output = self.res.GetOutput() if self.res.Succeeded() else self.res.GetError() # Assemble the absolute path to the check file. As a convenience for # LLDB inline tests, assume that the check file is a relative path to # a file within the inline test directory. - if check_file.endswith('.pyc'): + if check_file.endswith(".pyc"): check_file = check_file[:-1] check_file_abs = os.path.abspath(check_file) @@ -2244,7 +2320,13 @@ class TestBase(Base, metaclass=LLDBTestCaseFactory): filecheck_args = [filecheck_bin, check_file_abs] if filecheck_options: filecheck_args.append(filecheck_options) - subproc = Popen(filecheck_args, stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines = True) + subproc = Popen( + filecheck_args, + stdin=PIPE, + stdout=PIPE, + stderr=PIPE, + universal_newlines=True, + ) cmd_stdout, cmd_stderr = subproc.communicate(input=output) cmd_status = subproc.returncode @@ -2259,7 +2341,9 @@ FileCheck input: FileCheck output: {3} {4} -""".format(cmd_status, filecheck_cmd, output, cmd_stdout, cmd_stderr) +""".format( + cmd_status, filecheck_cmd, output, cmd_stdout, cmd_stderr + ) trace = cmd_status != 0 or traceAlways with recording(self, trace) as sbuf: @@ -2268,19 +2352,20 @@ FileCheck output: self.assertTrue(cmd_status == 0) def expect( - self, - string, - msg=None, - patterns=None, - startstr=None, - endstr=None, - substrs=None, - trace=False, - error=False, - ordered=True, - matching=True, - exe=True, - inHistory=False): + self, + string, + msg=None, + patterns=None, + startstr=None, + endstr=None, + substrs=None, + trace=False, + error=False, + ordered=True, + matching=True, + exe=True, + inHistory=False, + ): """ Similar to runCmd; with additional expect style output matching ability. @@ -2319,12 +2404,10 @@ FileCheck output: assert False, "expect() missing a matcher argument" # Check `patterns` and `substrs` are not accidentally given as strings. - assert not isinstance(patterns, str), \ - "patterns must be a collection of strings" - assert not isinstance(substrs, str), \ - "substrs must be a collection of strings" + assert not isinstance(patterns, str), "patterns must be a collection of strings" + assert not isinstance(substrs, str), "substrs must be a collection of strings" - trace = (True if traceAlways else trace) + trace = True if traceAlways else trace if exe: # First run the command. If we are expecting error, set check=False. @@ -2333,18 +2416,20 @@ FileCheck output: self.runCmd( string, msg=msg, - trace=( - True if trace else False), + trace=(True if trace else False), check=not error, - inHistory=inHistory) + inHistory=inHistory, + ) # Then compare the output against expected strings. output = self.res.GetError() if error else self.res.GetOutput() # If error is True, the API client expects the command to fail! if error: - self.assertFalse(self.res.Succeeded(), - "Command '" + string + "' is expected to fail!") + self.assertFalse( + self.res.Succeeded(), + "Command '" + string + "' is expected to fail!", + ) else: # No execution required, just compare string against the golden input. if isinstance(string, lldb.SBCommandReturnObject): @@ -2355,15 +2440,16 @@ FileCheck output: print("looking at:", output, file=sbuf) expecting_str = "Expecting" if matching else "Not expecting" + def found_str(matched): return "was found" if matched else "was not found" # To be used as assert fail message and/or trace content log_lines = [ - "{}:".format("Ran command" if exe else "Checking string"), - "\"{}\"".format(string), - # Space out command and output - "", + "{}:".format("Ran command" if exe else "Checking string"), + '"{}"'.format(string), + # Space out command and output + "", ] if exe: # Newline before output to make large strings more readable @@ -2377,13 +2463,19 @@ FileCheck output: # We will stop checking on first failure if startstr: matched = output.startswith(startstr) - log_lines.append("{} start string: \"{}\" ({})".format( - expecting_str, startstr, found_str(matched))) + log_lines.append( + '{} start string: "{}" ({})'.format( + expecting_str, startstr, found_str(matched) + ) + ) if endstr and matched == matching: matched = output.endswith(endstr) - log_lines.append("{} end string: \"{}\" ({})".format( - expecting_str, endstr, found_str(matched))) + log_lines.append( + '{} end string: "{}" ({})'.format( + expecting_str, endstr, found_str(matched) + ) + ) if substrs and matched == matching: start = 0 @@ -2391,8 +2483,11 @@ FileCheck output: index = output[start:].find(substr) start = start + index + len(substr) if ordered and matching else 0 matched = index != -1 - log_lines.append("{} sub string: \"{}\" ({})".format( - expecting_str, substr, found_str(matched))) + log_lines.append( + '{} sub string: "{}" ({})'.format( + expecting_str, substr, found_str(matched) + ) + ) if matched != matching: break @@ -2401,11 +2496,11 @@ FileCheck output: for pattern in patterns: matched = re.search(pattern, output) - pattern_line = "{} regex pattern: \"{}\" ({}".format( - expecting_str, pattern, found_str(matched)) + pattern_line = '{} regex pattern: "{}" ({}'.format( + expecting_str, pattern, found_str(matched) + ) if matched: - pattern_line += ", matched \"{}\"".format( - matched.group(0)) + pattern_line += ', matched "{}"'.format(matched.group(0)) pattern_line += ")" log_lines.append(pattern_line) @@ -2426,13 +2521,13 @@ FileCheck output: self.fail(log_msg) def expect_expr( - self, - expr, - result_summary=None, - result_value=None, - result_type=None, - result_children=None - ): + self, + expr, + result_summary=None, + result_value=None, + result_type=None, + result_children=None, + ): """ Evaluates the given expression and verifies the result. :param expr: The expression as a string. @@ -2442,7 +2537,10 @@ FileCheck output: :param result_children: The expected children of the expression result as a list of ValueChecks. None if the children shouldn't be checked. """ - self.assertTrue(expr.strip() == expr, "Expression contains trailing/leading whitespace: '" + expr + "'") + self.assertTrue( + expr.strip() == expr, + "Expression contains trailing/leading whitespace: '" + expr + "'", + ) frame = self.frame() options = lldb.SBExpressionOptions() @@ -2464,19 +2562,18 @@ FileCheck output: target = self.dbg.GetDummyTarget() eval_result = target.EvaluateExpression(expr, options) - value_check = ValueCheck(type=result_type, value=result_value, - summary=result_summary, children=result_children) + value_check = ValueCheck( + type=result_type, + value=result_value, + summary=result_summary, + children=result_children, + ) value_check.check_value(self, eval_result, str(eval_result)) return eval_result def expect_var_path( - self, - var_path, - summary=None, - value=None, - type=None, - children=None - ): + self, var_path, summary=None, value=None, type=None, children=None + ): """ Evaluates the given variable path and verifies the result. See also 'frame variable' and SBFrame.GetValueForVariablePath. @@ -2487,49 +2584,59 @@ FileCheck output: :param children: The expected children of the variable as a list of ValueChecks. None if the children shouldn't be checked. """ - self.assertTrue(var_path.strip() == var_path, - "Expression contains trailing/leading whitespace: '" + var_path + "'") + self.assertTrue( + var_path.strip() == var_path, + "Expression contains trailing/leading whitespace: '" + var_path + "'", + ) frame = self.frame() eval_result = frame.GetValueForVariablePath(var_path) - value_check = ValueCheck(type=type, value=value, - summary=summary, children=children) + value_check = ValueCheck( + type=type, value=value, summary=summary, children=children + ) value_check.check_value(self, eval_result, str(eval_result)) return eval_result """Assert that an lldb.SBError is in the "success" state.""" + def assertSuccess(self, obj, msg=None): if not obj.Success(): error = obj.GetCString() - self.fail(self._formatMessage(msg, - "'{}' is not success".format(error))) + self.fail(self._formatMessage(msg, "'{}' is not success".format(error))) """Assert that a command return object is successful""" + def assertCommandReturn(self, obj, msg=None): if not obj.Succeeded(): error = obj.GetError() - self.fail(self._formatMessage(msg, - "'{}' is not success".format(error))) + self.fail(self._formatMessage(msg, "'{}' is not success".format(error))) """Assert two states are equal""" + def assertState(self, first, second, msg=None): if first != second: error = "{} ({}) != {} ({})".format( - lldbutil.state_type_to_str(first), first, - lldbutil.state_type_to_str(second), second) + lldbutil.state_type_to_str(first), + first, + lldbutil.state_type_to_str(second), + second, + ) self.fail(self._formatMessage(msg, error)) """Assert two stop reasons are equal""" + def assertStopReason(self, first, second, msg=None): if first != second: error = "{} ({}) != {} ({})".format( - lldbutil.stop_reason_to_str(first), first, - lldbutil.stop_reason_to_str(second), second) + lldbutil.stop_reason_to_str(first), + first, + lldbutil.stop_reason_to_str(second), + second, + ) self.fail(self._formatMessage(msg, error)) - def createTestTarget(self, file_path=None, msg=None, - load_dependent_modules=True): + def createTestTarget(self, file_path=None, msg=None, load_dependent_modules=True): """ Creates a target from the file found at the given file path. Asserts that the resulting target is valid. @@ -2543,11 +2650,13 @@ FileCheck output: error = lldb.SBError() triple = "" platform = "" - target = self.dbg.CreateTarget(file_path, triple, platform, - load_dependent_modules, error) + target = self.dbg.CreateTarget( + file_path, triple, platform, load_dependent_modules, error + ) if error.Fail(): - err = "Couldn't create target for path '{}': {}".format(file_path, - str(error)) + err = "Couldn't create target for path '{}': {}".format( + file_path, str(error) + ) self.fail(self._formatMessage(msg, err)) self.assertTrue(target.IsValid(), "Got invalid target without error") @@ -2566,24 +2675,17 @@ FileCheck output: err = sys.stderr err.write(val.GetName() + ":\n") - err.write('\t' + "TypeName -> " + val.GetTypeName() + '\n') - err.write('\t' + "ByteSize -> " + - str(val.GetByteSize()) + '\n') - err.write('\t' + "NumChildren -> " + - str(val.GetNumChildren()) + '\n') - err.write('\t' + "Value -> " + str(val.GetValue()) + '\n') - err.write('\t' + "ValueAsUnsigned -> " + - str(val.GetValueAsUnsigned()) + '\n') + err.write("\t" + "TypeName -> " + val.GetTypeName() + "\n") + err.write("\t" + "ByteSize -> " + str(val.GetByteSize()) + "\n") + err.write("\t" + "NumChildren -> " + str(val.GetNumChildren()) + "\n") + err.write("\t" + "Value -> " + str(val.GetValue()) + "\n") + err.write("\t" + "ValueAsUnsigned -> " + str(val.GetValueAsUnsigned()) + "\n") err.write( - '\t' + - "ValueType -> " + - value_type_to_str( - val.GetValueType()) + - '\n') - err.write('\t' + "Summary -> " + str(val.GetSummary()) + '\n') - err.write('\t' + "IsPointerType -> " + - str(val.TypeIsPointerType()) + '\n') - err.write('\t' + "Location -> " + val.GetLocation() + '\n') + "\t" + "ValueType -> " + value_type_to_str(val.GetValueType()) + "\n" + ) + err.write("\t" + "Summary -> " + str(val.GetSummary()) + "\n") + err.write("\t" + "IsPointerType -> " + str(val.TypeIsPointerType()) + "\n") + err.write("\t" + "Location -> " + val.GetLocation() + "\n") def DebugSBType(self, type): """Debug print a SBType object, if traceAlways is True.""" @@ -2592,14 +2694,10 @@ FileCheck output: err = sys.stderr err.write(type.GetName() + ":\n") - err.write('\t' + "ByteSize -> " + - str(type.GetByteSize()) + '\n') - err.write('\t' + "IsAggregateType -> " + - str(type.IsAggregateType()) + '\n') - err.write('\t' + "IsPointerType -> " + - str(type.IsPointerType()) + '\n') - err.write('\t' + "IsReferenceType -> " + - str(type.IsReferenceType()) + '\n') + err.write("\t" + "ByteSize -> " + str(type.GetByteSize()) + "\n") + err.write("\t" + "IsAggregateType -> " + str(type.IsAggregateType()) + "\n") + err.write("\t" + "IsPointerType -> " + str(type.IsPointerType()) + "\n") + err.write("\t" + "IsReferenceType -> " + str(type.IsReferenceType()) + "\n") def DebugPExpect(self, child): """Debug the spwaned pexpect object.""" @@ -2613,6 +2711,7 @@ FileCheck output: if os.path.exists(file): remove_file(file) + # On Windows, the first attempt to delete a recently-touched file can fail # because of a race with antimalware scanners. This function will detect a # failure and retry. diff --git a/lldb/packages/Python/lldbsuite/test/lldbutil.py b/lldb/packages/Python/lldbsuite/test/lldbutil.py index 309b51b..3491370 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbutil.py +++ b/lldb/packages/Python/lldbsuite/test/lldbutil.py @@ -28,6 +28,7 @@ SIMULATOR_RETRY = 3 # Utilities for locating/checking executable programs # =================================================== + def is_exe(fpath): """Returns True if fpath is an executable.""" return os.path.isfile(fpath) and os.access(fpath, os.X_OK) @@ -46,6 +47,7 @@ def which(program): return exe_file return None + def mkdir_p(path): try: os.makedirs(path) @@ -53,13 +55,14 @@ def mkdir_p(path): if e.errno != errno.EEXIST: raise if not os.path.isdir(path): - raise OSError(errno.ENOTDIR, "%s is not a directory"%path) + raise OSError(errno.ENOTDIR, "%s is not a directory" % path) # ============================ # Dealing with SDK and triples # ============================ + def get_xcode_sdk(os, env): # Respect --apple-sdk <path> if it's specified. If the SDK is simply # mounted from some disk image, and not actually installed, this is the @@ -84,18 +87,27 @@ def get_xcode_sdk(os, env): def get_xcode_sdk_version(sdk): - return subprocess.check_output( - ['xcrun', '--sdk', sdk, '--show-sdk-version']).rstrip().decode('utf-8') + return ( + subprocess.check_output(["xcrun", "--sdk", sdk, "--show-sdk-version"]) + .rstrip() + .decode("utf-8") + ) def get_xcode_sdk_root(sdk): - return subprocess.check_output(['xcrun', '--sdk', sdk, '--show-sdk-path' - ]).rstrip().decode('utf-8') + return ( + subprocess.check_output(["xcrun", "--sdk", sdk, "--show-sdk-path"]) + .rstrip() + .decode("utf-8") + ) def get_xcode_clang(sdk): - return subprocess.check_output(['xcrun', '-sdk', sdk, '-f', 'clang' - ]).rstrip().decode("utf-8") + return ( + subprocess.check_output(["xcrun", "-sdk", sdk, "-f", "clang"]) + .rstrip() + .decode("utf-8") + ) # =================================================== @@ -114,6 +126,7 @@ def disassemble(target, function_or_symbol): print(i, file=buf) return buf.getvalue() + # ========================================================== # Integer (byte size 1, 2, 4, and 8) to bytearray conversion # ========================================================== @@ -133,11 +146,11 @@ def int_to_bytearray(val, bytesize): # Little endian followed by a format character. template = "<%c" if bytesize == 2: - fmt = template % 'h' + fmt = template % "h" elif bytesize == 4: - fmt = template % 'i' + fmt = template % "i" elif bytesize == 4: - fmt = template % 'q' + fmt = template % "q" else: return None @@ -159,11 +172,11 @@ def bytearray_to_int(bytes, bytesize): # Little endian followed by a format character. template = "<%c" if bytesize == 2: - fmt = template % 'h' + fmt = template % "h" elif bytesize == 4: - fmt = template % 'i' + fmt = template % "i" elif bytesize == 4: - fmt = template % 'q' + fmt = template % "q" else: return None @@ -184,7 +197,7 @@ def get_description(obj, option=None): o lldb.eDescriptionLevelFull o lldb.eDescriptionLevelVerbose """ - method = getattr(obj, 'GetDescription') + method = getattr(obj, "GetDescription") if not method: return None tuple = (lldb.SBTarget, lldb.SBBreakpointLocation, lldb.SBWatchpoint) @@ -206,6 +219,7 @@ def get_description(obj, option=None): # Convert some enum value to its string counterpart # ================================================= + def _enum_names(prefix: str) -> Dict[int, str]: """Generate a mapping of enum value to name, for the enum prefix.""" suffix_start = len(prefix) @@ -218,6 +232,7 @@ def _enum_names(prefix: str) -> Dict[int, str]: _STATE_NAMES = _enum_names(prefix="eState") + def state_type_to_str(enum: int) -> str: """Returns the stateType string given an enum.""" name = _STATE_NAMES.get(enum) @@ -228,6 +243,7 @@ def state_type_to_str(enum: int) -> str: _STOP_REASON_NAMES = _enum_names(prefix="eStopReason") + def stop_reason_to_str(enum: int) -> str: """Returns the stopReason string given an enum.""" name = _STOP_REASON_NAMES.get(enum) @@ -238,6 +254,7 @@ def stop_reason_to_str(enum: int) -> str: _SYMBOL_TYPE_NAMES = _enum_names(prefix="eSymbolType") + def symbol_type_to_str(enum: int) -> str: """Returns the symbolType string given an enum.""" name = _SYMBOL_TYPE_NAMES.get(enum) @@ -248,6 +265,7 @@ def symbol_type_to_str(enum: int) -> str: _VALUE_TYPE_NAMES = _enum_names(prefix="eValueType") + def value_type_to_str(enum: int) -> str: """Returns the valueType string given an enum.""" name = _VALUE_TYPE_NAMES.get(enum) @@ -260,46 +278,53 @@ def value_type_to_str(enum: int) -> str: # Get stopped threads due to each stop reason. # ================================================== -def sort_stopped_threads(process, - breakpoint_threads=None, - crashed_threads=None, - watchpoint_threads=None, - signal_threads=None, - exiting_threads=None, - other_threads=None): - """ Fills array *_threads with threads stopped for the corresponding stop - reason. + +def sort_stopped_threads( + process, + breakpoint_threads=None, + crashed_threads=None, + watchpoint_threads=None, + signal_threads=None, + exiting_threads=None, + other_threads=None, +): + """Fills array *_threads with threads stopped for the corresponding stop + reason. """ - for lst in [breakpoint_threads, - watchpoint_threads, - signal_threads, - exiting_threads, - other_threads]: + for lst in [ + breakpoint_threads, + watchpoint_threads, + signal_threads, + exiting_threads, + other_threads, + ]: if lst is not None: lst[:] = [] for thread in process: dispatched = False - for (reason, list) in [(lldb.eStopReasonBreakpoint, breakpoint_threads), - (lldb.eStopReasonException, crashed_threads), - (lldb.eStopReasonWatchpoint, watchpoint_threads), - (lldb.eStopReasonSignal, signal_threads), - (lldb.eStopReasonThreadExiting, exiting_threads), - (None, other_threads)]: + for reason, list in [ + (lldb.eStopReasonBreakpoint, breakpoint_threads), + (lldb.eStopReasonException, crashed_threads), + (lldb.eStopReasonWatchpoint, watchpoint_threads), + (lldb.eStopReasonSignal, signal_threads), + (lldb.eStopReasonThreadExiting, exiting_threads), + (None, other_threads), + ]: if not dispatched and list is not None: if thread.GetStopReason() == reason or reason is None: list.append(thread) dispatched = True + # ================================================== # Utility functions for setting breakpoints # ================================================== + def run_break_set_by_script( - test, - class_name, - extra_options=None, - num_expected_locations=1): + test, class_name, extra_options=None, num_expected_locations=1 +): """Set a scripted breakpoint. Check that it got the right number of locations.""" test.assertTrue(class_name is not None, "Must pass in a class name.") command = "breakpoint set -P " + class_name @@ -310,14 +335,16 @@ def run_break_set_by_script( check_breakpoint_result(test, break_results, num_locations=num_expected_locations) return get_bpno_from_match(break_results) + def run_break_set_by_file_and_line( - test, - file_name, - line_number, - extra_options=None, - num_expected_locations=1, - loc_exact=False, - module_name=None): + test, + file_name, + line_number, + extra_options=None, + num_expected_locations=1, + loc_exact=False, + module_name=None, +): """Set a breakpoint by file and line, returning the breakpoint number. If extra_options is not None, then we append it to the breakpoint set command. @@ -325,10 +352,11 @@ def run_break_set_by_file_and_line( If num_expected_locations is -1, we check that we got AT LEAST one location. If num_expected_locations is -2, we don't check the actual number at all. Otherwise, we check that num_expected_locations equals the number of locations. - If loc_exact is true, we check that there is one location, and that location must be at the input file and line number.""" + If loc_exact is true, we check that there is one location, and that location must be at the input file and line number. + """ if file_name is None: - command = 'breakpoint set -l %d' % (line_number) + command = "breakpoint set -l %d" % (line_number) else: command = 'breakpoint set -f "%s" -l %d' % (file_name, line_number) @@ -347,26 +375,28 @@ def run_break_set_by_file_and_line( num_locations=num_expected_locations, file_name=file_name, line_number=line_number, - module_name=module_name) + module_name=module_name, + ) else: check_breakpoint_result( - test, - break_results, - num_locations=num_expected_locations) + test, break_results, num_locations=num_expected_locations + ) return get_bpno_from_match(break_results) def run_break_set_by_symbol( - test, - symbol, - extra_options=None, - num_expected_locations=-1, - sym_exact=False, - module_name=None): + test, + symbol, + extra_options=None, + num_expected_locations=-1, + sym_exact=False, + module_name=None, +): """Set a breakpoint by symbol name. Common options are the same as run_break_set_by_file_and_line. - If sym_exact is true, then the output symbol must match the input exactly, otherwise we do a substring match.""" + If sym_exact is true, then the output symbol must match the input exactly, otherwise we do a substring match. + """ command = 'breakpoint set -n "%s"' % (symbol) if module_name: @@ -383,22 +413,19 @@ def run_break_set_by_symbol( break_results, num_locations=num_expected_locations, symbol_name=symbol, - module_name=module_name) + module_name=module_name, + ) else: check_breakpoint_result( - test, - break_results, - num_locations=num_expected_locations) + test, break_results, num_locations=num_expected_locations + ) return get_bpno_from_match(break_results) def run_break_set_by_selector( - test, - selector, - extra_options=None, - num_expected_locations=-1, - module_name=None): + test, selector, extra_options=None, num_expected_locations=-1, module_name=None +): """Set a breakpoint by selector. Common options are the same as run_break_set_by_file_and_line.""" command = 'breakpoint set -S "%s"' % (selector) @@ -418,21 +445,19 @@ def run_break_set_by_selector( num_locations=num_expected_locations, symbol_name=selector, symbol_match_exact=False, - module_name=module_name) + module_name=module_name, + ) else: check_breakpoint_result( - test, - break_results, - num_locations=num_expected_locations) + test, break_results, num_locations=num_expected_locations + ) return get_bpno_from_match(break_results) def run_break_set_by_regexp( - test, - regexp, - extra_options=None, - num_expected_locations=-1): + test, regexp, extra_options=None, num_expected_locations=-1 +): """Set a breakpoint by regular expression match on symbol name. Common options are the same as run_break_set_by_file_and_line.""" command = 'breakpoint set -r "%s"' % (regexp) @@ -441,19 +466,14 @@ def run_break_set_by_regexp( break_results = run_break_set_command(test, command) - check_breakpoint_result( - test, - break_results, - num_locations=num_expected_locations) + check_breakpoint_result(test, break_results, num_locations=num_expected_locations) return get_bpno_from_match(break_results) def run_break_set_by_source_regexp( - test, - regexp, - extra_options=None, - num_expected_locations=-1): + test, regexp, extra_options=None, num_expected_locations=-1 +): """Set a breakpoint by source regular expression. Common options are the same as run_break_set_by_file_and_line.""" command = 'breakpoint set -p "%s"' % (regexp) if extra_options: @@ -461,22 +481,21 @@ def run_break_set_by_source_regexp( break_results = run_break_set_command(test, command) - check_breakpoint_result( - test, - break_results, - num_locations=num_expected_locations) + check_breakpoint_result(test, break_results, num_locations=num_expected_locations) return get_bpno_from_match(break_results) + def run_break_set_by_file_colon_line( - test, - specifier, - path, - line_number, - column_number = 0, - extra_options=None, - num_expected_locations=-1): - command = 'breakpoint set -y "%s"'%(specifier) + test, + specifier, + path, + line_number, + column_number=0, + extra_options=None, + num_expected_locations=-1, +): + command = 'breakpoint set -y "%s"' % (specifier) if extra_options: command += " " + extra_options @@ -485,13 +504,15 @@ def run_break_set_by_file_colon_line( check_breakpoint_result( test, break_results, - num_locations = num_expected_locations, - file_name = path, - line_number = line_number, - column_number = column_number) + num_locations=num_expected_locations, + file_name=path, + line_number=line_number, + column_number=column_number, + ) return get_bpno_from_match(break_results) + def run_break_set_command(test, command): """Run the command passed in - it must be some break set variant - and analyze the result. Returns a dictionary of information gleaned from the command-line results. @@ -515,146 +536,147 @@ def run_break_set_command(test, command): r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>[0-9]+) locations\.$", r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>no) locations \(pending\)\.", r"^Breakpoint (?P<bpno>[0-9]+): where = (?P<module>.*)`(?P<symbol>[+\-]{0,1}[^+]+)( \+ (?P<offset>[0-9]+)){0,1}( \[inlined\] (?P<inline_symbol>.*)){0,1} at (?P<file>[^:]+):(?P<line_no>[0-9]+)(?P<column>(:[0-9]+)?), address = (?P<address>0x[0-9a-fA-F]+)$", - r"^Breakpoint (?P<bpno>[0-9]+): where = (?P<module>.*)`(?P<symbol>.*)( \+ (?P<offset>[0-9]+)){0,1}, address = (?P<address>0x[0-9a-fA-F]+)$"] + r"^Breakpoint (?P<bpno>[0-9]+): where = (?P<module>.*)`(?P<symbol>.*)( \+ (?P<offset>[0-9]+)){0,1}, address = (?P<address>0x[0-9a-fA-F]+)$", + ] match_object = test.match(command, patterns) break_results = match_object.groupdict() # We always insert the breakpoint number, setting it to -1 if we couldn't find it # Also, make sure it gets stored as an integer. - if not 'bpno' in break_results: - break_results['bpno'] = -1 + if not "bpno" in break_results: + break_results["bpno"] = -1 else: - break_results['bpno'] = int(break_results['bpno']) + break_results["bpno"] = int(break_results["bpno"]) # We always insert the number of locations # If ONE location is set for the breakpoint, then the output doesn't mention locations, but it has to be 1... # We also make sure it is an integer. - if not 'num_locations' in break_results: + if not "num_locations" in break_results: num_locations = 1 else: - num_locations = break_results['num_locations'] - if num_locations == 'no': + num_locations = break_results["num_locations"] + if num_locations == "no": num_locations = 0 else: - num_locations = int(break_results['num_locations']) + num_locations = int(break_results["num_locations"]) - break_results['num_locations'] = num_locations + break_results["num_locations"] = num_locations - if 'line_no' in break_results: - break_results['line_no'] = int(break_results['line_no']) + if "line_no" in break_results: + break_results["line_no"] = int(break_results["line_no"]) return break_results def get_bpno_from_match(break_results): - return int(break_results['bpno']) + return int(break_results["bpno"]) def check_breakpoint_result( - test, - break_results, - file_name=None, - line_number=-1, - column_number=0, - symbol_name=None, - symbol_match_exact=True, - module_name=None, - offset=-1, - num_locations=-1): - - out_num_locations = break_results['num_locations'] + test, + break_results, + file_name=None, + line_number=-1, + column_number=0, + symbol_name=None, + symbol_match_exact=True, + module_name=None, + offset=-1, + num_locations=-1, +): + out_num_locations = break_results["num_locations"] if num_locations == -1: - test.assertTrue(out_num_locations > 0, - "Expecting one or more locations, got none.") + test.assertTrue( + out_num_locations > 0, "Expecting one or more locations, got none." + ) elif num_locations != -2: test.assertTrue( num_locations == out_num_locations, - "Expecting %d locations, got %d." % - (num_locations, - out_num_locations)) + "Expecting %d locations, got %d." % (num_locations, out_num_locations), + ) if file_name: out_file_name = "" - if 'file' in break_results: - out_file_name = break_results['file'] + if "file" in break_results: + out_file_name = break_results["file"] test.assertTrue( file_name.endswith(out_file_name), - "Breakpoint file name '%s' doesn't match resultant name '%s'." % - (file_name, - out_file_name)) + "Breakpoint file name '%s' doesn't match resultant name '%s'." + % (file_name, out_file_name), + ) if line_number != -1: out_line_number = -1 - if 'line_no' in break_results: - out_line_number = break_results['line_no'] + if "line_no" in break_results: + out_line_number = break_results["line_no"] test.assertTrue( line_number == out_line_number, - "Breakpoint line number %s doesn't match resultant line %s." % - (line_number, - out_line_number)) + "Breakpoint line number %s doesn't match resultant line %s." + % (line_number, out_line_number), + ) if column_number != 0: out_column_number = 0 - if 'column' in break_results: - out_column_number = break_results['column'] + if "column" in break_results: + out_column_number = break_results["column"] test.assertTrue( column_number == out_column_number, - "Breakpoint column number %s doesn't match resultant column %s." % - (column_number, - out_column_number)) + "Breakpoint column number %s doesn't match resultant column %s." + % (column_number, out_column_number), + ) if symbol_name: out_symbol_name = "" # Look first for the inlined symbol name, otherwise use the symbol # name: - if 'inline_symbol' in break_results and break_results['inline_symbol']: - out_symbol_name = break_results['inline_symbol'] - elif 'symbol' in break_results: - out_symbol_name = break_results['symbol'] + if "inline_symbol" in break_results and break_results["inline_symbol"]: + out_symbol_name = break_results["inline_symbol"] + elif "symbol" in break_results: + out_symbol_name = break_results["symbol"] if symbol_match_exact: test.assertTrue( symbol_name == out_symbol_name, - "Symbol name '%s' doesn't match resultant symbol '%s'." % - (symbol_name, - out_symbol_name)) + "Symbol name '%s' doesn't match resultant symbol '%s'." + % (symbol_name, out_symbol_name), + ) else: test.assertTrue( - out_symbol_name.find(symbol_name) != - - 1, - "Symbol name '%s' isn't in resultant symbol '%s'." % - (symbol_name, - out_symbol_name)) + out_symbol_name.find(symbol_name) != -1, + "Symbol name '%s' isn't in resultant symbol '%s'." + % (symbol_name, out_symbol_name), + ) if module_name: out_module_name = None - if 'module' in break_results: - out_module_name = break_results['module'] + if "module" in break_results: + out_module_name = break_results["module"] test.assertTrue( - module_name.find(out_module_name) != - - 1, - "Symbol module name '%s' isn't in expected module name '%s'." % - (out_module_name, - module_name)) + module_name.find(out_module_name) != -1, + "Symbol module name '%s' isn't in expected module name '%s'." + % (out_module_name, module_name), + ) + def check_breakpoint( - test, - bpno, - expected_locations = None, - expected_resolved_count = None, - expected_hit_count = None, - location_id = None, - expected_location_resolved = True, - expected_location_hit_count = None): + test, + bpno, + expected_locations=None, + expected_resolved_count=None, + expected_hit_count=None, + location_id=None, + expected_location_resolved=True, + expected_location_hit_count=None, +): """ Test breakpoint or breakpoint location. - Breakpoint resolved count is always checked. If not specified the assumption is that all locations - should be resolved. + Breakpoint resolved count is always checked. If not specified the assumption is that all locations + should be resolved. To test a breakpoint location, breakpoint number (bpno) and location_id must be set. In this case the resolved count for a breakpoint is not tested by default. The location is expected to be resolved, unless expected_location_resolved is set to False. @@ -697,7 +719,6 @@ def check_breakpoint( test.assertEquals(expected_location_hit_count, loc_bkpt.GetHitCount()) - # ================================================== # Utility functions related to Threads and Processes # ================================================== @@ -745,7 +766,7 @@ def get_stopped_thread(process, reason): def get_threads_stopped_at_breakpoint_id(process, bpid): - """ For a stopped process returns the thread stopped at the breakpoint passed in bkpt""" + """For a stopped process returns the thread stopped at the breakpoint passed in bkpt""" stopped_threads = [] threads = [] @@ -767,8 +788,7 @@ def get_threads_stopped_at_breakpoint(process, bkpt): return get_threads_stopped_at_breakpoint_id(process, bkpt.GetID()) -def get_one_thread_stopped_at_breakpoint_id( - process, bpid, require_exactly_one=True): +def get_one_thread_stopped_at_breakpoint_id(process, bpid, require_exactly_one=True): threads = get_threads_stopped_at_breakpoint_id(process, bpid) if len(threads) == 0: return None @@ -778,21 +798,26 @@ def get_one_thread_stopped_at_breakpoint_id( return threads[0] -def get_one_thread_stopped_at_breakpoint( - process, bkpt, require_exactly_one=True): +def get_one_thread_stopped_at_breakpoint(process, bkpt, require_exactly_one=True): return get_one_thread_stopped_at_breakpoint_id( - process, bkpt.GetID(), require_exactly_one) + process, bkpt.GetID(), require_exactly_one + ) def is_thread_crashed(test, thread): """In the test suite we dereference a null pointer to simulate a crash. The way this is reported depends on the platform.""" if test.platformIsDarwin(): - return thread.GetStopReason( - ) == lldb.eStopReasonException and "EXC_BAD_ACCESS" in thread.GetStopDescription(100) + return ( + thread.GetStopReason() == lldb.eStopReasonException + and "EXC_BAD_ACCESS" in thread.GetStopDescription(100) + ) elif test.getPlatform() == "linux": - return thread.GetStopReason() == lldb.eStopReasonSignal and thread.GetStopReasonDataAtIndex( - 0) == thread.GetProcess().GetUnixSignals().GetSignalNumberFromName("SIGSEGV") + return ( + thread.GetStopReason() == lldb.eStopReasonSignal + and thread.GetStopReasonDataAtIndex(0) + == thread.GetProcess().GetUnixSignals().GetSignalNumberFromName("SIGSEGV") + ) elif test.getPlatform() == "windows": return "Exception 0xc0000005" in thread.GetStopDescription(200) else: @@ -808,24 +833,29 @@ def get_crashed_threads(test, process): threads.append(thread) return threads + # Helper functions for run_to_{source,name}_breakpoint: -def run_to_breakpoint_make_target(test, exe_name = "a.out", in_cwd = True): + +def run_to_breakpoint_make_target(test, exe_name="a.out", in_cwd=True): exe = test.getBuildArtifact(exe_name) if in_cwd else exe_name # Create the target target = test.dbg.CreateTarget(exe) - test.assertTrue(target, "Target: %s is not valid."%(exe_name)) + test.assertTrue(target, "Target: %s is not valid." % (exe_name)) # Set environment variables for the inferior. if lldbtest_config.inferior_env: - test.runCmd('settings set target.env-vars {}'.format( - lldbtest_config.inferior_env)) + test.runCmd( + "settings set target.env-vars {}".format(lldbtest_config.inferior_env) + ) return target -def run_to_breakpoint_do_run(test, target, bkpt, launch_info = None, - only_one_thread = True, extra_images = None): + +def run_to_breakpoint_do_run( + test, target, bkpt, launch_info=None, only_one_thread=True, extra_images=None +): # Launch the process, and do not stop at the entry point. if not launch_info: launch_info = target.GetLaunchInfo() @@ -840,20 +870,26 @@ def run_to_breakpoint_do_run(test, target, bkpt, launch_info = None, # Unfortunate workaround for the iPhone simulator. retry = SIMULATOR_RETRY - while (retry and error.Fail() and error.GetCString() and - "Unable to boot the Simulator" in error.GetCString()): + while ( + retry + and error.Fail() + and error.GetCString() + and "Unable to boot the Simulator" in error.GetCString() + ): retry -= 1 - print("** Simulator is unresponsive. Retrying %d more time(s)"%retry) + print("** Simulator is unresponsive. Retrying %d more time(s)" % retry) import time + time.sleep(60) error = lldb.SBError() process = target.Launch(launch_info, error) - test.assertTrue(process, - "Could not create a valid process for %s: %s" % - (target.GetExecutable().GetFilename(), error.GetCString())) - test.assertFalse(error.Fail(), - "Process launch failed: %s" % (error.GetCString())) + test.assertTrue( + process, + "Could not create a valid process for %s: %s" + % (target.GetExecutable().GetFilename(), error.GetCString()), + ) + test.assertFalse(error.Fail(), "Process launch failed: %s" % (error.GetCString())) def processStateInfo(process): info = "state: {}".format(state_type_to_str(process.state)) @@ -870,115 +906,149 @@ def run_to_breakpoint_do_run(test, target, bkpt, launch_info = None, return info if process.state != lldb.eStateStopped: - test.fail("Test process is not stopped at breakpoint: {}".format(processStateInfo(process))) + test.fail( + "Test process is not stopped at breakpoint: {}".format( + processStateInfo(process) + ) + ) # Frame #0 should be at our breakpoint. - threads = get_threads_stopped_at_breakpoint( - process, bkpt) + threads = get_threads_stopped_at_breakpoint(process, bkpt) num_threads = len(threads) if only_one_thread: - test.assertEqual(num_threads, 1, "Expected 1 thread to stop at breakpoint, %d did."%(num_threads)) + test.assertEqual( + num_threads, + 1, + "Expected 1 thread to stop at breakpoint, %d did." % (num_threads), + ) else: test.assertGreater(num_threads, 0, "No threads stopped at breakpoint") thread = threads[0] return (target, process, thread, bkpt) -def run_to_name_breakpoint (test, bkpt_name, launch_info = None, - exe_name = "a.out", - bkpt_module = None, - in_cwd = True, - only_one_thread = True, - extra_images = None): + +def run_to_name_breakpoint( + test, + bkpt_name, + launch_info=None, + exe_name="a.out", + bkpt_module=None, + in_cwd=True, + only_one_thread=True, + extra_images=None, +): """Start up a target, using exe_name as the executable, and run it to - a breakpoint set by name on bkpt_name restricted to bkpt_module. + a breakpoint set by name on bkpt_name restricted to bkpt_module. - If you want to pass in launch arguments or environment - variables, you can optionally pass in an SBLaunchInfo. If you - do that, remember to set the working directory as well. + If you want to pass in launch arguments or environment + variables, you can optionally pass in an SBLaunchInfo. If you + do that, remember to set the working directory as well. - If your executable isn't called a.out, you can pass that in. - And if your executable isn't in the CWD, pass in the absolute - path to the executable in exe_name, and set in_cwd to False. + If your executable isn't called a.out, you can pass that in. + And if your executable isn't in the CWD, pass in the absolute + path to the executable in exe_name, and set in_cwd to False. - If you need to restrict the breakpoint to a particular module, - pass the module name (a string not a FileSpec) in bkpt_module. If - nothing is passed in setting will be unrestricted. + If you need to restrict the breakpoint to a particular module, + pass the module name (a string not a FileSpec) in bkpt_module. If + nothing is passed in setting will be unrestricted. - If the target isn't valid, the breakpoint isn't found, or hit, the - function will cause a testsuite failure. + If the target isn't valid, the breakpoint isn't found, or hit, the + function will cause a testsuite failure. - If successful it returns a tuple with the target process and - thread that hit the breakpoint, and the breakpoint that we set - for you. + If successful it returns a tuple with the target process and + thread that hit the breakpoint, and the breakpoint that we set + for you. - If only_one_thread is true, we require that there be only one - thread stopped at the breakpoint. Otherwise we only require one - or more threads stop there. If there are more than one, we return - the first thread that stopped. + If only_one_thread is true, we require that there be only one + thread stopped at the breakpoint. Otherwise we only require one + or more threads stop there. If there are more than one, we return + the first thread that stopped. """ target = run_to_breakpoint_make_target(test, exe_name, in_cwd) breakpoint = target.BreakpointCreateByName(bkpt_name, bkpt_module) - - test.assertTrue(breakpoint.GetNumLocations() > 0, - "No locations found for name breakpoint: '%s'."%(bkpt_name)) - return run_to_breakpoint_do_run(test, target, breakpoint, launch_info, - only_one_thread, extra_images) - -def run_to_source_breakpoint(test, bkpt_pattern, source_spec, - launch_info = None, exe_name = "a.out", - bkpt_module = None, - in_cwd = True, - only_one_thread = True, - extra_images = None, - has_locations_before_run = True): + test.assertTrue( + breakpoint.GetNumLocations() > 0, + "No locations found for name breakpoint: '%s'." % (bkpt_name), + ) + return run_to_breakpoint_do_run( + test, target, breakpoint, launch_info, only_one_thread, extra_images + ) + + +def run_to_source_breakpoint( + test, + bkpt_pattern, + source_spec, + launch_info=None, + exe_name="a.out", + bkpt_module=None, + in_cwd=True, + only_one_thread=True, + extra_images=None, + has_locations_before_run=True, +): """Start up a target, using exe_name as the executable, and run it to - a breakpoint set by source regex bkpt_pattern. + a breakpoint set by source regex bkpt_pattern. - The rest of the behavior is the same as run_to_name_breakpoint. + The rest of the behavior is the same as run_to_name_breakpoint. """ target = run_to_breakpoint_make_target(test, exe_name, in_cwd) # Set the breakpoints breakpoint = target.BreakpointCreateBySourceRegex( - bkpt_pattern, source_spec, bkpt_module) + bkpt_pattern, source_spec, bkpt_module + ) if has_locations_before_run: - test.assertTrue(breakpoint.GetNumLocations() > 0, - 'No locations found for source breakpoint: "%s", file: "%s", dir: "%s"' - %(bkpt_pattern, source_spec.GetFilename(), source_spec.GetDirectory())) - return run_to_breakpoint_do_run(test, target, breakpoint, launch_info, - only_one_thread, extra_images) - -def run_to_line_breakpoint(test, source_spec, line_number, column = 0, - launch_info = None, exe_name = "a.out", - bkpt_module = None, - in_cwd = True, - only_one_thread = True, - extra_images = None): + test.assertTrue( + breakpoint.GetNumLocations() > 0, + 'No locations found for source breakpoint: "%s", file: "%s", dir: "%s"' + % (bkpt_pattern, source_spec.GetFilename(), source_spec.GetDirectory()), + ) + return run_to_breakpoint_do_run( + test, target, breakpoint, launch_info, only_one_thread, extra_images + ) + + +def run_to_line_breakpoint( + test, + source_spec, + line_number, + column=0, + launch_info=None, + exe_name="a.out", + bkpt_module=None, + in_cwd=True, + only_one_thread=True, + extra_images=None, +): """Start up a target, using exe_name as the executable, and run it to - a breakpoint set by (source_spec, line_number(, column)). + a breakpoint set by (source_spec, line_number(, column)). - The rest of the behavior is the same as run_to_name_breakpoint. + The rest of the behavior is the same as run_to_name_breakpoint. """ target = run_to_breakpoint_make_target(test, exe_name, in_cwd) # Set the breakpoints breakpoint = target.BreakpointCreateByLocation( - source_spec, line_number, column, 0, lldb.SBFileSpecList()) - test.assertTrue(breakpoint.GetNumLocations() > 0, + source_spec, line_number, column, 0, lldb.SBFileSpecList() + ) + test.assertTrue( + breakpoint.GetNumLocations() > 0, 'No locations found for line breakpoint: "%s:%d(:%d)", dir: "%s"' - %(source_spec.GetFilename(), line_number, column, - source_spec.GetDirectory())) - return run_to_breakpoint_do_run(test, target, breakpoint, launch_info, - only_one_thread, extra_images) + % (source_spec.GetFilename(), line_number, column, source_spec.GetDirectory()), + ) + return run_to_breakpoint_do_run( + test, target, breakpoint, launch_info, only_one_thread, extra_images + ) def continue_to_breakpoint(process, bkpt): - """ Continues the process, if it stops, returns the threads stopped at bkpt; otherwise, returns None""" + """Continues the process, if it stops, returns the threads stopped at bkpt; otherwise, returns None""" process.Continue() if process.GetState() != lldb.eStateStopped: return None @@ -992,10 +1062,13 @@ def continue_to_source_breakpoint(test, process, bkpt_pattern, source_spec): Otherwise the same as `continue_to_breakpoint` """ breakpoint = process.target.BreakpointCreateBySourceRegex( - bkpt_pattern, source_spec, None) - test.assertTrue(breakpoint.GetNumLocations() > 0, - 'No locations found for source breakpoint: "%s", file: "%s", dir: "%s"' - %(bkpt_pattern, source_spec.GetFilename(), source_spec.GetDirectory())) + bkpt_pattern, source_spec, None + ) + test.assertTrue( + breakpoint.GetNumLocations() > 0, + 'No locations found for source breakpoint: "%s", file: "%s", dir: "%s"' + % (bkpt_pattern, source_spec.GetFilename(), source_spec.GetDirectory()), + ) stopped_threads = continue_to_breakpoint(process, breakpoint) process.target.BreakpointDelete(breakpoint.GetID()) return stopped_threads @@ -1019,6 +1092,7 @@ def get_function_names(thread): """ Returns a sequence of function names from the stack frames of this thread. """ + def GetFuncName(i): return thread.GetFrameAtIndex(i).GetFunctionName() @@ -1029,6 +1103,7 @@ def get_symbol_names(thread): """ Returns a sequence of symbols for this thread. """ + def GetSymbol(i): return thread.GetFrameAtIndex(i).GetSymbol().GetName() @@ -1039,6 +1114,7 @@ def get_pc_addresses(thread): """ Returns a sequence of pc addresses for this thread. """ + def GetPCAddress(i): return thread.GetFrameAtIndex(i).GetPCAddress() @@ -1049,9 +1125,9 @@ def get_filenames(thread): """ Returns a sequence of file names from the stack frames of this thread. """ + def GetFilename(i): - return thread.GetFrameAtIndex( - i).GetLineEntry().GetFileSpec().GetFilename() + return thread.GetFrameAtIndex(i).GetLineEntry().GetFileSpec().GetFilename() return list(map(GetFilename, list(range(thread.GetNumFrames())))) @@ -1060,6 +1136,7 @@ def get_line_numbers(thread): """ Returns a sequence of line numbers from the stack frames of this thread. """ + def GetLineNumber(i): return thread.GetFrameAtIndex(i).GetLineEntry().GetLine() @@ -1070,9 +1147,9 @@ def get_module_names(thread): """ Returns a sequence of module names from the stack frames of this thread. """ + def GetModuleName(i): - return thread.GetFrameAtIndex( - i).GetModule().GetFileSpec().GetFilename() + return thread.GetFrameAtIndex(i).GetModule().GetFileSpec().GetFilename() return list(map(GetModuleName, list(range(thread.GetNumFrames())))) @@ -1081,6 +1158,7 @@ def get_stack_frames(thread): """ Returns a sequence of stack frames for this thread. """ + def GetStackFrame(i): return thread.GetFrameAtIndex(i) @@ -1108,10 +1186,11 @@ def print_stacktrace(thread, string_buffer=False): desc = "" print( "Stack trace for thread id={0:#x} name={1} queue={2} ".format( - thread.GetThreadID(), - thread.GetName(), - thread.GetQueueName()) + desc, - file=output) + thread.GetThreadID(), thread.GetName(), thread.GetQueueName() + ) + + desc, + file=output, + ) for i in range(depth): frame = thread.GetFrameAtIndex(i) @@ -1128,22 +1207,25 @@ def print_stacktrace(thread, string_buffer=False): addr=load_addr, mod=mods[i], symbol=symbols[i], - offset=symbol_offset), - file=output) + offset=symbol_offset, + ), + file=output, + ) else: print( " frame #{num}: {addr:#016x} {mod}`{func} at {file}:{line} {args}".format( num=i, addr=load_addr, mod=mods[i], - func='%s [inlined]' % - funcs[i] if frame.IsInlined() else funcs[i], + func="%s [inlined]" % funcs[i] if frame.IsInlined() else funcs[i], file=files[i], line=lines[i], - args=get_args_as_string( - frame, - showFuncName=False) if not frame.IsInlined() else '()'), - file=output) + args=get_args_as_string(frame, showFuncName=False) + if not frame.IsInlined() + else "()", + ), + file=output, + ) if string_buffer: return output.getvalue() @@ -1165,35 +1247,40 @@ def print_stacktraces(process, string_buffer=False): def expect_state_changes(test, listener, process, states, timeout=30): """Listens for state changed events on the listener and makes sure they match what we - expect. Stop-and-restart events (where GetRestartedFromEvent() returns true) are ignored.""" + expect. Stop-and-restart events (where GetRestartedFromEvent() returns true) are ignored. + """ for expected_state in states: + def get_next_event(): event = lldb.SBEvent() if not listener.WaitForEventForBroadcasterWithType( - timeout, - process.GetBroadcaster(), - lldb.SBProcess.eBroadcastBitStateChanged, - event): + timeout, + process.GetBroadcaster(), + lldb.SBProcess.eBroadcastBitStateChanged, + event, + ): test.fail( - "Timed out while waiting for a transition to state %s" % - lldb.SBDebugger.StateAsCString(expected_state)) + "Timed out while waiting for a transition to state %s" + % lldb.SBDebugger.StateAsCString(expected_state) + ) return event event = get_next_event() - while (lldb.SBProcess.GetStateFromEvent(event) == lldb.eStateStopped and - lldb.SBProcess.GetRestartedFromEvent(event)): + while lldb.SBProcess.GetStateFromEvent( + event + ) == lldb.eStateStopped and lldb.SBProcess.GetRestartedFromEvent(event): # Ignore restarted event and the subsequent running event. event = get_next_event() test.assertEqual( lldb.SBProcess.GetStateFromEvent(event), lldb.eStateRunning, - "Restarted event followed by a running event") + "Restarted event followed by a running event", + ) event = get_next_event() - test.assertEqual( - lldb.SBProcess.GetStateFromEvent(event), - expected_state) + test.assertEqual(lldb.SBProcess.GetStateFromEvent(event), expected_state) + def start_listening_from(broadcaster, event_mask): """Creates a listener for a specific event mask and add it to the source broadcaster.""" @@ -1202,6 +1289,7 @@ def start_listening_from(broadcaster, event_mask): broadcaster.AddListener(listener, event_mask) return listener + def fetch_next_event(test, listener, broadcaster, match_class=False, timeout=10): """Fetch one event from the listener and return it if it matches the provided broadcaster. If `match_class` is set to True, this will match an event with an entire broadcaster class. @@ -1219,8 +1307,10 @@ def fetch_next_event(test, listener, broadcaster, match_class=False, timeout=10) stream = lldb.SBStream() event.GetDescription(stream) - test.fail("received event '%s' from unexpected broadcaster '%s'." % - (stream.GetData(), event.GetBroadcaster().GetName())) + test.fail( + "received event '%s' from unexpected broadcaster '%s'." + % (stream.GetData(), event.GetBroadcaster().GetName()) + ) test.fail("couldn't fetch an event before reaching the timeout.") @@ -1257,9 +1347,7 @@ def get_args_as_string(frame, showFuncName=True): vars = frame.GetVariables(True, False, False, True) # type of SBValueList args = [] # list of strings for var in vars: - args.append("(%s)%s=%s" % (var.GetTypeName(), - var.GetName(), - var.GetValue())) + args.append("(%s)%s=%s" % (var.GetTypeName(), var.GetName(), var.GetValue())) if frame.GetFunction(): name = frame.GetFunction().GetName() elif frame.GetSymbol(): @@ -1280,18 +1368,20 @@ def print_registers(frame, string_buffer=False): print("Register sets for " + str(frame), file=output) registerSet = frame.GetRegisters() # Return type of SBValueList. - print("Frame registers (size of register set = %d):" % - registerSet.GetSize(), file=output) + print( + "Frame registers (size of register set = %d):" % registerSet.GetSize(), + file=output, + ) for value in registerSet: - #print(value, file=output) - print("%s (number of children = %d):" % - (value.GetName(), value.GetNumChildren()), file=output) + # print(value, file=output) + print( + "%s (number of children = %d):" % (value.GetName(), value.GetNumChildren()), + file=output, + ) for child in value: print( - "Name: %s, Value: %s" % - (child.GetName(), - child.GetValue()), - file=output) + "Name: %s, Value: %s" % (child.GetName(), child.GetValue()), file=output + ) if string_buffer: return output.getvalue() @@ -1351,6 +1441,7 @@ def get_ESRs(frame): """ return get_registers(frame, "exception state") + # ====================================== # Utility classes/functions for SBValues # ====================================== @@ -1371,11 +1462,15 @@ class BasicFormatter(object): val = value.GetValue() if val is None and value.GetNumChildren() > 0: val = "%s (location)" % value.GetLocation() - print("{indentation}({type}) {name} = {value}".format( - indentation=' ' * indent, - type=value.GetTypeName(), - name=value.GetName(), - value=val), file=output) + print( + "{indentation}({type}) {name} = {value}".format( + indentation=" " * indent, + type=value.GetTypeName(), + name=value.GetName(), + value=val, + ), + file=output, + ) return output.getvalue() @@ -1397,8 +1492,7 @@ class ChildVisitingFormatter(BasicFormatter): BasicFormatter.format(self, value, buffer=output) for child in value: - BasicFormatter.format( - self, child, buffer=output, indent=self.cindent) + BasicFormatter.format(self, child, buffer=output, indent=self.cindent) return output.getvalue() @@ -1426,18 +1520,17 @@ class RecursiveDecentFormatter(BasicFormatter): new_indent = self.lindent + self.cindent for child in value: if child.GetSummary() is not None: - BasicFormatter.format( - self, child, buffer=output, indent=new_indent) + BasicFormatter.format(self, child, buffer=output, indent=new_indent) else: if child.GetNumChildren() > 0: rdf = RecursiveDecentFormatter(indent_level=new_indent) rdf.format(child, buffer=output) else: - BasicFormatter.format( - self, child, buffer=output, indent=new_indent) + BasicFormatter.format(self, child, buffer=output, indent=new_indent) return output.getvalue() + # =========================================================== # Utility functions for path manipulation on remote platforms # =========================================================== @@ -1445,9 +1538,9 @@ class RecursiveDecentFormatter(BasicFormatter): def join_remote_paths(*paths): # TODO: update with actual platform name for remote windows once it exists - if lldb.remote_platform.GetName() == 'remote-windows': - return os.path.join(*paths).replace(os.path.sep, '\\') - return os.path.join(*paths).replace(os.path.sep, '/') + if lldb.remote_platform.GetName() == "remote-windows": + return os.path.join(*paths).replace(os.path.sep, "\\") + return os.path.join(*paths).replace(os.path.sep, "/") def append_to_process_working_directory(test, *paths): @@ -1456,6 +1549,7 @@ def append_to_process_working_directory(test, *paths): return join_remote_paths(remote.GetWorkingDirectory(), *paths) return os.path.join(test.getBuildDir(), *paths) + # ================================================== # Utility functions to get the correct signal number # ================================================== @@ -1474,45 +1568,51 @@ def get_signal_number(signal_name): # No remote platform; fall back to using local python signals. return getattr(signal, signal_name) -def get_actions_for_signal(testcase, signal_name, from_target=False, expected_absent=False): + +def get_actions_for_signal( + testcase, signal_name, from_target=False, expected_absent=False +): """Returns a triple of (pass, stop, notify)""" return_obj = lldb.SBCommandReturnObject() command = "process handle {0}".format(signal_name) if from_target: command += " -t" - testcase.dbg.GetCommandInterpreter().HandleCommand( - command, return_obj) + testcase.dbg.GetCommandInterpreter().HandleCommand(command, return_obj) match = re.match( - 'NAME *PASS *STOP *NOTIFY.*(false|true|not set) *(false|true|not set) *(false|true|not set)', + "NAME *PASS *STOP *NOTIFY.*(false|true|not set) *(false|true|not set) *(false|true|not set)", return_obj.GetOutput(), - re.IGNORECASE | re.DOTALL) + re.IGNORECASE | re.DOTALL, + ) if match and expected_absent: testcase.fail('Signal "{0}" was supposed to be absent'.format(signal_name)) if not match: if expected_absent: return (None, None, None) - testcase.fail('Unable to retrieve default signal disposition.') + testcase.fail("Unable to retrieve default signal disposition.") return (match.group(1), match.group(2), match.group(3)) +def set_actions_for_signal( + testcase, signal_name, pass_action, stop_action, notify_action, expect_success=True +): + return_obj = lldb.SBCommandReturnObject() + command = "process handle {0}".format(signal_name) + if pass_action != None: + command += " -p {0}".format(pass_action) + if stop_action != None: + command += " -s {0}".format(stop_action) + if notify_action != None: + command += " -n {0}".format(notify_action) -def set_actions_for_signal(testcase, signal_name, pass_action, stop_action, notify_action, expect_success=True): - return_obj = lldb.SBCommandReturnObject() - command = "process handle {0}".format(signal_name) - if pass_action != None: - command += " -p {0}".format(pass_action) - if stop_action != None: - command += " -s {0}".format(stop_action) - if notify_action != None: - command +=" -n {0}".format(notify_action) - - testcase.dbg.GetCommandInterpreter().HandleCommand(command, return_obj) - testcase.assertEqual(expect_success, - return_obj.Succeeded(), - "Setting signal handling for {0} worked as expected".format(signal_name)) + testcase.dbg.GetCommandInterpreter().HandleCommand(command, return_obj) + testcase.assertEqual( + expect_success, + return_obj.Succeeded(), + "Setting signal handling for {0} worked as expected".format(signal_name), + ) -class PrintableRegex(object): +class PrintableRegex(object): def __init__(self, text): self.regex = re.compile(text) self.text = text @@ -1542,36 +1642,41 @@ def skip_if_library_missing(test, target, library): if isinstance(library, str): if library == filename: return False - elif hasattr(library, 'match'): + elif hasattr(library, "match"): if library.match(filename): return False return True def find_library_callable(test): return find_library(target, library) + return skip_if_callable( test, find_library_callable, - "could not find library matching '%s' in target %s" % - (library, - target)) + "could not find library matching '%s' in target %s" % (library, target), + ) def read_file_on_target(test, remote): if lldb.remote_platform: local = test.getBuildArtifact("file_from_target") - error = lldb.remote_platform.Get(lldb.SBFileSpec(remote, False), - lldb.SBFileSpec(local, True)) - test.assertTrue(error.Success(), "Reading file {0} failed: {1}".format(remote, error)) + error = lldb.remote_platform.Get( + lldb.SBFileSpec(remote, False), lldb.SBFileSpec(local, True) + ) + test.assertTrue( + error.Success(), "Reading file {0} failed: {1}".format(remote, error) + ) else: local = remote - with open(local, 'r') as f: + with open(local, "r") as f: return f.read() + def read_file_from_process_wd(test, name): path = append_to_process_working_directory(test, name) return read_file_on_target(test, path) + def wait_for_file_on_target(testcase, file_path, max_attempts=6): for i in range(max_attempts): err, retcode, msg = testcase.run_platform_command("ls %s" % file_path) @@ -1580,14 +1685,16 @@ def wait_for_file_on_target(testcase, file_path, max_attempts=6): if i < max_attempts: # Exponential backoff! import time + time.sleep(pow(2, i) * 0.25) else: testcase.fail( - "File %s not found even after %d attempts." % - (file_path, max_attempts)) + "File %s not found even after %d attempts." % (file_path, max_attempts) + ) return read_file_on_target(testcase, file_path) + def packetlog_get_process_info(log): """parse a gdb-remote packet log file and extract the response to qProcessInfo""" process_info = dict() @@ -1596,32 +1703,37 @@ def packetlog_get_process_info(log): expect_process_info_response = False for line in logfile: if expect_process_info_response: - for pair in line.split(';'): - keyval = pair.split(':') + for pair in line.split(";"): + keyval = pair.split(":") if len(keyval) == 2: process_info[keyval[0]] = keyval[1] break - if 'send packet: $qProcessInfo#' in line: + if "send packet: $qProcessInfo#" in line: expect_process_info_response = True return process_info + def packetlog_get_dylib_info(log): """parse a gdb-remote packet log file and extract the *last* complete (=> fetch_all_solibs=true) response to jGetLoadedDynamicLibrariesInfos""" import json + dylib_info = None with open(log, "r") as logfile: dylib_info = None expect_dylib_info_response = False for line in logfile: if expect_dylib_info_response: - while line[0] != '$': + while line[0] != "$": line = line[1:] line = line[1:] # Unescape '}'. - dylib_info = json.loads(line.replace('}]','}')[:-4]) + dylib_info = json.loads(line.replace("}]", "}")[:-4]) expect_dylib_info_response = False - if 'send packet: $jGetLoadedDynamicLibrariesInfos:{"fetch_all_solibs":true}' in line: + if ( + 'send packet: $jGetLoadedDynamicLibrariesInfos:{"fetch_all_solibs":true}' + in line + ): expect_dylib_info_response = True return dylib_info diff --git a/lldb/packages/Python/lldbsuite/test/test_categories.py b/lldb/packages/Python/lldbsuite/test/test_categories.py index f3d8b07..c5a624c 100644 --- a/lldb/packages/Python/lldbsuite/test/test_categories.py +++ b/lldb/packages/Python/lldbsuite/test/test_categories.py @@ -15,37 +15,32 @@ from lldbsuite.support import gmodules # Key: Category name # Value: should be used in lldbtest's debug-info replication -debug_info_categories = { - 'dwarf' : True, - 'dwo' : True, - 'dsym' : True, - 'gmodules' : False -} +debug_info_categories = {"dwarf": True, "dwo": True, "dsym": True, "gmodules": False} all_categories = { - 'basic_process': 'Basic process execution sniff tests.', - 'cmdline': 'Tests related to the LLDB command-line interface', - 'dataformatters': 'Tests related to the type command and the data formatters subsystem', - 'debugserver': 'Debugserver tests', - 'dsym': 'Tests that can be run with DSYM debug information', - 'dwarf': 'Tests that can be run with DWARF debug information', - 'dwo': 'Tests that can be run with DWO debug information', - 'dyntype': 'Tests related to dynamic type support', - 'expression': 'Tests related to the expression parser', - 'flakey': 'Flakey test cases, i.e. tests that do not reliably pass at each execution', - 'fork': 'Tests requiring the process plugin fork/vfork event support', - 'gmodules': 'Tests that can be run with -gmodules debug information', - 'instrumentation-runtime': 'Tests for the instrumentation runtime plugins', - 'libc++': 'Test for libc++ data formatters', - 'libstdcxx': 'Test for libstdcxx data formatters', - 'lldb-server': 'Tests related to lldb-server', - 'lldb-vscode': 'Visual Studio Code debug adaptor tests', - 'llgs': 'Tests for the gdb-server functionality of lldb-server', - 'objc': 'Tests related to the Objective-C programming language support', - 'pyapi': 'Tests related to the Python API', - 'std-module': 'Tests related to importing the std module', - 'stresstest': 'Tests related to stressing lldb limits', - 'watchpoint': 'Watchpoint-related tests', + "basic_process": "Basic process execution sniff tests.", + "cmdline": "Tests related to the LLDB command-line interface", + "dataformatters": "Tests related to the type command and the data formatters subsystem", + "debugserver": "Debugserver tests", + "dsym": "Tests that can be run with DSYM debug information", + "dwarf": "Tests that can be run with DWARF debug information", + "dwo": "Tests that can be run with DWO debug information", + "dyntype": "Tests related to dynamic type support", + "expression": "Tests related to the expression parser", + "flakey": "Flakey test cases, i.e. tests that do not reliably pass at each execution", + "fork": "Tests requiring the process plugin fork/vfork event support", + "gmodules": "Tests that can be run with -gmodules debug information", + "instrumentation-runtime": "Tests for the instrumentation runtime plugins", + "libc++": "Test for libc++ data formatters", + "libstdcxx": "Test for libstdcxx data formatters", + "lldb-server": "Tests related to lldb-server", + "lldb-vscode": "Visual Studio Code debug adaptor tests", + "llgs": "Tests for the gdb-server functionality of lldb-server", + "objc": "Tests related to the Objective-C programming language support", + "pyapi": "Tests related to the Python API", + "std-module": "Tests related to importing the std module", + "stresstest": "Tests related to stressing lldb limits", + "watchpoint": "Watchpoint-related tests", } @@ -88,12 +83,15 @@ def validate(categories, exact_match): category = unique_string_match(category, all_categories) if (category not in all_categories) or category is None: print( - "fatal error: category '" + - origCategory + - "' is not a valid category") - print("if you have added a new category, please edit test_categories.py, adding your new category to all_categories") - print("else, please specify one or more of the following: " + - str(list(all_categories.keys()))) + "fatal error: category '" + origCategory + "' is not a valid category" + ) + print( + "if you have added a new category, please edit test_categories.py, adding your new category to all_categories" + ) + print( + "else, please specify one or more of the following: " + + str(list(all_categories.keys())) + ) sys.exit(1) result.append(category) return result diff --git a/lldb/packages/Python/lldbsuite/test/test_result.py b/lldb/packages/Python/lldbsuite/test/test_result.py index ff01b21..cb84c90 100644 --- a/lldb/packages/Python/lldbsuite/test/test_result.py +++ b/lldb/packages/Python/lldbsuite/test/test_result.py @@ -28,12 +28,14 @@ class LLDBTestResult(unittest2.TextTestResult): is used in the LLDB test framework to emit detailed trace messages to a log file for easier human inspection of test failures/errors. """ + __singleton__ = None __ignore_singleton__ = False @staticmethod def getTerminalSize(): import os + env = os.environ def ioctl_GWINSZ(fd): @@ -41,11 +43,12 @@ class LLDBTestResult(unittest2.TextTestResult): import fcntl import termios import struct - cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, - '1234')) + + cr = struct.unpack("hh", fcntl.ioctl(fd, termios.TIOCGWINSZ, "1234")) except: return return cr + cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2) if not cr: try: @@ -55,7 +58,7 @@ class LLDBTestResult(unittest2.TextTestResult): except: pass if not cr: - cr = (env.get('LINES', 25), env.get('COLUMNS', 80)) + cr = (env.get("LINES", 25), env.get("COLUMNS", 80)) return int(cr[1]), int(cr[0]) def __init__(self, *args): @@ -68,7 +71,7 @@ class LLDBTestResult(unittest2.TextTestResult): # Computes the format string for displaying the counter. counterWidth = len(str(configuration.suite.countTestCases())) self.fmt = "%" + str(counterWidth) + "d: " - self.indentation = ' ' * (counterWidth + 2) + self.indentation = " " * (counterWidth + 2) # This counts from 1 .. suite.countTestCases(). self.counter = 0 (width, height) = LLDBTestResult.getTerminalSize() @@ -76,25 +79,24 @@ class LLDBTestResult(unittest2.TextTestResult): def _config_string(self, test): compiler = getattr(test, "getCompiler", None) arch = getattr(test, "getArchitecture", None) - return "%s-%s" % (compiler() if compiler else "", - arch() if arch else "") + return "%s-%s" % (compiler() if compiler else "", arch() if arch else "") def _exc_info_to_string(self, err, test): """Overrides superclass TestResult's method in order to append our test config info string to the exception info string.""" if hasattr(test, "getArchitecture") and hasattr(test, "getCompiler"): - return '%sConfig=%s-%s' % (super(LLDBTestResult, - self)._exc_info_to_string(err, - test), - test.getArchitecture(), - test.getCompiler()) + return "%sConfig=%s-%s" % ( + super(LLDBTestResult, self)._exc_info_to_string(err, test), + test.getArchitecture(), + test.getCompiler(), + ) else: return super(LLDBTestResult, self)._exc_info_to_string(err, test) def getDescription(self, test): doc_first_line = test.shortDescription() if self.descriptions and doc_first_line: - return '\n'.join((str(test), self.indentation + doc_first_line)) + return "\n".join((str(test), self.indentation + doc_first_line)) else: return str(test) @@ -107,6 +109,7 @@ class LLDBTestResult(unittest2.TextTestResult): return test.test_filename else: import inspect + return inspect.getsourcefile(test.__class__) def _getFileBasedCategories(self, test): @@ -118,20 +121,24 @@ class LLDBTestResult(unittest2.TextTestResult): start_path = self._getTestPath(test) import os.path + folder = os.path.dirname(start_path) from lldbsuite import lldb_test_root as test_root + if test_root != os.path.commonprefix([folder, test_root]): - raise Exception("The test file %s is outside the test root directory" % start_path) + raise Exception( + "The test file %s is outside the test root directory" % start_path + ) categories = set() while not os.path.samefile(folder, test_root): categories_file_name = os.path.join(folder, "categories") if os.path.exists(categories_file_name): - categories_file = open(categories_file_name, 'r') + categories_file = open(categories_file_name, "r") categories_str = categories_file.readline().strip() categories_file.close() - categories.update(categories_str.split(',')) + categories.update(categories_str.split(",")) folder = os.path.dirname(folder) return list(categories) @@ -152,27 +159,27 @@ class LLDBTestResult(unittest2.TextTestResult): def hardMarkAsSkipped(self, test): getattr(test, test._testMethodName).__func__.__unittest_skip__ = True getattr( - test, - test._testMethodName).__func__.__unittest_skip_why__ = "test case does not fall in any category of interest for this run" + test, test._testMethodName + ).__func__.__unittest_skip_why__ = ( + "test case does not fall in any category of interest for this run" + ) def checkExclusion(self, exclusion_list, name): if exclusion_list: import re + for item in exclusion_list: if re.search(item, name): return True return False def checkCategoryExclusion(self, exclusion_list, test): - return not set(exclusion_list).isdisjoint( - self.getCategoriesForTest(test)) + return not set(exclusion_list).isdisjoint(self.getCategoriesForTest(test)) def startTest(self, test): - if configuration.shouldSkipBecauseOfCategories( - self.getCategoriesForTest(test)): + if configuration.shouldSkipBecauseOfCategories(self.getCategoriesForTest(test)): self.hardMarkAsSkipped(test) - if self.checkExclusion( - configuration.skip_tests, test.id()): + if self.checkExclusion(configuration.skip_tests, test.id()): self.hardMarkAsSkipped(test) self.counter += 1 @@ -182,17 +189,16 @@ class LLDBTestResult(unittest2.TextTestResult): super(LLDBTestResult, self).startTest(test) def addSuccess(self, test): - if (self.checkExclusion( - configuration.xfail_tests, test.id()) or - self.checkCategoryExclusion( - configuration.xfail_categories, test)): + if self.checkExclusion( + configuration.xfail_tests, test.id() + ) or self.checkCategoryExclusion(configuration.xfail_categories, test): self.addUnexpectedSuccess(test, None) return super(LLDBTestResult, self).addSuccess(test) self.stream.write( - "PASS: LLDB (%s) :: %s\n" % - (self._config_string(test), str(test))) + "PASS: LLDB (%s) :: %s\n" % (self._config_string(test), str(test)) + ) def _isBuildError(self, err_tuple): exception = err_tuple[1] @@ -203,8 +209,8 @@ class LLDBTestResult(unittest2.TextTestResult): # rather than an uninformative Python backtrace. build_error = err[1] error_description = "{}\nTest Directory:\n{}".format( - str(build_error), - os.path.dirname(self._getTestPath(test))) + str(build_error), os.path.dirname(self._getTestPath(test)) + ) self.errors.append((test, error_description)) self._mirrorOutput = True @@ -219,8 +225,8 @@ class LLDBTestResult(unittest2.TextTestResult): if method: method() self.stream.write( - "FAIL: LLDB (%s) :: %s\n" % - (self._config_string(test), str(test))) + "FAIL: LLDB (%s) :: %s\n" % (self._config_string(test), str(test)) + ) def addCleanupError(self, test, err): configuration.sdir_has_content = True @@ -229,14 +235,14 @@ class LLDBTestResult(unittest2.TextTestResult): if method: method() self.stream.write( - "CLEANUP ERROR: LLDB (%s) :: %s\n%s\n" % - (self._config_string(test), str(test), traceback.format_exc())) + "CLEANUP ERROR: LLDB (%s) :: %s\n%s\n" + % (self._config_string(test), str(test), traceback.format_exc()) + ) def addFailure(self, test, err): - if (self.checkExclusion( - configuration.xfail_tests, test.id()) or - self.checkCategoryExclusion( - configuration.xfail_categories, test)): + if self.checkExclusion( + configuration.xfail_tests, test.id() + ) or self.checkCategoryExclusion(configuration.xfail_categories, test): self.addExpectedFailure(test, err, None) return @@ -246,14 +252,15 @@ class LLDBTestResult(unittest2.TextTestResult): if method: method() self.stream.write( - "FAIL: LLDB (%s) :: %s\n" % - (self._config_string(test), str(test))) + "FAIL: LLDB (%s) :: %s\n" % (self._config_string(test), str(test)) + ) if configuration.use_categories: test_categories = self.getCategoriesForTest(test) for category in test_categories: if category in configuration.failures_per_category: - configuration.failures_per_category[ - category] = configuration.failures_per_category[category] + 1 + configuration.failures_per_category[category] = ( + configuration.failures_per_category[category] + 1 + ) else: configuration.failures_per_category[category] = 1 @@ -264,8 +271,8 @@ class LLDBTestResult(unittest2.TextTestResult): if method: method(err, bugnumber) self.stream.write( - "XFAIL: LLDB (%s) :: %s\n" % - (self._config_string(test), str(test))) + "XFAIL: LLDB (%s) :: %s\n" % (self._config_string(test), str(test)) + ) def addSkip(self, test, reason): configuration.sdir_has_content = True @@ -274,8 +281,9 @@ class LLDBTestResult(unittest2.TextTestResult): if method: method() self.stream.write( - "UNSUPPORTED: LLDB (%s) :: %s (%s) \n" % - (self._config_string(test), str(test), reason)) + "UNSUPPORTED: LLDB (%s) :: %s (%s) \n" + % (self._config_string(test), str(test), reason) + ) def addUnexpectedSuccess(self, test, bugnumber): configuration.sdir_has_content = True @@ -284,5 +292,5 @@ class LLDBTestResult(unittest2.TextTestResult): if method: method(bugnumber) self.stream.write( - "XPASS: LLDB (%s) :: %s\n" % - (self._config_string(test), str(test))) + "XPASS: LLDB (%s) :: %s\n" % (self._config_string(test), str(test)) + ) diff --git a/lldb/packages/Python/lldbsuite/test/test_runner/process_control.py b/lldb/packages/Python/lldbsuite/test/test_runner/process_control.py index 687f105..07c1799 100644 --- a/lldb/packages/Python/lldbsuite/test/test_runner/process_control.py +++ b/lldb/packages/Python/lldbsuite/test/test_runner/process_control.py @@ -42,7 +42,9 @@ class CommunicatorThread(threading.Thread): if self.output_file: self.output_file.write( "exception while using communicate() for pid: {}\n".format( - exception)) + exception + ) + ) finally: # Signal that the thread's run is complete. self.event.set() @@ -70,23 +72,22 @@ def timeout_to_seconds(timeout): if units is None: # default is seconds. No conversion necessary. return value - elif units == 's': + elif units == "s": # Seconds. No conversion necessary. return value - elif units == 'm': + elif units == "m": # Value is in minutes. return 60.0 * value - elif units == 'h': + elif units == "h": # Value is in hours. return (60.0 * 60.0) * value - elif units == 'd': + elif units == "d": # Value is in days. return 24 * (60.0 * 60.0) * value else: raise Exception("unexpected units value '{}'".format(units)) else: - raise Exception("could not parse TIMEOUT spec '{}'".format( - timeout)) + raise Exception("could not parse TIMEOUT spec '{}'".format(timeout)) class ProcessHelper(object): @@ -306,7 +307,8 @@ class UnixProcessHelper(ProcessHelper): stderr=subprocess.PIPE, universal_newlines=True, # Elicits automatic byte -> string decoding in Py3 close_fds=True, - preexec_fn=preexec_func) + preexec_fn=preexec_func, + ) # Remember whether we're using process groups for this # process. @@ -345,7 +347,9 @@ class UnixProcessHelper(ProcessHelper): log_file.write( "requested to terminate pid {} but it has already " "terminated, returncode {}".format( - popen_process.pid, popen_process.returncode)) + popen_process.pid, popen_process.returncode + ) + ) # Move along... return False @@ -374,6 +378,7 @@ class UnixProcessHelper(ProcessHelper): os.kill(popen_process.pid, signum) except OSError as error: import errno + if error.errno == errno.ESRCH: # This is okay - failed to find the process. It may be that # that the timeout pre-kill hook eliminated the process. We'll @@ -415,8 +420,10 @@ class UnixProcessHelper(ProcessHelper): @classmethod def _signal_names_by_number(cls): return dict( - (k, v) for v, k in reversed(sorted(signal.__dict__.items())) - if v.startswith('SIG') and not v.startswith('SIG_')) + (k, v) + for v, k in reversed(sorted(signal.__dict__.items())) + if v.startswith("SIG") and not v.startswith("SIG_") + ) def exceptional_exit_details(self, popen_status): signo = -popen_status @@ -444,7 +451,8 @@ class WindowsProcessHelper(ProcessHelper): stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, # Elicits automatic byte -> string decoding in Py3 - creationflags=creation_flags) + creationflags=creation_flags, + ) def was_hard_terminate(self, returncode): return returncode != 0 @@ -528,15 +536,11 @@ class ProcessDriver(object): if self.returncode is None: raise Exception( "no exit status available for pid {} after the " - " inferior dotest.py should have completed".format( - self.process.pid)) + " inferior dotest.py should have completed".format(self.process.pid) + ) # Notify of non-timeout exit. - self.on_process_exited( - command, - self.io_thread.output, - False, - self.returncode) + self.on_process_exited(command, self.io_thread.output, False, self.returncode) def run_command_with_timeout(self, command, timeout, want_core): # Figure out how many seconds our timeout description is requesting. @@ -563,8 +567,7 @@ class ProcessDriver(object): # complete (i.e. the inferior process has finished). self.done_event.clear() - self.io_thread = CommunicatorThread( - self.process, self.done_event, self.write) + self.io_thread = CommunicatorThread(self.process, self.done_event, self.write) self.io_thread.start() def _attempt_soft_kill(self, want_core): @@ -573,9 +576,8 @@ class ProcessDriver(object): # and/or generate a core dump). Often the OS can't guarantee # that the process will really terminate after this. self.process_helper.soft_terminate( - self.process, - want_core=want_core, - log_file=self) + self.process, want_core=want_core, log_file=self + ) # Now wait up to a certain timeout period for the io thread # to say that the communication ended. If that wraps up @@ -589,9 +591,12 @@ class ProcessDriver(object): terminated = True done_trying = None else: - self.write("soft kill attempt of process {} timed out " - "after {} seconds\n".format( - self.process.pid, self.soft_terminate_timeout)) + self.write( + "soft kill attempt of process {} timed out " + "after {} seconds\n".format( + self.process.pid, self.soft_terminate_timeout + ) + ) terminated = False done_trying = False return terminated, done_trying @@ -599,9 +604,7 @@ class ProcessDriver(object): def _attempt_hard_kill(self): # Instruct the process to terminate and really force it to # happen. Don't give the process a chance to ignore. - self.process_helper.hard_terminate( - self.process, - log_file=self) + self.process_helper.hard_terminate(self.process, log_file=self) # Reap the child process. This should not hang as the # hard_kill() mechanism is supposed to really kill it. @@ -619,7 +622,9 @@ class ProcessDriver(object): self.write( "hard kill of process {} timed out after {} seconds waiting " "for the io thread (ignoring)\n".format( - self.process.pid, self.hard_terminate_timeout)) + self.process.pid, self.hard_terminate_timeout + ) + ) # Set if it terminated. (Set up for optional improvement above). terminated = self.returncode is not None @@ -661,7 +666,6 @@ class ProcessDriver(object): # Reap the child process here. self.returncode = self.process.wait() else: - # Allow derived classes to do some work after we detected # a timeout but before we touch the timed-out process. self.on_timeout_pre_kill() @@ -676,7 +680,8 @@ class ProcessDriver(object): terminate_attempt_count += 1 # Attempt to terminate. process_terminated, done_trying = self._attempt_termination( - terminate_attempt_count, want_core) + terminate_attempt_count, want_core + ) # Check if there's nothing more to try. if done_trying: # Break out of our termination attempt loop. @@ -686,10 +691,8 @@ class ProcessDriver(object): # finished gracefully, was shut down after one or more # attempts, or we failed but gave it our best effort. self.on_process_exited( - command, - self.io_thread.output, - not completed_normally, - self.returncode) + command, self.io_thread.output, not completed_normally, self.returncode + ) def patched_init(self, *args, **kwargs): @@ -732,6 +735,7 @@ def patch_up_subprocess_popen(): subprocess.Popen.original_poll = subprocess.Popen.poll subprocess.Popen.poll = patched_poll + # Replace key subprocess.Popen() threading-unprotected methods with # threading-protected versions. patch_up_subprocess_popen() diff --git a/lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py index 5c70bad..fd1eb64 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py @@ -3,7 +3,8 @@ import os import time import json -ADDRESS_REGEX = '0x[0-9a-fA-F]*' +ADDRESS_REGEX = "0x[0-9a-fA-F]*" + # Decorator that runs a test with both modes of USE_SB_API. # It assumes that no tests can be executed in parallel. @@ -13,8 +14,10 @@ def testSBAPIAndCommands(func): func(*args, **kwargs) TraceIntelPTTestCaseBase.USE_SB_API = False func(*args, **kwargs) + return wrapper + # Class that should be used by all python Intel PT tests. # # It has a handy check that skips the test if the intel-pt plugin is not enabled. @@ -22,7 +25,6 @@ def testSBAPIAndCommands(func): # It also contains many functions that can test both the SB API or the command line version # of the most important tracing actions. class TraceIntelPTTestCaseBase(TestBase): - NO_DEBUG_INFO_TESTCASE = True # If True, the trace test methods will use the SB API, otherwise they'll use raw commands. @@ -30,7 +32,7 @@ class TraceIntelPTTestCaseBase(TestBase): def setUp(self): TestBase.setUp(self) - if 'intel-pt' not in configuration.enabled_plugins: + if "intel-pt" not in configuration.enabled_plugins: self.skipTest("The intel-pt test plugin is not enabled") def skipIfPerCpuTracingIsNotSupported(self): @@ -42,10 +44,13 @@ class TraceIntelPTTestCaseBase(TestBase): return True except: return False + if not is_supported(): - self.skipTest("Per cpu tracing is not supported. You need " + self.skipTest( + "Per cpu tracing is not supported. You need " "/proc/sys/kernel/perf_event_paranoid to be 0 or -1. " - "You can use `sudo sysctl -w kernel.perf_event_paranoid=-1` for that.") + "You can use `sudo sysctl -w kernel.perf_event_paranoid=-1` for that." + ) def getTraceOrCreate(self): if not self.target().GetTrace().IsValid(): @@ -59,9 +64,14 @@ class TraceIntelPTTestCaseBase(TestBase): else: self.assertSuccess(sberror) - def createConfiguration(self, iptTraceSize=None, - processBufferSizeLimit=None, enableTsc=False, - psbPeriod=None, perCpuTracing=False): + def createConfiguration( + self, + iptTraceSize=None, + processBufferSizeLimit=None, + enableTsc=False, + psbPeriod=None, + perCpuTracing=False, + ): obj = {} if processBufferSizeLimit is not None: obj["processBufferSizeLimit"] = processBufferSizeLimit @@ -76,14 +86,21 @@ class TraceIntelPTTestCaseBase(TestBase): configuration.SetFromJSON(json.dumps(obj)) return configuration - def traceStartThread(self, thread=None, error=False, substrs=None, - iptTraceSize=None, enableTsc=False, psbPeriod=None): + def traceStartThread( + self, + thread=None, + error=False, + substrs=None, + iptTraceSize=None, + enableTsc=False, + psbPeriod=None, + ): if self.USE_SB_API: trace = self.getTraceOrCreate() thread = thread if thread is not None else self.thread() configuration = self.createConfiguration( - iptTraceSize=iptTraceSize, enableTsc=enableTsc, - psbPeriod=psbPeriod) + iptTraceSize=iptTraceSize, enableTsc=enableTsc, psbPeriod=psbPeriod + ) self.assertSBError(trace.Start(thread, configuration), error) else: command = "thread trace start" @@ -97,14 +114,23 @@ class TraceIntelPTTestCaseBase(TestBase): command += " --psb-period " + str(psbPeriod) self.expect(command, error=error, substrs=substrs) - def traceStartProcess(self, processBufferSizeLimit=None, error=False, - substrs=None, enableTsc=False, psbPeriod=None, - perCpuTracing=False): + def traceStartProcess( + self, + processBufferSizeLimit=None, + error=False, + substrs=None, + enableTsc=False, + psbPeriod=None, + perCpuTracing=False, + ): if self.USE_SB_API: trace = self.getTraceOrCreate() configuration = self.createConfiguration( - processBufferSizeLimit=processBufferSizeLimit, enableTsc=enableTsc, - psbPeriod=psbPeriod, perCpuTracing=perCpuTracing) + processBufferSizeLimit=processBufferSizeLimit, + enableTsc=enableTsc, + psbPeriod=psbPeriod, + perCpuTracing=perCpuTracing, + ) self.assertSBError(trace.Start(configuration), error=error) else: command = "process trace start" @@ -149,7 +175,8 @@ class TraceIntelPTTestCaseBase(TestBase): if self.USE_SB_API: save_error = lldb.SBError() self.target().GetTrace().SaveToDisk( - save_error, lldb.SBFileSpec(traceBundleDir), compact) + save_error, lldb.SBFileSpec(traceBundleDir), compact + ) self.assertSBError(save_error, error) else: command = f"trace save {traceBundleDir}" diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/fork_testbase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/fork_testbase.py index 1a3cc4a..4d3dee8 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/fork_testbase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/fork_testbase.py @@ -2,157 +2,200 @@ import gdbremote_testcase class GdbRemoteForkTestBase(gdbremote_testcase.GdbRemoteTestCaseBase): - fork_regex = ("[$]T[0-9a-fA-F]{{2}}thread:p([0-9a-f]+)[.]([0-9a-f]+);.*" - "{}:p([0-9a-f]+)[.]([0-9a-f]+).*") - fork_regex_nonstop = ("%Stop:T[0-9a-fA-F]{{2}}" - "thread:p([0-9a-f]+)[.]([0-9a-f]+);.*" - "{}:p([0-9a-f]+)[.]([0-9a-f]+).*") - fork_capture = {1: "parent_pid", 2: "parent_tid", - 3: "child_pid", 4: "child_tid"} + fork_regex = ( + "[$]T[0-9a-fA-F]{{2}}thread:p([0-9a-f]+)[.]([0-9a-f]+);.*" + "{}:p([0-9a-f]+)[.]([0-9a-f]+).*" + ) + fork_regex_nonstop = ( + "%Stop:T[0-9a-fA-F]{{2}}" + "thread:p([0-9a-f]+)[.]([0-9a-f]+);.*" + "{}:p([0-9a-f]+)[.]([0-9a-f]+).*" + ) + fork_capture = {1: "parent_pid", 2: "parent_tid", 3: "child_pid", 4: "child_tid"} stop_regex_base = "T[0-9a-fA-F]{{2}}thread:p{}.{};.*reason:signal.*" stop_regex = "^[$]" + stop_regex_base def start_fork_test(self, args, variant="fork", nonstop=False): self.build() self.prep_debug_monitor_and_inferior(inferior_args=args) - self.add_qSupported_packets(["multiprocess+", - "{}-events+".format(variant)]) + self.add_qSupported_packets(["multiprocess+", "{}-events+".format(variant)]) ret = self.expect_gdbremote_sequence() self.assertIn("{}-events+".format(variant), ret["qSupported_response"]) self.reset_test_sequence() # continue and expect fork if nonstop: - self.test_sequence.add_log_lines([ - "read packet: $QNonStop:1#00", - "send packet: $OK#00", - "read packet: $c#00", - "send packet: $OK#00", - {"direction": "send", - "regex": self.fork_regex_nonstop.format(variant), - "capture": self.fork_capture}, - "read packet: $vStopped#00", - "send packet: $OK#00", - ], True) + self.test_sequence.add_log_lines( + [ + "read packet: $QNonStop:1#00", + "send packet: $OK#00", + "read packet: $c#00", + "send packet: $OK#00", + { + "direction": "send", + "regex": self.fork_regex_nonstop.format(variant), + "capture": self.fork_capture, + }, + "read packet: $vStopped#00", + "send packet: $OK#00", + ], + True, + ) else: - self.test_sequence.add_log_lines([ - "read packet: $c#00", - {"direction": "send", "regex": self.fork_regex.format(variant), - "capture": self.fork_capture}, - ], True) + self.test_sequence.add_log_lines( + [ + "read packet: $c#00", + { + "direction": "send", + "regex": self.fork_regex.format(variant), + "capture": self.fork_capture, + }, + ], + True, + ) ret = self.expect_gdbremote_sequence() self.reset_test_sequence() - return tuple(ret[x] for x in ("parent_pid", "parent_tid", - "child_pid", "child_tid")) + return tuple( + ret[x] for x in ("parent_pid", "parent_tid", "child_pid", "child_tid") + ) def fork_and_detach_test(self, variant, nonstop=False): - parent_pid, parent_tid, child_pid, child_tid = ( - self.start_fork_test([variant], variant, nonstop=nonstop)) + parent_pid, parent_tid, child_pid, child_tid = self.start_fork_test( + [variant], variant, nonstop=nonstop + ) # detach the forked child - self.test_sequence.add_log_lines([ - "read packet: $D;{}#00".format(child_pid), - "send packet: $OK#00", - # verify that the current process is correct - "read packet: $qC#00", - "send packet: $QCp{}.{}#00".format(parent_pid, parent_tid), - # verify that the correct processes are detached/available - "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), - "send packet: $Eff#00", - "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid), - "send packet: $OK#00", - ], True) + self.test_sequence.add_log_lines( + [ + "read packet: $D;{}#00".format(child_pid), + "send packet: $OK#00", + # verify that the current process is correct + "read packet: $qC#00", + "send packet: $QCp{}.{}#00".format(parent_pid, parent_tid), + # verify that the correct processes are detached/available + "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), + "send packet: $Eff#00", + "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid), + "send packet: $OK#00", + ], + True, + ) self.expect_gdbremote_sequence() self.reset_test_sequence() return parent_pid, parent_tid def fork_and_follow_test(self, variant, nonstop=False): - parent_pid, parent_tid, child_pid, child_tid = ( - self.start_fork_test([variant], variant, nonstop=nonstop)) + parent_pid, parent_tid, child_pid, child_tid = self.start_fork_test( + [variant], variant, nonstop=nonstop + ) # switch to the forked child - self.test_sequence.add_log_lines([ - "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), - "send packet: $OK#00", - "read packet: $Hcp{}.{}#00".format(child_pid, child_tid), - "send packet: $OK#00", - # detach the parent - "read packet: $D;{}#00".format(parent_pid), - "send packet: $OK#00", - # verify that the correct processes are detached/available - "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid), - "send packet: $Eff#00", - "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), - "send packet: $OK#00", - # then resume the child - "read packet: $c#00", - ], True) - - if nonstop: - self.test_sequence.add_log_lines([ + self.test_sequence.add_log_lines( + [ + "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), + "send packet: $OK#00", + "read packet: $Hcp{}.{}#00".format(child_pid, child_tid), "send packet: $OK#00", - "send packet: %Stop:W00;process:{}#00".format(child_pid), - "read packet: $vStopped#00", + # detach the parent + "read packet: $D;{}#00".format(parent_pid), "send packet: $OK#00", - ], True) + # verify that the correct processes are detached/available + "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid), + "send packet: $Eff#00", + "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), + "send packet: $OK#00", + # then resume the child + "read packet: $c#00", + ], + True, + ) + + if nonstop: + self.test_sequence.add_log_lines( + [ + "send packet: $OK#00", + "send packet: %Stop:W00;process:{}#00".format(child_pid), + "read packet: $vStopped#00", + "send packet: $OK#00", + ], + True, + ) else: - self.test_sequence.add_log_lines([ - "send packet: $W00;process:{}#00".format(child_pid), - ], True) + self.test_sequence.add_log_lines( + [ + "send packet: $W00;process:{}#00".format(child_pid), + ], + True, + ) self.expect_gdbremote_sequence() def detach_all_test(self, nonstop=False): - parent_pid, parent_tid, child_pid, child_tid = ( - self.start_fork_test(["fork"], nonstop=nonstop)) - - self.test_sequence.add_log_lines([ - # double-check our PIDs - "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid), - "send packet: $OK#00", - "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), - "send packet: $OK#00", - # detach all processes - "read packet: $D#00", - "send packet: $OK#00", - # verify that both PIDs are invalid now - "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid), - "send packet: $Eff#00", - "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), - "send packet: $Eff#00", - ], True) + parent_pid, parent_tid, child_pid, child_tid = self.start_fork_test( + ["fork"], nonstop=nonstop + ) + + self.test_sequence.add_log_lines( + [ + # double-check our PIDs + "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid), + "send packet: $OK#00", + "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), + "send packet: $OK#00", + # detach all processes + "read packet: $D#00", + "send packet: $OK#00", + # verify that both PIDs are invalid now + "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid), + "send packet: $Eff#00", + "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), + "send packet: $Eff#00", + ], + True, + ) self.expect_gdbremote_sequence() def vkill_test(self, kill_parent=False, kill_child=False, nonstop=False): assert kill_parent or kill_child - parent_pid, parent_tid, child_pid, child_tid = ( - self.start_fork_test(["fork"], nonstop=nonstop)) + parent_pid, parent_tid, child_pid, child_tid = self.start_fork_test( + ["fork"], nonstop=nonstop + ) if kill_parent: - self.test_sequence.add_log_lines([ - # kill the process - "read packet: $vKill;{}#00".format(parent_pid), - "send packet: $OK#00", - ], True) + self.test_sequence.add_log_lines( + [ + # kill the process + "read packet: $vKill;{}#00".format(parent_pid), + "send packet: $OK#00", + ], + True, + ) if kill_child: - self.test_sequence.add_log_lines([ - # kill the process - "read packet: $vKill;{}#00".format(child_pid), - "send packet: $OK#00", - ], True) - self.test_sequence.add_log_lines([ - # check child PID/TID - "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), - "send packet: ${}#00".format("Eff" if kill_child else "OK"), - # check parent PID/TID - "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid), - "send packet: ${}#00".format("Eff" if kill_parent else "OK"), - ], True) + self.test_sequence.add_log_lines( + [ + # kill the process + "read packet: $vKill;{}#00".format(child_pid), + "send packet: $OK#00", + ], + True, + ) + self.test_sequence.add_log_lines( + [ + # check child PID/TID + "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), + "send packet: ${}#00".format("Eff" if kill_child else "OK"), + # check parent PID/TID + "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid), + "send packet: ${}#00".format("Eff" if kill_parent else "OK"), + ], + True, + ) self.expect_gdbremote_sequence() def resume_one_test(self, run_order, use_vCont=False, nonstop=False): - parent_pid, parent_tid, child_pid, child_tid = ( - self.start_fork_test(["fork", "stop"], nonstop=nonstop)) + parent_pid, parent_tid, child_pid, child_tid = self.start_fork_test( + ["fork", "stop"], nonstop=nonstop + ) parent_expect = [ self.stop_regex_base.format(parent_pid, parent_tid), @@ -174,34 +217,49 @@ class GdbRemoteForkTestBase(gdbremote_testcase.GdbRemoteTestCaseBase): assert False, "unexpected x={}".format(x) if use_vCont: - self.test_sequence.add_log_lines([ - # continue the selected process - "read packet: $vCont;c:p{}.{}#00".format(*pidtid), - ], True) + self.test_sequence.add_log_lines( + [ + # continue the selected process + "read packet: $vCont;c:p{}.{}#00".format(*pidtid), + ], + True, + ) else: - self.test_sequence.add_log_lines([ - # continue the selected process - "read packet: $Hcp{}.{}#00".format(*pidtid), - "send packet: $OK#00", - "read packet: $c#00", - ], True) + self.test_sequence.add_log_lines( + [ + # continue the selected process + "read packet: $Hcp{}.{}#00".format(*pidtid), + "send packet: $OK#00", + "read packet: $c#00", + ], + True, + ) if nonstop: - self.test_sequence.add_log_lines([ - "send packet: $OK#00", - {"direction": "send", "regex": "%Stop:" + expect}, - "read packet: $vStopped#00", - "send packet: $OK#00", - ], True) + self.test_sequence.add_log_lines( + [ + "send packet: $OK#00", + {"direction": "send", "regex": "%Stop:" + expect}, + "read packet: $vStopped#00", + "send packet: $OK#00", + ], + True, + ) else: - self.test_sequence.add_log_lines([ - {"direction": "send", "regex": "[$]" + expect}, - ], True) + self.test_sequence.add_log_lines( + [ + {"direction": "send", "regex": "[$]" + expect}, + ], + True, + ) # if at least one process remained, check both PIDs if parent_expect or child_expect: - self.test_sequence.add_log_lines([ - "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid), - "send packet: ${}#00".format("OK" if parent_expect else "Eff"), - "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), - "send packet: ${}#00".format("OK" if child_expect else "Eff"), - ], True) + self.test_sequence.add_log_lines( + [ + "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid), + "send packet: ${}#00".format("OK" if parent_expect else "Eff"), + "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), + "send packet: ${}#00".format("OK" if child_expect else "Eff"), + ], + True, + ) self.expect_gdbremote_sequence() diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py index 1653910..93e21d0 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py @@ -28,7 +28,6 @@ class _ConnectionRefused(IOError): class GdbRemoteTestCaseFactory(type): - def __new__(cls, name, bases, attrs): newattrs = {} for attrname, attrvalue in attrs.items(): @@ -40,12 +39,12 @@ class GdbRemoteTestCaseFactory(type): # that list to be authoritative. If none were specified, try # all of them. all_categories = set(["debugserver", "llgs"]) - categories = set( - getattr(attrvalue, "categories", [])) & all_categories + categories = set(getattr(attrvalue, "categories", [])) & all_categories if not categories: categories = all_categories for cat in categories: + @decorators.add_test_categories([cat]) @wraps(attrvalue) def test_method(self, attrvalue=attrvalue): @@ -56,15 +55,14 @@ class GdbRemoteTestCaseFactory(type): test_method.debug_server = cat newattrs[method_name] = test_method - return super(GdbRemoteTestCaseFactory, cls).__new__( - cls, name, bases, newattrs) + return super(GdbRemoteTestCaseFactory, cls).__new__(cls, name, bases, newattrs) -class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): +class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): # Default time out in seconds. The timeout is increased tenfold under Asan. - DEFAULT_TIMEOUT = 20 * (10 if ('ASAN_OPTIONS' in os.environ) else 1) + DEFAULT_TIMEOUT = 20 * (10 if ("ASAN_OPTIONS" in os.environ) else 1) # Default sleep time in seconds. The sleep time is doubled under Asan. - DEFAULT_SLEEP = 5 * (2 if ('ASAN_OPTIONS' in os.environ) else 1) + DEFAULT_SLEEP = 5 * (2 if ("ASAN_OPTIONS" in os.environ) else 1) _GDBREMOTE_KILL_PACKET = b"$k#6b" @@ -88,8 +86,7 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): TARGET_EXC_BREAKPOINT = 0x96 _verbose_log_handler = None - _log_formatter = logging.Formatter( - fmt='%(asctime)-15s %(levelname)-8s %(message)s') + _log_formatter = logging.Formatter(fmt="%(asctime)-15s %(levelname)-8s %(message)s") def setUpBaseLogging(self): self.logger = logging.getLogger(__name__) @@ -109,8 +106,7 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): def isVerboseLoggingRequested(self): # We will report our detailed logs if the user requested that the "gdb-remote" channel is # logged. - return any(("gdb-remote" in channel) - for channel in lldbtest_config.channels) + return any(("gdb-remote" in channel) for channel in lldbtest_config.channels) def getDebugServer(self): method = getattr(self, self.testMethodName) @@ -125,7 +121,8 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): if self.isVerboseLoggingRequested(): # If requested, full logs go to a log file self._verbose_log_handler = logging.FileHandler( - self.getLogBasenameForCurrentTest() + "-host.log") + self.getLogBasenameForCurrentTest() + "-host.log" + ) self._verbose_log_handler.setFormatter(self._log_formatter) self._verbose_log_handler.setLevel(logging.DEBUG) self.logger.addHandler(self._verbose_log_handler) @@ -135,15 +132,19 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): self.port = self.get_next_port() self.stub_sends_two_stop_notifications_on_kill = False if configuration.lldb_platform_url: - if configuration.lldb_platform_url.startswith('unix-'): - url_pattern = '(.+)://\[?(.+?)\]?/.*' + if configuration.lldb_platform_url.startswith("unix-"): + url_pattern = "(.+)://\[?(.+?)\]?/.*" else: - url_pattern = '(.+)://(.+):\d+' + url_pattern = "(.+)://(.+):\d+" scheme, host = re.match( - url_pattern, configuration.lldb_platform_url).groups() - if configuration.lldb_platform_name == 'remote-android' and host != 'localhost': + url_pattern, configuration.lldb_platform_url + ).groups() + if ( + configuration.lldb_platform_name == "remote-android" + and host != "localhost" + ): self.stub_device = host - self.stub_hostname = 'localhost' + self.stub_hostname = "localhost" else: self.stub_device = None self.stub_hostname = host @@ -170,17 +171,21 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): if lldb.remote_platform: log_file = lldbutil.join_remote_paths( - lldb.remote_platform.GetWorkingDirectory(), "server.log") + lldb.remote_platform.GetWorkingDirectory(), "server.log" + ) else: log_file = self.getLocalServerLogFile() if is_llgs: self.debug_monitor_extra_args.append("--log-file=" + log_file) self.debug_monitor_extra_args.append( - "--log-channels={}".format(":".join(lldbtest_config.channels))) + "--log-channels={}".format(":".join(lldbtest_config.channels)) + ) else: self.debug_monitor_extra_args = [ - "--log-file=" + log_file, "--log-flags=0x800000"] + "--log-file=" + log_file, + "--log-flags=0x800000", + ] def get_next_port(self): return 12000 + random.randint(0, 3999) @@ -188,7 +193,6 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): def reset_test_sequence(self): self.test_sequence = GdbRemoteTestSequence(self.logger) - def _init_llgs_test(self): reverse_connect = True if lldb.remote_platform: @@ -198,29 +202,28 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): # FIXME: This is extremely linux-oriented # Grab the ppid from /proc/[shell pid]/stat - err, retcode, shell_stat = self.run_platform_command( - "cat /proc/$$/stat") + err, retcode, shell_stat = self.run_platform_command("cat /proc/$$/stat") self.assertTrue( err.Success() and retcode == 0, - "Failed to read file /proc/$$/stat: %s, retcode: %d" % - (err.GetCString(), - retcode)) + "Failed to read file /proc/$$/stat: %s, retcode: %d" + % (err.GetCString(), retcode), + ) # [pid] ([executable]) [state] [*ppid*] pid = re.match(r"^\d+ \(.+\) . (\d+)", shell_stat).group(1) err, retcode, ls_output = self.run_platform_command( - "ls -l /proc/%s/exe" % pid) + "ls -l /proc/%s/exe" % pid + ) self.assertTrue( err.Success() and retcode == 0, - "Failed to read file /proc/%s/exe: %s, retcode: %d" % - (pid, - err.GetCString(), - retcode)) + "Failed to read file /proc/%s/exe: %s, retcode: %d" + % (pid, err.GetCString(), retcode), + ) exe = ls_output.split()[-1] # If the binary has been deleted, the link name has " (deleted)" appended. # Remove if it's there. - self.debug_monitor_exe = re.sub(r' \(deleted\)$', '', exe) + self.debug_monitor_exe = re.sub(r" \(deleted\)$", "", exe) else: self.debug_monitor_exe = get_lldb_server_exe() @@ -239,7 +242,7 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): self.stub_sends_two_stop_notifications_on_kill = True def forward_adb_port(self, source, target, direction, device): - adb = ['adb'] + (['-s', device] if device else []) + [direction] + adb = ["adb"] + (["-s", device] if device else []) + [direction] def remove_port_forward(): subprocess.call(adb + ["--remove", "tcp:%d" % source]) @@ -275,16 +278,11 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): triple = self.dbg.GetSelectedPlatform().GetTriple() if re.match(".*-.*-.*-android", triple): - self.forward_adb_port( - self.port, - self.port, - "forward", - self.stub_device) + self.forward_adb_port(self.port, self.port, "forward", self.stub_device) logger.info( - "Connecting to debug monitor on %s:%d", - self.stub_hostname, - self.port) + "Connecting to debug monitor on %s:%d", self.stub_hostname, self.port + ) connect_info = (self.stub_hostname, self.port) try: sock.connect(connect_info) @@ -301,14 +299,18 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): except: logger.warning( "failed to send kill packet to debug monitor: {}; ignoring".format( - sys.exc_info()[0])) + sys.exc_info()[0] + ) + ) try: sock.close() except: logger.warning( "failed to close socket to debug monitor: {}; ignoring".format( - sys.exc_info()[0])) + sys.exc_info()[0] + ) + ) self.addTearDownHook(shutdown_socket) @@ -346,7 +348,9 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): def launch_debug_monitor(self, attach_pid=None, logfile=None): if self.reverse_connect: - family, type, proto, _, addr = socket.getaddrinfo("localhost", 0, proto=socket.IPPROTO_TCP)[0] + family, type, proto, _, addr = socket.getaddrinfo( + "localhost", 0, proto=socket.IPPROTO_TCP + )[0] sock = socket.socket(family, type, proto) sock.settimeout(self.DEFAULT_TIMEOUT) @@ -355,16 +359,15 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): addr = sock.getsockname() self.connect_address = "[{}]:{}".format(*addr) - # Create the command line. commandline_args = self.get_debug_monitor_command_line_args( - attach_pid=attach_pid) + attach_pid=attach_pid + ) # Start the server. server = self.spawnSubprocess( - self.debug_monitor_exe, - commandline_args, - install_remote=False) + self.debug_monitor_exe, commandline_args, install_remote=False + ) self.assertIsNotNone(server) if self.reverse_connect: @@ -417,8 +420,9 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): # Increment attempts. print( - "connect to debug monitor on port %d failed, attempt #%d of %d" % - (self.port, attempts + 1, MAX_ATTEMPTS)) + "connect to debug monitor on port %d failed, attempt #%d of %d" + % (self.port, attempts + 1, MAX_ATTEMPTS) + ) attempts += 1 # And wait a random length of time before next attempt, to avoid @@ -429,14 +433,13 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): self.port = self.get_next_port() raise Exception( - "failed to create a socket to the launched debug monitor after %d tries" % - attempts) + "failed to create a socket to the launched debug monitor after %d tries" + % attempts + ) def launch_process_for_attach( - self, - inferior_args=None, - sleep_seconds=3, - exe_path=None): + self, inferior_args=None, sleep_seconds=3, exe_path=None + ): # We're going to start a child process that the debug monitor stub can later attach to. # This process needs to be started so that it just hangs around for a while. We'll # have it sleep. @@ -452,11 +455,12 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): return self.spawnSubprocess(exe_path, args) def prep_debug_monitor_and_inferior( - self, - inferior_args=None, - inferior_sleep_seconds=3, - inferior_exe_path=None, - inferior_env=None): + self, + inferior_args=None, + inferior_sleep_seconds=3, + inferior_exe_path=None, + inferior_env=None, + ): """Prep the debug monitor, the inferior, and the expected packet stream. Handle the separate cases of using the debug monitor in attach-to-inferior mode @@ -479,12 +483,16 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): inferior = None attach_pid = None - if self._inferior_startup == self._STARTUP_ATTACH or self._inferior_startup == self._STARTUP_ATTACH_MANUALLY: + if ( + self._inferior_startup == self._STARTUP_ATTACH + or self._inferior_startup == self._STARTUP_ATTACH_MANUALLY + ): # Launch the process that we'll use as the inferior. inferior = self.launch_process_for_attach( inferior_args=inferior_args, sleep_seconds=inferior_sleep_seconds, - exe_path=inferior_exe_path) + exe_path=inferior_exe_path, + ) self.assertIsNotNone(inferior) self.assertTrue(inferior.pid > 0) if self._inferior_startup == self._STARTUP_ATTACH: @@ -498,15 +506,18 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): inferior_exe_path = self.getBuildArtifact("a.out") if lldb.remote_platform: - remote_path = lldbutil.append_to_process_working_directory(self, - os.path.basename(inferior_exe_path)) + remote_path = lldbutil.append_to_process_working_directory( + self, os.path.basename(inferior_exe_path) + ) remote_file_spec = lldb.SBFileSpec(remote_path, False) - err = lldb.remote_platform.Install(lldb.SBFileSpec( - inferior_exe_path, True), remote_file_spec) + err = lldb.remote_platform.Install( + lldb.SBFileSpec(inferior_exe_path, True), remote_file_spec + ) if err.Fail(): raise Exception( - "remote_platform.Install('%s', '%s') failed: %s" % - (inferior_exe_path, remote_path, err)) + "remote_platform.Install('%s', '%s') failed: %s" + % (inferior_exe_path, remote_path, err) + ) inferior_exe_path = remote_path launch_args = [inferior_exe_path] @@ -538,29 +549,45 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): def add_verified_launch_packets(self, launch_args): self.test_sequence.add_log_lines( - ["read packet: %s" % build_gdbremote_A_packet(launch_args), - "send packet: $OK#00", - "read packet: $qLaunchSuccess#a5", - "send packet: $OK#00"], - True) + [ + "read packet: %s" % build_gdbremote_A_packet(launch_args), + "send packet: $OK#00", + "read packet: $qLaunchSuccess#a5", + "send packet: $OK#00", + ], + True, + ) def add_thread_suffix_request_packets(self): self.test_sequence.add_log_lines( - ["read packet: $QThreadSuffixSupported#e4", - "send packet: $OK#00", - ], True) + [ + "read packet: $QThreadSuffixSupported#e4", + "send packet: $OK#00", + ], + True, + ) def add_process_info_collection_packets(self): self.test_sequence.add_log_lines( - ["read packet: $qProcessInfo#dc", - {"direction": "send", "regex": r"^\$(.+)#[0-9a-fA-F]{2}$", "capture": {1: "process_info_raw"}}], - True) + [ + "read packet: $qProcessInfo#dc", + { + "direction": "send", + "regex": r"^\$(.+)#[0-9a-fA-F]{2}$", + "capture": {1: "process_info_raw"}, + }, + ], + True, + ) def add_set_environment_packets(self, name, value): self.test_sequence.add_log_lines( - ["read packet: $QEnvironment:" + name + "=" + value + "#00", - "send packet: $OK#00", - ], True) + [ + "read packet: $QEnvironment:" + name + "=" + value + "#00", + "send packet: $OK#00", + ], + True, + ) _KNOWN_PROCESS_INFO_KEYS = [ "pid", @@ -576,7 +603,7 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): "vendor", "endian", "elf_abi", - "ptrsize" + "ptrsize", ] def parse_process_info_response(self, context): @@ -587,11 +614,12 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): # Pull out key:value; pairs. process_info_dict = { - match.group(1): match.group(2) for match in re.finditer( - r"([^:]+):([^;]+);", process_info_raw)} + match.group(1): match.group(2) + for match in re.finditer(r"([^:]+):([^;]+);", process_info_raw) + } # Validate keys are known. - for (key, val) in list(process_info_dict.items()): + for key, val in list(process_info_dict.items()): self.assertTrue(key in self._KNOWN_PROCESS_INFO_KEYS) self.assertIsNotNone(val) @@ -599,10 +627,17 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): def add_register_info_collection_packets(self): self.test_sequence.add_log_lines( - [{"type": "multi_response", "query": "qRegisterInfo", "append_iteration_suffix": True, - "end_regex": re.compile(r"^\$(E\d+)?#[0-9a-fA-F]{2}$"), - "save_key": "reg_info_responses"}], - True) + [ + { + "type": "multi_response", + "query": "qRegisterInfo", + "append_iteration_suffix": True, + "end_regex": re.compile(r"^\$(E\d+)?#[0-9a-fA-F]{2}$"), + "save_key": "reg_info_responses", + } + ], + True, + ) def parse_register_info_packets(self, context): """Return an array of register info dictionaries, one per register info.""" @@ -610,8 +645,10 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): self.assertIsNotNone(reg_info_responses) # Parse register infos. - return [parse_reg_info_response(reg_info_response) - for reg_info_response in reg_info_responses] + return [ + parse_reg_info_response(reg_info_response) + for reg_info_response in reg_info_responses + ] def expect_gdbremote_sequence(self): return expect_lldb_gdbserver_replay( @@ -619,7 +656,8 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): self._server, self.test_sequence, self.DEFAULT_TIMEOUT * len(self.test_sequence), - self.logger) + self.logger, + ) _KNOWN_REGINFO_KEYS = [ "name", @@ -636,7 +674,7 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): "container-regs", "invalidate-regs", "dynamic_size_dwarf_expr_bytes", - "dynamic_size_dwarf_len" + "dynamic_size_dwarf_len", ] def assert_valid_reg_info(self, reg_info): @@ -648,7 +686,7 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): self.assertTrue("name" in reg_info) self.assertTrue("bitsize" in reg_info) - if not self.getArchitecture() == 'aarch64': + if not self.getArchitecture() == "aarch64": self.assertTrue("offset" in reg_info) self.assertTrue("encoding" in reg_info) @@ -678,9 +716,16 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): def add_query_memory_region_packets(self, address): self.test_sequence.add_log_lines( - ["read packet: $qMemoryRegionInfo:{0:x}#00".format(address), - {"direction": "send", "regex": r"^\$(.+)#[0-9a-fA-F]{2}$", "capture": {1: "memory_region_response"}}], - True) + [ + "read packet: $qMemoryRegionInfo:{0:x}#00".format(address), + { + "direction": "send", + "regex": r"^\$(.+)#[0-9a-fA-F]{2}$", + "capture": {1: "memory_region_response"}, + }, + ], + True, + ) def parse_key_val_dict(self, key_val_text, allow_dupes=True): self.assertIsNotNone(key_val_text) @@ -698,7 +743,9 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): else: self.fail( "key '{}' already present when attempting to add value '{}' (text='{}', dict={})".format( - key, val, key_val_text, kv_dict)) + key, val, key_val_text, kv_dict + ) + ) else: kv_dict[key] = val return kv_dict @@ -708,28 +755,30 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): self.assertIsNotNone(context.get("memory_region_response")) # Pull out key:value; pairs. - mem_region_dict = self.parse_key_val_dict( - context.get("memory_region_response")) + mem_region_dict = self.parse_key_val_dict(context.get("memory_region_response")) # Validate keys are known. - for (key, val) in list(mem_region_dict.items()): - self.assertIn(key, - ["start", - "size", - "permissions", - "flags", - "name", - "error", - "dirty-pages", - "type"]) + for key, val in list(mem_region_dict.items()): + self.assertIn( + key, + [ + "start", + "size", + "permissions", + "flags", + "name", + "error", + "dirty-pages", + "type", + ], + ) self.assertIsNotNone(val) mem_region_dict["name"] = seven.unhexlify(mem_region_dict.get("name", "")) # Return the dictionary of key-value pairs for the memory region. return mem_region_dict - def assert_address_within_memory_region( - self, test_address, mem_region_dict): + def assert_address_within_memory_region(self, test_address, mem_region_dict): self.assertIsNotNone(mem_region_dict) self.assertTrue("start" in mem_region_dict) self.assertTrue("size" in mem_region_dict) @@ -741,24 +790,30 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): if test_address < range_start: self.fail( "address 0x{0:x} comes before range 0x{1:x} - 0x{2:x} (size 0x{3:x})".format( - test_address, - range_start, - range_end, - range_size)) + test_address, range_start, range_end, range_size + ) + ) elif test_address >= range_end: self.fail( "address 0x{0:x} comes after range 0x{1:x} - 0x{2:x} (size 0x{3:x})".format( - test_address, - range_start, - range_end, - range_size)) + test_address, range_start, range_end, range_size + ) + ) def add_threadinfo_collection_packets(self): self.test_sequence.add_log_lines( - [{"type": "multi_response", "first_query": "qfThreadInfo", "next_query": "qsThreadInfo", - "append_iteration_suffix": False, "end_regex": re.compile(r"^\$(l)?#[0-9a-fA-F]{2}$"), - "save_key": "threadinfo_responses"}], - True) + [ + { + "type": "multi_response", + "first_query": "qfThreadInfo", + "next_query": "qsThreadInfo", + "append_iteration_suffix": False, + "end_regex": re.compile(r"^\$(l)?#[0-9a-fA-F]{2}$"), + "save_key": "threadinfo_responses", + } + ], + True, + ) def parse_threadinfo_packets(self, context): """Return an array of thread ids (decimal ints), one per thread.""" @@ -773,13 +828,20 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): def launch_with_threads(self, thread_count): procs = self.prep_debug_monitor_and_inferior( - inferior_args=["thread:new"]*(thread_count-1) + ["trap"]) + inferior_args=["thread:new"] * (thread_count - 1) + ["trap"] + ) - self.test_sequence.add_log_lines([ + self.test_sequence.add_log_lines( + [ "read packet: $c#00", - {"direction": "send", + { + "direction": "send", "regex": r"^\$T([0-9a-fA-F]{2})([^#]*)#..$", - "capture": {1: "stop_signo", 2: "stop_reply_kv"}}], True) + "capture": {1: "stop_signo", 2: "stop_reply_kv"}, + }, + ], + True, + ) self.add_threadinfo_collection_packets() context = self.expect_gdbremote_sequence() threads = self.parse_threadinfo_packets(context) @@ -787,49 +849,60 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): return context, threads def add_set_breakpoint_packets( - self, - address, - z_packet_type=0, - do_continue=True, - breakpoint_kind=1): + self, address, z_packet_type=0, do_continue=True, breakpoint_kind=1 + ): self.test_sequence.add_log_lines( [ # Set the breakpoint. "read packet: $Z{2},{0:x},{1}#00".format( - address, breakpoint_kind, z_packet_type), + address, breakpoint_kind, z_packet_type + ), # Verify the stub could set it. "send packet: $OK#00", - ], True) + ], + True, + ) - if (do_continue): + if do_continue: self.test_sequence.add_log_lines( [ # Continue the inferior. "read packet: $c#63", # Expect a breakpoint stop report. - {"direction": "send", - "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", - "capture": {1: "stop_signo", - 2: "stop_thread_id"}}, - ], True) + { + "direction": "send", + "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", + "capture": {1: "stop_signo", 2: "stop_thread_id"}, + }, + ], + True, + ) def add_remove_breakpoint_packets( - self, - address, - z_packet_type=0, - breakpoint_kind=1): + self, address, z_packet_type=0, breakpoint_kind=1 + ): self.test_sequence.add_log_lines( [ # Remove the breakpoint. "read packet: $z{2},{0:x},{1}#00".format( - address, breakpoint_kind, z_packet_type), + address, breakpoint_kind, z_packet_type + ), # Verify the stub could unset it. "send packet: $OK#00", - ], True) + ], + True, + ) def add_qSupported_packets(self, client_features=[]): - features = ''.join(';' + x for x in client_features) + features = "".join(";" + x for x in client_features) self.test_sequence.add_log_lines( - ["read packet: $qSupported{}#00".format(features), - {"direction": "send", "regex": r"^\$(.*)#[0-9a-fA-F]{2}", "capture": {1: "qSupported_response"}}, - ], True) + [ + "read packet: $qSupported{}#00".format(features), + { + "direction": "send", + "regex": r"^\$(.*)#[0-9a-fA-F]{2}", + "capture": {1: "qSupported_response"}, + }, + ], + True, + ) _KNOWN_QSUPPORTED_STUB_FEATURES = [ "augmented-libraries-svr4-read", @@ -872,18 +945,20 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): else: if len(key) < 2: raise Exception( - "singular stub feature is too short: must be stub_feature{+,-,?}") + "singular stub feature is too short: must be stub_feature{+,-,?}" + ) supported_type = key[-1] key = key[:-1] if not supported_type in ["+", "-", "?"]: raise Exception( - "malformed stub feature: final character {} not in expected set (+,-,?)".format(supported_type)) + "malformed stub feature: final character {} not in expected set (+,-,?)".format( + supported_type + ) + ) supported_dict[key] = supported_type # Ensure we know the supported element if key not in self._KNOWN_QSUPPORTED_STUB_FEATURES: - raise Exception( - "unknown qSupported stub feature reported: %s" % - key) + raise Exception("unknown qSupported stub feature reported: %s" % key) return supported_dict @@ -905,7 +980,11 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): def select_modifiable_register(self, reg_infos): """Find a register that can be read/written freely.""" - PREFERRED_REGISTER_NAMES = set(["rax", ]) + PREFERRED_REGISTER_NAMES = set( + [ + "rax", + ] + ) # First check for the first register from the preferred register name # set. @@ -913,12 +992,12 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): self.assertIsNotNone(reg_infos) for reg_info in reg_infos: - if ("name" in reg_info) and ( - reg_info["name"] in PREFERRED_REGISTER_NAMES): + if ("name" in reg_info) and (reg_info["name"] in PREFERRED_REGISTER_NAMES): # We found a preferred register. Use it. return reg_info["lldb_register_index"] - if ("generic" in reg_info) and (reg_info["generic"] == "fp" or - reg_info["generic"] == "arg1"): + if ("generic" in reg_info) and ( + reg_info["generic"] == "fp" or reg_info["generic"] == "arg1" + ): # A frame pointer or first arg register will do as a # register to modify temporarily. alternative_register_index = reg_info["lldb_register_index"] @@ -932,7 +1011,7 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): kv_dict = self.parse_key_val_dict(stop_key_vals_text) registers = {} - for (key, val) in list(kv_dict.items()): + for key, val in list(kv_dict.items()): if re.match(r"^[0-9a-fA-F]+$", key): registers[int(key, 16)] = val return registers @@ -953,8 +1032,7 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): def find_generic_register_with_name(self, reg_infos, generic_name): self.assertIsNotNone(reg_infos) for reg_info in reg_infos: - if ("generic" in reg_info) and ( - reg_info["generic"] == generic_name): + if ("generic" in reg_info) and (reg_info["generic"] == generic_name): return reg_info return None @@ -999,7 +1077,7 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): # break this test check for repeated keys. # # AT_IGNOREPPC = 22 - ignored_keys_for_arch = { 'powerpc64le' : [22] } + ignored_keys_for_arch = {"powerpc64le": [22]} arch = self.getArchitecture() ignore_keys = None if arch in ignored_keys_for_arch: @@ -1031,7 +1109,8 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): auxv_dict[key] = value self.fail( - "should not reach here - implies required double zero entry not found") + "should not reach here - implies required double zero entry not found" + ) return auxv_dict def read_binary_data_in_chunks(self, command_prefix, chunk_length): @@ -1046,18 +1125,18 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): self.test_sequence.add_log_lines( [ "read packet: ${}{:x},{:x}:#00".format( - command_prefix, - offset, - chunk_length), + command_prefix, offset, chunk_length + ), { "direction": "send", "regex": re.compile( - r"^\$([^E])(.*)#[0-9a-fA-F]{2}$", - re.MULTILINE | re.DOTALL), - "capture": { - 1: "response_type", - 2: "content_raw"}}], - True) + r"^\$([^E])(.*)#[0-9a-fA-F]{2}$", re.MULTILINE | re.DOTALL + ), + "capture": {1: "response_type", 2: "content_raw"}, + }, + ], + True, + ) context = self.expect_gdbremote_sequence() self.assertIsNotNone(context) @@ -1080,36 +1159,48 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): return decoded_data def add_interrupt_packets(self): - self.test_sequence.add_log_lines([ - # Send the intterupt. - "read packet: {}".format(chr(3)), - # And wait for the stop notification. - {"direction": "send", - "regex": r"^\$T([0-9a-fA-F]{2})(.*)#[0-9a-fA-F]{2}$", - "capture": {1: "stop_signo", - 2: "stop_key_val_text"}}, - ], True) + self.test_sequence.add_log_lines( + [ + # Send the intterupt. + "read packet: {}".format(chr(3)), + # And wait for the stop notification. + { + "direction": "send", + "regex": r"^\$T([0-9a-fA-F]{2})(.*)#[0-9a-fA-F]{2}$", + "capture": {1: "stop_signo", 2: "stop_key_val_text"}, + }, + ], + True, + ) def parse_interrupt_packets(self, context): self.assertIsNotNone(context.get("stop_signo")) self.assertIsNotNone(context.get("stop_key_val_text")) - return (int(context["stop_signo"], 16), self.parse_key_val_dict( - context["stop_key_val_text"])) + return ( + int(context["stop_signo"], 16), + self.parse_key_val_dict(context["stop_key_val_text"]), + ) def add_QSaveRegisterState_packets(self, thread_id): if thread_id: # Use the thread suffix form. request = "read packet: $QSaveRegisterState;thread:{:x}#00".format( - thread_id) + thread_id + ) else: request = "read packet: $QSaveRegisterState#00" - self.test_sequence.add_log_lines([request, - {"direction": "send", - "regex": r"^\$(E?.*)#[0-9a-fA-F]{2}$", - "capture": {1: "save_response"}}, - ], - True) + self.test_sequence.add_log_lines( + [ + request, + { + "direction": "send", + "regex": r"^\$(E?.*)#[0-9a-fA-F]{2}$", + "capture": {1: "save_response"}, + }, + ], + True, + ) def parse_QSaveRegisterState_response(self, context): self.assertIsNotNone(context) @@ -1127,18 +1218,14 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): if thread_id: # Use the thread suffix form. request = "read packet: $QRestoreRegisterState:{};thread:{:x}#00".format( - save_id, thread_id) + save_id, thread_id + ) else: - request = "read packet: $QRestoreRegisterState:{}#00".format( - save_id) + request = "read packet: $QRestoreRegisterState:{}#00".format(save_id) - self.test_sequence.add_log_lines([ - request, - "send packet: $OK#00" - ], True) + self.test_sequence.add_log_lines([request, "send packet: $OK#00"], True) - def flip_all_bits_in_each_register_value( - self, reg_infos, endian, thread_id=None): + def flip_all_bits_in_each_register_value(self, reg_infos, endian, thread_id=None): self.assertIsNotNone(reg_infos) successful_writes = 0 @@ -1157,24 +1244,31 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): # Handle thread suffix. if thread_id: p_request = "read packet: $p{:x};thread:{:x}#00".format( - reg_index, thread_id) + reg_index, thread_id + ) else: p_request = "read packet: $p{:x}#00".format(reg_index) # Read the existing value. self.reset_test_sequence() - self.test_sequence.add_log_lines([ - p_request, - {"direction": "send", "regex": r"^\$([0-9a-fA-F]+)#", "capture": {1: "p_response"}}, - ], True) + self.test_sequence.add_log_lines( + [ + p_request, + { + "direction": "send", + "regex": r"^\$([0-9a-fA-F]+)#", + "capture": {1: "p_response"}, + }, + ], + True, + ) context = self.expect_gdbremote_sequence() self.assertIsNotNone(context) # Verify the response length. p_response = context.get("p_response") self.assertIsNotNone(p_response) - initial_reg_value = unpack_register_hex_unsigned( - endian, p_response) + initial_reg_value = unpack_register_hex_unsigned(endian, p_response) # Flip the value by xoring with all 1s all_one_bits_raw = "ff" * (int(reg_info["bitsize"]) // 8) @@ -1184,21 +1278,33 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): # Handle thread suffix for P. if thread_id: P_request = "read packet: $P{:x}={};thread:{:x}#00".format( - reg_index, pack_register_hex( - endian, flipped_bits_int, byte_size=reg_byte_size), thread_id) + reg_index, + pack_register_hex( + endian, flipped_bits_int, byte_size=reg_byte_size + ), + thread_id, + ) else: P_request = "read packet: $P{:x}={}#00".format( - reg_index, pack_register_hex( - endian, flipped_bits_int, byte_size=reg_byte_size)) + reg_index, + pack_register_hex( + endian, flipped_bits_int, byte_size=reg_byte_size + ), + ) # Write the flipped value to the register. self.reset_test_sequence() - self.test_sequence.add_log_lines([P_request, - {"direction": "send", - "regex": r"^\$(OK|E[0-9a-fA-F]+)#[0-9a-fA-F]{2}", - "capture": {1: "P_response"}}, - ], - True) + self.test_sequence.add_log_lines( + [ + P_request, + { + "direction": "send", + "regex": r"^\$(OK|E[0-9a-fA-F]+)#[0-9a-fA-F]{2}", + "capture": {1: "P_response"}, + }, + ], + True, + ) context = self.expect_gdbremote_sequence() self.assertIsNotNone(context) @@ -1217,17 +1323,25 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): # value. if P_response == "OK": self.reset_test_sequence() - self.test_sequence.add_log_lines([ - p_request, - {"direction": "send", "regex": r"^\$([0-9a-fA-F]+)#", "capture": {1: "p_response"}}, - ], True) + self.test_sequence.add_log_lines( + [ + p_request, + { + "direction": "send", + "regex": r"^\$([0-9a-fA-F]+)#", + "capture": {1: "p_response"}, + }, + ], + True, + ) context = self.expect_gdbremote_sequence() self.assertIsNotNone(context) verify_p_response_raw = context.get("p_response") self.assertIsNotNone(verify_p_response_raw) verify_bits = unpack_register_hex_unsigned( - endian, verify_p_response_raw) + endian, verify_p_response_raw + ) if verify_bits != flipped_bits_int: # Some registers, like mxcsrmask and others, will permute what's written. Adjust succeed/fail counts. @@ -1244,8 +1358,7 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): return False if reg_info["set"] != "General Purpose Registers": return False - if ("container-regs" in reg_info) and ( - len(reg_info["container-regs"]) > 0): + if ("container-regs" in reg_info) and (len(reg_info["container-regs"]) > 0): # Don't try to bit flip registers contained in another register. return False if re.match("^.s$", reg_info["name"]): @@ -1271,16 +1384,24 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): # Handle thread suffix. if thread_id: p_request = "read packet: $p{:x};thread:{:x}#00".format( - reg_index, thread_id) + reg_index, thread_id + ) else: p_request = "read packet: $p{:x}#00".format(reg_index) # Read it with p. self.reset_test_sequence() - self.test_sequence.add_log_lines([ - p_request, - {"direction": "send", "regex": r"^\$([0-9a-fA-F]+)#", "capture": {1: "p_response"}}, - ], True) + self.test_sequence.add_log_lines( + [ + p_request, + { + "direction": "send", + "regex": r"^\$([0-9a-fA-F]+)#", + "capture": {1: "p_response"}, + }, + ], + True, + ) context = self.expect_gdbremote_sequence() self.assertIsNotNone(context) @@ -1290,18 +1411,22 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): self.assertTrue(len(p_response) > 0) self.assertFalse(p_response[0] == "E") - values[reg_index] = unpack_register_hex_unsigned( - endian, p_response) + values[reg_index] = unpack_register_hex_unsigned(endian, p_response) return values def add_vCont_query_packets(self): - self.test_sequence.add_log_lines(["read packet: $vCont?#49", - {"direction": "send", - "regex": r"^\$(vCont)?(.*)#[0-9a-fA-F]{2}$", - "capture": {2: "vCont_query_response"}}, - ], - True) + self.test_sequence.add_log_lines( + [ + "read packet: $vCont?#49", + { + "direction": "send", + "regex": r"^\$(vCont)?(.*)#[0-9a-fA-F]{2}$", + "capture": {2: "vCont_query_response"}, + }, + ], + True, + ) def parse_vCont_query_response(self, context): self.assertIsNotNone(context) @@ -1312,17 +1437,19 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): if not vCont_query_response or len(vCont_query_response) == 0: return {} - return {key: 1 for key in vCont_query_response.split( - ";") if key and len(key) > 0} + return { + key: 1 for key in vCont_query_response.split(";") if key and len(key) > 0 + } def count_single_steps_until_true( - self, - thread_id, - predicate, - args, - max_step_count=100, - use_Hc_packet=True, - step_instruction="s"): + self, + thread_id, + predicate, + args, + max_step_count=100, + use_Hc_packet=True, + step_instruction="s", + ): """Used by single step test that appears in a few different contexts.""" single_step_count = 0 @@ -1332,7 +1459,8 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): # Build the packet for the single step instruction. We replace # {thread}, if present, with the thread_id. step_packet = "read packet: ${}#00".format( - re.sub(r"{thread}", "{:x}".format(thread_id), step_instruction)) + re.sub(r"{thread}", "{:x}".format(thread_id), step_instruction) + ) # print("\nstep_packet created: {}\n".format(step_packet)) # Single step. @@ -1342,22 +1470,30 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): [ # Set the continue thread. "read packet: $Hc{0:x}#00".format(thread_id), "send packet: $OK#00", - ], True) - self.test_sequence.add_log_lines([ - # Single step. - step_packet, - # "read packet: $vCont;s:{0:x}#00".format(thread_id), - # Expect a breakpoint stop report. - {"direction": "send", - "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", - "capture": {1: "stop_signo", - 2: "stop_thread_id"}}, - ], True) + ], + True, + ) + self.test_sequence.add_log_lines( + [ + # Single step. + step_packet, + # "read packet: $vCont;s:{0:x}#00".format(thread_id), + # Expect a breakpoint stop report. + { + "direction": "send", + "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", + "capture": {1: "stop_signo", 2: "stop_thread_id"}, + }, + ], + True, + ) context = self.expect_gdbremote_sequence() self.assertIsNotNone(context) self.assertIsNotNone(context.get("stop_signo")) - self.assertEqual(int(context.get("stop_signo"), 16), - lldbutil.get_signal_number('SIGTRAP')) + self.assertEqual( + int(context.get("stop_signo"), 16), + lldbutil.get_signal_number("SIGTRAP"), + ) single_step_count += 1 @@ -1378,11 +1514,22 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): # Read g_c1 and g_c2 contents. self.reset_test_sequence() self.test_sequence.add_log_lines( - ["read packet: $m{0:x},{1:x}#00".format(g_c1_address, 1), - {"direction": "send", "regex": r"^\$(.+)#[0-9a-fA-F]{2}$", "capture": {1: "g_c1_contents"}}, - "read packet: $m{0:x},{1:x}#00".format(g_c2_address, 1), - {"direction": "send", "regex": r"^\$(.+)#[0-9a-fA-F]{2}$", "capture": {1: "g_c2_contents"}}], - True) + [ + "read packet: $m{0:x},{1:x}#00".format(g_c1_address, 1), + { + "direction": "send", + "regex": r"^\$(.+)#[0-9a-fA-F]{2}$", + "capture": {1: "g_c1_contents"}, + }, + "read packet: $m{0:x},{1:x}#00".format(g_c2_address, 1), + { + "direction": "send", + "regex": r"^\$(.+)#[0-9a-fA-F]{2}$", + "capture": {1: "g_c2_contents"}, + }, + ], + True, + ) # Run the packet stream. context = self.expect_gdbremote_sequence() @@ -1393,10 +1540,12 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): self.assertIsNotNone(context.get("g_c2_contents")) return (seven.unhexlify(context.get("g_c1_contents")) == expected_g_c1) and ( - seven.unhexlify(context.get("g_c2_contents")) == expected_g_c2) + seven.unhexlify(context.get("g_c2_contents")) == expected_g_c2 + ) def single_step_only_steps_one_instruction( - self, use_Hc_packet=True, step_instruction="s"): + self, use_Hc_packet=True, step_instruction="s" + ): """Used by single step test that appears in a few different contexts.""" # Start up the inferior. procs = self.prep_debug_monitor_and_inferior( @@ -1406,7 +1555,9 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): "get-data-address-hex:g_c2", "sleep:1", "call-function:swap_chars", - "sleep:5"]) + "sleep:5", + ] + ) # Run the process self.test_sequence.add_log_lines( @@ -1414,13 +1565,26 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): "read packet: $c#63", # Match output line that prints the memory address of the function call entry point. # Note we require launch-only testing so we can get inferior otuput. - {"type": "output_match", "regex": r"^code address: 0x([0-9a-fA-F]+)\r\ndata address: 0x([0-9a-fA-F]+)\r\ndata address: 0x([0-9a-fA-F]+)\r\n$", - "capture": {1: "function_address", 2: "g_c1_address", 3: "g_c2_address"}}, + { + "type": "output_match", + "regex": r"^code address: 0x([0-9a-fA-F]+)\r\ndata address: 0x([0-9a-fA-F]+)\r\ndata address: 0x([0-9a-fA-F]+)\r\n$", + "capture": { + 1: "function_address", + 2: "g_c1_address", + 3: "g_c2_address", + }, + }, # Now stop the inferior. "read packet: {}".format(chr(3)), # And wait for the stop notification. - {"direction": "send", "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture": {1: "stop_signo", 2: "stop_thread_id"}}], - True) + { + "direction": "send", + "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", + "capture": {1: "stop_signo", 2: "stop_thread_id"}, + }, + ], + True, + ) # Run the packet stream. context = self.expect_gdbremote_sequence() @@ -1449,16 +1613,16 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): BREAKPOINT_KIND = 1 self.reset_test_sequence() self.add_set_breakpoint_packets( - function_address, - do_continue=True, - breakpoint_kind=BREAKPOINT_KIND) + function_address, do_continue=True, breakpoint_kind=BREAKPOINT_KIND + ) context = self.expect_gdbremote_sequence() self.assertIsNotNone(context) # Remove the breakpoint. self.reset_test_sequence() self.add_remove_breakpoint_packets( - function_address, breakpoint_kind=BREAKPOINT_KIND) + function_address, breakpoint_kind=BREAKPOINT_KIND + ) context = self.expect_gdbremote_sequence() self.assertIsNotNone(context) @@ -1475,25 +1639,27 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): # Might need to work through function entry prologue code. args["expected_g_c1"] = "1" args["expected_g_c2"] = "1" - (state_reached, - step_count) = self.count_single_steps_until_true(main_thread_id, - self.g_c1_c2_contents_are, - args, - max_step_count=25, - use_Hc_packet=use_Hc_packet, - step_instruction=step_instruction) + (state_reached, step_count) = self.count_single_steps_until_true( + main_thread_id, + self.g_c1_c2_contents_are, + args, + max_step_count=25, + use_Hc_packet=use_Hc_packet, + step_instruction=step_instruction, + ) self.assertTrue(state_reached) # Verify we hit the next state. args["expected_g_c1"] = "1" args["expected_g_c2"] = "0" - (state_reached, - step_count) = self.count_single_steps_until_true(main_thread_id, - self.g_c1_c2_contents_are, - args, - max_step_count=5, - use_Hc_packet=use_Hc_packet, - step_instruction=step_instruction) + (state_reached, step_count) = self.count_single_steps_until_true( + main_thread_id, + self.g_c1_c2_contents_are, + args, + max_step_count=5, + use_Hc_packet=use_Hc_packet, + step_instruction=step_instruction, + ) self.assertTrue(state_reached) expected_step_count = 1 arch = self.getArchitecture() @@ -1513,8 +1679,10 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): if re.match("arm64", arch): before_materialization_step_count = 4 after_matrialization_step_count = 1 - self.assertIn(step_count, [before_materialization_step_count, - after_matrialization_step_count]) + self.assertIn( + step_count, + [before_materialization_step_count, after_matrialization_step_count], + ) expected_step_count = after_matrialization_step_count else: self.assertEqual(step_count, expected_step_count) @@ -1522,43 +1690,52 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory): # Verify we hit the next state. args["expected_g_c1"] = "0" args["expected_g_c2"] = "0" - (state_reached, - step_count) = self.count_single_steps_until_true(main_thread_id, - self.g_c1_c2_contents_are, - args, - max_step_count=5, - use_Hc_packet=use_Hc_packet, - step_instruction=step_instruction) + (state_reached, step_count) = self.count_single_steps_until_true( + main_thread_id, + self.g_c1_c2_contents_are, + args, + max_step_count=5, + use_Hc_packet=use_Hc_packet, + step_instruction=step_instruction, + ) self.assertTrue(state_reached) self.assertEqual(step_count, expected_step_count) # Verify we hit the next state. args["expected_g_c1"] = "0" args["expected_g_c2"] = "1" - (state_reached, - step_count) = self.count_single_steps_until_true(main_thread_id, - self.g_c1_c2_contents_are, - args, - max_step_count=5, - use_Hc_packet=use_Hc_packet, - step_instruction=step_instruction) + (state_reached, step_count) = self.count_single_steps_until_true( + main_thread_id, + self.g_c1_c2_contents_are, + args, + max_step_count=5, + use_Hc_packet=use_Hc_packet, + step_instruction=step_instruction, + ) self.assertTrue(state_reached) self.assertEqual(step_count, expected_step_count) def maybe_strict_output_regex(self, regex): - return '.*' + regex + \ - '.*' if lldbplatformutil.hasChattyStderr(self) else '^' + regex + '$' + return ( + ".*" + regex + ".*" + if lldbplatformutil.hasChattyStderr(self) + else "^" + regex + "$" + ) def install_and_create_launch_args(self): exe_path = self.getBuildArtifact("a.out") if not lldb.remote_platform: return [exe_path] - remote_path = lldbutil.append_to_process_working_directory(self, - os.path.basename(exe_path)) + remote_path = lldbutil.append_to_process_working_directory( + self, os.path.basename(exe_path) + ) remote_file_spec = lldb.SBFileSpec(remote_path, False) - err = lldb.remote_platform.Install(lldb.SBFileSpec(exe_path, True), - remote_file_spec) + err = lldb.remote_platform.Install( + lldb.SBFileSpec(exe_path, True), remote_file_spec + ) if err.Fail(): - raise Exception("remote_platform.Install('%s', '%s') failed: %s" % - (exe_path, remote_path, err)) + raise Exception( + "remote_platform.Install('%s', '%s') failed: %s" + % (exe_path, remote_path, err) + ) return [remote_path] diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py index 8e615ec..ba6e24c 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py @@ -16,6 +16,7 @@ from lldbsuite.test import configuration from textwrap import dedent import shutil + def _get_support_exe(basename): support_dir = lldb.SBHostOS.GetLLDBPath(lldb.ePathTypeSupportExecutableDir) @@ -40,14 +41,19 @@ def get_debugserver_exe(): A path to the debugserver exe if it is found to exist; otherwise, returns None. """ - if configuration.arch and configuration.arch == "x86_64" and \ - platform.machine().startswith("arm64"): - return '/Library/Apple/usr/libexec/oah/debugserver' + if ( + configuration.arch + and configuration.arch == "x86_64" + and platform.machine().startswith("arm64") + ): + return "/Library/Apple/usr/libexec/oah/debugserver" return _get_support_exe("debugserver") -_LOG_LINE_REGEX = re.compile(r'^(lldb-server|debugserver)\s+<\s*(\d+)>' + - '\s+(read|send)\s+packet:\s+(.+)$') + +_LOG_LINE_REGEX = re.compile( + r"^(lldb-server|debugserver)\s+<\s*(\d+)>" + "\s+(read|send)\s+packet:\s+(.+)$" +) def _is_packet_lldb_gdbserver_input(packet_type, llgs_input_is_read): @@ -65,11 +71,11 @@ def _is_packet_lldb_gdbserver_input(packet_type, llgs_input_is_read): True if the packet should be considered input for lldb-gdbserver; False otherwise. """ - if packet_type == 'read': + if packet_type == "read": # when llgs is the read side, then a read packet is meant for # input to llgs (when captured from the llgs/debugserver exe). return llgs_input_is_read - elif packet_type == 'send': + elif packet_type == "send": # when llgs is the send side, then a send packet is meant to # be input to llgs (when captured from the lldb exe). return not llgs_input_is_read @@ -78,7 +84,7 @@ def _is_packet_lldb_gdbserver_input(packet_type, llgs_input_is_read): raise "Unknown packet type: {}".format(packet_type) -_STRIP_CHECKSUM_REGEX = re.compile(r'#[0-9a-fA-F]{2}$') +_STRIP_CHECKSUM_REGEX = re.compile(r"#[0-9a-fA-F]{2}$") _STRIP_COMMAND_PREFIX_REGEX = re.compile(r"^\$") _STRIP_COMMAND_PREFIX_M_REGEX = re.compile(r"^\$m") @@ -87,17 +93,14 @@ def assert_packets_equal(asserter, actual_packet, expected_packet): # strip off the checksum digits of the packet. When we're in # no-ack mode, the # checksum is ignored, and should not be cause # for a mismatched packet. - actual_stripped = _STRIP_CHECKSUM_REGEX.sub('', actual_packet) - expected_stripped = _STRIP_CHECKSUM_REGEX.sub('', expected_packet) + actual_stripped = _STRIP_CHECKSUM_REGEX.sub("", actual_packet) + expected_stripped = _STRIP_CHECKSUM_REGEX.sub("", expected_packet) asserter.assertEqual(actual_stripped, expected_stripped) def expect_lldb_gdbserver_replay( - asserter, - server, - test_sequence, - timeout_seconds, - logger=None): + asserter, server, test_sequence, timeout_seconds, logger=None +): """Replay socket communication with lldb-gdbserver and verify responses. Args: @@ -149,8 +152,7 @@ def expect_lldb_gdbserver_replay( packet_desc = "^C" else: packet_desc = send_packet - logger.info( - "sending packet to remote: {}".format(packet_desc)) + logger.info("sending packet to remote: {}".format(packet_desc)) server.send_raw(send_packet.encode()) else: # This is an entry expecting to receive content from the remote @@ -168,14 +170,16 @@ def expect_lldb_gdbserver_replay( content = seven.bitcast_to_string(content) except socket.timeout: asserter.fail( - "timed out while waiting for '{}':\n{}".format(sequence_entry, server)) + "timed out while waiting for '{}':\n{}".format( + sequence_entry, server + ) + ) # Give the sequence entry the opportunity to match the content. # Output matchers might match or pass after more output accumulates. # Other packet types generally must match. asserter.assertIsNotNone(content) - context = sequence_entry.assert_match( - asserter, content, context=context) + context = sequence_entry.assert_match(asserter, content, context=context) # Move on to next sequence entry as needed. Some sequence entries support executing multiple # times in different states (for looping over query/response @@ -194,9 +198,9 @@ def expect_lldb_gdbserver_replay( def gdbremote_hex_encode_string(str): - output = '' + output = "" for c in str: - output += '{0:02x}'.format(ord(c)) + output += "{0:02x}".format(ord(c)) return output @@ -208,12 +212,11 @@ def gdbremote_packet_encode_string(str): checksum = 0 for c in str: checksum += ord(c) - return '$' + str + '#{0:02x}'.format(checksum % 256) + return "$" + str + "#{0:02x}".format(checksum % 256) def build_gdbremote_A_packet(args_list): - """Given a list of args, create a properly-formed $A packet containing each arg. - """ + """Given a list of args, create a properly-formed $A packet containing each arg.""" payload = "A" # build the arg content @@ -221,7 +224,7 @@ def build_gdbremote_A_packet(args_list): for arg in args_list: # Comma-separate the args. if arg_index > 0: - payload += ',' + payload += "," # Hex-encode the arg. hex_arg = gdbremote_hex_encode_string(arg) @@ -249,7 +252,7 @@ def parse_reg_info_response(response_packet): for kv in response_packet.split(";"): if len(kv) < 1: continue - (key, val) = kv.split(':') + (key, val) = kv.split(":") values[key] = val return values @@ -280,15 +283,15 @@ def unpack_endian_binary_string(endian, value_string): if not value_string or len(value_string) < 1: raise Exception("value_string cannot be None or empty") - if endian == 'little': + if endian == "little": value = 0 i = 0 while len(value_string) > 0: - value += (ord(value_string[0]) << i) + value += ord(value_string[0]) << i value_string = value_string[1:] i += 8 return value - elif endian == 'big': + elif endian == "big": value = 0 while len(value_string) > 0: value = (value << 8) + ord(value_string[0]) @@ -306,15 +309,15 @@ def unpack_register_hex_unsigned(endian, value_string): if not value_string or len(value_string) < 1: raise Exception("value_string cannot be None or empty") - if endian == 'little': + if endian == "little": value = 0 i = 0 while len(value_string) > 0: - value += (int(value_string[0:2], 16) << i) + value += int(value_string[0:2], 16) << i value_string = value_string[2:] i += 8 return value - elif endian == 'big': + elif endian == "big": return int(value_string, 16) else: # pdp is valid but need to add parse code once needed. @@ -326,21 +329,21 @@ def pack_register_hex(endian, value, byte_size=None): if not endian: raise Exception("endian cannot be None") - if endian == 'little': + if endian == "little": # Create the litt-endian return value. retval = "" while value != 0: - retval = retval + "{:02x}".format(value & 0xff) + retval = retval + "{:02x}".format(value & 0xFF) value = value >> 8 if byte_size: # Add zero-fill to the right/end (MSB side) of the value. retval += "00" * (byte_size - len(retval) // 2) return retval - elif endian == 'big': + elif endian == "big": retval = "" while value != 0: - retval = "{:02x}".format(value & 0xff) + retval + retval = "{:02x}".format(value & 0xFF) + retval value = value >> 8 if byte_size: # Add zero-fill to the left/front (MSB side) of the value. @@ -353,19 +356,14 @@ def pack_register_hex(endian, value, byte_size=None): class GdbRemoteEntryBase(object): - def is_output_matcher(self): return False class GdbRemoteEntry(GdbRemoteEntryBase): - def __init__( - self, - is_send_to_remote=True, - exact_payload=None, - regex=None, - capture=None): + self, is_send_to_remote=True, exact_payload=None, regex=None, capture=None + ): """Create an entry representing one piece of the I/O to/from a gdb remote debug monitor. Args: @@ -413,10 +411,12 @@ class GdbRemoteEntry(GdbRemoteEntryBase): def get_send_packet(self): if not self.is_send_to_remote(): raise Exception( - "get_send_packet() called on GdbRemoteEntry that is not a send-to-remote packet") + "get_send_packet() called on GdbRemoteEntry that is not a send-to-remote packet" + ) if not self.exact_payload: raise Exception( - "get_send_packet() called on GdbRemoteEntry but it doesn't have an exact payload") + "get_send_packet() called on GdbRemoteEntry but it doesn't have an exact payload" + ) return self.exact_payload def _assert_exact_payload_match(self, asserter, actual_packet): @@ -429,7 +429,9 @@ class GdbRemoteEntry(GdbRemoteEntryBase): if not match: asserter.fail( "regex '{}' failed to match against content '{}'".format( - self.regex.pattern, actual_packet)) + self.regex.pattern, actual_packet + ) + ) if self.capture: # Handle captures. @@ -447,7 +449,8 @@ class GdbRemoteEntry(GdbRemoteEntryBase): # remote debug monitor. if self.is_send_to_remote(): raise Exception( - "Attempted to match a packet being sent to the remote debug monitor, doesn't make sense.") + "Attempted to match a packet being sent to the remote debug monitor, doesn't make sense." + ) # Create a new context if needed. if not context: @@ -463,7 +466,8 @@ class GdbRemoteEntry(GdbRemoteEntryBase): return self._assert_regex_match(asserter, actual_packet, context) else: raise Exception( - "Don't know how to match a remote-sent packet when exact_payload isn't specified.") + "Don't know how to match a remote-sent packet when exact_payload isn't specified." + ) class MultiResponseGdbRemoteEntry(GdbRemoteEntryBase): @@ -507,13 +511,11 @@ class MultiResponseGdbRemoteEntry(GdbRemoteEntryBase): raise "either next_query or query key must be specified for MultiResponseGdbRemoteEntry" self._first_query = params.get("first_query", self._next_query) - self._append_iteration_suffix = params.get( - "append_iteration_suffix", False) + self._append_iteration_suffix = params.get("append_iteration_suffix", False) self._iteration = 0 self._end_regex = params["end_regex"] self._save_key = params["save_key"] - self._runaway_response_count = params.get( - "runaway_response_count", 10000) + self._runaway_response_count = params.get("runaway_response_count", 10000) self._is_send_to_remote = True self._end_matched = False @@ -523,10 +525,12 @@ class MultiResponseGdbRemoteEntry(GdbRemoteEntryBase): def get_send_packet(self): if not self.is_send_to_remote(): raise Exception( - "get_send_packet() called on MultiResponseGdbRemoteEntry that is not in the send state") + "get_send_packet() called on MultiResponseGdbRemoteEntry that is not in the send state" + ) if self._end_matched: raise Exception( - "get_send_packet() called on MultiResponseGdbRemoteEntry but end of query/response sequence has already been seen.") + "get_send_packet() called on MultiResponseGdbRemoteEntry but end of query/response sequence has already been seen." + ) # Choose the first or next query for the base payload. if self._iteration == 0 and self._first_query: @@ -556,11 +560,13 @@ class MultiResponseGdbRemoteEntry(GdbRemoteEntryBase): # monitor. if self.is_send_to_remote(): raise Exception( - "assert_match() called on MultiResponseGdbRemoteEntry but state is set to send a query packet.") + "assert_match() called on MultiResponseGdbRemoteEntry but state is set to send a query packet." + ) if self._end_matched: raise Exception( - "assert_match() called on MultiResponseGdbRemoteEntry but end of query/response sequence has already been seen.") + "assert_match() called on MultiResponseGdbRemoteEntry but end of query/response sequence has already been seen." + ) # Set up a context as needed. if not context: @@ -580,12 +586,9 @@ class MultiResponseGdbRemoteEntry(GdbRemoteEntryBase): # Check for a runaway response cycle. if len(context[self._save_key]) >= self._runaway_response_count: raise Exception( - "runaway query/response cycle detected: %d responses captured so far. Last response: %s" % - (len( - context[ - self._save_key]), context[ - self._save_key][ - -1])) + "runaway query/response cycle detected: %d responses captured so far. Last response: %s" + % (len(context[self._save_key]), context[self._save_key][-1]) + ) # Flip the mode to send for generating the query. self._is_send_to_remote = True @@ -630,8 +633,10 @@ class MatchRemoteOutputEntry(GdbRemoteEntryBase): if not self._regex_mode in ["match", "search"]: raise Exception( - "unsupported regex mode \"{}\": must be \"match\" or \"search\"".format( - self._regex_mode)) + 'unsupported regex mode "{}": must be "match" or "search"'.format( + self._regex_mode + ) + ) def is_output_matcher(self): return True @@ -653,7 +658,8 @@ class MatchRemoteOutputEntry(GdbRemoteEntryBase): # Validate that we haven't already matched. if self._matched: raise Exception( - "invalid state - already matched, attempting to match again") + "invalid state - already matched, attempting to match again" + ) # If we don't have any content yet, we don't match. if len(accumulated_output) < 1: @@ -665,9 +671,7 @@ class MatchRemoteOutputEntry(GdbRemoteEntryBase): elif self._regex_mode == "search": match = self._regex.search(accumulated_output) else: - raise Exception( - "Unexpected regex mode: {}".format( - self._regex_mode)) + raise Exception("Unexpected regex mode: {}".format(self._regex_mode)) # If we don't match, wait to try again after next $O content, or time # out. @@ -685,16 +689,14 @@ class MatchRemoteOutputEntry(GdbRemoteEntryBase): for group_index, var_name in list(self._capture.items()): capture_text = match.group(group_index) if not capture_text: - raise Exception( - "No content for group index {}".format(group_index)) + raise Exception("No content for group index {}".format(group_index)) context[var_name] = capture_text return context class GdbRemoteTestSequence(object): - - _LOG_LINE_REGEX = re.compile(r'^.*(read|send)\s+packet:\s+(.+)$') + _LOG_LINE_REGEX = re.compile(r"^.*(read|send)\s+packet:\s+(.+)$") def __init__(self, logger): self.entries = [] @@ -713,26 +715,26 @@ class GdbRemoteTestSequence(object): if match: playback_packet = match.group(2) direction = match.group(1) - if _is_packet_lldb_gdbserver_input( - direction, remote_input_is_read): + if _is_packet_lldb_gdbserver_input(direction, remote_input_is_read): # Handle as something to send to the remote debug monitor. # if self.logger: # self.logger.info("processed packet to send to remote: {}".format(playback_packet)) self.entries.append( GdbRemoteEntry( - is_send_to_remote=True, - exact_payload=playback_packet)) + is_send_to_remote=True, exact_payload=playback_packet + ) + ) else: # Log line represents content to be expected from the remote debug monitor. # if self.logger: # self.logger.info("receiving packet from llgs, should match: {}".format(playback_packet)) self.entries.append( GdbRemoteEntry( - is_send_to_remote=False, - exact_payload=playback_packet)) + is_send_to_remote=False, exact_payload=playback_packet + ) + ) else: - raise Exception( - "failed to interpret log line: {}".format(line)) + raise Exception("failed to interpret log line: {}".format(line)) elif isinstance(line, dict): entry_type = line.get("type", "regex_capture") if entry_type == "regex_capture": @@ -745,29 +747,27 @@ class GdbRemoteTestSequence(object): if regex and (isinstance(regex, str)): regex = re.compile(regex, re.DOTALL) - if _is_packet_lldb_gdbserver_input( - direction, remote_input_is_read): + if _is_packet_lldb_gdbserver_input(direction, remote_input_is_read): # Handle as something to send to the remote debug monitor. # if self.logger: # self.logger.info("processed dict sequence to send to remote") self.entries.append( GdbRemoteEntry( - is_send_to_remote=True, - regex=regex, - capture=capture)) + is_send_to_remote=True, regex=regex, capture=capture + ) + ) else: # Log line represents content to be expected from the remote debug monitor. # if self.logger: # self.logger.info("processed dict sequence to match receiving from remote") self.entries.append( GdbRemoteEntry( - is_send_to_remote=False, - regex=regex, - capture=capture)) + is_send_to_remote=False, regex=regex, capture=capture + ) + ) elif entry_type == "multi_response": self.entries.append(MultiResponseGdbRemoteEntry(line)) elif entry_type == "output_match": - regex = line.get("regex", None) # Compile the regex. if regex and (isinstance(regex, str)): @@ -777,11 +777,11 @@ class GdbRemoteTestSequence(object): capture = line.get("capture", None) self.entries.append( MatchRemoteOutputEntry( - regex=regex, - regex_mode=regex_mode, - capture=capture)) + regex=regex, regex_mode=regex_mode, capture=capture + ) + ) else: - raise Exception("unknown entry type \"%s\"" % entry_type) + raise Exception('unknown entry type "%s"' % entry_type) def process_is_running(pid, unknown_value=True): @@ -804,8 +804,8 @@ def process_is_running(pid, unknown_value=True): """ if not isinstance(pid, int): raise Exception( - "pid must be an integral type (actual type: %s)" % str( - type(pid))) + "pid must be an integral type (actual type: %s)" % str(type(pid)) + ) process_ids = [] @@ -813,20 +813,21 @@ def process_is_running(pid, unknown_value=True): # Don't know how to get list of running process IDs on a remote # platform return unknown_value - elif platform.system() in ['Darwin', 'Linux', 'FreeBSD', 'NetBSD']: + elif platform.system() in ["Darwin", "Linux", "FreeBSD", "NetBSD"]: # Build the list of running process ids output = subprocess.check_output( - "ps ax | awk '{ print $1; }'", shell=True).decode("utf-8") - text_process_ids = output.split('\n')[1:] + "ps ax | awk '{ print $1; }'", shell=True + ).decode("utf-8") + text_process_ids = output.split("\n")[1:] # Convert text pids to ints - process_ids = [int(text_pid) - for text_pid in text_process_ids if text_pid != ''] - elif platform.system() == 'Windows': + process_ids = [int(text_pid) for text_pid in text_process_ids if text_pid != ""] + elif platform.system() == "Windows": output = subprocess.check_output( - "for /f \"tokens=2 delims=,\" %F in ('tasklist /nh /fi \"PID ne 0\" /fo csv') do @echo %~F", shell=True).decode("utf-8") - text_process_ids = output.split('\n')[1:] - process_ids = [int(text_pid) - for text_pid in text_process_ids if text_pid != ''] + 'for /f "tokens=2 delims=," %F in (\'tasklist /nh /fi "PID ne 0" /fo csv\') do @echo %~F', + shell=True, + ).decode("utf-8") + text_process_ids = output.split("\n")[1:] + process_ids = [int(text_pid) for text_pid in text_process_ids if text_pid != ""] # elif {your_platform_here}: # fill in process_ids as a list of int type process IDs running on # the local system. @@ -851,13 +852,12 @@ def _handle_output_packet_string(packet_contents): class Server(object): - - _GDB_REMOTE_PACKET_REGEX = re.compile(br'^([\$%][^\#]*)#[0-9a-fA-F]{2}') + _GDB_REMOTE_PACKET_REGEX = re.compile(rb"^([\$%][^\#]*)#[0-9a-fA-F]{2}") class ChecksumMismatch(Exception): pass - def __init__(self, sock, proc = None): + def __init__(self, sock, proc=None): self._accumulated_output = b"" self._receive_buffer = b"" self._normal_queue = [] @@ -872,7 +872,7 @@ class Server(object): self.send_raw(b"+") def send_packet(self, packet): - self.send_raw(b'$%s#%02x'%(packet, self._checksum(packet))) + self.send_raw(b"$%s#%02x" % (packet, self._checksum(packet))) @staticmethod def _checksum(packet): @@ -901,13 +901,13 @@ class Server(object): self._normal_queue += [b"+"] self._receive_buffer = self._receive_buffer[1:] else: - packet_match = self._GDB_REMOTE_PACKET_REGEX.match( - self._receive_buffer) + packet_match = self._GDB_REMOTE_PACKET_REGEX.match(self._receive_buffer) if packet_match: # Our receive buffer matches a packet at the # start of the receive buffer. new_output_content = _handle_output_packet_string( - packet_match.group(1)) + packet_match.group(1) + ) if new_output_content: # This was an $O packet with new content. self._accumulated_output += new_output_content @@ -919,7 +919,8 @@ class Server(object): # Remove the parsed packet from the receive # buffer. self._receive_buffer = self._receive_buffer[ - len(packet_match.group(0)):] + len(packet_match.group(0)) : + ] else: # We don't have enough in the receive bufferto make a full # packet. Stop trying until we read more. @@ -941,7 +942,8 @@ class Server(object): def get_normal_packet(self): frame = self.get_raw_normal_packet() - if frame == b"+": return frame + if frame == b"+": + return frame return self._get_payload(frame) def get_accumulated_output(self): @@ -953,12 +955,19 @@ class Server(object): return output def __str__(self): - return dedent("""\ + return dedent( + """\ server '{}' on '{}' _receive_buffer: {} _normal_queue: {} _output_queue: {} _accumulated_output: {} - """).format(self._proc, self._sock, self._receive_buffer, - self._normal_queue, self._output_queue, - self._accumulated_output) + """ + ).format( + self._proc, + self._sock, + self._receive_buffer, + self._normal_queue, + self._output_queue, + self._accumulated_output, + ) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py index d6ed0ee..adc8436 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py @@ -1,4 +1,3 @@ - from lldbsuite.test.lldbtest import * import os import vscode @@ -6,53 +5,55 @@ import time class VSCodeTestCaseBase(TestBase): - NO_DEBUG_INFO_TESTCASE = True def create_debug_adaptor(self, lldbVSCodeEnv=None): - '''Create the Visual Studio Code debug adaptor''' - self.assertTrue(is_exe(self.lldbVSCodeExec), - 'lldb-vscode must exist and be executable') - log_file_path = self.getBuildArtifact('vscode.txt') + """Create the Visual Studio Code debug adaptor""" + self.assertTrue( + is_exe(self.lldbVSCodeExec), "lldb-vscode must exist and be executable" + ) + log_file_path = self.getBuildArtifact("vscode.txt") self.vscode = vscode.DebugAdaptor( - executable=self.lldbVSCodeExec, init_commands=self.setUpCommands(), - log_file=log_file_path, env=lldbVSCodeEnv) + executable=self.lldbVSCodeExec, + init_commands=self.setUpCommands(), + log_file=log_file_path, + env=lldbVSCodeEnv, + ) def build_and_create_debug_adaptor(self, lldbVSCodeEnv=None): self.build() self.create_debug_adaptor(lldbVSCodeEnv) def set_source_breakpoints(self, source_path, lines, data=None): - '''Sets source breakpoints and returns an array of strings containing - the breakpoint IDs ("1", "2") for each breakpoint that was set. - Parameter data is array of data objects for breakpoints. - Each object in data is 1:1 mapping with the entry in lines. - It contains optional location/hitCondition/logMessage parameters. - ''' - response = self.vscode.request_setBreakpoints( - source_path, lines, data) + """Sets source breakpoints and returns an array of strings containing + the breakpoint IDs ("1", "2") for each breakpoint that was set. + Parameter data is array of data objects for breakpoints. + Each object in data is 1:1 mapping with the entry in lines. + It contains optional location/hitCondition/logMessage parameters. + """ + response = self.vscode.request_setBreakpoints(source_path, lines, data) if response is None: return [] - breakpoints = response['body']['breakpoints'] + breakpoints = response["body"]["breakpoints"] breakpoint_ids = [] for breakpoint in breakpoints: - breakpoint_ids.append('%i' % (breakpoint['id'])) + breakpoint_ids.append("%i" % (breakpoint["id"])) return breakpoint_ids - def set_function_breakpoints(self, functions, condition=None, - hitCondition=None): - '''Sets breakpoints by function name given an array of function names - and returns an array of strings containing the breakpoint IDs - ("1", "2") for each breakpoint that was set. - ''' + def set_function_breakpoints(self, functions, condition=None, hitCondition=None): + """Sets breakpoints by function name given an array of function names + and returns an array of strings containing the breakpoint IDs + ("1", "2") for each breakpoint that was set. + """ response = self.vscode.request_setFunctionBreakpoints( - functions, condition=condition, hitCondition=hitCondition) + functions, condition=condition, hitCondition=hitCondition + ) if response is None: return [] - breakpoints = response['body']['breakpoints'] + breakpoints = response["body"]["breakpoints"] breakpoint_ids = [] for breakpoint in breakpoints: - breakpoint_ids.append('%i' % (breakpoint['id'])) + breakpoint_ids.append("%i" % (breakpoint["id"])) return breakpoint_ids def waitUntil(self, condition_callback): @@ -63,20 +64,20 @@ class VSCodeTestCaseBase(TestBase): return False def verify_breakpoint_hit(self, breakpoint_ids): - '''Wait for the process we are debugging to stop, and verify we hit - any breakpoint location in the "breakpoint_ids" array. - "breakpoint_ids" should be a list of breakpoint ID strings - (["1", "2"]). The return value from self.set_source_breakpoints() - or self.set_function_breakpoints() can be passed to this function''' + """Wait for the process we are debugging to stop, and verify we hit + any breakpoint location in the "breakpoint_ids" array. + "breakpoint_ids" should be a list of breakpoint ID strings + (["1", "2"]). The return value from self.set_source_breakpoints() + or self.set_function_breakpoints() can be passed to this function""" stopped_events = self.vscode.wait_for_stopped() for stopped_event in stopped_events: - if 'body' in stopped_event: - body = stopped_event['body'] - if 'reason' not in body: + if "body" in stopped_event: + body = stopped_event["body"] + if "reason" not in body: continue - if body['reason'] != 'breakpoint': + if body["reason"] != "breakpoint": continue - if 'description' not in body: + if "description" not in body: continue # Descriptions for breakpoints will be in the form # "breakpoint 1.1", so look for any description that matches @@ -86,29 +87,29 @@ class VSCodeTestCaseBase(TestBase): # So when looking at the description we just want to make sure # the right breakpoint matches and not worry about the actual # location. - description = body['description'] + description = body["description"] for breakpoint_id in breakpoint_ids: - match_desc = 'breakpoint %s.' % (breakpoint_id) + match_desc = "breakpoint %s." % (breakpoint_id) if match_desc in description: return self.assertTrue(False, "breakpoint not hit") def verify_stop_exception_info(self, expected_description): - '''Wait for the process we are debugging to stop, and verify the stop - reason is 'exception' and that the description matches - 'expected_description' - ''' + """Wait for the process we are debugging to stop, and verify the stop + reason is 'exception' and that the description matches + 'expected_description' + """ stopped_events = self.vscode.wait_for_stopped() for stopped_event in stopped_events: - if 'body' in stopped_event: - body = stopped_event['body'] - if 'reason' not in body: + if "body" in stopped_event: + body = stopped_event["body"] + if "reason" not in body: continue - if body['reason'] != 'exception': + if body["reason"] != "exception": continue - if 'description' not in body: + if "description" not in body: continue - description = body['description'] + description = body["description"] if expected_description == description: return True return False @@ -116,96 +117,96 @@ class VSCodeTestCaseBase(TestBase): def verify_commands(self, flavor, output, commands): self.assertTrue(output and len(output) > 0, "expect console output") lines = output.splitlines() - prefix = '(lldb) ' + prefix = "(lldb) " for cmd in commands: found = False for line in lines: if line.startswith(prefix) and cmd in line: found = True break - self.assertTrue(found, - "verify '%s' found in console output for '%s'" % ( - cmd, flavor)) + self.assertTrue( + found, "verify '%s' found in console output for '%s'" % (cmd, flavor) + ) def get_dict_value(self, d, key_path): - '''Verify each key in the key_path array is in contained in each - dictionary within "d". Assert if any key isn't in the - corresponding dictionary. This is handy for grabbing values from VS - Code response dictionary like getting - response['body']['stackFrames'] - ''' + """Verify each key in the key_path array is in contained in each + dictionary within "d". Assert if any key isn't in the + corresponding dictionary. This is handy for grabbing values from VS + Code response dictionary like getting + response['body']['stackFrames'] + """ value = d for key in key_path: if key in value: value = value[key] else: - self.assertTrue(key in value, - 'key "%s" from key_path "%s" not in "%s"' % ( - key, key_path, d)) + self.assertTrue( + key in value, + 'key "%s" from key_path "%s" not in "%s"' % (key, key_path, d), + ) return value - def get_stackFrames_and_totalFramesCount(self, threadId=None, startFrame=None, - levels=None, dump=False): - response = self.vscode.request_stackTrace(threadId=threadId, - startFrame=startFrame, - levels=levels, - dump=dump) + def get_stackFrames_and_totalFramesCount( + self, threadId=None, startFrame=None, levels=None, dump=False + ): + response = self.vscode.request_stackTrace( + threadId=threadId, startFrame=startFrame, levels=levels, dump=dump + ) if response: - stackFrames = self.get_dict_value(response, ['body', 'stackFrames']) - totalFrames = self.get_dict_value(response, ['body', 'totalFrames']) - self.assertTrue(totalFrames > 0, - 'verify totalFrames count is provided by extension that supports ' - 'async frames loading') + stackFrames = self.get_dict_value(response, ["body", "stackFrames"]) + totalFrames = self.get_dict_value(response, ["body", "totalFrames"]) + self.assertTrue( + totalFrames > 0, + "verify totalFrames count is provided by extension that supports " + "async frames loading", + ) return (stackFrames, totalFrames) return (None, 0) - def get_stackFrames(self, threadId=None, startFrame=None, levels=None, - dump=False): + def get_stackFrames(self, threadId=None, startFrame=None, levels=None, dump=False): (stackFrames, totalFrames) = self.get_stackFrames_and_totalFramesCount( - threadId=threadId, - startFrame=startFrame, - levels=levels, - dump=dump) + threadId=threadId, startFrame=startFrame, levels=levels, dump=dump + ) return stackFrames def get_source_and_line(self, threadId=None, frameIndex=0): - stackFrames = self.get_stackFrames(threadId=threadId, - startFrame=frameIndex, - levels=1) + stackFrames = self.get_stackFrames( + threadId=threadId, startFrame=frameIndex, levels=1 + ) if stackFrames is not None: stackFrame = stackFrames[0] - ['source', 'path'] - if 'source' in stackFrame: - source = stackFrame['source'] - if 'path' in source: - if 'line' in stackFrame: - return (source['path'], stackFrame['line']) - return ('', 0) + ["source", "path"] + if "source" in stackFrame: + source = stackFrame["source"] + if "path" in source: + if "line" in stackFrame: + return (source["path"], stackFrame["line"]) + return ("", 0) def get_stdout(self, timeout=0.0): - return self.vscode.get_output('stdout', timeout=timeout) + return self.vscode.get_output("stdout", timeout=timeout) def get_console(self, timeout=0.0): - return self.vscode.get_output('console', timeout=timeout) + return self.vscode.get_output("console", timeout=timeout) def collect_console(self, duration): - return self.vscode.collect_output('console', duration=duration) + return self.vscode.collect_output("console", duration=duration) def get_local_as_int(self, name, threadId=None): value = self.vscode.get_local_variable_value(name, threadId=threadId) - if value.startswith('0x'): + if value.startswith("0x"): return int(value, 16) - elif value.startswith('0'): + elif value.startswith("0"): return int(value, 8) else: return int(value) def set_local(self, name, value, id=None): - '''Set a top level local variable only.''' + """Set a top level local variable only.""" return self.vscode.request_setVariable(1, name, str(value), id=id) def set_global(self, name, value, id=None): - '''Set a top level global variable only.''' + """Set a top level global variable only.""" return self.vscode.request_setVariable(2, name, str(value), id=id) def stepIn(self, threadId=None, waitForStop=True): @@ -236,27 +237,48 @@ class VSCodeTestCaseBase(TestBase): def continue_to_exception_breakpoint(self, filter_label): self.vscode.request_continue() - self.assertTrue(self.verify_stop_exception_info(filter_label), - 'verify we got "%s"' % (filter_label)) + self.assertTrue( + self.verify_stop_exception_info(filter_label), + 'verify we got "%s"' % (filter_label), + ) def continue_to_exit(self, exitCode=0): self.vscode.request_continue() stopped_events = self.vscode.wait_for_stopped() - self.assertEquals(len(stopped_events), 1, - "stopped_events = {}".format(stopped_events)) - self.assertEquals(stopped_events[0]['event'], 'exited', - 'make sure program ran to completion') - self.assertEquals(stopped_events[0]['body']['exitCode'], exitCode, - 'exitCode == %i' % (exitCode)) - - def attach(self, program=None, pid=None, waitFor=None, trace=None, - initCommands=None, preRunCommands=None, stopCommands=None, - exitCommands=None, attachCommands=None, coreFile=None, - disconnectAutomatically=True, terminateCommands=None, - postRunCommands=None, sourceMap=None, sourceInitFile=False): - '''Build the default Makefile target, create the VSCode debug adaptor, - and attach to the process. - ''' + self.assertEquals( + len(stopped_events), 1, "stopped_events = {}".format(stopped_events) + ) + self.assertEquals( + stopped_events[0]["event"], "exited", "make sure program ran to completion" + ) + self.assertEquals( + stopped_events[0]["body"]["exitCode"], + exitCode, + "exitCode == %i" % (exitCode), + ) + + def attach( + self, + program=None, + pid=None, + waitFor=None, + trace=None, + initCommands=None, + preRunCommands=None, + stopCommands=None, + exitCommands=None, + attachCommands=None, + coreFile=None, + disconnectAutomatically=True, + terminateCommands=None, + postRunCommands=None, + sourceMap=None, + sourceInitFile=False, + ): + """Build the default Makefile target, create the VSCode debug adaptor, + and attach to the process. + """ + # Make sure we disconnect and terminate the VSCode debug adaptor even # if we throw an exception during the test case. def cleanup(): @@ -269,26 +291,52 @@ class VSCodeTestCaseBase(TestBase): # Initialize and launch the program self.vscode.request_initialize(sourceInitFile) response = self.vscode.request_attach( - program=program, pid=pid, waitFor=waitFor, trace=trace, - initCommands=initCommands, preRunCommands=preRunCommands, - stopCommands=stopCommands, exitCommands=exitCommands, - attachCommands=attachCommands, terminateCommands=terminateCommands, - coreFile=coreFile, postRunCommands=postRunCommands, - sourceMap=sourceMap) - if not (response and response['success']): - self.assertTrue(response['success'], - 'attach failed (%s)' % (response['message'])) - - def launch(self, program=None, args=None, cwd=None, env=None, - stopOnEntry=False, disableASLR=True, - disableSTDIO=False, shellExpandArguments=False, - trace=False, initCommands=None, preRunCommands=None, - stopCommands=None, exitCommands=None, terminateCommands=None, - sourcePath=None, debuggerRoot=None, sourceInitFile=False, launchCommands=None, - sourceMap=None, disconnectAutomatically=True, runInTerminal=False, - expectFailure=False, postRunCommands=None): - '''Sending launch request to vscode - ''' + program=program, + pid=pid, + waitFor=waitFor, + trace=trace, + initCommands=initCommands, + preRunCommands=preRunCommands, + stopCommands=stopCommands, + exitCommands=exitCommands, + attachCommands=attachCommands, + terminateCommands=terminateCommands, + coreFile=coreFile, + postRunCommands=postRunCommands, + sourceMap=sourceMap, + ) + if not (response and response["success"]): + self.assertTrue( + response["success"], "attach failed (%s)" % (response["message"]) + ) + + def launch( + self, + program=None, + args=None, + cwd=None, + env=None, + stopOnEntry=False, + disableASLR=True, + disableSTDIO=False, + shellExpandArguments=False, + trace=False, + initCommands=None, + preRunCommands=None, + stopCommands=None, + exitCommands=None, + terminateCommands=None, + sourcePath=None, + debuggerRoot=None, + sourceInitFile=False, + launchCommands=None, + sourceMap=None, + disconnectAutomatically=True, + runInTerminal=False, + expectFailure=False, + postRunCommands=None, + ): + """Sending launch request to vscode""" # Make sure we disconnect and terminate the VSCode debug adapter, # if we throw an exception during the test case @@ -322,36 +370,67 @@ class VSCodeTestCaseBase(TestBase): launchCommands=launchCommands, sourceMap=sourceMap, runInTerminal=runInTerminal, - postRunCommands=postRunCommands) + postRunCommands=postRunCommands, + ) if expectFailure: return response - if not (response and response['success']): - self.assertTrue(response['success'], - 'launch failed (%s)' % (response['message'])) + if not (response and response["success"]): + self.assertTrue( + response["success"], "launch failed (%s)" % (response["message"]) + ) return response - - def build_and_launch(self, program, args=None, cwd=None, env=None, - stopOnEntry=False, disableASLR=True, - disableSTDIO=False, shellExpandArguments=False, - trace=False, initCommands=None, preRunCommands=None, - stopCommands=None, exitCommands=None, - terminateCommands=None, sourcePath=None, - debuggerRoot=None, sourceInitFile=False, runInTerminal=False, - disconnectAutomatically=True, postRunCommands=None, - lldbVSCodeEnv=None): - '''Build the default Makefile target, create the VSCode debug adaptor, - and launch the process. - ''' + def build_and_launch( + self, + program, + args=None, + cwd=None, + env=None, + stopOnEntry=False, + disableASLR=True, + disableSTDIO=False, + shellExpandArguments=False, + trace=False, + initCommands=None, + preRunCommands=None, + stopCommands=None, + exitCommands=None, + terminateCommands=None, + sourcePath=None, + debuggerRoot=None, + sourceInitFile=False, + runInTerminal=False, + disconnectAutomatically=True, + postRunCommands=None, + lldbVSCodeEnv=None, + ): + """Build the default Makefile target, create the VSCode debug adaptor, + and launch the process. + """ self.build_and_create_debug_adaptor(lldbVSCodeEnv) - self.assertTrue(os.path.exists(program), 'executable must exist') - - return self.launch(program, args, cwd, env, stopOnEntry, disableASLR, - disableSTDIO, shellExpandArguments, trace, - initCommands, preRunCommands, stopCommands, exitCommands, - terminateCommands, sourcePath, debuggerRoot, sourceInitFile, - runInTerminal=runInTerminal, - disconnectAutomatically=disconnectAutomatically, - postRunCommands=postRunCommands) + self.assertTrue(os.path.exists(program), "executable must exist") + + return self.launch( + program, + args, + cwd, + env, + stopOnEntry, + disableASLR, + disableSTDIO, + shellExpandArguments, + trace, + initCommands, + preRunCommands, + stopCommands, + exitCommands, + terminateCommands, + sourcePath, + debuggerRoot, + sourceInitFile, + runInTerminal=runInTerminal, + disconnectAutomatically=disconnectAutomatically, + postRunCommands=postRunCommands, + ) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py index 3cfc888..236e26c 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py @@ -14,14 +14,13 @@ import time def dump_memory(base_addr, data, num_per_line, outfile): - data_len = len(data) hex_string = binascii.hexlify(data) addr = base_addr - ascii_str = '' + ascii_str = "" i = 0 while i < data_len: - outfile.write('0x%8.8x: ' % (addr + i)) + outfile.write("0x%8.8x: " % (addr + i)) bytes_left = data_len - i if bytes_left >= num_per_line: curr_data_len = num_per_line @@ -34,38 +33,38 @@ def dump_memory(base_addr, data, num_per_line, outfile): # current line with no spaces between bytes t = iter(curr_hex_str) # Print hex bytes separated by space - outfile.write(' '.join(a + b for a, b in zip(t, t))) + outfile.write(" ".join(a + b for a, b in zip(t, t))) # Print two spaces - outfile.write(' ') + outfile.write(" ") # Calculate ASCII string for bytes into 'ascii_str' - ascii_str = '' + ascii_str = "" for j in range(i, i + curr_data_len): ch = data[j] if ch in string.printable and ch not in string.whitespace: - ascii_str += '%c' % (ch) + ascii_str += "%c" % (ch) else: - ascii_str += '.' + ascii_str += "." # Print ASCII representation and newline outfile.write(ascii_str) i = i + curr_data_len - outfile.write('\n') + outfile.write("\n") def read_packet(f, verbose=False, trace_file=None): - '''Decode a JSON packet that starts with the content length and is - followed by the JSON bytes from a file 'f'. Returns None on EOF. - ''' + """Decode a JSON packet that starts with the content length and is + followed by the JSON bytes from a file 'f'. Returns None on EOF. + """ line = f.readline().decode("utf-8") if len(line) == 0: return None # EOF. # Watch for line that starts with the prefix - prefix = 'Content-Length: ' + prefix = "Content-Length: " if line.startswith(prefix): # Decode length of JSON bytes if verbose: print('content: "%s"' % (line)) - length = int(line[len(prefix):]) + length = int(line[len(prefix) :]) if verbose: print('length: "%u"' % (length)) # Skip empty line @@ -77,7 +76,7 @@ def read_packet(f, verbose=False, trace_file=None): if verbose: print('json: "%s"' % (json_str)) if trace_file: - trace_file.write('from adaptor:\n%s\n' % (json_str)) + trace_file.write("from adaptor:\n%s\n" % (json_str)) # Decode the JSON bytes into a python dictionary return json.loads(json_str) @@ -85,7 +84,8 @@ def read_packet(f, verbose=False, trace_file=None): def packet_type_is(packet, packet_type): - return 'type' in packet and packet['type'] == packet_type + return "type" in packet and packet["type"] == packet_type + def dump_dap_log(log_file): print("========= DEBUG ADAPTER PROTOCOL LOGS =========") @@ -111,15 +111,15 @@ def read_packet_thread(vs_comm, log_file): class DebugCommunication(object): - def __init__(self, recv, send, init_commands, log_file=None): self.trace_file = None self.send = send self.recv = recv self.recv_packets = [] self.recv_condition = threading.Condition() - self.recv_thread = threading.Thread(target=read_packet_thread, - args=(self, log_file)) + self.recv_thread = threading.Thread( + target=read_packet_thread, args=(self, log_file) + ) self.process_event_body = None self.exit_status = None self.initialize_body = None @@ -141,16 +141,16 @@ class DebugCommunication(object): @classmethod def validate_response(cls, command, response): - if command['command'] != response['command']: - raise ValueError('command mismatch in response') - if command['seq'] != response['request_seq']: - raise ValueError('seq mismatch in response') + if command["command"] != response["command"]: + raise ValueError("command mismatch in response") + if command["seq"] != response["request_seq"]: + raise ValueError("seq mismatch in response") def get_modules(self): - module_list = self.request_modules()['body']['modules'] + module_list = self.request_modules()["body"]["modules"] modules = {} for module in module_list: - modules[module['name']] = module + modules[module["name"]] = module return modules def get_output(self, category, timeout=0.0, clear=True): @@ -185,12 +185,12 @@ class DebugCommunication(object): self.recv_condition.release() def handle_recv_packet(self, packet): - '''Called by the read thread that is waiting for all incoming packets - to store the incoming packet in "self.recv_packets" in a thread safe - way. This function will then signal the "self.recv_condition" to - indicate a new packet is available. Returns True if the caller - should keep calling this function for more packets. - ''' + """Called by the read thread that is waiting for all incoming packets + to store the incoming packet in "self.recv_packets" in a thread safe + way. This function will then signal the "self.recv_condition" to + indicate a new packet is available. Returns True if the caller + should keep calling this function for more packets. + """ # If EOF, notify the read thread by enqueuing a None. if not packet: self.enqueue_recv_packet(None) @@ -198,18 +198,18 @@ class DebugCommunication(object): # Check the packet to see if is an event packet keepGoing = True - packet_type = packet['type'] - if packet_type == 'event': - event = packet['event'] + packet_type = packet["type"] + if packet_type == "event": + event = packet["event"] body = None - if 'body' in packet: - body = packet['body'] + if "body" in packet: + body = packet["body"] # Handle the event packet and cache information from these packets # as they come in - if event == 'output': + if event == "output": # Store any output we receive so clients can retrieve it later. - category = body['category'] - output = body['output'] + category = body["category"] + output = body["output"] self.output_condition.acquire() if category in self.output: self.output[category] += output @@ -219,26 +219,26 @@ class DebugCommunication(object): self.output_condition.release() # no need to add 'output' event packets to our packets list return keepGoing - elif event == 'process': + elif event == "process": # When a new process is attached or launched, remember the # details that are available in the body of the event self.process_event_body = body - elif event == 'stopped': + elif event == "stopped": # Each thread that stops with a reason will send a # 'stopped' event. We need to remember the thread stop # reasons since the 'threads' command doesn't return # that information. self._process_stopped() - tid = body['threadId'] + tid = body["threadId"] self.thread_stop_reasons[tid] = body - elif event == 'breakpoint': + elif event == "breakpoint": # Breakpoint events come in when a breakpoint has locations # added or removed. Keep track of them so we can look for them # in tests. self.breakpoint_events.append(packet) # no need to add 'breakpoint' event packets to our packets list return keepGoing - elif event.startswith('progress'): + elif event.startswith("progress"): # Progress events come in as 'progressStart', 'progressUpdate', # and 'progressEnd' events. Keep these around in case test # cases want to verify them. @@ -246,24 +246,24 @@ class DebugCommunication(object): # No need to add 'progress' event packets to our packets list. return keepGoing - elif packet_type == 'response': - if packet['command'] == 'disconnect': + elif packet_type == "response": + if packet["command"] == "disconnect": keepGoing = False self.enqueue_recv_packet(packet) return keepGoing def send_packet(self, command_dict, set_sequence=True): - '''Take the "command_dict" python dictionary and encode it as a JSON - string and send the contents as a packet to the VSCode debug - adaptor''' + """Take the "command_dict" python dictionary and encode it as a JSON + string and send the contents as a packet to the VSCode debug + adaptor""" # Set the sequence ID for this command automatically if set_sequence: - command_dict['seq'] = self.sequence + command_dict["seq"] = self.sequence self.sequence += 1 # Encode our command dictionary as a JSON string - json_str = json.dumps(command_dict, separators=(',', ':')) + json_str = json.dumps(command_dict, separators=(",", ":")) if self.trace_file: - self.trace_file.write('to adaptor:\n%s\n' % (json_str)) + self.trace_file.write("to adaptor:\n%s\n" % (json_str)) length = len(json_str) if length > 0: # Send the encoded JSON packet and flush the 'send' file @@ -271,24 +271,25 @@ class DebugCommunication(object): self.send.flush() def recv_packet(self, filter_type=None, filter_event=None, timeout=None): - '''Get a JSON packet from the VSCode debug adaptor. This function - assumes a thread that reads packets is running and will deliver - any received packets by calling handle_recv_packet(...). This - function will wait for the packet to arrive and return it when - it does.''' + """Get a JSON packet from the VSCode debug adaptor. This function + assumes a thread that reads packets is running and will deliver + any received packets by calling handle_recv_packet(...). This + function will wait for the packet to arrive and return it when + it does.""" while True: try: self.recv_condition.acquire() packet = None while True: - for (i, curr_packet) in enumerate(self.recv_packets): + for i, curr_packet in enumerate(self.recv_packets): if not curr_packet: raise EOFError - packet_type = curr_packet['type'] + packet_type = curr_packet["type"] if filter_type is None or packet_type in filter_type: - if (filter_event is None or - (packet_type == 'event' and - curr_packet['event'] in filter_event)): + if filter_event is None or ( + packet_type == "event" + and curr_packet["event"] in filter_event + ): packet = self.recv_packets.pop(i) break if packet: @@ -308,80 +309,89 @@ class DebugCommunication(object): return None def send_recv(self, command): - '''Send a command python dictionary as JSON and receive the JSON - response. Validates that the response is the correct sequence and - command in the reply. Any events that are received are added to the - events list in this object''' + """Send a command python dictionary as JSON and receive the JSON + response. Validates that the response is the correct sequence and + command in the reply. Any events that are received are added to the + events list in this object""" self.send_packet(command) done = False while not done: - response_or_request = self.recv_packet(filter_type=['response', 'request']) + response_or_request = self.recv_packet(filter_type=["response", "request"]) if response_or_request is None: - desc = 'no response for "%s"' % (command['command']) + desc = 'no response for "%s"' % (command["command"]) raise ValueError(desc) - if response_or_request['type'] == 'response': + if response_or_request["type"] == "response": self.validate_response(command, response_or_request) return response_or_request else: - if response_or_request['command'] == 'runInTerminal': - subprocess.Popen(response_or_request['arguments']['args'], - env=response_or_request['arguments']['env']) - self.send_packet({ - "type": "response", - "seq": -1, - "request_seq": response_or_request['seq'], - "success": True, - "command": "runInTerminal", - "body": {} - }, set_sequence=False) + if response_or_request["command"] == "runInTerminal": + subprocess.Popen( + response_or_request["arguments"]["args"], + env=response_or_request["arguments"]["env"], + ) + self.send_packet( + { + "type": "response", + "seq": -1, + "request_seq": response_or_request["seq"], + "success": True, + "command": "runInTerminal", + "body": {}, + }, + set_sequence=False, + ) else: - desc = 'unkonwn reverse request "%s"' % (response_or_request['command']) + desc = 'unkonwn reverse request "%s"' % ( + response_or_request["command"] + ) raise ValueError(desc) return None def wait_for_event(self, filter=None, timeout=None): while True: - return self.recv_packet(filter_type='event', filter_event=filter, - timeout=timeout) + return self.recv_packet( + filter_type="event", filter_event=filter, timeout=timeout + ) return None def wait_for_stopped(self, timeout=None): stopped_events = [] - stopped_event = self.wait_for_event(filter=['stopped', 'exited'], - timeout=timeout) + stopped_event = self.wait_for_event( + filter=["stopped", "exited"], timeout=timeout + ) exited = False while stopped_event: stopped_events.append(stopped_event) # If we exited, then we are done - if stopped_event['event'] == 'exited': - self.exit_status = stopped_event['body']['exitCode'] + if stopped_event["event"] == "exited": + self.exit_status = stopped_event["body"]["exitCode"] exited = True break # Otherwise we stopped and there might be one or more 'stopped' # events for each thread that stopped with a reason, so keep # checking for more 'stopped' events and return all of them - stopped_event = self.wait_for_event(filter='stopped', timeout=0.25) + stopped_event = self.wait_for_event(filter="stopped", timeout=0.25) if exited: self.threads = [] return stopped_events def wait_for_exited(self): - event_dict = self.wait_for_event('exited') + event_dict = self.wait_for_event("exited") if event_dict is None: raise ValueError("didn't get exited event") return event_dict def wait_for_terminated(self): - event_dict = self.wait_for_event('terminated') + event_dict = self.wait_for_event("terminated") if event_dict is None: raise ValueError("didn't get terminated event") return event_dict def get_initialize_value(self, key): - '''Get a value for the given key if it there is a key/value pair in - the "initialize" request response body. - ''' + """Get a value for the given key if it there is a key/value pair in + the "initialize" request response body. + """ if self.initialize_body and key in self.initialize_body: return self.initialize_body[key] return None @@ -392,172 +402,179 @@ class DebugCommunication(object): return self.threads def get_thread_id(self, threadIndex=0): - '''Utility function to get the first thread ID in the thread list. - If the thread list is empty, then fetch the threads. - ''' + """Utility function to get the first thread ID in the thread list. + If the thread list is empty, then fetch the threads. + """ if self.threads is None: self.request_threads() if self.threads and threadIndex < len(self.threads): - return self.threads[threadIndex]['id'] + return self.threads[threadIndex]["id"] return None def get_stackFrame(self, frameIndex=0, threadId=None): - '''Get a single "StackFrame" object from a "stackTrace" request and - return the "StackFrame as a python dictionary, or None on failure - ''' + """Get a single "StackFrame" object from a "stackTrace" request and + return the "StackFrame as a python dictionary, or None on failure + """ if threadId is None: threadId = self.get_thread_id() if threadId is None: - print('invalid threadId') + print("invalid threadId") return None - response = self.request_stackTrace(threadId, startFrame=frameIndex, - levels=1) + response = self.request_stackTrace(threadId, startFrame=frameIndex, levels=1) if response: - return response['body']['stackFrames'][0] - print('invalid response') + return response["body"]["stackFrames"][0] + print("invalid response") return None def get_completions(self, text): response = self.request_completions(text) - return response['body']['targets'] + return response["body"]["targets"] def get_scope_variables(self, scope_name, frameIndex=0, threadId=None): - stackFrame = self.get_stackFrame(frameIndex=frameIndex, - threadId=threadId) + stackFrame = self.get_stackFrame(frameIndex=frameIndex, threadId=threadId) if stackFrame is None: return [] - frameId = stackFrame['id'] + frameId = stackFrame["id"] if frameId in self.frame_scopes: frame_scopes = self.frame_scopes[frameId] else: scopes_response = self.request_scopes(frameId) - frame_scopes = scopes_response['body']['scopes'] + frame_scopes = scopes_response["body"]["scopes"] self.frame_scopes[frameId] = frame_scopes for scope in frame_scopes: - if scope['name'] == scope_name: - varRef = scope['variablesReference'] + if scope["name"] == scope_name: + varRef = scope["variablesReference"] variables_response = self.request_variables(varRef) if variables_response: - if 'body' in variables_response: - body = variables_response['body'] - if 'variables' in body: - vars = body['variables'] + if "body" in variables_response: + body = variables_response["body"] + if "variables" in body: + vars = body["variables"] return vars return [] def get_global_variables(self, frameIndex=0, threadId=None): - return self.get_scope_variables('Globals', frameIndex=frameIndex, - threadId=threadId) + return self.get_scope_variables( + "Globals", frameIndex=frameIndex, threadId=threadId + ) def get_local_variables(self, frameIndex=0, threadId=None): - return self.get_scope_variables('Locals', frameIndex=frameIndex, - threadId=threadId) + return self.get_scope_variables( + "Locals", frameIndex=frameIndex, threadId=threadId + ) def get_registers(self, frameIndex=0, threadId=None): - return self.get_scope_variables('Registers', frameIndex=frameIndex, - threadId=threadId) + return self.get_scope_variables( + "Registers", frameIndex=frameIndex, threadId=threadId + ) def get_local_variable(self, name, frameIndex=0, threadId=None): - locals = self.get_local_variables(frameIndex=frameIndex, - threadId=threadId) + locals = self.get_local_variables(frameIndex=frameIndex, threadId=threadId) for local in locals: - if 'name' in local and local['name'] == name: + if "name" in local and local["name"] == name: return local return None def get_local_variable_value(self, name, frameIndex=0, threadId=None): - variable = self.get_local_variable(name, frameIndex=frameIndex, - threadId=threadId) - if variable and 'value' in variable: - return variable['value'] + variable = self.get_local_variable( + name, frameIndex=frameIndex, threadId=threadId + ) + if variable and "value" in variable: + return variable["value"] return None def replay_packets(self, replay_file_path): - f = open(replay_file_path, 'r') - mode = 'invalid' + f = open(replay_file_path, "r") + mode = "invalid" set_sequence = False command_dict = None - while mode != 'eof': - if mode == 'invalid': + while mode != "eof": + if mode == "invalid": line = f.readline() - if line.startswith('to adapter:'): - mode = 'send' - elif line.startswith('from adapter:'): - mode = 'recv' - elif mode == 'send': + if line.startswith("to adapter:"): + mode = "send" + elif line.startswith("from adapter:"): + mode = "recv" + elif mode == "send": command_dict = read_packet(f) # Skip the end of line that follows the JSON f.readline() if command_dict is None: - raise ValueError('decode packet failed from replay file') - print('Sending:') + raise ValueError("decode packet failed from replay file") + print("Sending:") pprint.PrettyPrinter(indent=2).pprint(command_dict) # raw_input('Press ENTER to send:') self.send_packet(command_dict, set_sequence) - mode = 'invalid' - elif mode == 'recv': - print('Replay response:') + mode = "invalid" + elif mode == "recv": + print("Replay response:") replay_response = read_packet(f) # Skip the end of line that follows the JSON f.readline() pprint.PrettyPrinter(indent=2).pprint(replay_response) actual_response = self.recv_packet() if actual_response: - type = actual_response['type'] - print('Actual response:') - if type == 'response': + type = actual_response["type"] + print("Actual response:") + if type == "response": self.validate_response(command_dict, actual_response) pprint.PrettyPrinter(indent=2).pprint(actual_response) else: print("error: didn't get a valid response") - mode = 'invalid' - - def request_attach(self, program=None, pid=None, waitFor=None, trace=None, - initCommands=None, preRunCommands=None, - stopCommands=None, exitCommands=None, - attachCommands=None, terminateCommands=None, - coreFile=None, postRunCommands=None, - sourceMap=None): + mode = "invalid" + + def request_attach( + self, + program=None, + pid=None, + waitFor=None, + trace=None, + initCommands=None, + preRunCommands=None, + stopCommands=None, + exitCommands=None, + attachCommands=None, + terminateCommands=None, + coreFile=None, + postRunCommands=None, + sourceMap=None, + ): args_dict = {} if pid is not None: - args_dict['pid'] = pid + args_dict["pid"] = pid if program is not None: - args_dict['program'] = program + args_dict["program"] = program if waitFor is not None: - args_dict['waitFor'] = waitFor + args_dict["waitFor"] = waitFor if trace: - args_dict['trace'] = trace - args_dict['initCommands'] = self.init_commands + args_dict["trace"] = trace + args_dict["initCommands"] = self.init_commands if initCommands: - args_dict['initCommands'].extend(initCommands) + args_dict["initCommands"].extend(initCommands) if preRunCommands: - args_dict['preRunCommands'] = preRunCommands + args_dict["preRunCommands"] = preRunCommands if stopCommands: - args_dict['stopCommands'] = stopCommands + args_dict["stopCommands"] = stopCommands if exitCommands: - args_dict['exitCommands'] = exitCommands + args_dict["exitCommands"] = exitCommands if terminateCommands: - args_dict['terminateCommands'] = terminateCommands + args_dict["terminateCommands"] = terminateCommands if attachCommands: - args_dict['attachCommands'] = attachCommands + args_dict["attachCommands"] = attachCommands if coreFile: - args_dict['coreFile'] = coreFile + args_dict["coreFile"] = coreFile if postRunCommands: - args_dict['postRunCommands'] = postRunCommands + args_dict["postRunCommands"] = postRunCommands if sourceMap: - args_dict['sourceMap'] = sourceMap - command_dict = { - 'command': 'attach', - 'type': 'request', - 'arguments': args_dict - } + args_dict["sourceMap"] = sourceMap + command_dict = {"command": "attach", "type": "request", "arguments": args_dict} return self.send_recv(command_dict) def request_configurationDone(self): command_dict = { - 'command': 'configurationDone', - 'type': 'request', - 'arguments': {} + "command": "configurationDone", + "type": "request", + "arguments": {}, } response = self.send_recv(command_dict) if response: @@ -570,7 +587,7 @@ class DebugCommunication(object): def request_continue(self, threadId=None): if self.exit_status is not None: - raise ValueError('request_continue called after process exited') + raise ValueError("request_continue called after process exited") # If we have launched or attached, then the first continue is done by # sending the 'configurationDone' request if not self.configuration_done_sent: @@ -578,11 +595,11 @@ class DebugCommunication(object): args_dict = {} if threadId is None: threadId = self.get_thread_id() - args_dict['threadId'] = threadId + args_dict["threadId"] = threadId command_dict = { - 'command': 'continue', - 'type': 'request', - 'arguments': args_dict + "command": "continue", + "type": "request", + "arguments": args_dict, } response = self.send_recv(command_dict) # Caller must still call wait_for_stopped. @@ -590,11 +607,11 @@ class DebugCommunication(object): def request_restart(self, restartArguments=None): command_dict = { - 'command': 'restart', - 'type': 'request', + "command": "restart", + "type": "request", } if restartArguments: - command_dict['arguments'] = restartArguments + command_dict["arguments"] = restartArguments response = self.send_recv(command_dict) # Caller must still call wait_for_stopped. @@ -604,323 +621,303 @@ class DebugCommunication(object): args_dict = {} if terminateDebuggee is not None: if terminateDebuggee: - args_dict['terminateDebuggee'] = True + args_dict["terminateDebuggee"] = True else: - args_dict['terminateDebuggee'] = False + args_dict["terminateDebuggee"] = False command_dict = { - 'command': 'disconnect', - 'type': 'request', - 'arguments': args_dict + "command": "disconnect", + "type": "request", + "arguments": args_dict, } return self.send_recv(command_dict) def request_evaluate(self, expression, frameIndex=0, threadId=None, context=None): - stackFrame = self.get_stackFrame(frameIndex=frameIndex, - threadId=threadId) + stackFrame = self.get_stackFrame(frameIndex=frameIndex, threadId=threadId) if stackFrame is None: return [] args_dict = { - 'expression': expression, - 'context': context, - 'frameId': stackFrame['id'], + "expression": expression, + "context": context, + "frameId": stackFrame["id"], } command_dict = { - 'command': 'evaluate', - 'type': 'request', - 'arguments': args_dict + "command": "evaluate", + "type": "request", + "arguments": args_dict, } return self.send_recv(command_dict) def request_initialize(self, sourceInitFile): command_dict = { - 'command': 'initialize', - 'type': 'request', - 'arguments': { - 'adapterID': 'lldb-native', - 'clientID': 'vscode', - 'columnsStartAt1': True, - 'linesStartAt1': True, - 'locale': 'en-us', - 'pathFormat': 'path', - 'supportsRunInTerminalRequest': True, - 'supportsVariablePaging': True, - 'supportsVariableType': True, - 'sourceInitFile': sourceInitFile - } + "command": "initialize", + "type": "request", + "arguments": { + "adapterID": "lldb-native", + "clientID": "vscode", + "columnsStartAt1": True, + "linesStartAt1": True, + "locale": "en-us", + "pathFormat": "path", + "supportsRunInTerminalRequest": True, + "supportsVariablePaging": True, + "supportsVariableType": True, + "sourceInitFile": sourceInitFile, + }, } response = self.send_recv(command_dict) if response: - if 'body' in response: - self.initialize_body = response['body'] + if "body" in response: + self.initialize_body = response["body"] return response - def request_launch(self, program, args=None, cwd=None, env=None, - stopOnEntry=False, disableASLR=True, - disableSTDIO=False, shellExpandArguments=False, - trace=False, initCommands=None, preRunCommands=None, - stopCommands=None, exitCommands=None, - terminateCommands=None ,sourcePath=None, - debuggerRoot=None, launchCommands=None, sourceMap=None, - runInTerminal=False, postRunCommands=None): - args_dict = { - 'program': program - } + def request_launch( + self, + program, + args=None, + cwd=None, + env=None, + stopOnEntry=False, + disableASLR=True, + disableSTDIO=False, + shellExpandArguments=False, + trace=False, + initCommands=None, + preRunCommands=None, + stopCommands=None, + exitCommands=None, + terminateCommands=None, + sourcePath=None, + debuggerRoot=None, + launchCommands=None, + sourceMap=None, + runInTerminal=False, + postRunCommands=None, + ): + args_dict = {"program": program} if args: - args_dict['args'] = args + args_dict["args"] = args if cwd: - args_dict['cwd'] = cwd + args_dict["cwd"] = cwd if env: - args_dict['env'] = env + args_dict["env"] = env if stopOnEntry: - args_dict['stopOnEntry'] = stopOnEntry + args_dict["stopOnEntry"] = stopOnEntry if disableASLR: - args_dict['disableASLR'] = disableASLR + args_dict["disableASLR"] = disableASLR if disableSTDIO: - args_dict['disableSTDIO'] = disableSTDIO + args_dict["disableSTDIO"] = disableSTDIO if shellExpandArguments: - args_dict['shellExpandArguments'] = shellExpandArguments + args_dict["shellExpandArguments"] = shellExpandArguments if trace: - args_dict['trace'] = trace - args_dict['initCommands'] = self.init_commands + args_dict["trace"] = trace + args_dict["initCommands"] = self.init_commands if initCommands: - args_dict['initCommands'].extend(initCommands) + args_dict["initCommands"].extend(initCommands) if preRunCommands: - args_dict['preRunCommands'] = preRunCommands + args_dict["preRunCommands"] = preRunCommands if stopCommands: - args_dict['stopCommands'] = stopCommands + args_dict["stopCommands"] = stopCommands if exitCommands: - args_dict['exitCommands'] = exitCommands + args_dict["exitCommands"] = exitCommands if terminateCommands: - args_dict['terminateCommands'] = terminateCommands + args_dict["terminateCommands"] = terminateCommands if sourcePath: - args_dict['sourcePath'] = sourcePath + args_dict["sourcePath"] = sourcePath if debuggerRoot: - args_dict['debuggerRoot'] = debuggerRoot + args_dict["debuggerRoot"] = debuggerRoot if launchCommands: - args_dict['launchCommands'] = launchCommands + args_dict["launchCommands"] = launchCommands if sourceMap: - args_dict['sourceMap'] = sourceMap + args_dict["sourceMap"] = sourceMap if runInTerminal: - args_dict['runInTerminal'] = runInTerminal + args_dict["runInTerminal"] = runInTerminal if postRunCommands: - args_dict['postRunCommands'] = postRunCommands - command_dict = { - 'command': 'launch', - 'type': 'request', - 'arguments': args_dict - } + args_dict["postRunCommands"] = postRunCommands + command_dict = {"command": "launch", "type": "request", "arguments": args_dict} response = self.send_recv(command_dict) - if response['success']: + if response["success"]: # Wait for a 'process' and 'initialized' event in any order - self.wait_for_event(filter=['process', 'initialized']) - self.wait_for_event(filter=['process', 'initialized']) + self.wait_for_event(filter=["process", "initialized"]) + self.wait_for_event(filter=["process", "initialized"]) return response def request_next(self, threadId): if self.exit_status is not None: - raise ValueError('request_continue called after process exited') - args_dict = {'threadId': threadId} - command_dict = { - 'command': 'next', - 'type': 'request', - 'arguments': args_dict - } + raise ValueError("request_continue called after process exited") + args_dict = {"threadId": threadId} + command_dict = {"command": "next", "type": "request", "arguments": args_dict} return self.send_recv(command_dict) def request_stepIn(self, threadId): if self.exit_status is not None: - raise ValueError('request_continue called after process exited') - args_dict = {'threadId': threadId} - command_dict = { - 'command': 'stepIn', - 'type': 'request', - 'arguments': args_dict - } + raise ValueError("request_continue called after process exited") + args_dict = {"threadId": threadId} + command_dict = {"command": "stepIn", "type": "request", "arguments": args_dict} return self.send_recv(command_dict) def request_stepOut(self, threadId): if self.exit_status is not None: - raise ValueError('request_continue called after process exited') - args_dict = {'threadId': threadId} - command_dict = { - 'command': 'stepOut', - 'type': 'request', - 'arguments': args_dict - } + raise ValueError("request_continue called after process exited") + args_dict = {"threadId": threadId} + command_dict = {"command": "stepOut", "type": "request", "arguments": args_dict} return self.send_recv(command_dict) def request_pause(self, threadId=None): if self.exit_status is not None: - raise ValueError('request_continue called after process exited') + raise ValueError("request_continue called after process exited") if threadId is None: threadId = self.get_thread_id() - args_dict = {'threadId': threadId} - command_dict = { - 'command': 'pause', - 'type': 'request', - 'arguments': args_dict - } + args_dict = {"threadId": threadId} + command_dict = {"command": "pause", "type": "request", "arguments": args_dict} return self.send_recv(command_dict) def request_scopes(self, frameId): - args_dict = {'frameId': frameId} - command_dict = { - 'command': 'scopes', - 'type': 'request', - 'arguments': args_dict - } + args_dict = {"frameId": frameId} + command_dict = {"command": "scopes", "type": "request", "arguments": args_dict} return self.send_recv(command_dict) def request_setBreakpoints(self, file_path, line_array, data=None): - ''' data is array of parameters for breakpoints in line_array. - Each parameter object is 1:1 mapping with entries in line_entry. - It contains optional location/hitCondition/logMessage parameters. - ''' + """data is array of parameters for breakpoints in line_array. + Each parameter object is 1:1 mapping with entries in line_entry. + It contains optional location/hitCondition/logMessage parameters. + """ (dir, base) = os.path.split(file_path) - source_dict = { - 'name': base, - 'path': file_path - } + source_dict = {"name": base, "path": file_path} args_dict = { - 'source': source_dict, - 'sourceModified': False, + "source": source_dict, + "sourceModified": False, } if line_array is not None: - args_dict['lines'] = '%s' % line_array + args_dict["lines"] = "%s" % line_array breakpoints = [] for i, line in enumerate(line_array): breakpoint_data = None if data is not None and i < len(data): breakpoint_data = data[i] - bp = {'line': line} + bp = {"line": line} if breakpoint_data is not None: - if 'condition' in breakpoint_data and breakpoint_data['condition']: - bp['condition'] = breakpoint_data['condition'] - if 'hitCondition' in breakpoint_data and breakpoint_data['hitCondition']: - bp['hitCondition'] = breakpoint_data['hitCondition'] - if 'logMessage' in breakpoint_data and breakpoint_data['logMessage']: - bp['logMessage'] = breakpoint_data['logMessage'] + if "condition" in breakpoint_data and breakpoint_data["condition"]: + bp["condition"] = breakpoint_data["condition"] + if ( + "hitCondition" in breakpoint_data + and breakpoint_data["hitCondition"] + ): + bp["hitCondition"] = breakpoint_data["hitCondition"] + if ( + "logMessage" in breakpoint_data + and breakpoint_data["logMessage"] + ): + bp["logMessage"] = breakpoint_data["logMessage"] breakpoints.append(bp) - args_dict['breakpoints'] = breakpoints + args_dict["breakpoints"] = breakpoints command_dict = { - 'command': 'setBreakpoints', - 'type': 'request', - 'arguments': args_dict + "command": "setBreakpoints", + "type": "request", + "arguments": args_dict, } return self.send_recv(command_dict) def request_setExceptionBreakpoints(self, filters): - args_dict = {'filters': filters} + args_dict = {"filters": filters} command_dict = { - 'command': 'setExceptionBreakpoints', - 'type': 'request', - 'arguments': args_dict + "command": "setExceptionBreakpoints", + "type": "request", + "arguments": args_dict, } return self.send_recv(command_dict) - def request_setFunctionBreakpoints(self, names, condition=None, - hitCondition=None): + def request_setFunctionBreakpoints(self, names, condition=None, hitCondition=None): breakpoints = [] for name in names: - bp = {'name': name} + bp = {"name": name} if condition is not None: - bp['condition'] = condition + bp["condition"] = condition if hitCondition is not None: - bp['hitCondition'] = hitCondition + bp["hitCondition"] = hitCondition breakpoints.append(bp) - args_dict = {'breakpoints': breakpoints} + args_dict = {"breakpoints": breakpoints} command_dict = { - 'command': 'setFunctionBreakpoints', - 'type': 'request', - 'arguments': args_dict + "command": "setFunctionBreakpoints", + "type": "request", + "arguments": args_dict, } return self.send_recv(command_dict) def request_compileUnits(self, moduleId): - args_dict = {'moduleId': moduleId} + args_dict = {"moduleId": moduleId} command_dict = { - 'command': 'compileUnits', - 'type': 'request', - 'arguments': args_dict + "command": "compileUnits", + "type": "request", + "arguments": args_dict, } response = self.send_recv(command_dict) return response def request_completions(self, text): - args_dict = { - 'text': text, - 'column': len(text) - } + args_dict = {"text": text, "column": len(text)} command_dict = { - 'command': 'completions', - 'type': 'request', - 'arguments': args_dict + "command": "completions", + "type": "request", + "arguments": args_dict, } return self.send_recv(command_dict) def request_modules(self): - return self.send_recv({ - 'command': 'modules', - 'type': 'request' - }) + return self.send_recv({"command": "modules", "type": "request"}) - def request_stackTrace(self, threadId=None, startFrame=None, levels=None, - dump=False): + def request_stackTrace( + self, threadId=None, startFrame=None, levels=None, dump=False + ): if threadId is None: threadId = self.get_thread_id() - args_dict = {'threadId': threadId} + args_dict = {"threadId": threadId} if startFrame is not None: - args_dict['startFrame'] = startFrame + args_dict["startFrame"] = startFrame if levels is not None: - args_dict['levels'] = levels + args_dict["levels"] = levels command_dict = { - 'command': 'stackTrace', - 'type': 'request', - 'arguments': args_dict + "command": "stackTrace", + "type": "request", + "arguments": args_dict, } response = self.send_recv(command_dict) if dump: - for (idx, frame) in enumerate(response['body']['stackFrames']): - name = frame['name'] - if 'line' in frame and 'source' in frame: - source = frame['source'] - if 'sourceReference' not in source: - if 'name' in source: - source_name = source['name'] - line = frame['line'] - print("[%3u] %s @ %s:%u" % (idx, name, source_name, - line)) + for idx, frame in enumerate(response["body"]["stackFrames"]): + name = frame["name"] + if "line" in frame and "source" in frame: + source = frame["source"] + if "sourceReference" not in source: + if "name" in source: + source_name = source["name"] + line = frame["line"] + print("[%3u] %s @ %s:%u" % (idx, name, source_name, line)) continue print("[%3u] %s" % (idx, name)) return response def request_threads(self): - '''Request a list of all threads and combine any information from any - "stopped" events since those contain more information about why a - thread actually stopped. Returns an array of thread dictionaries - with information about all threads''' - command_dict = { - 'command': 'threads', - 'type': 'request', - 'arguments': {} - } + """Request a list of all threads and combine any information from any + "stopped" events since those contain more information about why a + thread actually stopped. Returns an array of thread dictionaries + with information about all threads""" + command_dict = {"command": "threads", "type": "request", "arguments": {}} response = self.send_recv(command_dict) - body = response['body'] + body = response["body"] # Fill in "self.threads" correctly so that clients that call # self.get_threads() or self.get_thread_id(...) can get information # on threads when the process is stopped. - if 'threads' in body: - self.threads = body['threads'] + if "threads" in body: + self.threads = body["threads"] for thread in self.threads: # Copy the thread dictionary so we can add key/value pairs to # it without affecting the original info from the "threads" # command. - tid = thread['id'] + tid = thread["id"] if tid in self.thread_stop_reasons: thread_stop_info = self.thread_stop_reasons[tid] - copy_keys = ['reason', 'description', 'text'] + copy_keys = ["reason", "description", "text"] for key in copy_keys: if key in thread_stop_info: thread[key] = thread_stop_info[key] @@ -929,42 +926,42 @@ class DebugCommunication(object): return response def request_variables(self, variablesReference, start=None, count=None): - args_dict = {'variablesReference': variablesReference} + args_dict = {"variablesReference": variablesReference} if start is not None: - args_dict['start'] = start + args_dict["start"] = start if count is not None: - args_dict['count'] = count + args_dict["count"] = count command_dict = { - 'command': 'variables', - 'type': 'request', - 'arguments': args_dict + "command": "variables", + "type": "request", + "arguments": args_dict, } return self.send_recv(command_dict) def request_setVariable(self, containingVarRef, name, value, id=None): args_dict = { - 'variablesReference': containingVarRef, - 'name': name, - 'value': str(value) + "variablesReference": containingVarRef, + "name": name, + "value": str(value), } if id is not None: - args_dict['id'] = id + args_dict["id"] = id command_dict = { - 'command': 'setVariable', - 'type': 'request', - 'arguments': args_dict + "command": "setVariable", + "type": "request", + "arguments": args_dict, } return self.send_recv(command_dict) def request_testGetTargetBreakpoints(self): - '''A request packet used in the LLDB test suite to get all currently - set breakpoint infos for all breakpoints currently set in the - target. - ''' + """A request packet used in the LLDB test suite to get all currently + set breakpoint infos for all breakpoints currently set in the + target. + """ command_dict = { - 'command': '_testGetTargetBreakpoints', - 'type': 'request', - 'arguments': {} + "command": "_testGetTargetBreakpoints", + "type": "request", + "arguments": {}, } return self.send_recv(command_dict) @@ -974,7 +971,9 @@ class DebugCommunication(object): class DebugAdaptor(DebugCommunication): - def __init__(self, executable=None, port=None, init_commands=[], log_file=None, env=None): + def __init__( + self, executable=None, port=None, init_commands=[], log_file=None, env=None + ): self.process = None if executable is not None: adaptor_env = os.environ.copy() @@ -982,19 +981,23 @@ class DebugAdaptor(DebugCommunication): adaptor_env.update(env) if log_file: - adaptor_env['LLDBVSCODE_LOG'] = log_file - self.process = subprocess.Popen([executable], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - env=adaptor_env) - DebugCommunication.__init__(self, self.process.stdout, - self.process.stdin, init_commands, log_file) + adaptor_env["LLDBVSCODE_LOG"] = log_file + self.process = subprocess.Popen( + [executable], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + env=adaptor_env, + ) + DebugCommunication.__init__( + self, self.process.stdout, self.process.stdin, init_commands, log_file + ) elif port is not None: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.connect(('127.0.0.1', port)) - DebugCommunication.__init__(self, s.makefile('r'), s.makefile('w'), - init_commands) + s.connect(("127.0.0.1", port)) + DebugCommunication.__init__( + self, s.makefile("r"), s.makefile("w"), init_commands + ) def get_pid(self): if self.process: @@ -1024,36 +1027,39 @@ def attach_options_specified(options): def run_vscode(dbg, args, options): dbg.request_initialize(options.sourceInitFile) if attach_options_specified(options): - response = dbg.request_attach(program=options.program, - pid=options.pid, - waitFor=options.waitFor, - attachCommands=options.attachCmds, - initCommands=options.initCmds, - preRunCommands=options.preRunCmds, - stopCommands=options.stopCmds, - exitCommands=options.exitCmds, - terminateCommands=options.terminateCmds) + response = dbg.request_attach( + program=options.program, + pid=options.pid, + waitFor=options.waitFor, + attachCommands=options.attachCmds, + initCommands=options.initCmds, + preRunCommands=options.preRunCmds, + stopCommands=options.stopCmds, + exitCommands=options.exitCmds, + terminateCommands=options.terminateCmds, + ) else: - response = dbg.request_launch(options.program, - args=args, - env=options.envs, - cwd=options.workingDir, - debuggerRoot=options.debuggerRoot, - sourcePath=options.sourcePath, - initCommands=options.initCmds, - preRunCommands=options.preRunCmds, - stopCommands=options.stopCmds, - exitCommands=options.exitCmds, - terminateCommands=options.terminateCmds) - - if response['success']: + response = dbg.request_launch( + options.program, + args=args, + env=options.envs, + cwd=options.workingDir, + debuggerRoot=options.debuggerRoot, + sourcePath=options.sourcePath, + initCommands=options.initCmds, + preRunCommands=options.preRunCmds, + stopCommands=options.stopCmds, + exitCommands=options.exitCmds, + terminateCommands=options.terminateCmds, + ) + + if response["success"]: if options.sourceBreakpoints: source_to_lines = {} for file_line in options.sourceBreakpoints: - (path, line) = file_line.split(':') + (path, line) = file_line.split(":") if len(path) == 0 or len(line) == 0: - print('error: invalid source with line "%s"' % - (file_line)) + print('error: invalid source with line "%s"' % (file_line)) else: if path in source_to_lines: @@ -1067,202 +1073,257 @@ def run_vscode(dbg, args, options): dbg.request_configurationDone() dbg.wait_for_stopped() else: - if 'message' in response: - print(response['message']) + if "message" in response: + print(response["message"]) dbg.request_disconnect(terminateDebuggee=True) def main(): parser = optparse.OptionParser( - description=('A testing framework for the Visual Studio Code Debug ' - 'Adaptor protocol')) + description=( + "A testing framework for the Visual Studio Code Debug " "Adaptor protocol" + ) + ) parser.add_option( - '--vscode', - type='string', - dest='vscode_path', - help=('The path to the command line program that implements the ' - 'Visual Studio Code Debug Adaptor protocol.'), - default=None) + "--vscode", + type="string", + dest="vscode_path", + help=( + "The path to the command line program that implements the " + "Visual Studio Code Debug Adaptor protocol." + ), + default=None, + ) parser.add_option( - '--program', - type='string', - dest='program', - help='The path to the program to debug.', - default=None) + "--program", + type="string", + dest="program", + help="The path to the program to debug.", + default=None, + ) parser.add_option( - '--workingDir', - type='string', - dest='workingDir', + "--workingDir", + type="string", + dest="workingDir", default=None, - help='Set the working directory for the process we launch.') + help="Set the working directory for the process we launch.", + ) parser.add_option( - '--sourcePath', - type='string', - dest='sourcePath', + "--sourcePath", + type="string", + dest="sourcePath", default=None, - help=('Set the relative source root for any debug info that has ' - 'relative paths in it.')) + help=( + "Set the relative source root for any debug info that has " + "relative paths in it." + ), + ) parser.add_option( - '--debuggerRoot', - type='string', - dest='debuggerRoot', + "--debuggerRoot", + type="string", + dest="debuggerRoot", default=None, - help=('Set the working directory for lldb-vscode for any object files ' - 'with relative paths in the Mach-o debug map.')) + help=( + "Set the working directory for lldb-vscode for any object files " + "with relative paths in the Mach-o debug map." + ), + ) parser.add_option( - '-r', '--replay', - type='string', - dest='replay', - help=('Specify a file containing a packet log to replay with the ' - 'current Visual Studio Code Debug Adaptor executable.'), - default=None) + "-r", + "--replay", + type="string", + dest="replay", + help=( + "Specify a file containing a packet log to replay with the " + "current Visual Studio Code Debug Adaptor executable." + ), + default=None, + ) parser.add_option( - '-g', '--debug', - action='store_true', - dest='debug', + "-g", + "--debug", + action="store_true", + dest="debug", default=False, - help='Pause waiting for a debugger to attach to the debug adaptor') + help="Pause waiting for a debugger to attach to the debug adaptor", + ) parser.add_option( - '--sourceInitFile', - action='store_true', - dest='sourceInitFile', + "--sourceInitFile", + action="store_true", + dest="sourceInitFile", default=False, - help='Whether lldb-vscode should source .lldbinit file or not') + help="Whether lldb-vscode should source .lldbinit file or not", + ) parser.add_option( - '--port', - type='int', - dest='port', + "--port", + type="int", + dest="port", help="Attach a socket to a port instead of using STDIN for VSCode", - default=None) + default=None, + ) parser.add_option( - '--pid', - type='int', - dest='pid', + "--pid", + type="int", + dest="pid", help="The process ID to attach to", - default=None) + default=None, + ) parser.add_option( - '--attach', - action='store_true', - dest='attach', + "--attach", + action="store_true", + dest="attach", default=False, - help=('Specify this option to attach to a process by name. The ' - 'process name is the basename of the executable specified with ' - 'the --program option.')) + help=( + "Specify this option to attach to a process by name. The " + "process name is the basename of the executable specified with " + "the --program option." + ), + ) parser.add_option( - '-f', '--function-bp', - type='string', - action='append', - dest='funcBreakpoints', - help=('Specify the name of a function to break at. ' - 'Can be specified more than once.'), - default=[]) + "-f", + "--function-bp", + type="string", + action="append", + dest="funcBreakpoints", + help=( + "Specify the name of a function to break at. " + "Can be specified more than once." + ), + default=[], + ) parser.add_option( - '-s', '--source-bp', - type='string', - action='append', - dest='sourceBreakpoints', + "-s", + "--source-bp", + type="string", + action="append", + dest="sourceBreakpoints", default=[], - help=('Specify source breakpoints to set in the format of ' - '<source>:<line>. ' - 'Can be specified more than once.')) + help=( + "Specify source breakpoints to set in the format of " + "<source>:<line>. " + "Can be specified more than once." + ), + ) parser.add_option( - '--attachCommand', - type='string', - action='append', - dest='attachCmds', + "--attachCommand", + type="string", + action="append", + dest="attachCmds", default=[], - help=('Specify a LLDB command that will attach to a process. ' - 'Can be specified more than once.')) + help=( + "Specify a LLDB command that will attach to a process. " + "Can be specified more than once." + ), + ) parser.add_option( - '--initCommand', - type='string', - action='append', - dest='initCmds', + "--initCommand", + type="string", + action="append", + dest="initCmds", default=[], - help=('Specify a LLDB command that will be executed before the target ' - 'is created. Can be specified more than once.')) + help=( + "Specify a LLDB command that will be executed before the target " + "is created. Can be specified more than once." + ), + ) parser.add_option( - '--preRunCommand', - type='string', - action='append', - dest='preRunCmds', + "--preRunCommand", + type="string", + action="append", + dest="preRunCmds", default=[], - help=('Specify a LLDB command that will be executed after the target ' - 'has been created. Can be specified more than once.')) + help=( + "Specify a LLDB command that will be executed after the target " + "has been created. Can be specified more than once." + ), + ) parser.add_option( - '--stopCommand', - type='string', - action='append', - dest='stopCmds', + "--stopCommand", + type="string", + action="append", + dest="stopCmds", default=[], - help=('Specify a LLDB command that will be executed each time the' - 'process stops. Can be specified more than once.')) + help=( + "Specify a LLDB command that will be executed each time the" + "process stops. Can be specified more than once." + ), + ) parser.add_option( - '--exitCommand', - type='string', - action='append', - dest='exitCmds', + "--exitCommand", + type="string", + action="append", + dest="exitCmds", default=[], - help=('Specify a LLDB command that will be executed when the process ' - 'exits. Can be specified more than once.')) + help=( + "Specify a LLDB command that will be executed when the process " + "exits. Can be specified more than once." + ), + ) parser.add_option( - '--terminateCommand', - type='string', - action='append', - dest='terminateCmds', + "--terminateCommand", + type="string", + action="append", + dest="terminateCmds", default=[], - help=('Specify a LLDB command that will be executed when the debugging ' - 'session is terminated. Can be specified more than once.')) + help=( + "Specify a LLDB command that will be executed when the debugging " + "session is terminated. Can be specified more than once." + ), + ) parser.add_option( - '--env', - type='string', - action='append', - dest='envs', + "--env", + type="string", + action="append", + dest="envs", default=[], - help=('Specify environment variables to pass to the launched ' - 'process.')) + help=("Specify environment variables to pass to the launched " "process."), + ) parser.add_option( - '--waitFor', - action='store_true', - dest='waitFor', + "--waitFor", + action="store_true", + dest="waitFor", default=False, - help=('Wait for the next process to be launched whose name matches ' - 'the basename of the program specified with the --program ' - 'option')) + help=( + "Wait for the next process to be launched whose name matches " + "the basename of the program specified with the --program " + "option" + ), + ) (options, args) = parser.parse_args(sys.argv[1:]) if options.vscode_path is None and options.port is None: - print('error: must either specify a path to a Visual Studio Code ' - 'Debug Adaptor vscode executable path using the --vscode ' - 'option, or a port to attach to for an existing lldb-vscode ' - 'using the --port option') + print( + "error: must either specify a path to a Visual Studio Code " + "Debug Adaptor vscode executable path using the --vscode " + "option, or a port to attach to for an existing lldb-vscode " + "using the --port option" + ) return dbg = DebugAdaptor(executable=options.vscode_path, port=options.port) if options.debug: - raw_input('Waiting for debugger to attach pid "%i"' % ( - dbg.get_pid())) + raw_input('Waiting for debugger to attach pid "%i"' % (dbg.get_pid())) if options.replay: dbg.replay_packets(options.replay) else: @@ -1270,5 +1331,5 @@ def main(): dbg.terminate() -if __name__ == '__main__': +if __name__ == "__main__": main() |