Author: Armin Rigo <[email protected]>
Branch: reverse-debugger
Changeset: r85224:31c1d222566e
Date: 2016-06-18 09:05 +0200
http://bitbucket.org/pypy/pypy/changeset/31c1d222566e/

Log:    Start the Python-side command-line reverse debugger

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
@@ -399,8 +399,8 @@
                     line += '\nPYPY_INHIBIT_TAIL_CALL();'
                     break
         elif self.db.reverse_debugger:
-            from rpython.translator.revdb import revdb_genc
-            line = revdb_genc.emit(line, self.lltypename(v_result), r)
+            from rpython.translator.revdb import gencsupp
+            line = gencsupp.emit(line, self.lltypename(v_result), r)
         return line
 
     def OP_DIRECT_CALL(self, op):
@@ -441,9 +441,9 @@
             if (S._gckind != 'gc' and not S._hints.get('is_excdata')
                     and not S._hints.get('static_immutable')
                     and not S._hints.get('ignore_revdb')):
-                from rpython.translator.revdb import revdb_genc
-                result = revdb_genc.emit(result, self.lltypename(op.result),
-                                         newvalue)
+                from rpython.translator.revdb import gencsupp
+                result = gencsupp.emit(result, self.lltypename(op.result),
+                                       newvalue)
         return result
 
     def generic_set(self, op, targetexpr):
@@ -455,8 +455,8 @@
         if self.db.reverse_debugger:
             S = self.lltypemap(op.args[0]).TO
             if S._gckind != 'gc' and not S._hints.get('is_excdata'):
-                from rpython.translator.revdb import revdb_genc
-                result = revdb_genc.emit_void(result)
+                from rpython.translator.revdb import gencsupp
+                result = gencsupp.emit_void(result)
         return result
 
     def OP_GETFIELD(self, op, ampersand=''):
@@ -586,8 +586,8 @@
             expr_result,
             is_atomic)
         if self.db.reverse_debugger:
-            from rpython.translator.revdb import revdb_genc
-            res += revdb_genc.record_malloc_uid(expr_result)
+            from rpython.translator.revdb import gencsupp
+            res += gencsupp.record_malloc_uid(expr_result)
         return res
 
     def OP_BOEHM_MALLOC(self, op):
diff --git a/rpython/translator/c/genc.py b/rpython/translator/c/genc.py
--- a/rpython/translator/c/genc.py
+++ b/rpython/translator/c/genc.py
@@ -160,8 +160,8 @@
             self.c_entrypoint_name = pfname
 
         if self.config.translation.reverse_debugger:
-            from rpython.translator.revdb import revdb_genc
-            revdb_genc.prepare_database(db)
+            from rpython.translator.revdb import gencsupp
+            gencsupp.prepare_database(db)
 
         for obj in exports.EXPORTS_obj2name.keys():
             db.getcontainernode(obj)
@@ -855,8 +855,8 @@
     if _CYGWIN:
         files.append(srcdir / 'cygwin_wait.c')
     if database.reverse_debugger:
-        from rpython.translator.revdb import revdb_genc
-        files += revdb_genc.extra_files()
+        from rpython.translator.revdb import gencsupp
+        files += gencsupp.extra_files()
     return eci.merge(ExternalCompilationInfo(separate_module_files=files))
 
 
diff --git a/rpython/translator/revdb/ancillary.py 
b/rpython/translator/revdb/ancillary.py
--- a/rpython/translator/revdb/ancillary.py
+++ b/rpython/translator/revdb/ancillary.py
@@ -1,5 +1,5 @@
+import py
 import os, sys
-from rpython.tool.udir import udir
 
 
 def build(tmpdir):
@@ -22,8 +22,12 @@
 
     ffibuilder.compile(tmpdir=tmpdir, verbose=True)
 
-def import_():
-    tmpdir = str(udir.ensure('ancillary', dir=1))
+def import_(verbose=False):
+    import rpython
+    basedir = py.path.local(rpython.__file__).dirpath()
+    tmpdir = str(basedir.ensure('_cache', 'ancillary', dir=1))
+    if verbose:
+        print tmpdir
     old_sys_path = sys.path[:]
     sys.path.insert(0, tmpdir)
     try:
@@ -50,4 +54,4 @@
 
 
 if __name__ == '__main__':
