@@ -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-
10481042class 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-
19061895class 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+
20492071class 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
20692083PyBacktraceFull ()
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
21082096PyBacktrace ()
21092097
0 commit comments