Author: Armin Rigo <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit