Author: Armin Rigo <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit