Author: Armin Rigo <ar...@tunes.org>
Branch: reverse-debugger
Changeset: r85314:a9996f5e2819
Date: 2016-06-21 18:45 +0200
http://bitbucket.org/pypy/pypy/changeset/a9996f5e2819/

Log:    in-progress

diff --git a/rpython/rlib/revdb.py b/rpython/rlib/revdb.py
--- a/rpython/rlib/revdb.py
+++ b/rpython/rlib/revdb.py
@@ -15,6 +15,7 @@
 CMD_LOCALS      = 3
 CMD_BREAKPOINTS = 4
 CMD_MOREINFO    = 5
+CMD_ATTACHID    = 6
 ANSWER_TEXT     = 20
 ANSWER_MOREINFO = 21
 ANSWER_NEXTNID  = 22
diff --git a/rpython/translator/c/funcgen.py b/rpython/translator/c/funcgen.py
--- a/rpython/translator/c/funcgen.py
+++ b/rpython/translator/c/funcgen.py
@@ -756,8 +756,8 @@
     def OP_DEBUG_PRINT(self, op):
         # XXX
         from rpython.rtyper.lltypesystem.rstr import STR
-        format = []
-        argv = []
+        format = ['{%d} ']
+        argv = ['(int)getpid()']
         free_line = ""
         for arg in op.args:
             T = arg.concretetype
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
@@ -7,6 +7,7 @@
 from rpython.translator.revdb.process import Breakpoint
 
 r_cmdline = re.compile(r"(\S+)\s*(.*)")
+r_dollar_num = re.compile(r"\$(\d+)\b")
 
 
 class RevDebugControl(object):
@@ -193,7 +194,9 @@
 
     def command_print(self, argument):
         """Print an expression"""
-        self.pgroup.print_cmd(argument)
+        # locate which $NUM appear used in the expression
+        nids = map(int, r_dollar_num.findall(argument))
+        self.pgroup.print_cmd(argument, nids=nids)
     command_p = command_print
 
     def command_backtrace(self, argument):
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
@@ -8,7 +8,6 @@
 CMD_QUIT      = -2     # Message(CMD_QUIT)
 CMD_FORWARD   = -3     # Message(CMD_FORWARD, steps, breakpoint_mode)
 CMD_FUTUREIDS = -4     # Message(CMD_FUTUREIDS, extra=list-of-8bytes-uids)
-CMD_ALLOCATING= -5     # Message(CMD_CREATING, uid, addr)
 # extra commands which are not handled by revdb.c, but
 # by revdb.register_debug_command()
 CMD_PRINT       = 1    # Message(CMD_PRINT, extra=expression)
@@ -17,6 +16,7 @@
 CMD_BREAKPOINTS = 4    # Message(CMD_BREAKPOINTS, stack_depth,
                        #         extra="\0-separated names")
 CMD_MOREINFO    = 5    # Message(CMD_MOREINFO)
+CMD_ATTACHID    = 6    # Message(CMD_ATTACHID, small-num, unique-id)
 
 
 # the first message sent by the first child:
@@ -73,7 +73,13 @@
         self.extra = extra
 
     def __repr__(self):
