Author: Armin Rigo <[email protected]>
Branch: reverse-debugger
Changeset: r85117:c146f7200672
Date: 2016-06-13 09:45 +0200
http://bitbucket.org/pypy/pypy/changeset/c146f7200672/
Log: Breakpoints
diff --git a/rpython/rlib/revdb.py b/rpython/rlib/revdb.py
--- a/rpython/rlib/revdb.py
+++ b/rpython/rlib/revdb.py
@@ -7,14 +7,14 @@
from rpython.rtyper.annlowlevel import llhelper, hlstr
-def stop_point(n):
+def stop_point():
"""Indicates a point in the execution of the RPython program where
the reverse-debugger can stop. When reverse-debugging, we see
the "time" as the index of the stop-point that happened.
"""
if we_are_translated():
if fetch_translated_config().translation.reverse_debugger:
- llop.revdb_stop_point(lltype.Void, n)
+ llop.revdb_stop_point(lltype.Void)
def register_debug_command(command, lambda_func):
"""Register the extra RPython-implemented debug command."""
@@ -25,18 +25,23 @@
def current_time():
"""For RPython debug commands: returns the current time."""
- return llop.revdb_get_value(lltype.Signed, 'c')
+ return llop.revdb_get_value(lltype.SignedLongLong, 'c')
+
+def current_break_time():
+ """Returns the time configured for the next break. When going forward,
+ this is the target time at which we'll stop going forward."""
+ return llop.revdb_get_value(lltype.SignedLongLong, 'b')
def most_recent_fork():
"""For RPython debug commands: returns the time of the most
recent fork. Going back to that time is fast; going back to a time
just before is slow."""
- return llop.revdb_get_value(lltype.Signed, 'm')
+ return llop.revdb_get_value(lltype.SignedLongLong, 'f')
def total_time():
"""For RPython debug commands: returns the total time (measured
as the total number of stop-points)."""
- return llop.revdb_get_value(lltype.Signed, 't')
+ return llop.revdb_get_value(lltype.SignedLongLong, 't')
@specialize.arg(1)
def go_forward(time_delta, callback, arg_string):
@@ -89,8 +94,8 @@
try:
cmds = t.revdb_commands
except AttributeError:
- cmds = t.revdb_commands = {}
- cmds[command] = func
+ cmds = t.revdb_commands = []
+ cmds.append((command, func))
s_func = self.bookkeeper.immutablevalue(func)
self.bookkeeper.emulate_pbc_call(self.bookkeeper.position_key,
s_func, [annmodel.s_Str0])
diff --git a/rpython/rtyper/lltypesystem/lloperation.py
b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -569,6 +569,7 @@
'revdb_send_output': LLOp(),
'revdb_change_time': LLOp(),
'revdb_get_value': LLOp(sideeffects=False),
+ 'revdb_set_value': LLOp(),
'revdb_identityhash': LLOp(),
}
# ***** Run test_lloperation after changes. *****
diff --git a/rpython/translator/revdb/revdb_genc.py
b/rpython/translator/revdb/revdb_genc.py
--- a/rpython/translator/revdb/revdb_genc.py
+++ b/rpython/translator/revdb/revdb_genc.py
@@ -23,7 +23,7 @@
FUNCPTR = lltype.Ptr(lltype.FuncType([lltype.Ptr(rstr.STR)], lltype.Void))
bk = db.translator.annotator.bookkeeper
- cmds = getattr(db.translator, 'revdb_commands', {}).items()
+ cmds = getattr(db.translator, 'revdb_commands', [])
array_names = lltype.malloc(rffi.CArray(rffi.CCHARP), len(cmds) + 1,
flavor='raw', immortal=True, zero=True)
diff --git a/rpython/translator/revdb/src-revdb/revdb.c
b/rpython/translator/revdb/src-revdb/revdb.c
--- a/rpython/translator/revdb/src-revdb/revdb.c
+++ b/rpython/translator/revdb/src-revdb/revdb.c
@@ -151,15 +151,17 @@
/* Boehm only */
if (obj->h_hash == 0) {
Signed h;
+ if (flag_io_disabled) {
+ /* This is when running debug commands. Don't cache the
+ hash on the object at all. */
+ return ~((Signed)obj);
+ }
/* When recording, we get the hash the normal way from the
pointer casted to an int, and record that. When replaying,
we read it from the record. In both cases, we cache the
hash in the object, so that we record/replay only once per
object. */
- if (flag_io_disabled)
- h = ~((Signed)obj);
- else
- RPY_REVDB_EMIT(h = ~((Signed)obj);, Signed _e, h);
+ RPY_REVDB_EMIT(h = ~((Signed)obj);, Signed _e, h);
assert(h != 0);
obj->h_hash = h;
}
@@ -297,7 +299,7 @@
}
fprintf(stderr, "%s", RDB_SIGNATURE);
while ((read_all(input, 1), input[0] != 0))
- fwrite(input, 1, 1, stderr);
+ fputc(input[0], stderr);
read_all(&h, sizeof(h));
if (h.version != RDB_VERSION) {
@@ -743,18 +745,12 @@
cmd_go(target_time, NULL, NULL);
}
-static void act_info_fork(char *p)
-{
- printf("most_recent_fork=%llu\n", (unsigned long long)most_recent_fork);
-}
-
static void act_info(char *p)
{
- static struct action_s actions_info[] = {
- { "fork", act_info_fork },
- { NULL }
- };
- process_input(p, "category", 0, actions_info);
+ char cmd = *p;
+ if (cmd == 0)
+ cmd = '?';
+ printf("info %c=%lld\n", cmd, (long long)rpy_reverse_db_get_value(cmd));
}
static void act_nop(char *p)
@@ -775,9 +771,9 @@
static void run_debug_process(void)
{
static struct action_s actions_1[] = {
- { "go", act_go },
{ "info", act_info },
{ "quit", act_quit },
+ { "__go", act_go },
{ "__forward", act_forward },
{ "", act_nop },
{ NULL }
@@ -801,7 +797,7 @@
}
RPY_EXTERN
-void rpy_reverse_db_break(long stop_point)
+void rpy_reverse_db_stop_point(void)
{
if (process_kind == PK_MAIN_PROCESS) {
make_new_frozen_process();
@@ -819,7 +815,7 @@
}
RPY_EXTERN
-void rpy_reverse_db_change_time(char mode, Signed time,
+void rpy_reverse_db_change_time(char mode, long long time,
void callback(RPyString *), RPyString *arg)
{
switch (mode) {
@@ -844,15 +840,17 @@
}
RPY_EXTERN
-Signed rpy_reverse_db_get_value(char value_id)
+long long rpy_reverse_db_get_value(char value_id)
{
switch (value_id) {
case 'c': /* current_time() */
return rpy_revdb.stop_point_seen;
- case 'm': /* most_recent_fork() */
+ case 'f': /* most_recent_fork() */
return most_recent_fork;
case 't': /* total_time() */
return total_stop_points;
+ case 'b':
+ return rpy_revdb.stop_point_break;
default:
return -1;
}
diff --git a/rpython/translator/revdb/src-revdb/revdb_include.h
b/rpython/translator/revdb/src-revdb/revdb_include.h
--- a/rpython/translator/revdb/src-revdb/revdb_include.h
+++ b/rpython/translator/revdb/src-revdb/revdb_include.h
@@ -67,9 +67,9 @@
#define RPY_REVDB_EMIT_VOID(normal_code) \
if (!RPY_RDB_REPLAY) { normal_code } else { }
-#define OP_REVDB_STOP_POINT(stop_point, r) \
+#define OP_REVDB_STOP_POINT(r) \
if (++rpy_revdb.stop_point_seen == rpy_revdb.stop_point_break) \
- rpy_reverse_db_break(stop_point)
+ rpy_reverse_db_stop_point()
#define OP_REVDB_SEND_OUTPUT(ll_string, r) \
rpy_reverse_db_send_output(ll_string)
@@ -86,13 +86,13 @@
RPY_EXTERN void rpy_reverse_db_flush(void);
RPY_EXTERN char *rpy_reverse_db_fetch(int expected_size,
const char *file, int line);
-RPY_EXTERN void rpy_reverse_db_break(long stop_point);
+RPY_EXTERN void rpy_reverse_db_stop_point(void);
RPY_EXTERN void rpy_reverse_db_send_output(RPyString *output);
RPY_EXTERN Signed rpy_reverse_db_identityhash(struct pypy_header0 *obj);
-RPY_EXTERN void rpy_reverse_db_change_time(char mode, Signed time,
+RPY_EXTERN void rpy_reverse_db_change_time(char mode, long long time,
void callback(RPyString *),
RPyString *arg);
-RPY_EXTERN Signed rpy_reverse_db_get_value(char value_id);
+RPY_EXTERN long long rpy_reverse_db_get_value(char value_id);
/* ------------------------------------------------------------ */
diff --git a/rpython/translator/revdb/test/test_basic.py
b/rpython/translator/revdb/test/test_basic.py
--- a/rpython/translator/revdb/test/test_basic.py
+++ b/rpython/translator/revdb/test/test_basic.py
@@ -192,7 +192,7 @@
def setup_class(cls):
def main(argv):
for op in argv[1:]:
- revdb.stop_point(42)
+ revdb.stop_point()
print op
return 9
compile(cls, main, [], backendopt=False)
@@ -204,11 +204,11 @@
child = self.replay()
child.expectx('stop_points=3\r\n'
'(3)$ ')
- child.sendline('go 1')
+ child.sendline('__go 1')
child.expectx('(1)$ ')
child.sendline('')
child.expectx('(1)$ ')
- child.sendline('go 52')
+ child.sendline('__go 52')
child.expectx('(3)$ ')
def test_help(self):
@@ -218,12 +218,12 @@
# ...
child.expectx('(3)$ ')
child.sendline('info')
- child.expectx("bad category '', try 'help'\r\n")
+ child.expectx("info ?=-1\r\n")
def test_info_fork(self):
child = self.replay()
child.sendline('info fork')
- child.expectx('most_recent_fork=3\r\n')
+ child.expectx('info f=3\r\n')
def test_quit(self):
child = self.replay()
@@ -232,19 +232,19 @@
def test_forward(self):
child = self.replay()
- child.sendline('go 1')
+ child.sendline('__go 1')
child.expectx('(1)$ ')
child.sendline('__forward 1')
child.expectx('(2)$ ')
child.sendline('__forward 1')
child.expectx('(3)$ ')
child.sendline('info fork')
- child.expectx('most_recent_fork=1\r\n')
+ child.expectx('info f=1\r\n')
child.sendline('__forward 1')
child.expectx('At end.\r\n'
'(3)$ ')
child.sendline('info fork')
- child.expectx('most_recent_fork=3\r\n')
+ child.expectx('info f=3\r\n')
class TestDebugCommands(InteractiveTests):
@@ -267,6 +267,9 @@
if revdb.current_time() != revdb.total_time():
revdb.go_forward(1, went_fw, "zz")
#
+ def _nothing(arg):
+ pass
+ #
def blip(cmdline):
revdb.send_output('<<<' + cmdline + '>>>\n')
if cmdline == 'oops':
@@ -287,13 +290,22 @@
revdb.go_forward(1, went_fw, "xx")
if cmdline == 'change-time':
revdb.jump_in_time(2, changed_time, "xyzzy")
+ if cmdline == 'set-break-after-0':
+ dbstate.break_after = 0
revdb.send_output('blipped\n')
lambda_blip = lambda: blip
#
+ class DBState:
+ break_after = -1
+ dbstate = DBState()
+ #
def main(argv):
revdb.register_debug_command('r', lambda_blip)
- for op in argv[1:]:
- revdb.stop_point(42)
+ for i, op in enumerate(argv[1:]):
+ revdb.stop_point()
+ if i == dbstate.break_after:
+ revdb.send_output('breakpoint!\n')
+ revdb.go_forward(1, _nothing, "")
print op
return 9
compile(cls, main, [], backendopt=False)
@@ -318,7 +330,7 @@
def test_interaction_with_forward(self):
child = self.replay()
child.expectx('(3)$ ')
- child.sendline('go 1')
+ child.sendline('__go 1')
child.expectx('(1)$ ')
child.sendline('r oops')
child.expectx('<<<oops>>>\r\n')
@@ -347,7 +359,7 @@
def test_get_value(self):
child = self.replay()
child.expectx('(3)$ ')
- child.sendline('go 2')
+ child.sendline('__go 2')
child.expectx('(2)$ ')
child.sendline('r get-value')
child.expectx('<<<get-value>>>\r\n'
@@ -358,7 +370,7 @@
def test_go_fw(self):
child = self.replay()
child.expectx('(3)$ ')
- child.sendline('go 1')
+ child.sendline('__go 1')
child.expectx('(1)$ ')
child.sendline('r go-fw')
child.expectx('<<<go-fw>>>\r\n'
@@ -375,3 +387,14 @@
'changed-time xyzzy -> 2\r\n'
'went-fw zz -> 3\r\n'
'(3)$ ')
+
+ def test_dynamic_breakpoint(self):
+ child = self.replay()
+ child.expectx('(3)$ ')
+ child.sendline('__go 1')
+ child.expectx('(1)$ ')
+ child.sendline('r set-break-after-0')
+ child.expectx('(1)$ ')
+ child.sendline('__forward 5')
+ child.expectx('breakpoint!\r\n'
+ '(2)$ ')
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit