Mercurial > cpython-lru_cache-weakref
diff Tools/gdb/libpython.py @ 74078:1cc8e9565339 2.7
Issue #13628: python-gdb.py is now able to retrieve more frames in the Python
traceback if Python is optimized.
* delay the lookup of the size_t type, it is not available at startup
* The second argument of the PyFrameObjectPtr constructor is optional, as
done in other constructors
* iter_builtins() and iter_globals() methods of PyFrameObjectPtr returns
an empty tuple instead of None if Python is optimized
* Fix py-bt to handle correctly "optimized" frames
* Frame.get_pyop() tries to get the frame pointer from PyEval_EvalCodeEx()
if the pointer is optimized out in PyEval_EvalFrameEx()
| author | Victor Stinner <victor.stinner@haypocalc.com> |
|---|---|
| date | Mon, 19 Dec 2011 13:59:58 +0100 |
| parents | 1322266f9611 |
| children | 33b156e118c0 |
line wrap: on
line diff
--- a/Tools/gdb/libpython.py Mon Dec 19 12:17:16 2011 +0100 +++ b/Tools/gdb/libpython.py Mon Dec 19 13:59:58 2011 +0100 @@ -47,7 +47,6 @@ _type_char_ptr = gdb.lookup_type('char').pointer() # char* _type_unsigned_char_ptr = gdb.lookup_type('unsigned char').pointer() # unsigned char* _type_void_ptr = gdb.lookup_type('void').pointer() # void* -_type_size_t = gdb.lookup_type('size_t') SIZEOF_VOID_P = _type_void_ptr.sizeof @@ -410,11 +409,15 @@ self.address) def _PyObject_VAR_SIZE(typeobj, nitems): + if _PyObject_VAR_SIZE._type_size_t is None: + _PyObject_VAR_SIZE._type_size_t = gdb.lookup_type('size_t') + return ( ( typeobj.field('tp_basicsize') + nitems * typeobj.field('tp_itemsize') + (SIZEOF_VOID_P - 1) ) & ~(SIZEOF_VOID_P - 1) - ).cast(_type_size_t) + ).cast(_PyObject_VAR_SIZE._type_size_t) +_PyObject_VAR_SIZE._type_size_t = None class HeapTypeObjectPtr(PyObjectPtr): _typename = 'PyObject' @@ -786,7 +789,7 @@ class PyFrameObjectPtr(PyObjectPtr): _typename = 'PyFrameObject' - def __init__(self, gdbval, cast_to): + def __init__(self, gdbval, cast_to=None): PyObjectPtr.__init__(self, gdbval, cast_to) if not self.is_optimized_out(): @@ -820,7 +823,7 @@ the global variables of this frame ''' if self.is_optimized_out(): - return + return () pyop_globals = self.pyop_field('f_globals') return pyop_globals.iteritems() @@ -831,7 +834,7 @@ the builtin variables ''' if self.is_optimized_out(): - return + return () pyop_builtins = self.pyop_field('f_builtins') return pyop_builtins.iteritems() @@ -1205,7 +1208,20 @@ def get_pyop(self): try: f = self._gdbframe.read_var('f') - return PyFrameObjectPtr.from_pyobject_ptr(f) + frame = PyFrameObjectPtr.from_pyobject_ptr(f) + if not frame.is_optimized_out(): + return frame + # gdb is unable to get the "f" argument of PyEval_EvalFrameEx() + # because it was "optimized out". Try to get "f" from the frame + # of the caller, PyEval_EvalCodeEx(). + orig_frame = frame + caller = self._gdbframe.older() + if caller: + f = caller.read_var('f') + frame = PyFrameObjectPtr.from_pyobject_ptr(f) + if not frame.is_optimized_out(): + return frame + return orig_frame except ValueError: return None @@ -1235,7 +1251,9 @@ pyop = self.get_pyop() if pyop: sys.stdout.write('#%i %s\n' % (self.get_index(), pyop.get_truncated_repr(MAX_OUTPUT_LEN))) - sys.stdout.write(pyop.current_line()) + if not pyop.is_optimized_out(): + line = pyop.current_line() + sys.stdout.write(' %s\n' % line.strip()) else: sys.stdout.write('#%i (unable to read python frame information)\n' % self.get_index()) else: @@ -1281,7 +1299,7 @@ return pyop = frame.get_pyop() - if not pyop: + if not pyop or pyop.is_optimized_out(): print 'Unable to read information on python frame' return
