From d468fd9a656e6d1a2a148ca6925dcc6010c0e17a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kul=C3=ADk?= Date: Sat, 17 Oct 2026 02:08:47 +0200 Subject: [PATCH] gh-98894: Fix test_dtrace on Solaris (#154803) Fix 'CheckDtraceProbes' tests by reading available probes from the test process itself. Co-authored-by: Victor Stinner (cherry picked from commit 967fb3afc7e2f706d757925e9346f0bc8aab3c46) --- Lib/test/test_dtrace.py | 52 +++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/Lib/test/test_dtrace.py b/Lib/test/test_dtrace.py index 7813ca3d3f652e..7a51a7092ffc1a 100644 --- a/Lib/test/test_dtrace.py +++ b/Lib/test/test_dtrace.py @@ -107,7 +107,7 @@ def terminate_process_group(proc): proc.communicate(timeout=TERMINATE_TIMEOUT) # Clean up -def run_readelf(cmd): +def run_command(cmd): # Force the C locale to disable localization. env = dict(os.environ, LC_ALL="C") try: @@ -119,7 +119,7 @@ def run_readelf(cmd): env=env, ) except OSError: - raise unittest.SkipTest("Couldn't find readelf on the path") + raise unittest.SkipTest(f"Couldn't find {cmd[0]!r} on the path") with proc: stdout, stderr = proc.communicate() @@ -340,6 +340,12 @@ class SystemTapOptimizedTests(TraceTests, unittest.TestCase): class CheckDtraceProbes(unittest.TestCase): @classmethod def setUpClass(cls): + if sys.platform == "sunos5": + # Solaris does not expose available probes through readable ELF + # section; it uses DTrace itself instead. + DTraceBackend().assert_usable() + return + readelf_major_version, readelf_minor_version = cls.get_readelf_version() if support.verbose: print(f"readelf version: {readelf_major_version}.{readelf_minor_version}") @@ -347,7 +353,7 @@ def setUpClass(cls): @staticmethod def get_readelf_version(): - version = run_readelf(["readelf", "--version"]) + version = run_command(["readelf", "--version"]) # Regex to parse: # 'GNU readelf (GNU Binutils) 2.40.0\n' -> 2.40 @@ -357,38 +363,50 @@ def get_readelf_version(): return int(match.group(1)), int(match.group(2)) - def get_readelf_output(self): - return run_readelf(["readelf", "-n", get_probe_binary()]) + def get_probe_output(self): + if sys.platform == "sunos5": + # Get probes available in this process. + return run_command( + ["dtrace", "-l", "-P", f"python{os.getpid()}"] + ) + + return run_command(["readelf", "-n", get_probe_binary()]) + + def assert_probe_present(self, probe_name, output): + if sys.platform == "sunos5": + self.assertIn(probe_name.replace("__", "-"), output) + else: + self.assertIn(f"Name: {probe_name}", output) def test_check_probes(self): - readelf_output = self.get_readelf_output() + probe_output = self.get_probe_output() available_probe_names = [ - "Name: import__find__load__done", - "Name: import__find__load__start", - "Name: audit", - "Name: gc__start", - "Name: gc__done", + "import__find__load__done", + "import__find__load__start", + "audit", + "gc__start", + "gc__done", ] for probe_name in available_probe_names: with self.subTest(probe_name=probe_name): - self.assertIn(probe_name, readelf_output) + self.assert_probe_present(probe_name, probe_output) @unittest.expectedFailure def test_missing_probes(self): - readelf_output = self.get_readelf_output() + probe_output = self.get_probe_output() # Missing probes will be added in the future. missing_probe_names = [ - "Name: function__entry", - "Name: function__return", - "Name: line", + "function__entry", + "function__return", + "line", ] for probe_name in missing_probe_names: with self.subTest(probe_name=probe_name): - self.assertIn(probe_name, readelf_output) + self.assert_probe_present(probe_name, probe_output) if __name__ == '__main__':