Skip to content

Commit c8af302

Browse files
committed
Issue python#28770: Update python-gdb.py for fastcalls
Frame.is_other_python_frame() now also handles _PyCFunction_FastCallDict() frames. Thanks to the new code to handle fast calls, python-gdb.py is now also able to detect the <built-in id method of module ...> frame. (grafted from f41d02d7da373ccaff97a42b66b051260bd55996)
1 parent 86368b8 commit c8af302

File tree

2 files changed

+41
-26
lines changed

2 files changed

+41
-26
lines changed

Lib/test/test_gdb.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -679,7 +679,7 @@ class StackNavigationTests(DebuggerTests):
679679
def test_pyup_command(self):
680680
'Verify that the "py-up" command works'
681681
bt = self.get_stack_trace(script=self.get_sample_script(),
682-
cmds_after_breakpoint=['py-up'])
682+
cmds_after_breakpoint=['py-up', 'py-up'])
683683
self.assertMultilineMatches(bt,
684684
r'''^.*
685685
#[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 7, in bar \(a=1, b=2, c=3\)
@@ -698,7 +698,7 @@ def test_down_at_bottom(self):
698698
def test_up_at_top(self):
699699
'Verify handling of "py-up" at the top of the stack'
700700
bt = self.get_stack_trace(script=self.get_sample_script(),
701-
cmds_after_breakpoint=['py-up'] * 4)
701+
cmds_after_breakpoint=['py-up'] * 5)
702702
self.assertEndsWith(bt,
703703
'Unable to find an older python frame\n')
704704

@@ -708,7 +708,7 @@ def test_up_at_top(self):
708708
def test_up_then_down(self):
709709
'Verify "py-up" followed by "py-down"'
710710
bt = self.get_stack_trace(script=self.get_sample_script(),
711-
cmds_after_breakpoint=['py-up', 'py-down'])
711+
cmds_after_breakpoint=['py-up', 'py-up', 'py-down'])
712712
self.assertMultilineMatches(bt,
713713
r'''^.*
714714
#[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 7, in bar \(a=1, b=2, c=3\)
@@ -727,6 +727,7 @@ def test_bt(self):
727727
self.assertMultilineMatches(bt,
728728
r'''^.*
729729
Traceback \(most recent call first\):
730+
<built-in method id of module object .*>
730731
File ".*gdb_sample.py", line 10, in baz
731732
id\(42\)
732733
File ".*gdb_sample.py", line 7, in bar
@@ -815,7 +816,6 @@ def test_gc(self):
815816
)
816817
self.assertIn('Garbage-collecting', gdb_output)
817818

818-
@unittest.skip("FIXME: builtin method is not shown in py-bt and py-bt-full")
819819
@unittest.skipIf(python_is_optimized(),
820820
"Python was compiled with optimizations")
821821
# Some older versions of gdb will fail with
@@ -854,7 +854,7 @@ class PyPrintTests(DebuggerTests):
854854
def test_basic_command(self):
855855
'Verify that the "py-print" command works'
856856
bt = self.get_stack_trace(script=self.get_sample_script(),
857-
cmds_after_breakpoint=['py-print args'])
857+
cmds_after_breakpoint=['py-up', 'py-print args'])
858858
self.assertMultilineMatches(bt,
859859
r".*\nlocal 'args' = \(1, 2, 3\)\n.*")
860860

@@ -863,23 +863,23 @@ def test_basic_command(self):
863863
@unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands")
864864
def test_print_after_up(self):
865865
bt = self.get_stack_trace(script=self.get_sample_script(),
866-
cmds_after_breakpoint=['py-up', 'py-print c', 'py-print b', 'py-print a'])
866+
cmds_after_breakpoint=['py-up', 'py-up', 'py-print c', 'py-print b', 'py-print a'])
867867
self.assertMultilineMatches(bt,
868868
r".*\nlocal 'c' = 3\nlocal 'b' = 2\nlocal 'a' = 1\n.*")
869869

870870
@unittest.skipIf(python_is_optimized(),
871871
"Python was compiled with optimizations")
872872
def test_printing_global(self):
873873
bt = self.get_stack_trace(script=self.get_sample_script(),
874-
cmds_after_breakpoint=['py-print __name__'])
874+
cmds_after_breakpoint=['py-up', 'py-print __name__'])
875875
self.assertMultilineMatches(bt,
876876
r".*\nglobal '__name__' = '__main__'\n.*")
877877

878878
@unittest.skipIf(python_is_optimized(),
879879
"Python was compiled with optimizations")
880880
def test_printing_builtin(self):
881881
bt = self.get_stack_trace(script=self.get_sample_script(),
882-
cmds_after_breakpoint=['py-print len'])
882+
cmds_after_breakpoint=['py-up', 'py-print len'])
883883
self.assertMultilineMatches(bt,
884884
r".*\nbuiltin 'len' = <built-in method len of module object at remote 0x-?[0-9a-f]+>\n.*")
885885

@@ -888,7 +888,7 @@ class PyLocalsTests(DebuggerTests):
888888
"Python was compiled with optimizations")
889889
def test_basic_command(self):
890890
bt = self.get_stack_trace(script=self.get_sample_script(),
891-
cmds_after_breakpoint=['py-locals'])
891+
cmds_after_breakpoint=['py-up', 'py-locals'])
892892
self.assertMultilineMatches(bt,
893893
r".*\nargs = \(1, 2, 3\)\n.*")
894894

@@ -897,7 +897,7 @@ def test_basic_command(self):
897897
"Python was compiled with optimizations")
898898
def test_locals_after_up(self):
899899
bt = self.get_stack_trace(script=self.get_sample_script(),
900-
cmds_after_breakpoint=['py-up', 'py-locals'])
900+
cmds_after_breakpoint=['py-up', 'py-up', 'py-locals'])
901901
self.assertMultilineMatches(bt,
902902
r".*\na = 1\nb = 2\nc = 3\n.*")
903903

Tools/gdb/libpython.py

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1492,23 +1492,38 @@ def is_other_python_frame(self):
14921492
'''
14931493
if self.is_waiting_for_gil():
14941494
return 'Waiting for the GIL'
1495-
elif self.is_gc_collect():
1495+
1496+
if self.is_gc_collect():
14961497
return 'Garbage-collecting'
1497-
else:
1498-
# Detect invocations of PyCFunction instances:
1499-
older = self.older()
1500-
if older and older._gdbframe.name() == 'PyCFunction_Call':
1501-
# Within that frame:
1502-
# "func" is the local containing the PyObject* of the
1503-
# PyCFunctionObject instance
1504-
# "f" is the same value, but cast to (PyCFunctionObject*)
1505-
# "self" is the (PyObject*) of the 'self'
1506-
try:
1507-
# Use the prettyprinter for the func:
1508-
func = older._gdbframe.read_var('func')
1509-
return str(func)
1510-
except RuntimeError:
1511-
return 'PyCFunction invocation (unable to read "func")'
1498+
1499+
# Detect invocations of PyCFunction instances:
1500+
older = self.older()
1501+
if not older:
1502+
return False
1503+
1504+
caller = older._gdbframe.name()
1505+
if not caller:
1506+
return False
1507+
1508+
if caller == 'PyCFunction_Call':
1509+
# Within that frame:
1510+
# "func" is the local containing the PyObject* of the
1511+
# PyCFunctionObject instance
1512+
# "f" is the same value, but cast to (PyCFunctionObject*)
1513+
# "self" is the (PyObject*) of the 'self'
1514+
try:
1515+
# Use the prettyprinter for the func:
1516+
func = older._gdbframe.read_var('func')
1517+
return str(func)
1518+
except RuntimeError:
1519+
return 'PyCFunction invocation (unable to read "func")'
1520+
1521+
elif caller == '_PyCFunction_FastCallDict':
1522+
try:
1523+
func = older._gdbframe.read_var('func_obj')
1524+
return str(func)
1525+
except RuntimeError:
1526+
return 'PyCFunction invocation (unable to read "func_obj")'
15121527

15131528
# This frame isn't worth reporting:
15141529
return False

0 commit comments

Comments
 (0)