Skip to content

Commit 64a5436

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

File tree

1 file changed

+74
-79
lines changed

1 file changed

+74
-79
lines changed

Tools/gdb/libpython.py

Lines changed: 74 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,17 @@ 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+
if interp_frame:
1888+
interp_frame.print_traceback_until_shim(self.get_index())
1889+
else:
1890+
sys.stdout.write('#%i (unable to read python frame information)\n' % self.get_index())
18761891
else:
18771892
info = self.is_other_python_frame()
18781893
if info:
18791894
sys.stdout.write('#%i %s\n' % (self.get_index(), info))
18801895
else:
18811896
sys.stdout.write('#%i\n' % self.get_index())
18821897

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-
19061898
class PyList(gdb.Command):
19071899
'''List the current Python source code, if any
19081900
@@ -2046,6 +2038,43 @@ def invoke(self, args, from_tty):
20462038
PyUp()
20472039
PyDown()
20482040

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

20572086

20582087
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()
2088+
print_traceback_helper(full_info=True)
20682089

20692090
PyBacktraceFull()
20702091

@@ -2076,34 +2097,8 @@ def __init__(self):
20762097
gdb.COMMAND_STACK,
20772098
gdb.COMPLETE_NONE)
20782099

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-
20902100
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')
2101+
print_traceback_helper(full_info=False)
21072102

21082103
PyBacktrace()
21092104

0 commit comments

Comments
 (0)