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