Author: Armin Rigo <ar...@tunes.org> Branch: reverse-debugger Changeset: r85490:b5ea52f65b84 Date: 2016-07-01 16:10 +0200 http://bitbucket.org/pypy/pypy/changeset/b5ea52f65b84/
Log: Tweak again the breakpoint detection code and the "next" and "bnext" commands 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 @@ -59,14 +59,14 @@ name = callee_frame.getcode().co_name if name in dbstate.breakpoint_funcnames: revdb.breakpoint(dbstate.breakpoint_funcnames[name]) - if dbstate.breakpoint_stack_id != 0: + if dbstate.breakpoint_stack_id != 0 and caller_frame is not None: 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 != 0 and caller_frame is not None: if dbstate.breakpoint_stack_id == revdb.get_unique_id(caller_frame): - revdb.breakpoint(-1) + revdb.breakpoint(-2) def jump_backward(frame, jumpto): 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 @@ -170,28 +170,31 @@ self.pgroup.go_forward(steps) return None except Breakpoint as b: - self.hit_breakpoint(b) + self.hit_breakpoints(b) return b - def move_backward(self, steps, rel_stop_at=-1): - ignore_bkpt = steps == 1 and rel_stop_at == -1 + def move_backward(self, steps): try: - self.pgroup.go_backward(steps, ignore_breakpoints=ignore_bkpt, - rel_stop_at=rel_stop_at) + self.pgroup.go_backward(steps) return None except Breakpoint as b: - self.hit_breakpoint(b, backward=True) + self.hit_breakpoints(b, backward=True) return b - def hit_breakpoint(self, b, backward=False): - if b.num != -1: - kind, name = self._bp_kind(b.num) - self.print_extra_pending_info = 'Hit %s %d: %s' % (kind, b.num, - name) - elif backward: - b.time -= 1 - if self.pgroup.get_current_time() != b.time: - self.pgroup.jump_in_time(b.time) + def hit_breakpoints(self, b, backward=False): + printing = [] + for num in b.regular_breakpoint_nums(): + kind, name = self._bp_kind(num) + printing.append('%s %s %d: %s' % ( + 'Reverse-hit' if backward else 'Hit', + kind, num, name)) + self.print_extra_pending_info = '\n'.join(printing) + target_time = b.time + if backward: + target_time -= 1 # when going backwards, we stop just before + # the breakpoint time, as opposed to just after + if self.pgroup.get_current_time() != target_time: + self.pgroup.jump_in_time(target_time) def remove_tainting(self): if self.pgroup.is_tainted(): @@ -226,33 +229,44 @@ 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 + while b is not None: + # if we hit a regular breakpoint, stop + if any(b.regular_breakpoint_nums()): + return + # we hit only calls and returns inside stack_id. If the + # last one of these is a "return", then we're now back inside + # stack_id, so stop + if b.nums[-1] == -2: + return + # else, the last one is a "call", so we entered another frame. + # Continue running until the next call/return event occurs + # inside stack_id with self._stack_id_break(stack_id): - self.command_continue("") + b = self.move_forward(self.pgroup.get_max_time() - + self.pgroup.get_current_time()) + # and then look at that 'b' again (closes the loop) command_n = command_next def command_bnext(self, argument): """Run backward for one step, skipping calls""" 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. + b = self.move_backward(1) + while b is not None: + # if we hit a regular breakpoint, stop + if any(b.regular_breakpoint_nums()): + return + # we hit only calls and returns inside stack_id. If the + # first one of these is a "call", then we're now back inside + # stack_id, so stop + if b.nums[0] == -1: + return + # else, the first one is a "return", so before, we were + # inside a different frame. Continue running until the next + # call/return event occurs inside stack_id with self._stack_id_break(stack_id): - self.command_bcontinue("") + b = self.move_backward(self.pgroup.get_current_time() - 1) + # and then look at that 'b' again (closes the loop) command_bn = command_bnext def command_finish(self, argument): 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 @@ -5,12 +5,21 @@ class Breakpoint(Exception): - def __init__(self, time, num): - self.time = time - self.num = num + def __init__(self, time): + self.time = time # time of the previous stop_point + self.nums = [] # list of breakpoint numbers that occurred, in order + + def record_num(self, num): + self.nums.append(num) + + def regular_breakpoint_nums(self): + for num in self.nums: + if num != -1 and num != -2: + yield num def __repr__(self): - return 'Breakpoint(%d, %d)' % (self.time, self.num) + return 'Breakpoint(%d, %r)' % (self.time, self.nums) + __str__ = __repr__ class AllBreakpoints(object): @@ -151,15 +160,15 @@ self.send(Message(CMD_FORWARD, steps, ord(breakpoint_mode))) # - # record the first ANSWER_BREAKPOINT, drop the others - # (in corner cases only could we get more than one) + # record all breakpoints that occur together during the *last* step bkpt = None while True: msg = self.recv() if msg.cmd != ANSWER_BREAKPOINT: break - if bkpt is None: - bkpt = Breakpoint(msg.arg1, msg.arg3) + if bkpt is None or bkpt.time != msg.arg1: + bkpt = Breakpoint(msg.arg1) + bkpt.record_num(msg.arg3) assert msg.cmd == ANSWER_READY, msg self.update_times(msg) return bkpt @@ -306,7 +315,7 @@ if bkpt: raise bkpt - def go_backward(self, steps, ignore_breakpoints=False, rel_stop_at=-1): + def go_backward(self, steps, ignore_breakpoints=False): """Go backward, for the given number of 'steps' of time. Closes the active process. Implemented as jump_in_time() @@ -323,7 +332,7 @@ first_steps = 957 self._backward_search_forward( search_start_time = initial_time - first_steps, - search_stop_time = initial_time + rel_stop_at, + search_stop_time = initial_time, search_go_on_until_time = initial_time - steps) def _backward_search_forward(self, search_start_time, search_stop_time, 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 @@ -483,6 +483,8 @@ #define ANSWER_AT_END (-23) #define ANSWER_BREAKPOINT (-24) +#define RECORD_BKPT_NUM 50 + typedef void (*rpy_revdb_command_fn)(rpy_revdb_command_t *, RPyString *); static int rpy_rev_sockfd; @@ -493,7 +495,8 @@ static void (*pending_after_forward)(void); static RPyString *empty_string; static uint64_t last_recorded_breakpoint_loc; -static int last_recorded_breakpoint_num; +static int n_last_recorded_breakpoints; +static int last_recorded_breakpoint_nums[RECORD_BKPT_NUM]; static char breakpoint_mode = 'i'; static uint64_t *future_ids, *future_next_id; static void *finalizer_tree, *destructor_tree; @@ -927,10 +930,11 @@ static void answer_recorded_breakpoint(void) { - if (last_recorded_breakpoint_loc != 0) { + int i; + for (i = 0; i < n_last_recorded_breakpoints; i++) write_answer(ANSWER_BREAKPOINT, last_recorded_breakpoint_loc, - 0, last_recorded_breakpoint_num); - } + 0, last_recorded_breakpoint_nums[i]); + n_last_recorded_breakpoints = 0; } static void command_forward(rpy_revdb_command_t *cmd) @@ -943,7 +947,7 @@ interactive_break = saved_state.stop_point_seen + cmd->arg1; breakpoint_mode = (char)cmd->arg2; if (breakpoint_mode == 'r') { - last_recorded_breakpoint_loc = 0; + n_last_recorded_breakpoints = 0; pending_after_forward = &answer_recorded_breakpoint; } } @@ -1102,8 +1106,14 @@ return; /* ignored breakpoints */ case 'r': /* record the breakpoint but continue */ - last_recorded_breakpoint_loc = rpy_revdb.stop_point_seen + 1; - last_recorded_breakpoint_num = num; + if (last_recorded_breakpoint_loc != rpy_revdb.stop_point_seen + 1) { + last_recorded_breakpoint_loc = rpy_revdb.stop_point_seen + 1; + n_last_recorded_breakpoints = 0; + } + if (n_last_recorded_breakpoints < RECORD_BKPT_NUM) { + last_recorded_breakpoint_nums[n_last_recorded_breakpoints] = num; + n_last_recorded_breakpoints++; + } return; case 'b': /* default handling of breakpoints */ _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit