Debugger: Fix a few libpython.py bugs
authorMark Florisson <markflorisson88@gmail.com>
Tue, 25 Jan 2011 20:41:31 +0000 (21:41 +0100)
committerMark Florisson <markflorisson88@gmail.com>
Tue, 25 Jan 2011 20:41:31 +0000 (21:41 +0100)
Cython/Debugger/libcython.py
Cython/Debugger/libpython.py

index 0aa4bcfad336ca56d844c8030a1881ce4b0e861a..8d7771b530c9ba05ac13a93fd96f0c9d1bca3d16 100644 (file)
@@ -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))
index 78534a490a7225d30742adecc59e315455bb1a74..4729412ca27a6574f1bc0d55ce21404d96ace33b 100644 (file)
@@ -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)