from __future__ import with_statement
-import os
import sys
import textwrap
-import operator
import traceback
import functools
import itertools
import gdb
try:
- from lxml import etree
- have_lxml = True
+ from lxml import etree
+ have_lxml = True
except ImportError:
have_lxml = False
try:
if self.is_cython_function(frame) or self.is_python_function(frame):
return True
elif older_frame and self.is_cython_function(older_frame):
- # direct C function call from a Cython function
+ # check for direct C function call from a Cython function
cython_func = self.get_cython_function(older_frame)
return name in cython_func.step_into_functions
breakpoint = '%s:%s' % (cython_module.c_filename, c_lineno)
gdb.execute('break ' + breakpoint)
else:
- raise GdbError("Not a valid line number. "
- "Does it contain actual code?")
+ raise gdb.GdbError("Not a valid line number. "
+ "Does it contain actual code?")
def _break_funcname(self, funcname):
func = self.cy.functions_by_qualified_name.get(funcname)
@require_running_program
def invoke(self, args, from_tty):
# get the first frame
- selected_frame = frame = gdb.selected_frame()
+ frame = gdb.selected_frame()
while frame.older():
frame = frame.older()
index = 0
while frame:
- is_c = False
-
- is_relevant = False
try:
is_relevant = self.is_relevant_function(frame)
except CyGDBError:
- pass
+ is_relevant = False
if print_all or is_relevant:
self.print_stackframe(frame, index)
index += 1
frame = frame.newer()
- selected_frame.select()
-
class CyList(CythonCommand):
"""
def _fill_locals_dict(self, executor, local_dict_pointer):
"Fill a remotely allocated dict with values from the Cython C stack"
cython_func = self.get_cython_function()
- current_lineno = self.get_cython_lineno()
for name, cyvar in cython_func.locals.iteritems():
if (cyvar.type == PythonObject and
'(PyObject *) PyModule_GetDict(__pyx_m)')
local_dict = gdb.parse_and_eval('(PyObject *) PyDict_New()')
- cython_function = self.get_cython_function()
-
try:
self._fill_locals_dict(executor,
libpython.pointervalue(local_dict))
out.write(quote)
+ def __unicode__(self):
+ return self.proxyval(set())
+
+ def __str__(self):
+ # In Python 3, everything is unicode (including attributes of e.g.
+ # code objects, such as function names). The Python 2 debugger code
+ # uses PyUnicodePtr objects to format strings etc, whereas with a
+ # Python 2 debuggee we'd get PyStringObjectPtr instances with __str__.
+ # Be compatible with that.
+ return unicode(self).encode('UTF-8')
def int_from_int(gdbval):
return int(str(gdbval))
return False
+ def read_var(self, varname):
+ """
+ read_var with respect to code blocks (gdbframe.read_var works with
+ respect to the most recent block)
+
+ Apparently this function doesn't work, though, as it seems to read
+ variables in other frames also sometimes.
+ """
+ block = self._gdbframe.block()
+ var = None
+
+ while block and var is None:
+ try:
+ var = self._gdbframe.read_var(varname, block)
+ except ValueError:
+ pass
+
+ block = block.superblock
+
+ return var
+
def get_pyop(self):
try:
- f = self._gdbframe.read_var('f')
- return PyFrameObjectPtr.from_pyobject_ptr(f)
- except ValueError:
+ # self.read_var does not always work properly, so select our frame
+ # and restore the previously selected frame
+ selected_frame = gdb.selected_frame()
+ self._gdbframe.select()
+ f = gdb.parse_and_eval('f')
+ selected_frame.select()
+ except RuntimeError:
return None
+ else:
+ return PyFrameObjectPtr.from_pyobject_ptr(f)
@classmethod
def get_selected_frame(cls):
"""
def python_step(self, stepinto):
- frame = gdb.selected_frame()
- framewrapper = Frame(frame)
-
+ """
+ Set a watchpoint on the Python bytecode instruction pointer and try
+ to finish the frame
+ """
output = gdb.execute('watch f->f_lasti', to_string=True)
watchpoint = int(re.search(r'[Ww]atchpoint (\d+):', output).group(1))
self.step(stepinto=stepinto, stepover_command='finish')
def fix_gdb(self):
"""
- So, you must be wondering what the story is this time! Yeeees, indeed,
- I have quite the story for you! It seems that invoking either 'cy exec'
- and 'py-exec' work perfectly fine, but after this gdb's python API is
- entirely broken. Some unset exception value is still set?
+ It seems that invoking either 'cy exec' and 'py-exec' work perfectly
+ fine, but after this gdb's python API is entirely broken.
+ Maybe some uncleared exception value is still set?
sys.exc_clear() didn't help. A demonstration:
(gdb) cy exec 'hello'
lines.append(line)
- return '\n'.join(lines), Py_file_input
+ return '\n'.join(lines), PythonCodeExecutor.Py_file_input
def invoke(self, expr, from_tty):
expr, input_type = self.readcode(expr)