Author: Armin Rigo <[email protected]>
Branch: reverse-debugger
Changeset: r85253:b894a632f9e3
Date: 2016-06-20 20:04 +0200
http://bitbucket.org/pypy/pypy/changeset/b894a632f9e3/

Log:    next/bnext, using temporary breakpoints that must trigger if the
        stack depth is smaller than a limit

diff --git a/rpython/rlib/revdb.py b/rpython/rlib/revdb.py
--- a/rpython/rlib/revdb.py
+++ b/rpython/rlib/revdb.py
@@ -14,7 +14,9 @@
 CMD_BACKTRACE   = 2
 CMD_LOCALS      = 3
 CMD_BREAKPOINTS = 4
+CMD_MOREINFO    = 5
 ANSWER_TEXT     = 20
+ANSWER_MOREINFO = 21
 
 
 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
@@ -91,26 +91,34 @@
     def move_forward(self, steps):
         try:
             self.pgroup.go_forward(steps)
+            return True
         except Breakpoint as b:
             self.hit_breakpoint(b)
+            return False
 
     def move_backward(self, steps):
         try:
             self.pgroup.go_backward(steps)
+            return True
         except Breakpoint as b:
             self.hit_breakpoint(b)
+            return False
 
     def hit_breakpoint(self, b):
-        print 'Hit breakpoint %d' % (b.num,)
+        if b.num != -1:
+            print 'Hit breakpoint %d' % (b.num,)
         if self.pgroup.get_current_time() != b.time:
             self.pgroup.jump_in_time(b.time)
 
+    def remove_tainting(self):
+        if self.pgroup.is_tainted():
+            self.pgroup.jump_in_time(self.pgroup.get_current_time())
+            assert not self.pgroup.is_tainted()
+
     def command_step(self, argument):
         """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())
-            assert not self.pgroup.is_tainted()
+        self.remove_tainting()
         self.move_forward(arg)
     command_s = command_step
 
@@ -120,6 +128,43 @@
         self.move_backward(arg)
     command_bs = command_bstep
 
+    def command_next(self, argument):
+        """Run forward for one step, skipping calls"""
+        self.remove_tainting()
+        depth1 = self.pgroup.get_stack_depth()
+        if self.move_forward(1):
+            depth2 = self.pgroup.get_stack_depth()
+            if depth2 > depth1:
+                # If, after running one step, the stack depth is greater
+                # than before, then continue until it is back to what it was.
+                # Can't do it more directly because the "breakpoint" of
+                # stack_depth is only checked for on function enters and
+                # returns (which simplifies and speeds up things for the
+                # RPython code).
+                b = self.pgroup.edit_breakpoints()
+                b.stack_depth = depth1 + 1   # must be < depth1+1
+                try:
+                    self.command_continue('')
+                finally:
+                    b.stack_depth = 0
+    command_n = command_next
+
+    def command_bnext(self, argument):
+        """Run backward for one step, skipping calls"""
+        depth1 = self.pgroup.get_stack_depth()
+        if self.move_backward(1):
+            depth2 = self.pgroup.get_stack_depth()
+            if depth2 > depth1:
+                # If, after running one bstep, the stack depth is greater
+                # than before, then bcontinue until it is back to what it was.
+                b = self.pgroup.edit_breakpoints()
+                b.stack_depth = depth1 + 1   # must be < depth1+1
+                try:
+                    self.command_bcontinue('')
+                finally:
+                    b.stack_depth = 0
+    command_bn = command_bnext
+
     def command_continue(self, argument):
         """Run forward"""
         self.move_forward(self.pgroup.get_max_time() -
@@ -147,18 +192,20 @@
 
     def command_break(self, argument):
         """Add a breakpoint"""
+        b = self.pgroup.edit_breakpoints()
         new = 1
-        while new in self.pgroup.breakpoints:
+        while new in b.num2name:
             new += 1
-        self.pgroup.breakpoints[new] = argument
+        b.num2name[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,)
+        b = self.pgroup.edit_breakpoints()
+        if arg not in b.num2name:
+            print "No breakpoint number %d" % (arg,)
         else:
-            del self.pgroup.breakpoints[arg]
-            print "Breakpoint %d deleted" % (new,)
+            del b.num2name[arg]
+            print "Breakpoint %d deleted" % (arg,)
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
@@ -12,8 +12,9 @@
 CMD_PRINT       = 1    # Message(CMD_PRINT, extra=expression)
 CMD_BACKTRACE   = 2    # Message(CMD_BACKTRACE)
 CMD_LOCALS      = 3    # Message(CMD_LOCALS)
-CMD_BREAKPOINTS = 4    # Message(CMD_BREAKPOINTS, extra="\0-separated names")
-
+CMD_BREAKPOINTS = 4    # Message(CMD_BREAKPOINTS, stack_depth,
+                       #         extra="\0-separated names")
+CMD_MOREINFO    = 5    # Message(CMD_MOREINFO)
 
 
 # the first message sent by the first child:
@@ -45,6 +46,10 @@
 #    Message(ANSWER_TEXT, extra=text)
 ANSWER_TEXT       = 20
 
+# sent after CMD_MOREINFO:
+#    Message(ANSWER_MOREINFO, stack_depth)
+ANSWER_MOREINFO   = 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
@@ -11,6 +11,35 @@
         self.time = time
         self.num = num
 
+    def __repr__(self):
+        return 'Breakpoint(%d, %d)' % (self.time, self.num)
+
+
+class AllBreakpoints(object):
+
+    def __init__(self):
+        self.num2name = {}    # {small number: function name}
+        self.stack_depth = 0     # breaks if the depth becomes lower than this
+
+    def __repr__(self):
+        return 'AllBreakpoints(%r, %d)' % (self.num2name, self.stack_depth)
+
+    def __eq__(self, other):
+        return (self.num2name == other.num2name and
+                self.stack_depth == other.stack_depth)
+
+    def __ne__(self, other):
+        return not (self == other)
+
+    def is_empty(self):
+        return len(self.num2name) == 0 and self.stack_depth == 0
+
+    def duplicate(self):
+        a = AllBreakpoints()
+        a.num2name.update(self.num2name)
+        a.stack_depth = self.stack_depth
+        return a
+
 
 class ReplayProcess(object):
     """Represent one replaying subprocess.
@@ -18,11 +47,11 @@
     It can be either the one started with --revdb-replay, or a fork.
     """
 
-    def __init__(self, pid, control_socket, breakpoints_cache={}):
+    def __init__(self, pid, control_socket, 
breakpoints_cache=AllBreakpoints()):
         self.pid = pid
         self.control_socket = control_socket
         self.tainted = False
-        self.breakpoints_cache = breakpoints_cache    # don't change this dict
+        self.breakpoints_cache = breakpoints_cache    # don't mutate this
 
     def _recv_all(self, size):
         pieces = []
@@ -75,7 +104,7 @@
         ancillary.send_fds(self.control_socket.fileno(), [s2.fileno()])
         s2.close()
         msg = self.expect(ANSWER_FORKED, Ellipsis)
-        child_pid = msg.arg3
+        child_pid = msg.arg1
         self.expect_ready()
         other = ReplayProcess(child_pid, s1,
                               breakpoints_cache=self.breakpoints_cache)
@@ -142,7 +171,7 @@
 
         self.active = child
         self.paused = {1: child.clone()}     # {time: subprocess}
-        self.breakpoints = {}
+        self.all_breakpoints = AllBreakpoints()
 
     def get_current_time(self):
         return self.active.current_time
@@ -214,7 +243,7 @@
         """
         assert steps >= 0
         initial_time = self.get_current_time()
-        if not self.breakpoints:
+        if self.all_breakpoints.is_empty():
             self.jump_in_time(initial_time - steps)
         else:
             self._backward_search_forward(
@@ -242,17 +271,19 @@
             search_start_time -= time_range_to_search * 3
 
     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_ready()
-            self.active.breakpoints_cache = self.breakpoints.copy()
+        if self.active.breakpoints_cache == self.all_breakpoints:
+            return
+        num2name = self.all_breakpoints.num2name
+        flat = []
+        if num2name:
+            flat = [num2name.get(n, '') for n in range(max(num2name) + 1)]
+        arg1 = self.all_breakpoints.stack_depth
+        extra = '\x00'.join(flat)
+        #
+        self.active.breakpoints_cache = None
+        self.active.send(Message(CMD_BREAKPOINTS, arg1, extra=extra))
+        self.active.expect_ready()
+        self.active.breakpoints_cache = self.all_breakpoints.duplicate()
 
     def _resume(self, from_time):
         clone_me = self.paused[from_time]
@@ -296,3 +327,12 @@
         """
         self.active.send(Message(CMD_LOCALS))
         self.active.print_text_answer()
+
+    def edit_breakpoints(self):
+        return self.all_breakpoints
+
+    def get_stack_depth(self):
+        self.active.send(Message(CMD_MOREINFO))
+        msg = self.active.expect(ANSWER_MOREINFO, Ellipsis)
+        self.active.expect_ready()
+        return msg.arg1
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to