[pypy-commit] pypy reverse-debugger: Breakpoint

arigo pypy.commits at gmail.com
Mon Jun 20 04:05:45 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: reverse-debugger
Changeset: r85233:29dbfbbe1024
Date: 2016-06-20 10:06 +0200
http://bitbucket.org/pypy/pypy/changeset/29dbfbbe1024/

Log:	Breakpoint

diff --git a/rpython/rlib/revdb.py b/rpython/rlib/revdb.py
--- a/rpython/rlib/revdb.py
+++ b/rpython/rlib/revdb.py
@@ -55,6 +55,9 @@
     """
     _change_time('f', time_delta, callback)
 
+def breakpoint(num):
+    llop.revdb_breakpoint(lltype.Void, num)
+
 @specialize.argtype(0)
 def get_unique_id(x):
     """Returns the creation number of the object 'x'.  For objects created
diff --git a/rpython/rtyper/lltypesystem/lloperation.py b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -568,6 +568,7 @@
     'revdb_stop_point':     LLOp(),
     'revdb_send_answer':    LLOp(),
     'revdb_change_time':    LLOp(),
+    'revdb_breakpoint':     LLOp(),
     'revdb_get_value':      LLOp(sideeffects=False),
     'revdb_get_unique_id':  LLOp(sideeffects=False),
     ## 'revdb_track_object':   LLOp(),
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
@@ -5,10 +5,11 @@
 CMD_QUIT     = -2
 CMD_FORWARD  = -3
 
-ANSWER_INIT    = -20
-ANSWER_STD     = -21
-ANSWER_FORKED  = -22
-ANSWER_AT_END  = -23
+ANSWER_INIT       = -20
+ANSWER_STD        = -21
+ANSWER_FORKED     = -22
+ANSWER_AT_END     = -23
+ANSWER_BREAKPOINT = -24
 
 
 class Message(object):
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
@@ -3,6 +3,11 @@
 from rpython.translator.revdb.message import *
 
 
+class Breakpoint(Exception):
+    def __init__(self, num):
+        self.num = num
+
+
 class ReplayProcess(object):
     """Represent one replaying subprocess.
 
@@ -73,8 +78,18 @@
     def forward(self, steps):
         """Move this subprocess forward in time."""
         self.send(Message(CMD_FORWARD, steps))
-        msg = self.expect(ANSWER_STD, Ellipsis, Ellipsis)
+        #
+        msg = self.recv()
+        if msg.cmd == ANSWER_BREAKPOINT:
+            bkpt_num = msg.arg3
+            msg = self.recv()
+        else:
+            bkpt_num = None
+        assert msg.cmd == ANSWER_STD
         self.update_times(msg)
+        #
+        if bkpt_num is not None:
+            raise Breakpoint(bkpt_num)
         return msg
 
 
@@ -83,7 +98,7 @@
     """
     MAX_SUBPROCESSES = 31       # maximum number of subprocesses
     STEP_RATIO = 0.25           # subprocess n is between subprocess n-1
-                                #   and the end, at this time fraction
+                                #   and the end, at this fraction of interval
 
     def __init__(self, executable, revdb_log_filename):
         s1, s2 = socket.socketpair()
@@ -120,7 +135,7 @@
             next_time = latest_done + int(self.STEP_RATIO * range_not_done) + 1
         return next_time
 
-    def forward(self, steps):
+    def go_forward(self, steps):
         """Go forward, for the given number of 'steps' of time.
 
         If needed, it will leave clones at intermediate times.
@@ -151,7 +166,9 @@
     def jump_in_time(self, target_time):
         """Jump in time at the given 'target_time'.
 
