Author: Armin Rigo <ar...@tunes.org> Branch: reverse-debugger Changeset: r85464:3c619ff91d4b Date: 2016-06-29 23:49 +0200 http://bitbucket.org/pypy/pypy/changeset/3c619ff91d4b/
Log: 'next', 'bnext', 'finish', 'bfinish' for Python diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py --- a/pypy/interpreter/executioncontext.py +++ b/pypy/interpreter/executioncontext.py @@ -64,6 +64,9 @@ return frame def enter(self, frame): + if self.space.config.translation.reverse_debugger: + from pypy.interpreter.reverse_debugging import enter_call + enter_call(self.topframeref(), frame) frame.f_backref = self.topframeref self.topframeref = jit.virtual_ref(frame) @@ -84,6 +87,9 @@ # be accessed also later frame_vref() jit.virtual_ref_finish(frame_vref, frame) + if self.space.config.translation.reverse_debugger: + from pypy.interpreter.reverse_debugging import leave_call + leave_call(self.topframeref(), frame) # ________________________________________________________________ diff --git a/pypy/interpreter/reverse_debugging.py b/pypy/interpreter/reverse_debugging.py --- a/pypy/interpreter/reverse_debugging.py +++ b/pypy/interpreter/reverse_debugging.py @@ -10,6 +10,7 @@ class DBState: extend_syntax_with_dollar_num = False + breakpoint_stack_id = 0 breakpoint_funcnames = [] printed_objects = {} metavars = [] @@ -37,8 +38,8 @@ revdb.register_debug_command(revdb.CMD_PRINT, lambda_print) revdb.register_debug_command(revdb.CMD_BACKTRACE, lambda_backtrace) revdb.register_debug_command(revdb.CMD_LOCALS, lambda_locals) - #revdb.register_debug_command(revdb.CMD_BREAKPOINTS, lambda_breakpoints) - #revdb.register_debug_command(revdb.CMD_MOREINFO, lambda_moreinfo) + revdb.register_debug_command(revdb.CMD_BREAKPOINTS, lambda_breakpoints) + revdb.register_debug_command(revdb.CMD_STACKID, lambda_stackid) revdb.register_debug_command("ALLOCATING", lambda_allocating) revdb.register_debug_command(revdb.CMD_ATTACHID, lambda_attachid) #revdb.register_debug_command(revdb.CMD_CHECKWATCH, lambda_checkwatch) @@ -48,6 +49,16 @@ pycode.PyCode.co_revdb_linestarts = None # or a string: an array of bits +def enter_call(caller_frame, callee_frame): + if dbstate.breakpoint_stack_id != 0: + if dbstate.breakpoint_stack_id == revdb.get_unique_id(caller_frame): + revdb.breakpoint(-1) + +def leave_call(caller_frame, callee_frame): + if dbstate.breakpoint_stack_id != 0: + if dbstate.breakpoint_stack_id == revdb.get_unique_id(caller_frame): + revdb.breakpoint(-1) + def potential_stop_point(frame): if not we_are_translated(): return @@ -369,6 +380,22 @@ lambda_locals = lambda: command_locals +def command_breakpoints(cmd, extra): + dbstate.breakpoint_stack_id = cmd.c_arg1 +lambda_breakpoints = lambda: command_breakpoints + +def command_stackid(cmd, extra): + frame = fetch_cur_frame() + if frame is not None and cmd.c_arg1 != 0: # parent_flag + frame = dbstate.space.getexecutioncontext().getnextframe_nohidden(frame) + if frame is None: + uid = 0 + else: + uid = revdb.get_unique_id(frame) + revdb.send_answer(revdb.ANSWER_STACKID, uid) +lambda_stackid = lambda: command_stackid + + def command_allocating(uid, gcref): w_obj = cast_gcref_to_instance(W_Root, gcref) dbstate.printed_objects[uid] = w_obj diff --git a/rpython/translator/revdb/interact.py b/rpython/translator/revdb/interact.py --- a/rpython/translator/revdb/interact.py +++ b/rpython/translator/revdb/interact.py @@ -154,18 +154,20 @@ self.remove_tainting() try: self.pgroup.go_forward(steps) - return True + return None except Breakpoint as b: self.hit_breakpoint(b) - return False + return b - def move_backward(self, steps): + def move_backward(self, steps, rel_stop_at=-1): + ignore_bkpt = steps == 1 and rel_stop_at == -1 try: - self.pgroup.go_backward(steps, ignore_breakpoints=(steps==1)) - return True + self.pgroup.go_backward(steps, ignore_breakpoints=ignore_bkpt, + rel_stop_at=rel_stop_at) + return None except Breakpoint as b: self.hit_breakpoint(b, backward=True) - return False + return b def hit_breakpoint(self, b, backward=False): if b.num != -1: @@ -198,7 +200,7 @@ @contextmanager def _stack_id_break(self, stack_id): # add temporarily a breakpoint that hits when we enter/leave - # the frame identified by 'stack_id' + # a frame from/to the frame identified by 'stack_id' b = self.pgroup.edit_breakpoints() b.stack_id = stack_id try: @@ -208,50 +210,55 @@ def command_next(self, argument): """Run forward for one step, skipping calls""" - depth1 = self.pgroup.get_stack_id() - with self._stack_id_break(depth1): - if not self.move_forward(1): - # we either hit a regular breakpoint, or we hit the - # temporary breakpoint - return - if depth1 == 0: # we started outside any frame - return - if self.pgroup.get_stack_id() == depth1: - return # we are still in the same frame - # - # If, after running one step, the stack id is different than - # before but we didn't leave that frame, then we must have - # entered a new one. Continue until we leave that new frame. - # Can't do it more directly because the "breakpoint" of - # stack_id is only checked for on function enters and returns - # (which simplifies and speeds up things for the RPython - # code). - self.command_finish('') + stack_id = self.pgroup.get_stack_id(is_parent=False) + with self._stack_id_break(stack_id): + b = self.move_forward(1) + if b is None: + return # no breakpoint hit, and no frame just entered: done + elif b.num != -1: + return # a regular breakpoint was hit + else: + # we entered a frame. Continue running until we leave that + # frame again + with self._stack_id_break(stack_id): + self.command_continue("") command_n = command_next def command_bnext(self, argument): """Run backward for one step, skipping calls""" - # similar to command_next() - depth1 = self.pgroup.get_stack_id() - with self._stack_id_break(depth1): - if not self.move_backward(1): - return - if depth1 == 0: - return - if self.pgroup.get_stack_id() == depth1: - return # we are still in the same frame - self.command_bfinish('') + stack_id = self.pgroup.get_stack_id(is_parent=False) + with self._stack_id_break(stack_id): + b = self.move_backward(1, rel_stop_at=0) + if b is None: + return # no breakpoint hit, and no frame just + # reverse-entered: done + elif b.num != -1: + return # a regular breakpoint was hit + else: + # we reverse-entered a frame. Continue running backward + # until we go past the reverse-leave (i.e. the entering) + # of that frame. + with self._stack_id_break(stack_id): + self.command_bcontinue("") command_bn = command_bnext def command_finish(self, argument): """Run forward until the current function finishes""" - with self._stack_id_break(self.pgroup.get_stack_id()): - self.command_continue('') + stack_id = self.pgroup.get_stack_id(is_parent=True) + if stack_id == 0: + print 'No stack.' + else: + with self._stack_id_break(stack_id): + self.command_continue('') def command_bfinish(self, argument): """Run backward until the current function is called""" - with self._stack_id_break(self.pgroup.get_stack_id()): - self.command_bcontinue('') + stack_id = self.pgroup.get_stack_id(is_parent=True) + if stack_id == 0: + print 'No stack.' + else: + with self._stack_id_break(stack_id): + self.command_bcontinue('') def command_continue(self, argument): """Run forward""" diff --git a/rpython/translator/revdb/message.py b/rpython/translator/revdb/message.py --- a/rpython/translator/revdb/message.py +++ b/rpython/translator/revdb/message.py @@ -58,8 +58,8 @@ # CMD_STACKID returns the id of the current or parent frame (depending # on the 'parent-flag' passed in), or 0 if not found. The id can be just # the stack depth, or it can be the unique id of the frame object. When -# used in CMD_BREAKPOINTS, it means "break if we are entering/leaving that -# frame". +# used in CMD_BREAKPOINTS, it means "break if we are entering/leaving a +# frame from/to the given frame". # Message(ANSWER_STACKID, stack-id) ANSWER_STACKID = 21 diff --git a/rpython/translator/revdb/process.py b/rpython/translator/revdb/process.py --- a/rpython/translator/revdb/process.py +++ b/rpython/translator/revdb/process.py @@ -19,10 +19,11 @@ self.num2name = {} # {small number: break/watchpoint} self.watchvalues = {} # {small number: resulting text} self.watchuids = {} # {small number: [uid...]} - self.stack_id = 0 # breaks when leaving/entering this frame; 0=none + self.stack_id = 0 # breaks when leaving/entering a frame from/to + # the frame identified by 'stack_id' def __repr__(self): - return 'AllBreakpoints(%r, %r, %r, %d)' % ( + return 'AllBreakpoints(%r, %r, %r, %r)' % ( self.num2name, self.watchvalues, self.watchuids, self.stack_id) @@ -304,7 +305,7 @@ if bkpt: raise bkpt - def go_backward(self, steps, ignore_breakpoints=False): + def go_backward(self, steps, ignore_breakpoints=False, rel_stop_at=-1): """Go backward, for the given number of 'steps' of time. Closes the active process. Implemented as jump_in_time() @@ -321,7 +322,7 @@ first_steps = 957 self._backward_search_forward( search_start_time = initial_time - first_steps, - search_stop_time = initial_time - 1, + search_stop_time = initial_time + rel_stop_at, search_go_on_until_time = initial_time - steps) def _backward_search_forward(self, search_start_time, search_stop_time, @@ -536,8 +537,8 @@ def edit_breakpoints(self): return self.all_breakpoints - def get_stack_id(self): - self.active.send(Message(CMD_STACKID)) + def get_stack_id(self, is_parent): + self.active.send(Message(CMD_STACKID, is_parent)) msg = self.active.expect(ANSWER_STACKID, Ellipsis) self.active.expect_ready() return msg.arg1 diff --git a/rpython/translator/revdb/src-revdb/revdb.c b/rpython/translator/revdb/src-revdb/revdb.c --- a/rpython/translator/revdb/src-revdb/revdb.c +++ b/rpython/translator/revdb/src-revdb/revdb.c @@ -1097,9 +1097,8 @@ void rpy_reverse_db_breakpoint(int64_t num) { if (flag_io_disabled != FID_REGULAR_MODE) { - fprintf(stderr, "revdb.breakpoint(): cannot be called from a " - "debug command\n"); - exit(1); + /* called from a debug command, ignore */ + return; } switch (breakpoint_mode) { _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit