Skip to content

Commit e37a049

Browse files
committed
Merge command into py-bt and fix free threaded build
1 parent 5072ec0 commit e37a049

File tree

1 file changed

+45
-107
lines changed

1 file changed

+45
-107
lines changed

Tools/gdb/libpython.py

Lines changed: 45 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,41 +1045,21 @@ def print_traceback(self):
10451045
return
10461046
return self._frame.print_traceback()
10471047

1048-
def current_line(filename, lineno):
1049-
if lineno is None:
1050-
return '(failed to get frame line number)'
1051-
1052-
try:
1053-
with open(os.fsencode(filename), 'r', encoding="utf-8") as fp:
1054-
lines = fp.readlines()
1055-
except IOError:
1056-
return None
1057-
1058-
try:
1059-
# Convert from 1-based current_line_num to 0-based list offset
1060-
return lines[lineno - 1]
1061-
except IndexError:
1062-
return None
1063-
1064-
10651048
class PyFramePtr:
10661049

10671050
def __init__(self, gdbval):
10681051
self._gdbval = gdbval
10691052

10701053
if not self.is_optimized_out():
1071-
try:
1072-
self.co = self._f_code()
1054+
self.co = self._f_code()
1055+
if not self.is_shim():
10731056
self.co_name = self.co.pyop_field('co_name')
10741057
self.co_filename = self.co.pyop_field('co_filename')
10751058

10761059
self.f_lasti = self._f_lasti()
10771060
self.co_nlocals = int_from_int(self.co.field('co_nlocals'))
10781061
pnames = self.co.field('co_localsplusnames')
10791062
self.co_localsplusnames = PyTupleObjectPtr.from_pyobject_ptr(pnames)
1080-
self._is_code = True
1081-
except:
1082-
self._is_code = False
10831063

10841064
def is_optimized_out(self):
10851065
return self._gdbval.is_optimized_out
@@ -1137,6 +1117,8 @@ def is_shim(self):
11371117
return self._f_special("owner", int) == FRAME_OWNED_BY_INTERPRETER
11381118

11391119
def previous(self):
1120+
if int(self._gdbval['previous']) == 0:
1121+
return None
11401122
return self._f_special("previous", PyFramePtr)
11411123

11421124
def iter_globals(self):
@@ -1210,9 +1192,22 @@ def current_line(self):
12101192
if self.is_optimized_out():
12111193
return FRAME_INFO_OPTIMIZED_OUT
12121194

1213-
filename = self.filename()
12141195
lineno = self.current_line_num()
1215-
return current_line(filename, lineno)
1196+
if lineno is None:
1197+
return '(failed to get frame line number)'
1198+
1199+
filename = self.filename()
1200+
try:
1201+
with open(os.fsencode(filename), 'r', encoding="utf-8") as fp:
1202+
lines = fp.readlines()
1203+
except IOError:
1204+
return None
1205+
1206+
try:
1207+
# Convert from 1-based current_line_num to 0-based list offset
1208+
return lines[lineno - 1]
1209+
except IndexError:
1210+
return None
12161211

12171212
def write_repr(self, out, visited):
12181213
if self.is_optimized_out():
@@ -2081,59 +2076,36 @@ def __init__(self):
20812076
gdb.COMMAND_STACK,
20822077
gdb.COMPLETE_NONE)
20832078

2084-
def invoke(self, args, from_tty):
2085-
frame = Frame.get_selected_python_frame()
2086-
if not frame:
2087-
print('Unable to locate python frame')
2088-
return
2089-
2090-
sys.stdout.write('Traceback (most recent call first):\n')
2091-
while frame:
2092-
if frame.is_python_frame():
2093-
frame.print_traceback()
2094-
frame = frame.older()
2095-
2096-
PyBacktrace()
2097-
2098-
class PyBacktraceTSS(gdb.Command):
2099-
'Similar to py-bt but read _Py_tss_gilstate or _Py_tss_tstate'
2100-
def __init__(self):
2101-
gdb.Command.__init__ (self,
2102-
"py-bt-tss",
2103-
gdb.COMMAND_STACK,
2104-
gdb.COMPLETE_NONE)
2105-
2106-
def invoke(self, args, from_tty):
2079+
@staticmethod
2080+
def get_interp_frame():
21072081
try:
2108-
iframe = gdb.parse_and_eval('_Py_tss_gilstate->current_frame')
2082+
return PyFramePtr(gdb.parse_and_eval('_Py_tss_gilstate->current_frame'))
21092083
except gdb.error:
2110-
iframe = gdb.parse_and_eval('_Py_tss_tstate->current_frame')
2111-
visited = set()
2084+
pass
2085+
try:
2086+
return PyFramePtr(gdb.parse_and_eval('_Py_tss_tstate->current_frame'))
2087+
except gdb.error:
2088+
return None
21122089

