[pypy-commit] pypy reverse-debugger: in-progress

arigo pypy.commits at gmail.com
Wed Jun 29 02:19:15 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: reverse-debugger
Changeset: r85442:1e8833dfdd80
Date: 2016-06-29 08:20 +0200
http://bitbucket.org/pypy/pypy/changeset/1e8833dfdd80/

Log:	in-progress

diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -813,9 +813,11 @@
     def fget_f_builtins(self, space):
         return self.get_builtin().getdict(space)
 
+    def get_f_back(self):
+        return ExecutionContext.getnextframe_nohidden(self)
+
     def fget_f_back(self, space):
-        f_back = ExecutionContext.getnextframe_nohidden(self)
-        return self.space.wrap(f_back)
+        return self.space.wrap(self.get_f_back())
 
     def fget_f_lasti(self, space):
         return self.space.wrap(self.last_instr)
diff --git a/pypy/interpreter/reverse_debugging.py b/pypy/interpreter/reverse_debugging.py
--- a/pypy/interpreter/reverse_debugging.py
+++ b/pypy/interpreter/reverse_debugging.py
@@ -1,7 +1,9 @@
 import sys
 from rpython.rlib import revdb
 from rpython.rlib.debug import make_sure_not_resized
-from pypy.interpreter.error import oefmt
+from pypy.interpreter.error import OperationError, oefmt
+from pypy.interpreter.baseobjspace import W_Root
+from pypy.interpreter import gateway, typedef
 
 
 class DBState:
@@ -17,8 +19,8 @@
     #make_sure_not_resized(dbstate.breakpoint_funcnames)
     #make_sure_not_resized(dbstate.watch_progs)
     make_sure_not_resized(dbstate.metavars)
-    #revdb.register_debug_command(revdb.CMD_PRINT, lambda_print)
-    #revdb.register_debug_command(revdb.CMD_BACKTRACE, lambda_backtrace)
+    revdb.register_debug_command(revdb.CMD_PRINT, lambda_print)
+    revdb.register_debug_command(revdb.CMD_BACKTRACE, lambda_backtrace)
     #revdb.register_debug_command(revdb.CMD_LOCALS, lambda_locals)
     #revdb.register_debug_command(revdb.CMD_BREAKPOINTS, lambda_breakpoints)
     #revdb.register_debug_command(revdb.CMD_MOREINFO, lambda_moreinfo)
@@ -39,3 +41,103 @@
                     "'$%d' refers to an object created later in time",
                     oparg)
     return w_var
+
+def fetch_cur_frame():
+    ec = dbstate.space.getexecutioncontext()
+    frame = ec.topframeref()
+    if frame is None:
+        revdb.send_output("No stack.\n")
+    return frame
+
+def compile(source, mode):
+    space = dbstate.space
+    compiler = space.createcompiler()
+    code = compiler.compile(source, '<revdb>', mode, 0,
+                            hidden_applevel=True)
+    return code
+
+
+class W_RevDBOutput(W_Root):
+    softspace = 0
+
+    def __init__(self, space):
+        self.space = space
+
+    def descr_write(self, w_buffer):
+        space = self.space
+        if space.isinstance_w(w_buffer, space.w_unicode):
+            w_buffer = space.call_method(w_buffer, 'encode',
+                                         space.wrap('utf-8'))   # safe?
+        revdb.send_output(space.str_w(w_buffer))
+
+W_RevDBOutput.typedef = typedef.TypeDef(
+    "revdb_output",
+    write = gateway.interp2app(W_RevDBOutput.descr_write),
+    softspace = typedef.interp_attrproperty("softspace", W_RevDBOutput),
+    )
+
+
+def command_print(cmd, expression):
+    frame = fetch_cur_frame()
+    if frame is None:
+        return
+    space = dbstate.space
+    try:
+        code = compile(expression, 'exec')
+        w_revdb_output = space.wrap(W_RevDBOutput(space))
+        space.sys.setdictvalue(space, 'stdout', w_revdb_output)
+        space.sys.setdictvalue(space, 'stderr', w_revdb_output)
+        try:
+            code.exec_code(space,
+                           frame.get_w_globals(),
+                           frame.getdictscope())
+
+        except OperationError as operationerr:
+            w_type = operationerr.w_type
+            w_value = operationerr.get_w_value(space)
+            w_traceback = space.wrap(operationerr.get_traceback())
+
+            # set the sys.last_xxx attributes
+            space.setitem(space.sys.w_dict, space.wrap('last_type'), w_type)
+            space.setitem(space.sys.w_dict, space.wrap('last_value'), w_value)
+            space.setitem(space.sys.w_dict, space.wrap('last_traceback'),
+                          w_traceback)
+
+            # call sys.excepthook if present
+            w_hook = space.sys.getdictvalue(space, 'excepthook')
+            if w_hook is None:
+                raise
+            space.call_function(w_hook, w_type, w_value, w_traceback)
+            return
+
+    except OperationError as e:
+        revdb.send_output('%s\n' % e.errorstr(space, use_repr=True))
+        return
+lambda_print = lambda: command_print
+
+
+def show_frame(frame, indent=''):
+    code = frame.getcode()
+    lineno = frame.get_last_lineno()
+    revdb.send_output('%sFile "%s", line %d in %s\n%s  ' % (
+        indent, code.co_filename, lineno, code.co_name, indent))
+    revdb.send_linecache(code.co_filename, lineno)
+
+def command_backtrace(cmd, extra):
+    frame = fetch_cur_frame()
+    if frame is None:
+        return
+    if cmd.c_arg1 == 0:
+        show_frame(frame)
+    else:
+        revdb.send_output("Traceback (most recent call last):\n")
+        frames = []
+        while frame is not None:
+            frames.append(frame)
+            if len(frames) == 200:
+                revdb.send_output("  ...\n")
+                break
+            frame = frame.get_f_back()
+        while len(frames) > 0:
+            show_frame(frames.pop(), indent='  ')
+lambda_backtrace = lambda: command_backtrace
diff --git a/rpython/rlib/revdb.py b/rpython/rlib/revdb.py
--- a/rpython/rlib/revdb.py
+++ b/rpython/rlib/revdb.py
@@ -18,6 +18,7 @@
 CMD_ATTACHID    = 6
 CMD_CHECKWATCH  = 7
 CMD_WATCHVALUES = 8
+ANSWER_LINECACHE= 19
 ANSWER_TEXT     = 20
 ANSWER_MOREINFO = 21
 ANSWER_NEXTNID  = 22
@@ -49,6 +50,9 @@
 def send_watch(text, ok_flag):
     send_answer(ANSWER_WATCH, ok_flag, extra=text)
 
+def send_linecache(filename, linenum):
+    send_answer(ANSWER_LINECACHE, linenum, extra=filename)
+
 def current_time():
     """For RPython debug commands: returns the current time."""
     return llop.revdb_get_value(lltype.SignedLongLong, 'c')
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
@@ -47,6 +47,10 @@
 # if breakpoint_mode=='i': ignored, never sent
 ANSWER_BREAKPOINT = -24
 
+# print one line of a file to the console, for CMD_PRINT
+#    Message(ANSWER_LINECACHE, linenum, extra=filename)
+ANSWER_LINECACHE  = 19
+
 # print text to the console, for CMD_PRINT and others
 #    Message(ANSWER_TEXT, extra=text)
 ANSWER_TEXT       = 20
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
+import linecache
 from rpython.translator.revdb import ancillary
 from rpython.translator.revdb.message import *
 
@@ -170,6 +171,12 @@
             elif msg.cmd == ANSWER_READY:
                 self.update_times(msg)
                 break
+            elif msg.cmd == ANSWER_LINECACHE:
+                line = linecache.getline(msg.extra, msg.arg1)
+                if not line.endswith('\n'):
+                    line += '\n'
+                sys.stdout.write(line)
+                sys.stdout.flush()
             elif msg.cmd == ANSWER_NEXTNID and pgroup is not None:
                 uid = msg.arg1
                 if uid < pgroup.initial_uid:
@@ -507,6 +514,8 @@
     def show_backtrace(self, complete=1):
         """Show the backtrace.
         """
+        if complete:
+            self.active.tainted = True
         self.active.send(Message(CMD_BACKTRACE, complete))
         self.active.print_text_answer()
 


More information about the pypy-commit mailing list