Author: Armin Rigo <[email protected]>
Branch: reverse-debugger
Changeset: r85241:813b058bf361
Date: 2016-06-20 13:01 +0200
http://bitbucket.org/pypy/pypy/changeset/813b058bf361/

Log:    Breakpoints

diff --git a/rpython/rlib/revdb.py b/rpython/rlib/revdb.py
--- a/rpython/rlib/revdb.py
+++ b/rpython/rlib/revdb.py
@@ -10,10 +10,11 @@
 from rpython.rtyper.lltypesystem import rffi
 
 
-CMD_PRINT     = 1
-CMD_BACKTRACE = 2
-CMD_LOCALS    = 3
-ANSWER_TEXT   = 20
+CMD_PRINT       = 1
+CMD_BACKTRACE   = 2
+CMD_LOCALS      = 3
+CMD_BREAKPOINTS = 4
+ANSWER_TEXT     = 20
 
 
 def stop_point():
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
@@ -2,6 +2,7 @@
 import subprocess, socket
 import traceback
 from rpython.translator.revdb.process import ReplayProcessGroup, maxint64
+from rpython.translator.revdb.process import Breakpoint
 
 r_cmdline = re.compile(r"(\S+)\s*(.*)")
 
@@ -91,11 +92,17 @@
         """Run forward ARG steps (default 1)"""
         arg = int(argument or '1')
         if self.pgroup.is_tainted():
-            self.pgroup.jump_in_time(self.pgroup.get_current_time() + arg)
-        else:
-            self.pgroup.go_forward(arg)
+            self.pgroup.jump_in_time(self.pgroup.get_current_time())
+            assert not self.pgroup.is_tainted()
+        self.move_forward(arg)
     command_s = command_step
 
+    def move_forward(self, steps):
+        try:
+            self.pgroup.go_forward(steps)
+        except Breakpoint as b:
+            print 'Hit breakpoint %d' % (b.num,)
+
     def command_bstep(self, argument):
         """Run backward ARG steps (default 1)"""
         arg = int(argument or '1')
@@ -104,7 +111,8 @@
 
     def command_continue(self, argument):
         """Run forward"""
-        self.pgroup.jump_in_time(maxint64)
+        self.move_forward(self.pgroup.get_max_time() -
+                          self.pgroup.get_current_time())
     command_c = command_continue
 
     def command_print(self, argument):
@@ -120,3 +128,21 @@
     def command_locals(self, argument):
         """Show the locals"""
         self.pgroup.show_locals()
+
+    def command_break(self, argument):
+        """Add a breakpoint"""
+        new = 1
+        while new in self.pgroup.breakpoints:
+            new += 1
+        self.pgroup.breakpoints[new] = argument
+        print "Breakpoint %d added" % (new,)
+    command_b = command_break
+
+    def command_delete(self, argument):
+        """Delete a breakpoint"""
+        arg = int(argument)
+        if arg not in self.pgroup.breakpoints:
+            print "No breakpoint number %d" % (new,)
+        else:
+            del self.pgroup.breakpoints[arg]
+            print "Breakpoint %d deleted" % (new,)
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
@@ -6,9 +6,10 @@
 CMD_FORWARD  = -3
 # extra commands which are not handled by revdb.c, but
 # by revdb.register_debug_command()
-CMD_PRINT     = 1
-CMD_BACKTRACE = 2
-CMD_LOCALS    = 3
+CMD_PRINT       = 1
+CMD_BACKTRACE   = 2
+CMD_LOCALS      = 3
+CMD_BREAKPOINTS = 4
 
 ANSWER_INIT       = -20
 ANSWER_STD        = -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
@@ -1,4 +1,5 @@
 import sys, os, struct, socket, errno, subprocess
+from contextlib import contextmanager
 from rpython.translator.revdb import ancillary
 from rpython.translator.revdb.message import *
 
@@ -17,10 +18,11 @@
     It can be either the one started with --revdb-replay, or a fork.
     """
 
-    def __init__(self, pid, control_socket):
+    def __init__(self, pid, control_socket, breakpoints_cache={}):
         self.pid = pid
         self.control_socket = control_socket
         self.tainted = False
+        self.breakpoints_cache = breakpoints_cache    # don't change this dict
 
     def _recv_all(self, size):
         pieces = []
@@ -56,6 +58,10 @@
             assert msg.extra == extra
         return msg
 
+    def expect_std(self):
+        msg = self.expect(ANSWER_STD, Ellipsis, Ellipsis)
+        self.update_times(msg)
+
     def update_times(self, msg):
         self.current_time = msg.arg1
         self.currently_created_objects = msg.arg2
@@ -71,7 +77,8 @@
         msg = self.expect(ANSWER_FORKED, Ellipsis, Ellipsis, Ellipsis)
         self.update_times(msg)
         child_pid = msg.arg3
-        other = ReplayProcess(child_pid, s1)
+        other = ReplayProcess(child_pid, s1,
+                              breakpoints_cache=self.breakpoints_cache)
         other.update_times(msg)
         return other
 
@@ -129,11 +136,11 @@
         child = ReplayProcess(initial_subproc.pid, s1)
         msg = child.expect(ANSWER_INIT, INIT_VERSION_NUMBER, Ellipsis)
         self.total_stop_points = msg.arg2
-        msg = child.expect(ANSWER_STD, 1, Ellipsis)
-        child.update_times(msg)
+        child.expect_std()
 
         self.active = child
         self.paused = {1: child.clone()}     # {time: subprocess}
+        self.breakpoints = {}
 
     def get_current_time(self):
         return self.active.current_time
@@ -166,6 +173,7 @@
         is_tainted() must return false in order to use this.
         """
         assert steps >= 0
+        self.update_breakpoints()
         while True:
             cur_time = self.get_current_time()
             if cur_time + steps > self.total_stop_points:
@@ -182,6 +190,19 @@
             self.paused[clone.current_time] = clone
         self.active.forward(steps)
 
+    def update_breakpoints(self):
+        if self.active.breakpoints_cache != self.breakpoints:
+            if self.breakpoints:
+                breakpoints = [self.breakpoints.get(n, '')
+                               for n in range(max(self.breakpoints) + 1)]
+            else:
+                breakpoints = []
+            extra = '\x00'.join(breakpoints)
+            self.active.breakpoints_cache = None
+            self.active.send(Message(CMD_BREAKPOINTS, extra=extra))
+            self.active.expect_std()
+            self.active.breakpoints_cache = self.breakpoints.copy()
+
     def _resume(self, from_time):
         clone_me = self.paused[from_time]
         self.active.close()
@@ -197,7 +218,17 @@
         if target_time > self.total_stop_points:
             target_time = self.total_stop_points
         self._resume(max(time for time in self.paused if time <= target_time))
-        self.go_forward(target_time - self.get_current_time())
+        with self._breakpoints_disabled():
+            self.go_forward(target_time - self.get_current_time())
+
+    @contextmanager
+    def _breakpoints_disabled(self):
+        old =  self.breakpoints
+        self.breakpoints = {}
+        try:
+            yield
+        finally:
+            self.breakpoints = old
 
     def close(self):
         """Close all subprocesses.
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to