Commit 61108333 authored by Victor Stinner's avatar Victor Stinner

python-gdb.py supports method-wrapper

Issue #29367: python-gdb.py now supports also method-wrapper (wrapperobject)
objects.
parent c9473b83
...@@ -3,13 +3,14 @@ ...@@ -3,13 +3,14 @@
# The code for testing gdb was adapted from similar work in Unladen Swallow's # The code for testing gdb was adapted from similar work in Unladen Swallow's
# Lib/test/test_jit_gdb.py # Lib/test/test_jit_gdb.py
import locale
import os import os
import re import re
import subprocess import subprocess
import sys import sys
import sysconfig import sysconfig
import textwrap
import unittest import unittest
import locale
# Is this Python configured to support threads? # Is this Python configured to support threads?
try: try:
...@@ -847,6 +848,24 @@ id(42) ...@@ -847,6 +848,24 @@ id(42)
) )
self.assertIn('#1 <built-in method gmtime', gdb_output) self.assertIn('#1 <built-in method gmtime', 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()
l = MyList()
''')
# Verify with "py-bt":
gdb_output = self.get_stack_trace(cmd,
breakpoint='wrapper_call',
cmds_after_breakpoint=['py-bt'],
)
self.assertIn("<method-wrapper '__init__' of MyList object at ",
gdb_output)
class PyPrintTests(DebuggerTests): class PyPrintTests(DebuggerTests):
@unittest.skipIf(python_is_optimized(), @unittest.skipIf(python_is_optimized(),
......
...@@ -746,6 +746,9 @@ Build ...@@ -746,6 +746,9 @@ Build
Tools/Demos Tools/Demos
----------- -----------
- Issue #29367: python-gdb.py now supports also ``method-wrapper``
(``wrapperobject``) objects.
- Issue #28023: Fix python-gdb.py didn't support new dict implementation. - Issue #28023: Fix python-gdb.py didn't support new dict implementation.
- Issue #15369: The pybench and pystone microbenchmark have been removed from - Issue #15369: The pybench and pystone microbenchmark have been removed from
......
...@@ -362,6 +362,7 @@ class PyObjectPtr(object): ...@@ -362,6 +362,7 @@ class PyObjectPtr(object):
'set' : PySetObjectPtr, 'set' : PySetObjectPtr,
'frozenset' : PySetObjectPtr, 'frozenset' : PySetObjectPtr,
'builtin_function_or_method' : PyCFunctionObjectPtr, 'builtin_function_or_method' : PyCFunctionObjectPtr,
'method-wrapper': wrapperobject,
} }
if tp_name in name_map: if tp_name in name_map:
return name_map[tp_name] return name_map[tp_name]
...@@ -1330,6 +1331,39 @@ class PyUnicodeObjectPtr(PyObjectPtr): ...@@ -1330,6 +1331,39 @@ class PyUnicodeObjectPtr(PyObjectPtr):
out.write(quote) out.write(quote)
class wrapperobject(PyObjectPtr):
_typename = 'wrapperobject'
def safe_name(self):
try:
name = self.field('descr')['d_base']['name'].string()
return repr(name)
except (NullPyObjectPtr, RuntimeError):
return '<unknown name>'
def safe_tp_name(self):
try:
return self.field('self')['ob_type']['tp_name'].string()
except (NullPyObjectPtr, RuntimeError):
return '<unknown tp_name>'
def safe_self_addresss(self):
try:
address = long(self.field('self'))
return '%#x' % address
except (NullPyObjectPtr, RuntimeError):
return '<failed to get self address>'
def proxyval(self, visited):
name = self.safe_name()
tp_name = self.safe_tp_name()
self_address = self.safe_self_addresss()
return ("<method-wrapper %s of %s object at %s>"
% (name, tp_name, self_address))
def write_repr(self, out, visited):
proxy = self.proxyval(visited)
out.write(proxy)
def int_from_int(gdbval): def int_from_int(gdbval):
...@@ -1364,11 +1398,13 @@ class PyObjectPtrPrinter: ...@@ -1364,11 +1398,13 @@ class PyObjectPtrPrinter:
def pretty_printer_lookup(gdbval): def pretty_printer_lookup(gdbval):
type = gdbval.type.unqualified() type = gdbval.type.unqualified()
if type.code == gdb.TYPE_CODE_PTR: if type.code != gdb.TYPE_CODE_PTR:
type = type.target().unqualified() return None
t = str(type)
if t in ("PyObject", "PyFrameObject", "PyUnicodeObject"): type = type.target().unqualified()
return PyObjectPtrPrinter(gdbval) t = str(type)
if t in ("PyObject", "PyFrameObject", "PyUnicodeObject", "wrapperobject"):
return PyObjectPtrPrinter(gdbval)
""" """
During development, I've been manually invoking the code in this way: During development, I've been manually invoking the code in this way:
...@@ -1520,6 +1556,13 @@ class Frame(object): ...@@ -1520,6 +1556,13 @@ class Frame(object):
except RuntimeError: except RuntimeError:
return 'PyCFunction invocation (unable to read %s)' % arg_name return 'PyCFunction invocation (unable to read %s)' % arg_name
if caller == 'wrapper_call':
try:
func = frame.read_var('wp')
return str(func)
except RuntimeError:
return '<wrapper_call invocation>'
# This frame isn't worth reporting: # This frame isn't worth reporting:
return False return False
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment