[pypy-commit] pypy reverse-debugger: 'next', 'bnext', 'finish', 'bfinish' for Python
arigo
pypy.commits at gmail.com
Wed Jun 29 17:48:18 EDT 2016
Author: Armin Rigo <arigo at tunes.org>
Branch: reverse-debugger
Changeset: r85464:3c619ff91d4b
Date: 2016-06-29 23:49 +0200
http://bitbucket.org/pypy/pypy/changeset/3c619ff91d4b/
Log: 'next', 'bnext', 'finish', 'bfinish' for Python
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -64,6 +64,9 @@
return frame
def enter(self, frame):
+ if self.space.config.translation.reverse_debugger:
+ from pypy.interpreter.reverse_debugging import enter_call
+ enter_call(self.topframeref(), frame)
frame.f_backref = self.topframeref
self.topframeref = jit.virtual_ref(frame)
@@ -84,6 +87,9 @@
# be accessed also later
frame_vref()
jit.virtual_ref_finish(frame_vref, frame)
+ if self.space.config.translation.reverse_debugger:
+ from pypy.interpreter.reverse_debugging import leave_call
+ leave_call(self.topframeref(), frame)
# ________________________________________________________________
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
@@ -10,6 +10,7 @@
class DBState:
extend_syntax_with_dollar_num = False
+ breakpoint_stack_id = 0
breakpoint_funcnames = []
printed_objects = {}
metavars = []
@@ -37,8 +38,8 @@
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)
+ revdb.register_debug_command(revdb.CMD_BREAKPOINTS, lambda_breakpoints)
+ revdb.register_debug_command(revdb.CMD_STACKID, lambda_stackid)
revdb.register_debug_command("ALLOCATING", lambda_allocating)
revdb.register_debug_command(revdb.CMD_ATTACHID, lambda_attachid)
#revdb.register_debug_command(revdb.CMD_CHECKWATCH, lambda_checkwatch)
@@ -48,6 +49,16 @@
pycode.PyCode.co_revdb_linestarts = None # or a string: an array of bits
+def enter_call(caller_frame, callee_frame):
+ if dbstate.breakpoint_stack_id != 0:
+ if dbstate.breakpoint_stack_id == revdb.get_unique_id(caller_frame):
+ revdb.breakpoint(-1)
+
+def leave_call(caller_frame, callee_frame):
+ if dbstate.breakpoint_stack_id != 0:
+ if dbstate.breakpoint_stack_id == revdb.get_unique_id(caller_frame):
+ revdb.breakpoint(-1)
+
def potential_stop_point(frame):
if not we_are_translated():
return
@@ -369,6 +380,22 @@
lambda_locals = lambda: command_locals
+def command_breakpoints(cmd, extra):
+ dbstate.breakpoint_stack_id = cmd.c_arg1
+lambda_breakpoints = lambda: command_breakpoints
+
+def command_stackid(cmd, extra):
+ frame = fetch_cur_frame()
+ if frame is not None and cmd.c_arg1 != 0: # parent_flag
+ frame = dbstate.space.getexecutioncontext().getnextframe_nohidden(frame)
+ if frame is None:
+ uid = 0
+ else:
+ uid = revdb.get_unique_id(frame)
+ revdb.send_answer(revdb.ANSWER_STACKID, uid)
+lambda_stackid = lambda: command_stackid
+
+
def command_allocating(uid, gcref):
w_obj = cast_gcref_to_instance(W_Root, gcref)
dbstate.printed_objects[uid] = w_obj
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
@@ -154,18 +154,20 @@
self.remove_tainting()
try:
self.pgroup.go_forward(steps)
- return True
+ return None
except Breakpoint as b:
self.hit_breakpoint(b)
- return False
+ return b
- def move_backward(self, steps):
+ def move_backward(self, steps, rel_stop_at=-1):
+ ignore_bkpt = steps == 1 and rel_stop_at == -1
try:
- self.pgroup.go_backward(steps, ignore_breakpoints=(steps==1))
- return True
+ self.pgroup.go_backward(steps, ignore_breakpoints=ignore_bkpt,
+ rel_stop_at=rel_stop_at)
+ return None
except Breakpoint as b:
self.hit_breakpoint(b, backward=True)
- return False
+ return b
def hit_breakpoint(self, b, backward=False):
if b.num != -1:
@@ -198,7 +200,7 @@
@contextmanager
def _stack_id_break(self, stack_id):
# add temporarily a breakpoint that hits when we enter/leave
- # the frame identified by 'stack_id'
+ # a frame from/to the frame identified by 'stack_id'
b = self.pgroup.edit_breakpoints()
b.stack_id = stack_id
try:
@@ -208,50 +210,55 @@
def command_next(self, argument):
"""Run forward for one step, skipping calls"""
- depth1 = self.pgroup.get_stack_id()
- with self._stack_id_break(depth1):
- if not self.move_forward(1):
- # we either hit a regular breakpoint, or we hit the
- # temporary breakpoint
- return
- if depth1 == 0: # we started outside any frame
- return
- if self.pgroup.get_stack_id() == depth1:
- return # we are still in the same frame
- #
- # If, after running one step, the stack id is different than
- # before but we didn't leave that frame, then we must have
- # entered a new one. Continue until we leave that new frame.
- # Can't do it more directly because the "breakpoint" of
- # stack_id is only checked for on function enters and returns
- # (which simplifies and speeds up things for the RPython
- # code).
- self.command_finish('')
+ stack_id = self.pgroup.get_stack_id(is_parent=False)
+ with self._stack_id_break(stack_id):
+ b = self.move_forward(1)
+ if b is None:
+ return # no breakpoint hit, and no frame just entered: done
+ elif b.num != -1:
+ return # a regular breakpoint was hit
+ else:
+ # we entered a frame. Continue running until we leave that
+ # frame again
+ with self._stack_id_break(stack_id):
+ self.command_continue("")
command_n = command_next
def command_bnext(self, argument):
"""Run backward for one step, skipping calls"""
- # similar to command_next()
- depth1 = self.pgroup.get_stack_id()
- with self._stack_id_break(depth1):
- if not self.move_backward(1):
- return
- if depth1 == 0:
- return
- if self.pgroup.get_stack_id() == depth1:
- return # we are still in the same frame
- self.command_bfinish('')
+ stack_id = self.pgroup.get_stack_id(is_parent=False)
+ with self._stack_id_break(stack_id):
+ b = self.move_backward(1, rel_stop_at=0)
+ if b is None:
+ return # no breakpoint hit, and no frame just
+ # reverse-entered: done
+ elif b.num != -1:
+ return # a regular breakpoint was hit
+ else:
+ # we reverse-entered a frame. Continue running backward
+ # until we go past the reverse-leave (i.e. the entering)
+ # of that frame.
+ with self._stack_id_break(stack_id):
+ self.command_bcontinue("")
command_bn = command_bnext
def command_finish(self, argument):
"""Run forward until the current function finishes"""
- with self._stack_id_break(self.pgroup.get_stack_id()):
- self.command_continue('')
+ stack_id = self.pgroup.get_stack_id(is_parent=True)
+ if stack_id == 0:
+ print 'No stack.'
+ else:
+ with self._stack_id_break(stack_id):
+ self.command_continue('')
def command_bfinish(self, argument):
"""Run backward until the current function is called"""
- with self._stack_id_break(self.pgroup.get_stack_id()):
- self.command_bcontinue('')
+ stack_id = self.pgroup.get_stack_id(is_parent=True)
+ if stack_id == 0:
+ print 'No stack.'
+ else:
+ with self._stack_id_break(stack_id):
+ self.command_bcontinue('')
def command_continue(self, argument):
"""Run forward"""
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
@@ -58,8 +58,8 @@
# CMD_STACKID returns the id of the current or parent frame (depending
# on the 'parent-flag' passed in), or 0 if not found. The id can be just
# the stack depth, or it can be the unique id of the frame object. When
-# used in CMD_BREAKPOINTS, it means "break if we are entering/leaving that
-# frame".
+# used in CMD_BREAKPOINTS, it means "break if we are entering/leaving a
+# frame from/to the given frame".
# Message(ANSWER_STACKID, stack-id)
ANSWER_STACKID = 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
@@ -19,10 +19,11 @@
self.num2name = {} # {small number: break/watchpoint}
self.watchvalues = {} # {small number: resulting text}
self.watchuids = {} # {small number: [uid...]}
- self.stack_id = 0 # breaks when leaving/entering this frame; 0=none
+ self.stack_id = 0 # breaks when leaving/entering a frame from/to
+ # the frame identified by 'stack_id'
def __repr__(self):
- return 'AllBreakpoints(%r, %r, %r, %d)' % (
+ return 'AllBreakpoints(%r, %r, %r, %r)' % (
self.num2name, self.watchvalues, self.watchuids,
self.stack_id)
@@ -304,7 +305,7 @@
if bkpt:
raise bkpt
- def go_backward(self, steps, ignore_breakpoints=False):
+ def go_backward(self, steps, ignore_breakpoints=False, rel_stop_at=-1):
"""Go backward, for the given number of 'steps' of time.
Closes the active process. Implemented as jump_in_time()
@@ -321,7 +322,7 @@
first_steps = 957
self._backward_search_forward(
search_start_time = initial_time - first_steps,
- search_stop_time = initial_time - 1,
+ search_stop_time = initial_time + rel_stop_at,
search_go_on_until_time = initial_time - steps)
def _backward_search_forward(self, search_start_time, search_stop_time,
@@ -536,8 +537,8 @@
def edit_breakpoints(self):
return self.all_breakpoints
- def get_stack_id(self):
- self.active.send(Message(CMD_STACKID))
+ def get_stack_id(self, is_parent):
+ self.active.send(Message(CMD_STACKID, is_parent))
msg = self.active.expect(ANSWER_STACKID, Ellipsis)
self.active.expect_ready()
return msg.arg1
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
@@ -1097,9 +1097,8 @@
void rpy_reverse_db_breakpoint(int64_t num)
{
if (flag_io_disabled != FID_REGULAR_MODE) {
- fprintf(stderr, "revdb.breakpoint(): cannot be called from a "
- "debug command\n");
- exit(1);
+ /* called from a debug command, ignore */
+ return;
}
switch (breakpoint_mode) {
More information about the pypy-commit
mailing list