|
|
6e8c2f |
--- Tools/gdb/libpython.py.orig 2013-10-09 10:54:59.894701668 +0200
|
|
|
6e8c2f |
+++ Tools/gdb/libpython.py 2013-10-09 11:09:30.278703290 +0200
|
|
|
6e8c2f |
@@ -1194,39 +1194,113 @@
|
|
|
6e8c2f |
iter_frame = iter_frame.newer()
|
|
|
6e8c2f |
return index
|
|
|
6e8c2f |
|
|
|
6e8c2f |
+ # We divide frames into:
|
|
|
6e8c2f |
+ # - "python frames":
|
|
|
6e8c2f |
+ # - "bytecode frames" i.e. PyEval_EvalFrameEx
|
|
|
6e8c2f |
+ # - "other python frames": things that are of interest from a python
|
|
|
6e8c2f |
+ # POV, but aren't bytecode (e.g. GC, GIL)
|
|
|
6e8c2f |
+ # - everything else
|
|
|
6e8c2f |
+
|
|
|
6e8c2f |
+ def is_python_frame(self):
|
|
|
6e8c2f |
+ '''Is this a PyEval_EvalFrameEx frame, or some other important
|
|
|
6e8c2f |
+ frame? (see is_other_python_frame for what "important" means in this
|
|
|
6e8c2f |
+ context)'''
|
|
|
6e8c2f |
+ if self.is_evalframeex():
|
|
|
6e8c2f |
+ return True
|
|
|
6e8c2f |
+ if self.is_other_python_frame():
|
|
|
6e8c2f |
+ return True
|
|
|
6e8c2f |
+ return False
|
|
|
6e8c2f |
+
|
|
|
6e8c2f |
def is_evalframeex(self):
|
|
|
6e8c2f |
- '''Is this a PyEval_EvalFrameEx frame?'''
|
|
|
6e8c2f |
- if self._gdbframe.name() == 'PyEval_EvalFrameEx':
|
|
|
6e8c2f |
- '''
|
|
|
6e8c2f |
- I believe we also need to filter on the inline
|
|
|
6e8c2f |
- struct frame_id.inline_depth, only regarding frames with
|
|
|
6e8c2f |
- an inline depth of 0 as actually being this function
|
|
|
6e8c2f |
-
|
|
|
6e8c2f |
- So we reject those with type gdb.INLINE_FRAME
|
|
|
6e8c2f |
- '''
|
|
|
6e8c2f |
- if self._gdbframe.type() == gdb.NORMAL_FRAME:
|
|
|
6e8c2f |
- # We have a PyEval_EvalFrameEx frame:
|
|
|
6e8c2f |
- return True
|
|
|
6e8c2f |
+ if self._gdbframe.function():
|
|
|
6e8c2f |
+ if self._gdbframe.function().name == 'PyEval_EvalFrameEx':
|
|
|
6e8c2f |
+ '''
|
|
|
6e8c2f |
+ I believe we also need to filter on the inline
|
|
|
6e8c2f |
+ struct frame_id.inline_depth, only regarding frames with
|
|
|
6e8c2f |
+ an inline depth of 0 as actually being this function
|
|
|
6e8c2f |
+
|
|
|
6e8c2f |
+ So we reject those with type gdb.INLINE_FRAME
|
|
|
6e8c2f |
+ '''
|
|
|
6e8c2f |
+ if self._gdbframe.type() == gdb.NORMAL_FRAME:
|
|
|
6e8c2f |
+ # We have a PyEval_EvalFrameEx frame:
|
|
|
6e8c2f |
+ return True
|
|
|
6e8c2f |
+
|
|
|
6e8c2f |
+ return False
|
|
|
6e8c2f |
+
|
|
|
6e8c2f |
+ def is_other_python_frame(self):
|
|
|
6e8c2f |
+ '''Is this frame worth displaying in python backtraces?
|
|
|
6e8c2f |
+ Examples:
|
|
|
6e8c2f |
+ - waiting on the GIL
|
|
|
6e8c2f |
+ - garbage-collecting
|
|
|
6e8c2f |
+ - within a CFunction
|
|
|
6e8c2f |
+ If it is, return a descriptive string
|
|
|
6e8c2f |
+ For other frames, return False
|
|
|
6e8c2f |
+ '''
|
|
|
6e8c2f |
+ if self.is_waiting_for_gil():
|
|
|
6e8c2f |
+ return 'Waiting for a lock (e.g. GIL)'
|
|
|
6e8c2f |
+ elif self.is_gc_collect():
|
|
|
6e8c2f |
+ return 'Garbage-collecting'
|
|
|
6e8c2f |
+ else:
|
|
|
6e8c2f |
+ # Detect invocations of PyCFunction instances:
|
|
|
6e8c2f |
+ if self._gdbframe.name() == 'PyCFunction_Call':
|
|
|
6e8c2f |
+ try:
|
|
|
6e8c2f |
+ func = self._gdbframe.read_var('func')
|
|
|
6e8c2f |
+ # Use the prettyprinter for the func:
|
|
|
6e8c2f |
+ return str(func)
|
|
|
6e8c2f |
+ except RuntimeError:
|
|
|
6e8c2f |
+ return 'PyCFunction invocation (unable to read "func")'
|
|
|
6e8c2f |
+ older = self.older()
|
|
|
6e8c2f |
+ if older and older._gdbframe.name() == 'call_function':
|
|
|
6e8c2f |
+ # Within that frame:
|
|
|
6e8c2f |
+ # 'call_function' contains, amongst other things, a
|
|
|
6e8c2f |
+ # hand-inlined copy of PyCFunction_Call.
|
|
|
6e8c2f |
+ # "func" is the local containing the PyObject* of the
|
|
|
6e8c2f |
+ # callable instance
|
|
|
6e8c2f |
+ # Report it, but only if it's a PyCFunction (since otherwise
|
|
|
6e8c2f |
+ # we'd be reporting an implementation detail of every other
|
|
|
6e8c2f |
+ # function invocation)
|
|
|
6e8c2f |
+ try:
|
|
|
6e8c2f |
+ func = older._gdbframe.read_var('func')
|
|
|
6e8c2f |
+ funcobj = PyObjectPtr.from_pyobject_ptr(func)
|
|
|
6e8c2f |
+ if isinstance(funcobj, PyCFunctionObjectPtr):
|
|
|
6e8c2f |
+ # Use the prettyprinter for the func:
|
|
|
6e8c2f |
+ return str(func)
|
|
|
6e8c2f |
+ except RuntimeError:
|
|
|
6e8c2f |
+ return False
|
|
|
6e8c2f |
|
|
|
6e8c2f |
+ # This frame isn't worth reporting:
|
|
|
6e8c2f |
return False
|
|
|
6e8c2f |
|
|
|
6e8c2f |
+ def is_waiting_for_gil(self):
|
|
|
6e8c2f |
+ '''Is this frame waiting for a lock?'''
|
|
|
6e8c2f |
+ framename = self._gdbframe.name()
|
|
|
6e8c2f |
+ if framename:
|
|
|
6e8c2f |
+ return 'pthread_cond_timedwait' in framename or \
|
|
|
6e8c2f |
+ 'PyThread_acquire_lock' in framename
|
|
|
6e8c2f |
+
|
|
|
6e8c2f |
+ def is_gc_collect(self):
|
|
|
6e8c2f |
+ '''Is this frame "collect" within the the garbage-collector?'''
|
|
|
6e8c2f |
+ return self._gdbframe.name() == 'collect'
|
|
|
6e8c2f |
+
|
|
|
6e8c2f |
def get_pyop(self):
|
|
|
6e8c2f |
try:
|
|
|
6e8c2f |
f = self._gdbframe.read_var('f')
|
|
|
6e8c2f |
- frame = PyFrameObjectPtr.from_pyobject_ptr(f)
|
|
|
6e8c2f |
- if not frame.is_optimized_out():
|
|
|
6e8c2f |
- return frame
|
|
|
6e8c2f |
- # gdb is unable to get the "f" argument of PyEval_EvalFrameEx()
|
|
|
6e8c2f |
- # because it was "optimized out". Try to get "f" from the frame
|
|
|
6e8c2f |
- # of the caller, PyEval_EvalCodeEx().
|
|
|
6e8c2f |
- orig_frame = frame
|
|
|
6e8c2f |
- caller = self._gdbframe.older()
|
|
|
6e8c2f |
- if caller:
|
|
|
6e8c2f |
- f = caller.read_var('f')
|
|
|
6e8c2f |
- frame = PyFrameObjectPtr.from_pyobject_ptr(f)
|
|
|
6e8c2f |
- if not frame.is_optimized_out():
|
|
|
6e8c2f |
- return frame
|
|
|
6e8c2f |
- return orig_frame
|
|
|
6e8c2f |
+ obj = PyFrameObjectPtr.from_pyobject_ptr(f)
|
|
|
6e8c2f |
+ if isinstance(obj, PyFrameObjectPtr):
|
|
|
6e8c2f |
+ return obj
|
|
|
6e8c2f |
+ else:
|
|
|
6e8c2f |
+ return None
|
|
|
6e8c2f |
+ except ValueError:
|
|
|
6e8c2f |
+ return None
|
|
|
6e8c2f |
+
|
|
|
6e8c2f |
+ def get_py_co(self):
|
|
|
6e8c2f |
+ try:
|
|
|
6e8c2f |
+ co = self._gdbframe.read_var('co')
|
|
|
6e8c2f |
+ obj = PyCodeObjectPtr.from_pyobject_ptr(co)
|
|
|
6e8c2f |
+ if isinstance(obj, PyCodeObjectPtr):
|
|
|
6e8c2f |
+ return obj
|
|
|
6e8c2f |
+ else:
|
|
|
6e8c2f |
+ return None
|
|
|
6e8c2f |
except ValueError:
|
|
|
6e8c2f |
return None
|
|
|
6e8c2f |
|
|
|
6e8c2f |
@@ -1239,8 +1313,22 @@
|
|
|
6e8c2f |
|
|
|
6e8c2f |
@classmethod
|
|
|
6e8c2f |
def get_selected_python_frame(cls):
|
|
|
6e8c2f |
- '''Try to obtain the Frame for the python code in the selected frame,
|
|
|
6e8c2f |
- or None'''
|
|
|
6e8c2f |
+ '''Try to obtain the Frame for the python-related code in the selected
|
|
|
6e8c2f |
+ frame, or None'''
|
|
|
6e8c2f |
+ frame = cls.get_selected_frame()
|
|
|
6e8c2f |
+
|
|
|
6e8c2f |
+ while frame:
|
|
|
6e8c2f |
+ if frame.is_python_frame():
|
|
|
6e8c2f |
+ return frame
|
|
|
6e8c2f |
+ frame = frame.older()
|
|
|
6e8c2f |
+
|
|
|
6e8c2f |
+ # Not found:
|
|
|
6e8c2f |
+ return None
|
|
|
6e8c2f |
+
|
|
|
6e8c2f |
+ @classmethod
|
|
|
6e8c2f |
+ def get_selected_bytecode_frame(cls):
|
|
|
6e8c2f |
+ '''Try to obtain the Frame for the python bytecode interpreter in the
|
|
|
6e8c2f |
+ selected GDB frame, or None'''
|
|
|
6e8c2f |
frame = cls.get_selected_frame()
|
|
|
6e8c2f |
|
|
|
6e8c2f |
while frame:
|
|
|
6e8c2f |
@@ -1265,7 +1353,11 @@
|
|
|
6e8c2f |
else:
|
|
|
6e8c2f |
sys.stdout.write('#%i (unable to read python frame information)\n' % self.get_index())
|
|
|
6e8c2f |
else:
|
|
|
6e8c2f |
- sys.stdout.write('#%i\n' % self.get_index())
|
|
|
6e8c2f |
+ info = self.is_other_python_frame()
|
|
|
6e8c2f |
+ if info:
|
|
|
6e8c2f |
+ sys.stdout.write('#%i %s\n' % (self.get_index(), info))
|
|
|
6e8c2f |
+ else:
|
|
|
6e8c2f |
+ sys.stdout.write('#%i\n' % self.get_index())
|
|
|
6e8c2f |
|
|
|
6e8c2f |
class PyList(gdb.Command):
|
|
|
6e8c2f |
'''List the current Python source code, if any
|
|
|
6e8c2f |
@@ -1301,7 +1393,7 @@
|
|
|
6e8c2f |
if m:
|
|
|
6e8c2f |
start, end = map(int, m.groups())
|
|
|
6e8c2f |
|
|
|
6e8c2f |
- frame = Frame.get_selected_python_frame()
|
|
|
6e8c2f |
+ frame = Frame.get_selected_bytecode_frame()
|
|
|
6e8c2f |
if not frame:
|
|
|
6e8c2f |
print 'Unable to locate python frame'
|
|
|
6e8c2f |
return
|
|
|
6e8c2f |
@@ -1353,7 +1445,7 @@
|
|
|
6e8c2f |
if not iter_frame:
|
|
|
6e8c2f |
break
|
|
|
6e8c2f |
|
|
|
6e8c2f |
- if iter_frame.is_evalframeex():
|
|
|
6e8c2f |
+ if iter_frame.is_python_frame():
|
|
|
6e8c2f |
# Result:
|
|
|
6e8c2f |
if iter_frame.select():
|
|
|
6e8c2f |
iter_frame.print_summary()
|
|
|
6e8c2f |
@@ -1407,7 +1499,7 @@
|
|
|
6e8c2f |
def invoke(self, args, from_tty):
|
|
|
6e8c2f |
frame = Frame.get_selected_python_frame()
|
|
|
6e8c2f |
while frame:
|
|
|
6e8c2f |
- if frame.is_evalframeex():
|
|
|
6e8c2f |
+ if frame.is_python_frame():
|
|
|
6e8c2f |
frame.print_summary()
|
|
|
6e8c2f |
frame = frame.older()
|
|
|
6e8c2f |
|