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

Reply via email to