2113-
print('Traceback (most recent call first):')
2114-
while True:
2115-
is_complete = not _PyFrame_IsIncomplete(iframe)
2116-
if is_complete:
2117-
code = _PyFrame_GetCode(iframe)
2118-
code = PyCodeObjectPtr.from_pyobject_ptr(code)
2119-
2120-
filename = code.pyop_field('co_filename')
2121-
filename = filename.proxyval(visited)
2122-
lasti = iframe['instr_ptr'] - _PyFrame_GetBytecode(iframe)
2123-
lineno = code.addr2line(lasti)
2124-
name = code.pyop_field('co_name')
2125-
name = name.proxyval(visited)
2126-
print(' File "%s", line %s, in %s'
2127-
% (filename, lineno, name))
2128-
line = current_line(filename, lineno)
2129-
if line is not None:
2130-
sys.stdout.write(' %s\n' % line.strip())
2131-
2132-
iframe = iframe['previous']
2133-
if not iframe:
2134-
break
2090+
def invoke(self, args, from_tty):
2091+
if iframe := PyBacktrace.get_interp_frame():
2092+
# Use the _PyInterpreterFrame in thread local state
2093+
print('Traceback (most recent call first):')
2094+
while iframe:
2095+
if not iframe.is_shim():
2096+
iframe.print_traceback()
2097+
iframe = iframe.previous()
2098+
elif frame := Frame.get_selected_python_frame():
2099+
# Try the selected frame route
2100+
sys.stdout.write('Traceback (most recent call first):\n')
2101+
while frame:
2102+
if frame.is_python_frame():
2103+
frame.print_traceback()
2104+
frame = frame.older()
2105+
else:
2106+
print('Unable to locate python frame')
21352107

2136-
PyBacktraceTSS()
2108+
PyBacktrace()
21372109

21382110
class PyPrint(gdb.Command):
21392111
'Look up the given python variable name, and print it'
@@ -2204,38 +2176,4 @@ def invoke(self, args, from_tty):
22042176

22052177
pyop_frame = pyop_frame.previous()
22062178

2207-
2208-
def _PyCode_CODE(code):
2209-
cast_to = gdb.lookup_type('PyCodeObject').pointer()
2210-
code = code.cast(cast_to)
2211-
cast_to = gdb.lookup_type('_Py_CODEUNIT').pointer()
2212-
return code['co_code_adaptive'].cast(cast_to)
2213-
2214-
def _PyFrame_GetCode(iframe):
2215-
executable = iframe['f_executable']
2216-
try:
2217-
# Python 3.14 and newer: f_executable is a _PyStackRef
2218-
return _PyStackRef_AsPyObjectBorrow(executable)
2219-
except gdb.error:
2220-
# Python 3.13: f_executable is a PyCodeObject*
2221-
return executable
2222-
2223-
def _PyFrame_GetBytecode(iframe):
2224-
# FIXME: #ifdef Py_GIL_DISABLED
2225-
# PyCodeObject *co = _PyFrame_GetCode(f);
2226-
# _PyCodeArray *tlbc = _PyCode_GetTLBCArray(co);
2227-
# assert(f->tlbc_index >= 0 && f->tlbc_index < tlbc->size);
2228-
# return (_Py_CODEUNIT *)tlbc->entries[f->tlbc_index];
2229-
return _PyCode_CODE(_PyFrame_GetCode(iframe))
2230-
2231-
def _PyFrame_IsIncomplete(iframe):
2232-
if iframe['owner'] >= FRAME_OWNED_BY_INTERPRETER:
2233-
return True
2234-
# FIXME:
2235-
# return frame->owner != FRAME_OWNED_BY_GENERATOR &&
2236-
# frame->instr_ptr < _PyFrame_GetBytecode(frame) +
2237-
# _PyFrame_GetCode(frame)->_co_firsttraceable;
2238-
return False
2239-
2240-
22412179
PyLocals()

0 commit comments

Comments
 (0)