@@ -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-
10651048class 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
21382110class 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-
22412179PyLocals ()
0 commit comments