Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 35 additions & 17 deletions Lib/test/test_dtrace.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def kill_process_group(proc):
proc.communicate() # 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:
Expand All @@ -86,7 +86,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()
Expand Down Expand Up @@ -437,14 +437,20 @@ class BPFTraceOptimizedTests(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}")


@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
Expand All @@ -454,7 +460,13 @@ def get_readelf_version():

return int(match.group(1)), int(match.group(2))

def get_readelf_output(self):
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()}"]
)

binary = sys.executable
if sysconfig.get_config_var("Py_ENABLE_SHARED"):
lib_dir = sysconfig.get_config_var("LIBDIR")
Expand All @@ -476,37 +488,43 @@ def get_readelf_output(self):
binary = libpython_path
break

return run_readelf(["readelf", "-n", binary])
return run_command(["readelf", "-n", 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",
"Name: function__entry",
"Name: function__return",
"import__find__load__done",
"import__find__load__start",
"audit",
"gc__start",
"gc__done",
"function__entry",
"function__return",
]

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: line",
"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__':
Expand Down
Loading