diff --git a/Lib/bdb.py b/Lib/bdb.py --- a/Lib/bdb.py +++ b/Lib/bdb.py @@ -25,6 +25,7 @@ self.breaks = {} self.fncache = {} self.frame_returning = None + self.botframe = None def canonic(self, filename): if filename == "<" + filename[1:-1] + ">": @@ -36,15 +37,16 @@ self.fncache[filename] = canonic return canonic - def reset(self): + def reset(self, botframe=None): import linecache linecache.checkcache() - self.botframe = None + self.botframe = botframe + self.quitting = False self._set_stopinfo(None, None) def trace_dispatch(self, frame, event, arg): - if self.quitting: - return # None + if not self.botframe: + self.botframe = frame if event == 'line': return self.dispatch_line(frame) if event == 'call': @@ -65,7 +67,9 @@ def dispatch_line(self, frame): if self.stop_here(frame) or self.break_here(frame): self.user_line(frame) - if self.quitting: raise BdbQuit + # Do not raise BdbQuit when debugging is started with set_trace + if self.quitting and self.botframe.f_back: + raise BdbQuit return self.trace_dispatch def dispatch_call(self, frame, arg): @@ -78,7 +82,8 @@ # No need to trace this function return # None self.user_call(frame, arg) - if self.quitting: raise BdbQuit + if self.quitting and self.botframe.f_back: + raise BdbQuit return self.trace_dispatch def dispatch_return(self, frame, arg): @@ -88,13 +93,15 @@ self.user_return(frame, arg) finally: self.frame_returning = None - if self.quitting: raise BdbQuit + if self.quitting and self.botframe.f_back: + raise BdbQuit return self.trace_dispatch def dispatch_exception(self, frame, arg): if self.stop_here(frame): self.user_exception(frame, arg) - if self.quitting: raise BdbQuit + if self.quitting and self.botframe.f_back: + raise BdbQuit return self.trace_dispatch # Normally derived classes don't override the following @@ -214,9 +221,14 @@ If frame is not specified, debugging starts from caller's frame. """ + # First disable tracing temporarily as set_trace() may be called while + # tracing is in use. For example when called from a signal handler and + # within a debugging session started with runcall(). + sys.settrace(None) + if frame is None: frame = sys._getframe().f_back - self.reset() + self.reset(botframe=self.botframe) while frame: frame.f_trace = self.trace_dispatch self.botframe = frame @@ -229,17 +241,22 @@ self._set_stopinfo(self.botframe, None, -1) if not self.breaks: # no breakpoints; run without debugger overhead - sys.settrace(None) - frame = sys._getframe().f_back - while frame and frame is not self.botframe: - del frame.f_trace - frame = frame.f_back + self.remove_trace() def set_quit(self): self.stopframe = self.botframe self.returnframe = None self.quitting = 1 + self.remove_trace() + + def remove_trace(self): sys.settrace(None) + # Remove the trace objects of frames in the call stack to invalidate + # those frames f_lineno. + frame = sys._getframe().f_back + while frame and frame is not self.botframe: + del frame.f_trace + frame = frame.f_back # Derived classes and clients can call the following methods # to manipulate breakpoints. These methods return an @@ -401,7 +418,6 @@ except BdbQuit: pass finally: - self.quitting = 1 sys.settrace(None) def runeval(self, expr, globals=None, locals=None): @@ -419,7 +435,6 @@ except BdbQuit: pass finally: - self.quitting = 1 sys.settrace(None) def runctx(self, cmd, globals, locals): @@ -437,7 +452,6 @@ except BdbQuit: pass finally: - self.quitting = 1 sys.settrace(None) return res diff --git a/Lib/pdb.py b/Lib/pdb.py --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -104,8 +104,8 @@ self.commands_bnum = None # The breakpoint number for which we are # defining a list - def reset(self): - bdb.Bdb.reset(self) + def reset(self, botframe=None): + bdb.Bdb.reset(self, botframe) self.forget() def forget(self):