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