-        return 'Message(%d, %d, %d, %d, %r)' % (self.cmd, self.arg1,
+        cmd = self.cmd
+        for key, value in globals().items():
+            if (key.startswith('CMD_') or key.startswith('ANSWER_')) and (
+                    value == cmd):
+                cmd = key
+                break
+        return 'Message(%s, %d, %d, %d, %r)' % (cmd, self.arg1,
                                                 self.arg2, self.arg3,
                                                 self.extra)
 
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
@@ -47,11 +47,18 @@
     It can be either the one started with --revdb-replay, or a fork.
     """
 
-    def __init__(self, pid, control_socket, 
breakpoints_cache=AllBreakpoints()):
+    def __init__(self, pid, control_socket,
+                 breakpoints_cache=AllBreakpoints(),
+                 printed_objects=frozenset()):
         self.pid = pid
         self.control_socket = control_socket
         self.tainted = False
         self.breakpoints_cache = breakpoints_cache    # don't mutate this
+        self.printed_objects = printed_objects        # don't mutate this
+        # ^^^ frozenset containing the uids of the objects that are
+        #     either already discovered in this child
+        #     (if uid < currently_created_objects), or that will
+        #     automatically be discovered when we move forward
 
     def _recv_all(self, size):
         pieces = []
@@ -64,6 +71,7 @@
         return ''.join(pieces)
 
     def send(self, msg):
+        print 'SENT:', self.pid, msg
         binary = struct.pack("iIqqq", msg.cmd, len(msg.extra),
                              msg.arg1, msg.arg2, msg.arg3)
         self.control_socket.sendall(binary + msg.extra)
@@ -72,7 +80,9 @@
         binary = self._recv_all(struct.calcsize("iIqqq"))
         cmd, size, arg1, arg2, arg3 = struct.unpack("iIqqq", binary)
         extra = self._recv_all(size)
-        return Message(cmd, arg1, arg2, arg3, extra)
+        msg = Message(cmd, arg1, arg2, arg3, extra)
+        print 'RECV:', self.pid, msg
+        return msg
 
     def expect(self, cmd, arg1=0, arg2=0, arg3=0, extra=""):
         msg = self.recv()
@@ -107,7 +117,8 @@
         child_pid = msg.arg1
         self.expect_ready()
         other = ReplayProcess(child_pid, s1,
-                              breakpoints_cache=self.breakpoints_cache)
+                              breakpoints_cache=self.breakpoints_cache,
+                              printed_objects=self.printed_objects)
         other.expect_ready()
         return other
 
@@ -138,7 +149,7 @@
         self.update_times(msg)
         return bkpt
 
-    def print_text_answer(self):
+    def print_text_answer(self, pgroup=None):
         while True:
             msg = self.recv()
             if msg.cmd == ANSWER_TEXT:
@@ -147,6 +158,16 @@
             elif msg.cmd == ANSWER_READY:
                 self.update_times(msg)
                 break
+            elif msg.cmd == ANSWER_NEXTNID and pgroup is not None:
+                uid = msg.arg1
+                if uid < pgroup.initial_uid:
+                    continue     # created before the first stop point, ignore
+                self.printed_objects = self.printed_objects.union([uid])
+                new_nid = len(pgroup.all_printed_objects_lst)
+                nid = pgroup.all_printed_objects.setdefault(uid, new_nid)
+                if nid == new_nid:
+                    pgroup.all_printed_objects_lst.append(uid)
+                sys.stdout.write('$%d = ' % nid)
             else:
                 print >> sys.stderr, "unexpected message %d" % (msg.cmd,)
 
@@ -168,15 +189,20 @@
         msg = child.expect(ANSWER_INIT, INIT_VERSION_NUMBER, Ellipsis)
         self.total_stop_points = msg.arg2
         child.expect_ready()
+        self.initial_uid = child.currently_created_objects
 
         self.active = child
         self.paused = {1: child.clone()}     # {time: subprocess}
         self.all_breakpoints = AllBreakpoints()
-        self.all_printed_objects = []
+        self.all_printed_objects = {}
+        self.all_printed_objects_lst = []
 
     def get_current_time(self):
         return self.active.current_time
 
+    def get_currently_created_objects(self):
+        return self.active.currently_created_objects
+
     def _check_current_time(self, time):
         assert self.get_current_time() == time
         self.active.send(Message(CMD_FORWARD, 0))
@@ -186,6 +212,19 @@
         return self.total_stop_points
 
     def get_next_clone_time(self):
+        # if 'active' has more printed_objects than the next process
+        # already in 'paused', then we re-clone 'active'.
+        cur_time = self.get_current_time()
+        future = [time for time in self.paused if time > cur_time]
+        if future:
+            for futime in sorted(future):
+                if (self.paused[futime].printed_objects !=
+                        frozenset(self.all_printed_objects_lst)):
+                    # 'futime' is the time of the first "future" childs
+                    # with an incomplete 'printed_objects'.  This will
+                    # be re-cloned.
+                    return futime
+        #
         if len(self.paused) >= self.MAX_SUBPROCESSES:
             next_time = self.total_stop_points + 1
         else:
@@ -228,6 +267,8 @@
                 elif bkpt:
                     raise bkpt
                 steps -= rel_next_clone
+            if self.active.current_time in self.paused:
+                self.paused[self.active.current_time].close()
             clone = self.active.clone()
             self.paused[clone.current_time] = clone
         bkpt = self.active.forward(steps, breakpoint_mode)
@@ -310,13 +351,69 @@
         for subp in [self.active] + self.paused.values():
             subp.close()
 
-    def print_cmd(self, expression):
+    def ensure_printed_objects(self, uids):
+        """Ensure that all the given unique_ids are loaded in the active
+        child, if necessary by forking another child from earlier.
+        """
+        import pdb;pdb.set_trace()
+        initial_time = self.get_current_time()
+        must_go_forward_again = False
+        while True:
+            uid_limit = self.get_currently_created_objects()
+            missing_uids = [uid for uid in uids
+                                if uid < uid_limit
+                                   and uid not in self.active.printed_objects]
+            if not missing_uids:
+                break
+
+            # we need to start with an older fork
+            start_time = self.get_current_time()
+            stop_time = max(time for time in self.paused if time < start_time)
+            self._resume(stop_time)
+            must_go_forward_again = True
+
+        # No missing_uids left: all uids are either already in
+        # self.active.printed_objects, or in the future.
+        future_uids = [uid for uid in uids if uid >= uid_limit]
+        if not must_go_forward_again:
+            assert not future_uids
+        else:
+            future_uids.sort()
+            pack_uids = [struct.pack('q', uid) for uid in future_uids]
+            self.active.send(Message(CMD_FUTUREIDS, extra=''.join(pack_uids)))
+            self.active.expect_ready()
+            self.active.printed_objects = (
+                self.active.printed_objects.union(future_uids))
+            self.go_forward(initial_time - self.get_current_time(),
+                            breakpoint_mode='i')
+        assert self.active.printed_objects.issuperset(uids)
+
+    def print_cmd(self, expression, nids=[]):
         """Print an expression.
         """
+        if nids:
+            uids = []
+            for nid in nids:
+                try:
+                    uid = self.all_printed_objects_lst[nid]
+                except IndexError:
+                    print >> sys.stderr, ("no print command printed any "
+                                          "value for '$%d'" % nid)
+                    return
+                if uid >= self.get_currently_created_objects():
+                    print >> sys.stderr, ("'$%d' refers to an object that is "
+                                          "only created later in time" % nid)
+                    return
+                uids.append(uid)
+            self.ensure_printed_objects(uids)
+        #
         self.active.tainted = True
-        next_nid = len(self.all_printed_objects)
-        self.active.send(Message(CMD_PRINT, next_nid, extra=expression))
-        self.active.print_text_answer()
+        for nid in nids:
+            uid = self.all_printed_objects_lst[nid]
+            self.active.send(Message(CMD_ATTACHID, nid, uid))
+            self.active.expect_ready()
+        self.active.send(Message(CMD_PRINT, extra=expression))
+        self.active.print_text_answer(pgroup=self)
 
     def show_backtrace(self):
         """Show the backtrace.
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to