Skip to content

Commit b08a103

Browse files
committed
More fixes and refactoring
1 parent 92b5c73 commit b08a103

File tree

1 file changed

+67
-79
lines changed

1 file changed

+67
-79
lines changed

Tools/gdb/libpython.py

Lines changed: 67 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,12 +1039,6 @@ def write_repr(self, out, visited):
10391039
return
10401040
return self._frame.write_repr(out, visited)
10411041

1042-
def print_traceback(self):
1043-
if self.is_optimized_out():
1044-
sys.stdout.write(' %s\n' % FRAME_INFO_OPTIMIZED_OUT)
1045-
return
1046-
return self._frame.print_traceback()
1047-
10481042
class PyFramePtr:
10491043

10501044
def __init__(self, gdbval):
@@ -1061,6 +1055,17 @@ def __init__(self, gdbval):
10611055
pnames = self.co.field('co_localsplusnames')
10621056
self.co_localsplusnames = PyTupleObjectPtr.from_pyobject_ptr(pnames)
10631057

1058+
@staticmethod
1059+
def get_thread_local_frame():
1060+
try:
1061+
return PyFramePtr(gdb.parse_and_eval('_Py_tss_gilstate->current_frame'))
1062+
except gdb.error:
1063+
pass
1064+
try:
1065+
return PyFramePtr(gdb.parse_and_eval('_Py_tss_tstate->current_frame'))
1066+
except gdb.error:
1067+
return None
1068+
10641069
def is_optimized_out(self):
10651070
return self._gdbval.is_optimized_out
10661071

@@ -1247,6 +1252,26 @@ def print_traceback(self):
12471252
lineno,
12481253
self.co_name.proxyval(visited)))
12491254

1255+
def print_traceback_until_shim(self, frame_index: int | None = None):
1256+
# Print traceback for _PyInterpreterFrame and return previous frame
1257+
interp_frame = self
1258+
while True:
1259+
if not interp_frame:
1260+
sys.stdout.write(' (unable to read python frame information)\n')
1261+
return None
1262+
elif interp_frame.is_shim():
1263+
return interp_frame.previous()
1264+
if frame_index is not None:
1265+
line = interp_frame.get_truncated_repr(MAX_OUTPUT_LEN)
1266+
sys.stdout.write('#%i %s\n' % (frame_index, line))
1267+
else:
1268+
interp_frame.print_traceback()
1269+
if not interp_frame.is_optimized_out():
1270+
line = interp_frame.current_line()
1271+
if line is not None:
1272+
sys.stdout.write(' %s\n' % line.strip())
1273+
interp_frame = interp_frame.previous()
1274+
12501275
def get_truncated_repr(self, maxlen):
12511276
'''
12521277
Get a repr-like string for the data, but truncate it at "maxlen" bytes
@@ -1859,50 +1884,14 @@ def get_selected_bytecode_frame(cls):
18591884
def print_summary(self):
18601885
if self.is_evalframe():
18611886
interp_frame = self.get_pyop()
1862-
while True:
1863-
if interp_frame:
1864-
if interp_frame.is_shim():
1865-
break
1866-
line = interp_frame.get_truncated_repr(MAX_OUTPUT_LEN)
1867-
sys.stdout.write('#%i %s\n' % (self.get_index(), line))
1868-
if not interp_frame.is_optimized_out():
1869-
line = interp_frame.current_line()
1870-
if line is not None:
1871-
sys.stdout.write(' %s\n' % line.strip())
1872-
else:
1873-
sys.stdout.write('#%i (unable to read python frame information)\n' % self.get_index())
1874-
break
1875-
interp_frame = interp_frame.previous()
1887+
interp_frame.print_traceback_until_shim(self.get_index())
18761888
else:
18771889
info = self.is_other_python_frame()
18781890
if info:
18791891
sys.stdout.write('#%i %s\n' % (self.get_index(), info))
18801892
else:
18811893
sys.stdout.write('#%i\n' % self.get_index())
18821894

1883-
def print_traceback(self):
1884-
if self.is_evalframe():
1885-
interp_frame = self.get_pyop()
1886-
while True:
1887-
if interp_frame:
1888-
if interp_frame.is_shim():
1889-
break
1890-
interp_frame.print_traceback()
1891-
if not interp_frame.is_optimized_out():
1892-
line = interp_frame.current_line()
1893-
if line is not None:
1894-
sys.stdout.write(' %s\n' % line.strip())
1895-
else:
1896-
sys.stdout.write(' (unable to read python frame information)\n')
1897-
break
1898-
interp_frame = interp_frame.previous()
1899-
else:
1900-
info = self.is_other_python_frame()
1901-
if info:
1902-
sys.stdout.write(' %s\n' % info)
1903-
else:
1904-
sys.stdout.write(' (not a python frame)\n')
1905-
19061895
class PyList(gdb.Command):
19071896
'''List the current Python source code, if any
19081897
@@ -2046,6 +2035,39 @@ def invoke(self, args, from_tty):
20462035
PyUp()
20472036
PyDown()
20482037

