Add 'cy finish', 'py-finish', 'py-run' and 'py-cont' commands.
authorMark Florisson <markflorisson88@gmail.com>
Thu, 11 Nov 2010 12:16:21 +0000 (13:16 +0100)
committerMark Florisson <markflorisson88@gmail.com>
Thu, 11 Nov 2010 12:16:21 +0000 (13:16 +0100)
Cython/Debugger/Tests/test_libcython_in_gdb.py
Cython/Debugger/libcython.py
Cython/Debugger/libpython.py

index 734df95fdcf046b0c4840acc87476a87328c060e..85a580ffb584cc83d18fa735ec38679f69af7334 100644 (file)
@@ -158,7 +158,6 @@ class TestStep(DebugStepperTestCase):
     
     def test_cython_step(self):
         gdb.execute('cy break codefile.spam')
-        libcython.parameters.step_into_c_code.value = False
         
         gdb.execute('run', to_string=True)
         self.lineno_equals('def spam(a=0):')
@@ -171,14 +170,12 @@ class TestStep(DebugStepperTestCase):
         self.step([('b', 1), ('c', 0)], source_line='c = 2')
         self.step([('c', 2)], source_line='int(10)')
         self.step([], source_line='puts("spam")')
-        self.step([], source_line='os.path.join("foo", "bar")')
         
         gdb.execute('cont', to_string=True)
         self.assertEqual(len(gdb.inferiors()), 1)
         self.assertEqual(gdb.inferiors()[0].pid, 0)
     
     def test_c_step(self):
-        libcython.parameters.step_into_c_code.value = True
         self.break_and_run('some_c_function()')
         gdb.execute('cy step', to_string=True)
         self.assertEqual(gdb.selected_frame().name(), 'some_c_function')
@@ -198,7 +195,6 @@ class TestStep(DebugStepperTestCase):
 class TestNext(DebugStepperTestCase):
     
     def test_cython_next(self):
-        libcython.parameters.step_into_c_code.value = True
         self.break_and_run('c = 2')
 
         lines = (
index dd3c99607986e8c6717f5b4e4379bf7c006b6202..d54545b127de870da325c849d227fb264db53a51 100644 (file)
@@ -277,8 +277,7 @@ class CythonBase(object):
         older_frame = frame.older()
         if self.is_cython_function(frame) or self.is_python_function(frame):
             return True
-        elif (parameters.step_into_c_code and 
-              older_frame and self.is_cython_function(older_frame)):
+        elif older_frame and self.is_cython_function(older_frame):
             # direct C function call from a Cython function
             cython_func = self.get_cython_function(older_frame)
             return name in cython_func.step_into_functions
@@ -506,12 +505,6 @@ class TerminalBackground(CythonParameter):
     Tell cygdb about the user's terminal background (light or dark).
     """
 
-class StepIntoCCode(CythonParameter):
-    """
-    Tells cygdb whether to step into C functions called directly from Cython
-    code.
-    """
-
 class CythonParameters(object):
     """
     Simple container class that might get more functionality in the distant
@@ -534,11 +527,6 @@ class CythonParameters(object):
             gdb.COMMAND_FILES,
             gdb.PARAM_STRING,
             "dark")
-        self.step_into_c_code = StepIntoCCode(
-            'cy_step_into_c_code',
-            gdb.COMMAND_RUNNING,
-            gdb.PARAM_BOOLEAN,
-            True)
         
 parameters = CythonParameters()
 
@@ -602,6 +590,7 @@ class CyCy(CythonCommand):
             next = CyNext.register(),
             run = CyRun.register(),
             cont = CyCont.register(),
+            finish = CyFinish.register(),
             up = CyUp.register(),
             down = CyDown.register(),
             bt = CyBacktrace.register(),
@@ -873,7 +862,7 @@ class CythonCodeStepper(CythonCommand, libpython.GenericCodeStepper):
                 
             self.finish_executing(gdb.execute(command, to_string=True))
         else:
-            super(CythonCodeStepper, self).invoke(args, from_tty)
+            self.step()
 
 
 class CyStep(CythonCodeStepper):
@@ -897,10 +886,8 @@ class CyRun(CythonCodeStepper):
     """
     
     name = 'cy run'
-    _command = 'run'
     
-    def invoke(self, *args):
-        self.finish_executing(gdb.execute(self._command, to_string=True))
+    invoke = CythonCodeStepper.run
 
 
 class CyCont(CyRun):
@@ -910,7 +897,16 @@ class CyCont(CyRun):
     """
     
     name = 'cy cont'
-    _command = 'cont'
+    invoke = CythonCodeStepper.cont
+
+
+class CyFinish(CyRun):
+    """
+    Execute until the function returns.
+    """
+    name = 'cy finish'
+
+    invoke = CythonCodeStepper.finish
 
 
 class CyUp(CythonCommand):
index fb51cda442ae8467b42c38d6fab4f002082c8667..7a5572e07386a6aebfb7ae518747940be8e6a1f2 100644 (file)
@@ -1686,6 +1686,72 @@ class GenericCodeStepper(gdb.Command):
         context.
         """
     
+    def stopped(self):
+        return gdb.inferiors()[0].pid == 0
+        
+    def _stackdepth(self, frame):
+        depth = 0
+        while frame:
+            frame = frame.older()
+            depth += 1
+            
+        return depth
+    
+    def finish_executing(self, result):
+        """
+        After doing some kind of code running in the inferior, print the line
+        of source code or the result of the last executed gdb command (passed
+        in as the `result` argument).
+        """
+        if self.stopped():
+            print result.strip()
+        else:
+            frame = gdb.selected_frame()
+            output = None
+            
+            if self.is_relevant_function(frame):
+                output = self.get_source_line(frame)
+            
+            if output is None:
+                pframe = getattr(self, 'print_stackframe', None)
+                if pframe:
+                    pframe(frame, index=0)
+                else:
+                    print result.strip()
+            else:
+                print output
+    
+    def _finish(self):
+        """
+        Execute until the function returns (or until something else makes it 
+        stop)
+        """
+        if gdb.selected_frame().older() is not None:
+            return gdb.execute('finish', to_string=True)
+        else:
+            # outermost frame, continue
+            return gdb.execute('cont', to_string=True)
+    
+    def finish(self, *args):
+        """
+        Execute until the function returns to a relevant caller.
+        """
+        
+        while True:
+            result = self._finish()
+            
+            try:
+                frame = gdb.selected_frame()
+            except RuntimeError:
+                break
+            
+            hitbp = re.search(r'Breakpoint (\d+)', result)
+            is_relavant = self.is_relevant_function(frame)
+            if hitbp or is_relavant or self.stopped():
+                break
+            
+        self.finish_executing(result)
+    
     def _step(self):
         """
         Do a single step or step-over. Returns the result of the last gdb
@@ -1706,10 +1772,7 @@ class GenericCodeStepper(gdb.Command):
             if self.is_relevant_function(newframe):
                 result = gdb.execute('next', to_string=True)
             else:
-                if self._stackdepth(newframe) == 1:
-                    result = gdb.execute('cont', to_string=True)
-                else:
-                    result = gdb.execute('finish', to_string=True)
+                result = self._finish()
             
             if self.stopped():
                 break
@@ -1749,39 +1812,15 @@ class GenericCodeStepper(gdb.Command):
             self.disable_breakpoints()
 
         return result
-        
-    def stopped(self):
-        return gdb.inferiors()[0].pid == 0
-        
-    def _stackdepth(self, frame):
-        depth = 0
-        while frame:
-            frame = frame.older()
-            depth += 1
-            
-        return depth
     
-    def invoke(self, args, from_tty):
-        self.finish_executing(self._step())
+    def step(self):
+        return self.finish_executing(self._step())
+
+    def run(self, *args):
+        self.finish_executing(gdb.execute('run', to_string=True))
     
-    def finish_executing(self, result):
-        if self.stopped():
-            print result.strip()
-        else:
-            frame = gdb.selected_frame()
-            output = None
-            
-            if self.is_relevant_function(frame):
-                output = self.get_source_line(frame)
-            
-            if output is None:
-                pframe = getattr(self, 'print_stackframe', None)
-                if pframe:
-                    pframe(frame, index=0)
-                else:
-                    print result.strip()
-            else:
-                print output
+    def cont(self, *args):
+        self.finish_executing(gdb.execute('cont', to_string=True))
 
 
 class PythonCodeStepper(GenericCodeStepper):
@@ -1813,11 +1852,33 @@ class PythonCodeStepper(GenericCodeStepper):
 
 class PyStep(PythonCodeStepper):
     "Step through Python code."
-
+    
+    invoke = PythonCodeStepper.step
+    
 class PyNext(PythonCodeStepper):
     "Step-over Python code."
+    
+    invoke = PythonCodeStepper.step
+    
+class PyFinish(PythonCodeStepper):
+    "Execute until function returns to a caller."
+    
+    invoke = PythonCodeStepper.finish
+
+class PyRun(PythonCodeStepper):
+    "Run the program."
+    
+    invoke = PythonCodeStepper.run
+
+class PyCont(PythonCodeStepper):
+    
+    invoke = PythonCodeStepper.cont
+
 
 py_step = PyStep('py-step', stepinto=True)
 py_next = PyNext('py-next', stepinto=False)
+py_finish = PyFinish('py-finish')
+py_run = PyRun('py-run')
+py_cont = PyCont('py-cont')
 
 py_step.init_breakpoints()
\ No newline at end of file