mirror of
https://github.com/python/cpython.git
synced 2025-10-30 01:47:38 +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)
188 lines
7.6 KiB
Python
188 lines
7.6 KiB
Python
import re
|
|
import unittest
|
|
from test.support import python_is_optimized
|
|
|
|
from .util import run_gdb, setup_module, DebuggerTests, SAMPLE_SCRIPT
|
|
|
|
|
|
def setUpModule():
|
|
setup_module()
|
|
|
|
|
|
def gdb_has_frame_select():
|
|
# Does this build of gdb have gdb.Frame.select ?
|
|
stdout, stderr = run_gdb("--eval-command=python print(dir(gdb.Frame))")
|
|
m = re.match(r'.*\[(.*)\].*', stdout)
|
|
if not m:
|
|
raise unittest.SkipTest(
|
|
f"Unable to parse output from gdb.Frame.select test\n"
|
|
f"stdout={stdout!r}\n"
|
|
f"stderr={stderr!r}\n")
|
|
gdb_frame_dir = m.group(1).split(', ')
|
|
return "'select'" in gdb_frame_dir
|
|
|
|
HAS_PYUP_PYDOWN = gdb_has_frame_select()
|
|
|
|
|
|
@unittest.skipIf(python_is_optimized(),
|
|
"Python was compiled with optimizations")
|
|
class PyListTests(DebuggerTests):
|
|
def assertListing(self, expected, actual):
|
|
self.assertEndsWith(actual, expected)
|
|
|
|
def test_basic_command(self):
|
|
'Verify that the "py-list" command works'
|
|
bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
|
|
cmds_after_breakpoint=['py-list'])
|
|
|
|
self.assertListing(' 5 \n'
|
|
' 6 def bar(a, b, c):\n'
|
|
' 7 baz(a, b, c)\n'
|
|
' 8 \n'
|
|
' 9 def baz(*args):\n'
|
|
' >10 id(42)\n'
|
|
' 11 \n'
|
|
' 12 foo(1, 2, 3)\n',
|
|
bt)
|
|
|
|
def test_one_abs_arg(self):
|
|
'Verify the "py-list" command with one absolute argument'
|
|
bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
|
|
cmds_after_breakpoint=['py-list 9'])
|
|
|
|
self.assertListing(' 9 def baz(*args):\n'
|
|
' >10 id(42)\n'
|
|
' 11 \n'
|
|
' 12 foo(1, 2, 3)\n',
|
|
bt)
|
|
|
|
def test_two_abs_args(self):
|
|
'Verify the "py-list" command with two absolute arguments'
|
|
bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
|
|
cmds_after_breakpoint=['py-list 1,3'])
|
|
|
|
self.assertListing(' 1 # Sample script for use by test_gdb\n'
|
|
' 2 \n'
|
|
' 3 def foo(a, b, c):\n',
|
|
bt)
|
|
|
|
SAMPLE_WITH_C_CALL = """
|
|
|
|
from _testcapi import pyobject_vectorcall
|
|
|
|
def foo(a, b, c):
|
|
bar(a, b, c)
|
|
|
|
def bar(a, b, c):
|
|
pyobject_vectorcall(baz, (a, b, c), None)
|
|
|
|
def baz(*args):
|
|
id(42)
|
|
|
|
foo(1, 2, 3)
|
|
|
|
"""
|
|
|
|
|
|
class StackNavigationTests(DebuggerTests):
|
|
@unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands")
|
|
@unittest.skipIf(python_is_optimized(),
|
|
"Python was compiled with optimizations")
|
|
def test_pyup_command(self):
|
|
'Verify that the "py-up" command works'
|
|
bt = self.get_stack_trace(source=SAMPLE_WITH_C_CALL,
|
|
cmds_after_breakpoint=['py-up', 'py-up'])
|
|
self.assertMultilineMatches(bt,
|
|
r'''^.*
|
|
#[0-9]+ Frame 0x-?[0-9a-f]+, for file <string>, line 12, in baz \(args=\(1, 2, 3\)\)
|
|
#[0-9]+ <built-in method pyobject_vectorcall of module object at remote 0x[0-9a-f]+>
|
|
$''')
|
|
|
|
@unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands")
|
|
def test_down_at_bottom(self):
|
|
'Verify handling of "py-down" at the bottom of the stack'
|
|
bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
|
|
cmds_after_breakpoint=['py-down'])
|
|
self.assertEndsWith(bt,
|
|
'Unable to find a newer python frame\n')
|
|
|
|
@unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands")
|
|
def test_up_at_top(self):
|
|
'Verify handling of "py-up" at the top of the stack'
|
|
bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
|
|
cmds_after_breakpoint=['py-up'] * 5)
|
|
self.assertEndsWith(bt,
|
|
'Unable to find an older python frame\n')
|
|
|
|
@unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands")
|
|
@unittest.skipIf(python_is_optimized(),
|
|
"Python was compiled with optimizations")
|
|
def test_up_then_down(self):
|
|
'Verify "py-up" followed by "py-down"'
|
|
bt = self.get_stack_trace(source=SAMPLE_WITH_C_CALL,
|
|
cmds_after_breakpoint=['py-up', 'py-up', 'py-down'])
|
|
self.assertMultilineMatches(bt,
|
|
r'''^.*
|
|
#[0-9]+ Frame 0x-?[0-9a-f]+, for file <string>, line 12, in baz \(args=\(1, 2, 3\)\)
|
|
#[0-9]+ <built-in method pyobject_vectorcall of module object at remote 0x[0-9a-f]+>
|
|
#[0-9]+ Frame 0x-?[0-9a-f]+, for file <string>, line 12, in baz \(args=\(1, 2, 3\)\)
|
|
$''')
|
|
|
|
class PyPrintTests(DebuggerTests):
|
|
@unittest.skipIf(python_is_optimized(),
|
|
"Python was compiled with optimizations")
|
|
def test_basic_command(self):
|
|
'Verify that the "py-print" command works'
|
|
bt = self.get_stack_trace(source=SAMPLE_WITH_C_CALL,
|
|
cmds_after_breakpoint=['py-up', 'py-print args'])
|
|
self.assertMultilineMatches(bt,
|
|
r".*\nlocal 'args' = \(1, 2, 3\)\n.*")
|
|
|
|
@unittest.skipIf(python_is_optimized(),
|
|
"Python was compiled with optimizations")
|
|
@unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands")
|
|
def test_print_after_up(self):
|
|
bt = self.get_stack_trace(source=SAMPLE_WITH_C_CALL,
|
|
cmds_after_breakpoint=['py-up', 'py-up', 'py-print c', 'py-print b', 'py-print a'])
|
|
self.assertMultilineMatches(bt,
|
|
r".*\nlocal 'c' = 3\nlocal 'b' = 2\nlocal 'a' = 1\n.*")
|
|
|
|
@unittest.skipIf(python_is_optimized(),
|
|
"Python was compiled with optimizations")
|
|
def test_printing_global(self):
|
|
bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
|
|
cmds_after_breakpoint=['py-up', 'py-print __name__'])
|
|
self.assertMultilineMatches(bt,
|
|
r".*\nglobal '__name__' = '__main__'\n.*")
|
|
|
|
@unittest.skipIf(python_is_optimized(),
|
|
"Python was compiled with optimizations")
|
|
def test_printing_builtin(self):
|
|
bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
|
|
cmds_after_breakpoint=['py-up', 'py-print len'])
|
|
self.assertMultilineMatches(bt,
|
|
r".*\nbuiltin 'len' = <built-in method len of module object at remote 0x-?[0-9a-f]+>\n.*")
|
|
|
|
class PyLocalsTests(DebuggerTests):
|
|
@unittest.skipIf(python_is_optimized(),
|
|
"Python was compiled with optimizations")
|
|
def test_basic_command(self):
|
|
bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
|
|
cmds_after_breakpoint=['py-up', 'py-locals'])
|
|
self.assertMultilineMatches(bt,
|
|
r".*\nargs = \(1, 2, 3\)\n.*")
|
|
|
|
@unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands")
|
|
@unittest.skipIf(python_is_optimized(),
|
|
"Python was compiled with optimizations")
|
|
def test_locals_after_up(self):
|
|
bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
|
|
cmds_after_breakpoint=['py-up', 'py-up', 'py-locals'])
|
|
self.assertMultilineMatches(bt,
|
|
r'''^.*
|
|
Locals for foo
|
|
a = 1
|
|
b = 2
|
|
c = 3
|
|
Locals for <module>
|
|
.*$''')
|