mirror of
https://github.com/python/cpython.git
synced 2025-10-29 17:38:56 +00:00
* gh-109972: Enhance test_gdb (#110026) * Split test_pycfunction.py: add test_cfunction_full.py. Split the function into the following 6 functions. In verbose mode, these "pycfunction" tests now log each tested call. * test_pycfunction_noargs() * test_pycfunction_o() * test_pycfunction_varargs() * test_pycfunction_varargs_keywords() * test_pycfunction_fastcall() * test_pycfunction_fastcall_keywords() * Move get_gdb_repr() to PrettyPrintTests. * Replace DebuggerTests.get_sample_script() with SAMPLE_SCRIPT. * Rename checkout_hook_path to CHECKOUT_HOOK_PATH. * Rename gdb_version to GDB_VERSION_TEXT. * Replace (gdb_major_version, gdb_minor_version) with GDB_VERSION. * run_gdb() uses "backslashreplace" error handler instead of "replace". * Add check_gdb() function to util.py. * Enhance support.check_cflags_pgo(): check also for sysconfig PGO_PROF_USE_FLAG (if available) in compiler flags. * Move some SkipTest checks to test_gdb/__init__.py. * Elaborate why gdb cannot be tested on Windows: gdb doesn't support PDB debug symbol files. (cherry picked from commit757cbd4f29) * gh-104736: Fix test_gdb tests on ppc64le with clang (#109360) Fix test_gdb on Python built with LLVM clang 16 on Linux ppc64le (ex: Fedora 38). Search patterns in gdb "bt" command output to detect when gdb fails to retrieve the traceback. For example, skip a test if "Backtrace stopped: frame did not save the PC" is found. (cherry picked from commit44d9a71ea2) * gh-110166: Fix gdb CFunctionFullTests on ppc64le clang build (#110331) CFunctionFullTests now also runs "bt" command before "py-bt-full", similar to CFunctionTests which also runs "bt" command before "py-bt". So test_gdb can skip the test if patterns like "?? ()" are found in the gdb output. (cherry picked from commit1de9406f91)
134 lines
4.9 KiB
Python
134 lines
4.9 KiB
Python
import textwrap
|
|
import unittest
|
|
from test import support
|
|
from test.support import python_is_optimized
|
|
|
|
from .util import setup_module, DebuggerTests, CET_PROTECTION, SAMPLE_SCRIPT
|
|
|
|
|
|
def setUpModule():
|
|
setup_module()
|
|
|
|
|
|
class PyBtTests(DebuggerTests):
|
|
@unittest.skipIf(python_is_optimized(),
|
|
"Python was compiled with optimizations")
|
|
def test_bt(self):
|
|
'Verify that the "py-bt" command works'
|
|
bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
|
|
cmds_after_breakpoint=['py-bt'])
|
|
self.assertMultilineMatches(bt,
|
|
r'''^.*
|
|
Traceback \(most recent call first\):
|
|
<built-in method id of module object .*>
|
|
File ".*gdb_sample.py", line 10, in baz
|
|
id\(42\)
|
|
File ".*gdb_sample.py", line 7, in bar
|
|
baz\(a, b, c\)
|
|
File ".*gdb_sample.py", line 4, in foo
|
|
bar\(a=a, b=b, c=c\)
|
|
File ".*gdb_sample.py", line 12, in <module>
|
|
foo\(1, 2, 3\)
|
|
''')
|
|
|
|
@unittest.skipIf(python_is_optimized(),
|
|
"Python was compiled with optimizations")
|
|
def test_bt_full(self):
|
|
'Verify that the "py-bt-full" command works'
|
|
bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
|
|
cmds_after_breakpoint=['py-bt-full'])
|
|
self.assertMultilineMatches(bt,
|
|
r'''^.*
|
|
#[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 7, in bar \(a=1, b=2, c=3\)
|
|
baz\(a, b, c\)
|
|
#[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 4, in foo \(a=1, b=2, c=3\)
|
|
bar\(a=a, b=b, c=c\)
|
|
#[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 12, in <module> \(\)
|
|
foo\(1, 2, 3\)
|
|
''')
|
|
|
|
@unittest.skipIf(python_is_optimized(),
|
|
"Python was compiled with optimizations")
|
|
@support.requires_resource('cpu')
|
|
def test_threads(self):
|
|
'Verify that "py-bt" indicates threads that are waiting for the GIL'
|
|
cmd = '''
|
|
from threading import Thread
|
|
|
|
class TestThread(Thread):
|
|
# These threads would run forever, but we'll interrupt things with the
|
|
# debugger
|
|
def run(self):
|
|
i = 0
|
|
while 1:
|
|
i += 1
|
|
|
|
t = {}
|
|
for i in range(4):
|
|
t[i] = TestThread()
|
|
t[i].start()
|
|
|
|
# Trigger a breakpoint on the main thread
|
|
id(42)
|
|
|
|
'''
|
|
# Verify with "py-bt":
|
|
gdb_output = self.get_stack_trace(cmd,
|
|
cmds_after_breakpoint=['thread apply all py-bt'])
|
|
self.assertIn('Waiting for the GIL', gdb_output)
|
|
|
|
# Verify with "py-bt-full":
|
|
gdb_output = self.get_stack_trace(cmd,
|
|
cmds_after_breakpoint=['thread apply all py-bt-full'])
|
|
self.assertIn('Waiting for the GIL', gdb_output)
|
|
|
|
@unittest.skipIf(python_is_optimized(),
|
|
"Python was compiled with optimizations")
|
|
# Some older versions of gdb will fail with
|
|
# "Cannot find new threads: generic error"
|
|
# unless we add LD_PRELOAD=PATH-TO-libpthread.so.1 as a workaround
|
|
def test_gc(self):
|
|
'Verify that "py-bt" indicates if a thread is garbage-collecting'
|
|
cmd = ('from gc import collect\n'
|
|
'id(42)\n'
|
|
'def foo():\n'
|
|
' collect()\n'
|
|
'def bar():\n'
|
|
' foo()\n'
|
|
'bar()\n')
|
|
# Verify with "py-bt":
|
|
gdb_output = self.get_stack_trace(cmd,
|
|
cmds_after_breakpoint=['break update_refs', 'continue', 'py-bt'],
|
|
)
|
|
self.assertIn('Garbage-collecting', gdb_output)
|
|
|
|
# Verify with "py-bt-full":
|
|
gdb_output = self.get_stack_trace(cmd,
|
|
cmds_after_breakpoint=['break update_refs', 'continue', 'py-bt-full'],
|
|
)
|
|
self.assertIn('Garbage-collecting', gdb_output)
|
|
|
|
@unittest.skipIf(python_is_optimized(),
|
|
"Python was compiled with optimizations")
|
|
def test_wrapper_call(self):
|
|
cmd = textwrap.dedent('''
|
|
class MyList(list):
|
|
def __init__(self):
|
|
super(*[]).__init__() # wrapper_call()
|
|
|
|
id("first break point")
|
|
l = MyList()
|
|
''')
|
|
cmds_after_breakpoint = ['break wrapper_call', 'continue']
|
|
if CET_PROTECTION:
|
|
# bpo-32962: same case as in get_stack_trace():
|
|
# we need an additional 'next' command in order to read
|
|
# arguments of the innermost function of the call stack.
|
|
cmds_after_breakpoint.append('next')
|
|
cmds_after_breakpoint.append('py-bt')
|
|
|
|
# Verify with "py-bt":
|
|
gdb_output = self.get_stack_trace(cmd,
|
|
cmds_after_breakpoint=cmds_after_breakpoint)
|
|
self.assertRegex(gdb_output,
|
|
r"<method-wrapper u?'__init__' of MyList object at ")
|