Python breakpoints (cy break -p / py-break)
authorMark Florisson <markflorisson88@gmail.com>
Tue, 2 Nov 2010 23:41:34 +0000 (00:41 +0100)
committerMark Florisson <markflorisson88@gmail.com>
Tue, 2 Nov 2010 23:41:34 +0000 (00:41 +0100)
Cython/Debugger/Tests/test_libcython_in_gdb.py
Cython/Debugger/libcython.py
Cython/Debugger/libpython.py

index f3126d9f020c6a8f5fac3da344c4a813a7a19b98..d9c3a068ab169677ef71a27a406ac5816a0625e8 100644 (file)
@@ -131,7 +131,11 @@ class TestBreak(DebugTestCase):
         assert self.spam_func.cname in bp.location
         assert bp.enabled
 
-        
+    
+    def test_python_break(self):
+        gdb.execute('cy break -p join')
+        assert 'def join(' in gdb.execute('cy run', to_string=True)
+    
 class DebugStepperTestCase(DebugTestCase):
     
     def step(self, varnames_and_values, source_line=None, lineno=None):
index d6df99be84f4f6db4e244e6ba7d1e6e2f766a933..50bcef6f3c5a215af0a0b5a7dbc58b39b7660c69 100644 (file)
@@ -494,7 +494,6 @@ class CythonCommand(gdb.Command, CythonBase):
     """
     
     command_class = gdb.COMMAND_NONE
-    completer_class = gdb.COMPLETE_NONE
     
     @classmethod
     def _register(cls, clsname, args, kwargs):
@@ -656,6 +655,15 @@ class CyBreak(CythonCommand):
     or for a line number:
     
         cy break cython_module:lineno...
+    
+    Set a Python breakpoint:
+        Break on any function or method named 'func' in module 'modname'
+            
+            cy break -p modname.func...
+        
+        Break on any function or method named 'func'
+            
+            cy break -p func...
     """
     
     name = 'cy break'
@@ -717,8 +725,17 @@ class CyBreak(CythonCommand):
                 gdb.execute('break %s' % func.pf_cname)
     
     def invoke(self, function_names, from_tty):
-        for funcname in string_to_argv(function_names.encode('UTF-8')):
-            if ':' in funcname:
+        argv = string_to_argv(function_names.encode('UTF-8'))
+        if function_names.startswith('-p'):
+            argv = argv[1:]
+            python_breakpoints = True
+        else:
+            python_breakpoints = False
+        
+        for funcname in argv:
+            if python_breakpoints:
+                gdb.execute('py-break %s' % funcname)
+            elif ':' in funcname:
                 self._break_pyx(funcname)
             else:
                 self._break_funcname(funcname)
index 880105dc9cd75d4cb81f57016817dbf0f6462e4a..1880b9af6c331ff01b55bb27a4de6590ab4d4b67 100644 (file)
@@ -1467,6 +1467,64 @@ PyLocals("py-locals", gdb.COMMAND_DATA, gdb.COMPLETE_NONE)
 PyGlobals("py-globals", gdb.COMMAND_DATA, gdb.COMPLETE_NONE)
 
 
+class PyNameEquals(gdb.Function):
+    
+    def _get_pycurframe_attr(self, attr):
+        frame = Frame(gdb.selected_frame())
+        if frame.is_evalframeex():
+            pyframe = frame.get_pyop()
+            if pyframe is None:
+                return None
+            
+            return str(getattr(pyframe, attr))
+        
+        return None
+    
+    def invoke(self, funcname):
+        attr = self._get_pycurframe_attr('co_name')
+        return attr is not None and attr == funcname.string()
+
+PyNameEquals("pyname_equals")
+
+
+class PyModEquals(PyNameEquals):
+    
+    def invoke(self, modname):
+        attr = self._get_pycurframe_attr('co_filename')
+        if attr is not None:
+            filename, ext = os.path.splitext(os.path.basename(attr))
+            return filename == modname.string()
+        return False
+
+PyModEquals("pymod_equals")
+
+
+class PyBreak(gdb.Command):
+    """
+    Set a Python breakpoint. Examples:
+    
+    Break on any function or method named 'func' in module 'modname'
+            
+        py-break modname.func 
+        
+    Break on any function or method named 'func'
+        
+        py-break func
+    """
+    
+    def invoke(self, funcname, from_tty):
+        if '.' in funcname:
+            modname, dot, funcname = funcname.rpartition('.')
+            cond = '$pyname_equals("%s") && $pymod_equals("%s")' % (funcname, 
+                                                                    modname)
+        else:
+            cond = '$pyname_equals("%s")' % funcname
+
+        gdb.execute('break PyEval_EvalFrameEx if ' + cond)
+
+PyBreak("py-break", gdb.COMMAND_RUNNING, gdb.COMPLETE_NONE)
+
+
 class _LoggingState(object):
     """
     State that helps to provide a reentrant gdb.execute() function.