2038+
2039+
def print_traceback_helper(full_info):
2040+
frame = Frame.get_selected_python_frame()
2041+
interp_frame = PyFramePtr.get_thread_local_frame()
2042+
if not frame and not interp_frame:
2043+
print('Unable to locate python frame')
2044+
return
2045+
2046+
sys.stdout.write('Traceback (most recent call first):\n')
2047+
if frame:
2048+
while frame:
2049+
frame_index = frame.get_index() if full_info else None
2050+
if frame.is_evalframe():
2051+
if pyop := frame.get_pyop():
2052+
# Use the _PyInterpreterFrame from the gdb frame
2053+
interp_frame = pyop
2054+
interp_frame = interp_frame.print_traceback_until_shim(frame_index)
2055+
else:
2056+
info = frame.is_other_python_frame()
2057+
if full_info:
2058+
if info:
2059+
sys.stdout.write('#%i %s\n' % (frame_index, info))
2060+
else:
2061+
sys.stdout.write('#%i\n' % frame_index)
2062+
elif info:
2063+
sys.stdout.write(' %s\n' % info)
2064+
frame = frame.older()
2065+
else:
2066+
# Fall back to just using the thread-local frame
2067+
while interp_frame:
2068+
interp_frame = interp_frame.print_traceback_until_shim()
2069+
2070+
20492071
class PyBacktraceFull(gdb.Command):
20502072
'Display the current python frame and all the frames within its call stack (if any)'
20512073
def __init__(self):
@@ -2056,15 +2078,7 @@ def __init__(self):
20562078

20572079

20582080
def invoke(self, args, from_tty):
2059-
frame = Frame.get_selected_python_frame()
2060-
if not frame:
2061-
print('Unable to locate python frame')
2062-
return
2063-
2064-
while frame:
2065-
if frame.is_python_frame():
2066-
frame.print_summary()
2067-
frame = frame.older()
2081+
print_traceback_helper(full_info=True)
20682082

20692083
PyBacktraceFull()
20702084

@@ -2076,34 +2090,8 @@ def __init__(self):
20762090
gdb.COMMAND_STACK,
20772091
gdb.COMPLETE_NONE)
20782092

2079-
@staticmethod
2080-
def get_interp_frame():
2081-
try:
2082-
return PyFramePtr(gdb.parse_and_eval('_Py_tss_gilstate->current_frame'))
2083-
except gdb.error:
2084-
pass
2085-
try:
2086-
return PyFramePtr(gdb.parse_and_eval('_Py_tss_tstate->current_frame'))
2087-
except gdb.error:
2088-
return None
2089-
20902093
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')
2094+
print_traceback_helper(full_info=False)
21072095

21082096
PyBacktrace()
21092097

0 commit comments

Comments
 (0)