[3.12] gh-109972: Enhance test_gdb (#110026) (#110351)

* 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 commit 757cbd4f29)

* 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 commit 44d9a71ea2)

* 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 commit 1de9406f91)
This commit is contained in:
Victor Stinner 2023-10-04 13:34:28 +02:00 committed by GitHub
parent 1d032ea3d6
commit bbce8bd05d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 303 additions and 218 deletions

View file

@ -1,8 +1,6 @@
import re
import textwrap
import unittest
from test import support
from test.support import python_is_optimized
from .util import setup_module, DebuggerTests
@ -11,10 +9,22 @@ def setUpModule():
setup_module()
@unittest.skipIf(python_is_optimized(),
@unittest.skipIf(support.python_is_optimized(),
"Python was compiled with optimizations")
@support.requires_resource('cpu')
class CFunctionTests(DebuggerTests):
def check(self, func_name, cmd):
# Verify with "py-bt":
gdb_output = self.get_stack_trace(
cmd,
breakpoint=func_name,
cmds_after_breakpoint=['bt', 'py-bt'],
# bpo-45207: Ignore 'Function "meth_varargs" not
# defined.' message in stderr.
ignore_stderr=True,
)
self.assertIn(f'<built-in method {func_name}', gdb_output)
# 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
@ -24,60 +34,52 @@ class CFunctionTests(DebuggerTests):
# This is because we are calling functions from an "external" module
# (_testcapimodule) rather than compiled-in functions. It seems difficult
# to suppress these. See also the comment in DebuggerTests.get_stack_trace
def test_pycfunction(self):
def check_pycfunction(self, func_name, args):
'Verify that "py-bt" displays invocations of PyCFunction instances'
# bpo-46600: If the compiler inlines _null_to_none() in meth_varargs()
# (ex: clang -Og), _null_to_none() is the frame #1. Otherwise,
# meth_varargs() is the frame #1.
expected_frame = r'#(1|2)'
if support.verbose:
print()
# Various optimizations multiply the code paths by which these are
# called, so test a variety of calling conventions.
for func_name, args in (
('meth_varargs', ''),
('meth_varargs_keywords', ''),
('meth_o', '[]'),
('meth_noargs', ''),
('meth_fastcall', ''),
('meth_fastcall_keywords', ''),
for obj in (
'_testcapi',
'_testcapi.MethClass',
'_testcapi.MethClass()',
'_testcapi.MethStatic()',
# XXX: bound methods don't yet give nice tracebacks
# '_testcapi.MethInstance()',
):
for obj in (
'_testcapi',
'_testcapi.MethClass',
'_testcapi.MethClass()',
'_testcapi.MethStatic()',
with self.subTest(f'{obj}.{func_name}'):
call = f'{obj}.{func_name}({args})'
cmd = textwrap.dedent(f'''
import _testcapi
def foo():
{call}
def bar():
foo()
bar()
''')
if support.verbose:
print(f' test call: {call}', flush=True)
# XXX: bound methods don't yet give nice tracebacks
# '_testcapi.MethInstance()',
):
with self.subTest(f'{obj}.{func_name}'):
cmd = textwrap.dedent(f'''
import _testcapi
def foo():
{obj}.{func_name}({args})
def bar():
foo()
bar()
''')
# Verify with "py-bt":
gdb_output = self.get_stack_trace(
cmd,
breakpoint=func_name,
cmds_after_breakpoint=['bt', 'py-bt'],
# bpo-45207: Ignore 'Function "meth_varargs" not
# defined.' message in stderr.
ignore_stderr=True,
)
self.assertIn(f'<built-in method {func_name}', gdb_output)
self.check(func_name, cmd)
# Verify with "py-bt-full":
gdb_output = self.get_stack_trace(
cmd,
breakpoint=func_name,
cmds_after_breakpoint=['py-bt-full'],
# bpo-45207: Ignore 'Function "meth_varargs" not
# defined.' message in stderr.
ignore_stderr=True,
)
regex = expected_frame
regex += re.escape(f' <built-in method {func_name}')
self.assertRegex(gdb_output, regex)
def test_pycfunction_noargs(self):
self.check_pycfunction('meth_noargs', '')
def test_pycfunction_o(self):
self.check_pycfunction('meth_o', '[]')
def test_pycfunction_varargs(self):
self.check_pycfunction('meth_varargs', '')
def test_pycfunction_varargs_keywords(self):
self.check_pycfunction('meth_varargs_keywords', '')
def test_pycfunction_fastcall(self):
self.check_pycfunction('meth_fastcall', '')
def test_pycfunction_fastcall_keywords(self):
self.check_pycfunction('meth_fastcall_keywords', '')