Commit b0f6eba4 authored by Mark Florisson's avatar Mark Florisson

Debugger: Fix a few libpython.py bugs

parent ae137ef7
......@@ -4,10 +4,8 @@ GDB extension that adds Cython support.
from __future__ import with_statement
import os
import sys
import textwrap
import operator
import traceback
import functools
import itertools
......@@ -16,8 +14,8 @@ import collections
import gdb
try:
from lxml import etree
have_lxml = True
from lxml import etree
have_lxml = True
except ImportError:
have_lxml = False
try:
......@@ -279,7 +277,7 @@ class CythonBase(object):
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
......@@ -756,8 +754,8 @@ class CyBreak(CythonCommand):
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)
......@@ -1030,7 +1028,7 @@ class CyBacktrace(CythonCommand):
@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()
......@@ -1038,13 +1036,10 @@ class CyBacktrace(CythonCommand):
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)
......@@ -1052,8 +1047,6 @@ class CyBacktrace(CythonCommand):
index += 1
frame = frame.newer()
selected_frame.select()
class CyList(CythonCommand):
"""
......@@ -1188,7 +1181,6 @@ class CyExec(CythonCommand, libpython.PyExec):
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
......@@ -1245,8 +1237,6 @@ class CyExec(CythonCommand, libpython.PyExec):
'(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))
......
......@@ -1322,6 +1322,16 @@ class PyUnicodeObjectPtr(PyObjectPtr):
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))
......@@ -1452,12 +1462,39 @@ class Frame(object):
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):
......@@ -2174,9 +2211,10 @@ class PythonStepperMixin(object):
"""
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')
......@@ -2392,10 +2430,9 @@ class FixGdbCommand(gdb.Command):
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'
......@@ -2443,7 +2480,7 @@ class PyExec(gdb.Command):
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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment