From ad032f3f48b32e37035ebc5926bbfc5a8265dbf7 Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Thu, 11 Nov 2010 13:16:21 +0100 Subject: [PATCH] Add 'cy finish', 'py-finish', 'py-run' and 'py-cont' commands. --- .../Debugger/Tests/test_libcython_in_gdb.py | 4 - Cython/Debugger/libcython.py | 32 ++--- Cython/Debugger/libpython.py | 133 +++++++++++++----- 3 files changed, 111 insertions(+), 58 deletions(-) diff --git a/Cython/Debugger/Tests/test_libcython_in_gdb.py b/Cython/Debugger/Tests/test_libcython_in_gdb.py index 734df95f..85a580ff 100644 --- a/Cython/Debugger/Tests/test_libcython_in_gdb.py +++ b/Cython/Debugger/Tests/test_libcython_in_gdb.py @@ -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 = ( diff --git a/Cython/Debugger/libcython.py b/Cython/Debugger/libcython.py index dd3c9960..d54545b1 100644 --- a/Cython/Debugger/libcython.py +++ b/Cython/Debugger/libcython.py @@ -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): diff --git a/Cython/Debugger/libpython.py b/Cython/Debugger/libpython.py index fb51cda4..7a5572e0 100644 --- a/Cython/Debugger/libpython.py +++ b/Cython/Debugger/libpython.py @@ -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 -- 2.26.2