-        This function can close the active subprocess.
+        This function can close the active subprocess.  But you should
+        remove the breakpoints first, in case the same subprocess remains
+        active.
         """
         if target_time < 1:
             target_time = 1
@@ -161,8 +178,8 @@
         cur_time = self.get_current_time()
         if target_time >= cur_time:    # can go forward
             if cur_time >= max(self.paused):  # current time is past all forks
-                self.forward(target_time - cur_time)
+                self.go_forward(target_time - cur_time)
                 return
         # else, start from a fork
         self._resume(max(time for time in self.paused if time <= target_time))
-        self.forward(target_time - self.get_current_time())
+        self.go_forward(target_time - self.get_current_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
@@ -196,10 +196,11 @@
 #define CMD_QUIT     (-2)
 #define CMD_FORWARD  (-3)
 
-#define ANSWER_INIT    (-20)
-#define ANSWER_STD     (-21)
-#define ANSWER_FORKED  (-22)
-#define ANSWER_AT_END  (-23)
+#define ANSWER_INIT       (-20)
+#define ANSWER_STD        (-21)
+#define ANSWER_FORKED     (-22)
+#define ANSWER_AT_END     (-23)
+#define ANSWER_BREAKPOINT (-24)
 
 typedef void (*rpy_revdb_command_fn)(rpy_revdb_command_t *, RPyString *);
 
@@ -640,27 +641,24 @@
         pending_after_forward = callback;
         break;
 
-    case 'k':       /* breakpoint */
-        if (time <= 0) {
-            fprintf(stderr, "revdb.breakpoint(): non-positive amount of "
-                            "steps\n");
-            exit(1);
-        }
-        if (stopped_time != 0) {
-            fprintf(stderr, "revdb.breakpoint(): cannot be called from a "
-                            "debug command\n");
-            exit(1);
-        }
-        rpy_revdb.stop_point_break = rpy_revdb.stop_point_seen + time;
-        pending_after_forward = callback;
-        break;
-
     default:
         abort();    /* unreachable */
     }
 }
 
 RPY_EXTERN
+void rpy_reverse_db_breakpoint(int64_t num)
+{
+    if (stopped_time != 0) {
+        fprintf(stderr, "revdb.breakpoint(): cannot be called from a "
+                        "debug command\n");
+        exit(1);
+    }
+    rpy_revdb.stop_point_break = rpy_revdb.stop_point_seen + 1;
+    write_answer(ANSWER_BREAKPOINT, rpy_revdb.stop_point_break, 0, num);
+}
+
+RPY_EXTERN
 long long rpy_reverse_db_get_value(char value_id)
 {
     switch (value_id) {
diff --git a/rpython/translator/revdb/src-revdb/revdb_include.h b/rpython/translator/revdb/src-revdb/revdb_include.h
--- a/rpython/translator/revdb/src-revdb/revdb_include.h
+++ b/rpython/translator/revdb/src-revdb/revdb_include.h
@@ -87,6 +87,9 @@
 #define OP_REVDB_CHANGE_TIME(mode, time, callback, r)                   \
     rpy_reverse_db_change_time(mode, time, callback)
 
+#define OP_REVDB_BREAKPOINT(num, r)                                     \
+    rpy_reverse_db_breakpoint(num)
+
 #define OP_REVDB_GET_VALUE(value_id, r)                                 \
     r = rpy_reverse_db_get_value(value_id)
 
@@ -108,6 +111,7 @@
 RPY_EXTERN Signed rpy_reverse_db_identityhash(struct pypy_header0 *obj);
 RPY_EXTERN void rpy_reverse_db_change_time(char mode, long long time,
                                            void callback(void));
+RPY_EXTERN void rpy_reverse_db_breakpoint(int64_t num);
 RPY_EXTERN long long rpy_reverse_db_get_value(char value_id);
 RPY_EXTERN uint64_t rpy_reverse_db_unique_id_break(void *new_object);
 RPY_EXTERN void rpy_reverse_db_track_object(long long unique_id,
diff --git a/rpython/translator/revdb/test/test_process.py b/rpython/translator/revdb/test/test_process.py
--- a/rpython/translator/revdb/test/test_process.py
+++ b/rpython/translator/revdb/test/test_process.py
@@ -1,6 +1,8 @@
+import py
 from rpython.rlib import revdb
+from rpython.rlib.debug import debug_print
 from rpython.translator.revdb.message import *
-from rpython.translator.revdb.process import ReplayProcessGroup
+from rpython.translator.revdb.process import ReplayProcessGroup, Breakpoint
 
 from hypothesis import given, strategies
 
@@ -14,13 +16,24 @@
             pass
 
         class DBState:
-            pass
+            break_loop = -1
         dbstate = DBState()
 
+        def blip(cmd, extra):
+            debug_print('<<<', cmd.c_cmd, cmd.c_arg1,
+                               cmd.c_arg2, cmd.c_arg3, extra, '>>>')
+            if extra == 'set-breakpoint':
+                dbstate.break_loop = cmd.c_arg1
+            revdb.send_answer(42, cmd.c_cmd, -43, -44, extra)
+        lambda_blip = lambda: blip
+
         def main(argv):
+            revdb.register_debug_command(1, lambda_blip)
             for i, op in enumerate(argv[1:]):
                 dbstate.stuff = Stuff()
                 dbstate.stuff.x = i + 1000
+                if dbstate.break_loop == i:
+                    revdb.breakpoint(99)
                 revdb.stop_point()
                 print op
             return 9
@@ -36,7 +49,7 @@
 
     def test_forward(self):
         group = ReplayProcessGroup(str(self.exename), self.rdbname)
-        group.forward(100)
+        group.go_forward(100)
         assert group.get_current_time() == 10
         assert sorted(group.paused) == [1, 4, 6, 8, 9, 10]
         assert group._check_current_time(10)
@@ -47,3 +60,11 @@
         for target_time in target_times:
             group.jump_in_time(target_time)
             group._check_current_time(target_time)
+
+    def test_breakpoint(self):
+        group = ReplayProcessGroup(str(self.exename), self.rdbname)
+        group.active.send(Message(1, 6, extra='set-breakpoint'))
+        group.active.expect(42, 1, -43, -44, 'set-breakpoint')
+        e = py.test.raises(Breakpoint, group.go_forward, 10)
+        assert e.value.num == 99
+        group._check_current_time(7)


More information about the pypy-commit mailing list