-    import_()
+    import_(verbose=True)
diff --git a/rpython/translator/revdb/revdb_genc.py 
b/rpython/translator/revdb/gencsupp.py
rename from rpython/translator/revdb/revdb_genc.py
rename to rpython/translator/revdb/gencsupp.py
diff --git a/rpython/translator/revdb/interact.py 
b/rpython/translator/revdb/interact.py
new file mode 100644
--- /dev/null
+++ b/rpython/translator/revdb/interact.py
@@ -0,0 +1,76 @@
+import sys, re
+import subprocess, socket
+import traceback
+from rpython.translator.revdb.message import *
+
+r_cmdline = re.compile(r"(\S+)\s*(.*)")
+
+
+class RevDebugControl(object):
+
+    def __init__(self, revdb_log_filename, executable=None):
+        with open(revdb_log_filename, 'rb') as f:
+            header = f.readline()
+        fields = header.split('\t')
+        if len(fields) < 2 or fields[0] != 'RevDB:':
+            raise ValueError("file %r is not a RevDB log" % (
+                revdb_log_filename,))
+        if executable is None:
+            executable = fields[1]
+        #
+        s1, s2 = socket.socketpair()
+        subproc = subprocess.Popen(
+            [executable, '--revdb-replay', revdb_log_filename,
+             str(s2.fileno())])
+        s2.close()
+        self.subproc = subproc
+        child = ReplayProcess(subproc.pid, s1)
+        msg = child.expect(ANSWER_INIT, INIT_VERSION_NUMBER, Ellipsis)
+        self.total_stop_points = msg.arg2
+        child.expect(ANSWER_STD, 1, Ellipsis)
+        self.active_child = child
+        self.paused_children = {}
+
+    def interact(self):
+        last_command = ''
+        while True:
+            prompt = '(%d)$ ' % self.active_child.current_time()
+            try:
+                cmdline = raw_input(prompt).strip()
+            except EOFError:
+                print
+                cmdline = 'quit'
+            if not cmdline:
+                cmdline = last_command
+            match = r_cmdline.match(cmdline)
+            if not match:
+                continue
+            command, argument = match.groups()
+            try:
+                runner = getattr(self, 'command_' + command)
+            except AttributeError:
+                print >> sys.stderr, "no command '%s', try 'help'" % (command,)
+            else:
+                try:
+                    runner(argument)
+                except Exception as e:
+                    for line in traceback.format_exception_only(type(e), e):
+                        sys.stderr.write(line)
+                last_command = cmdline
+
+    def command_help(self, argument):
+        """Display commands summary"""
+        print 'Available commands:'
+        for name in dir(self):
+            if name.startswith('command_'):
+                command = name[len('command_'):]
+                docstring = getattr(self, name).__doc__ or 'undocumented'
+                print '\t%s\t%s' % (command, docstring)
+
+    def command_quit(self, argument):
+        """Exit the reverse debugger"""
+        sys.exit(0)
+
+    def command_go(self, argument):
+        """Go to time ARG"""
+        target_time = int(argument)
diff --git a/rpython/translator/revdb/revmsg.py 
b/rpython/translator/revdb/message.py
rename from rpython/translator/revdb/revmsg.py
rename to rpython/translator/revdb/message.py
--- a/rpython/translator/revdb/revmsg.py
+++ b/rpython/translator/revdb/message.py
@@ -88,3 +88,13 @@
 
     def close(self):
         self.send(Message(CMD_QUIT))
+
+    def forward(self, steps):
+        self.send(Message(CMD_FORWARD, steps))
+        return self.expect(ANSWER_STD, Ellipsis, Ellipsis)
+
+    def current_time(self):
+        return self.forward(0).arg1
+
+    def currently_created_objects(self):
+        return self.forward(0).arg2
diff --git a/rpython/translator/revdb/revdb.py 
b/rpython/translator/revdb/revdb.py
new file mode 100755
--- /dev/null
+++ b/rpython/translator/revdb/revdb.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+
+import sys, os
+
+
+if __name__ == '__main__':
+    import argparse
+    parser = argparse.ArgumentParser(description='Reverse debugger')
+    parser.add_argument('log', metavar='LOG', help='log file name')
+    parser.add_argument('-x', '--executable', dest='executable',
+                        help='name of the executable file '
+                             'that recorded the log')
+    options = parser.parse_args(sys.argv[1:])
+
+    sys.path.insert(0, os.path.abspath(
+        os.path.join(__file__, '..', '..', '..', '..')))
+
+    from rpython.translator.revdb.interact import RevDebugControl
+    ctrl = RevDebugControl(options.log, executable=options.executable)
+    ctrl.interact()
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
@@ -120,7 +120,7 @@
 
         write_all(RDB_SIGNATURE, strlen(RDB_SIGNATURE));
         for (i = 0; i < argc; i++) {
-            write_all(" ", 1);
+            write_all("\t", 1);
             write_all(argv[i], strlen(argv[i]));
         }
         write_all("\n\0", 2);
@@ -336,7 +336,7 @@
     }
     fprintf(stderr, "%s", RDB_SIGNATURE);
     while ((read_all(input, 1), input[0] != 0))
-        fputc(input[0], stderr);
+        fputc(input[0] == '\t' ? ' ' : input[0], stderr);
 
     read_all(&h, sizeof(h));
     if (h.version != RDB_VERSION) {
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
@@ -9,7 +9,7 @@
 from rpython.rtyper.annlowlevel import cast_gcref_to_instance
 from rpython.rtyper.lltypesystem import lltype, llmemory
 
-from rpython.translator.revdb.revmsg import *
+from rpython.translator.revdb.message import *
 
 
 class RDB(object):
@@ -17,7 +17,7 @@
         with open(filename, 'rb') as f:
             header = f.readline()
             self.buffer = f.read()
-        assert header == 'RevDB: ' + ' '.join(expected_argv) + '\n'
+        assert header == 'RevDB:\t' + '\t'.join(expected_argv) + '\n'
         #
         self.cur = 0
         x = self.next('c'); assert x == '\x00'
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to