[pypy-commit] pypy reverse-debugger: Watchpoints. Still buggy
arigo
pypy.commits at gmail.com
Thu Jun 30 04:14:23 EDT 2016
Author: Armin Rigo <arigo at tunes.org>
Branch: reverse-debugger
Changeset: r85467:716b1a95fd64
Date: 2016-06-30 10:15 +0200
http://bitbucket.org/pypy/pypy/changeset/716b1a95fd64/
Log: Watchpoints. Still buggy
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
@@ -6,6 +6,7 @@
from pypy.interpreter.error import OperationError, oefmt
from pypy.interpreter.baseobjspace import W_Root
from pypy.interpreter import gateway, typedef, pycode, pytraceback
+from pypy.module.marshal import interp_marshal
class DBState:
@@ -41,8 +42,9 @@
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)
- #revdb.register_debug_command(revdb.CMD_WATCHVALUES, lambda_watchvalues)
+ revdb.register_debug_command(revdb.CMD_COMPILEWATCH, lambda_compilewatch)
+ revdb.register_debug_command(revdb.CMD_CHECKWATCH, lambda_checkwatch)
+ revdb.register_debug_command(revdb.CMD_WATCHVALUES, lambda_watchvalues)
pycode.PyCode.co_revdb_linestarts = None # or a string: an array of bits
@@ -138,13 +140,13 @@
def stop_point_at_start_of_line():
if revdb.watch_save_state():
any_watch_point = False
- #for prog, watch_id, expected in dbstate.watch_progs:
- # any_watch_point = True
- # got = _watch_expr(prog)
- # if got != expected:
- # break
- #else:
- watch_id = -1
+ for prog, watch_id, expected in dbstate.watch_progs:
+ any_watch_point = True
+ got = _run_watch(prog)
+ if got != expected:
+ break
+ else:
+ watch_id = -1
revdb.watch_restore_state(any_watch_point)
if watch_id != -1:
revdb.breakpoint(watch_id)
@@ -274,6 +276,7 @@
break
show_frame(tb.frame, tb.get_lineno(), indent=' ')
tb = tb.next
+ revdb.send_output('%s\n' % operationerr.errorstr(space))
# set the sys.last_xxx attributes
w_type = operationerr.w_type
@@ -283,9 +286,6 @@
space.setitem(space.sys.w_dict, space.wrap('last_value'), w_value)
space.setitem(space.sys.w_dict, space.wrap('last_traceback'), w_tb)
- # re-raise, catch me in the outside "except OperationError"
- raise
-
except OperationError as e:
revdb.send_output('%s\n' % e.errorstr(space, use_repr=True))
lambda_print = lambda: command_print
@@ -384,26 +384,33 @@
def command_breakpoints(cmd, extra):
+ space = dbstate.space
dbstate.breakpoint_stack_id = cmd.c_arg1
funcnames = None
- for i, name in enumerate(extra.split('\x00')):
- if name:
- if name[0] == 'B':
- if funcnames is None:
- funcnames = {}
- funcnames[name[1:]] = i
- elif name[0] == 'W':
- pass
- ## try:
- ## prog = compiler.parse(dbstate.space, name[1:])
- ## except DuhtonError, e:
- ## revdb.send_output('compiling "%s": %s\n' %
- ## (name[1:], e.msg))
- ## else:
- ## watch_progs.append((prog, i, ''))
+ watch_progs = []
+ for i, kind, name in revdb.split_breakpoints_arg(extra):
+ if kind == 'B':
+ if funcnames is None:
+ funcnames = {}
+ funcnames[name] = i
+ elif kind == 'W':
+ code = interp_marshal.loads(space, space.wrap(name))
+ watch_progs.append((code, i, ''))
dbstate.breakpoint_funcnames = funcnames
+ dbstate.watch_progs = watch_progs[:]
lambda_breakpoints = lambda: command_breakpoints
+
+def command_watchvalues(cmd, extra):
+ expected = extra.split('\x00')
+ for j in range(len(dbstate.watch_progs)):
+ prog, i, _ = dbstate.watch_progs[j]
+ if i >= len(expected):
+ raise IndexError
+ dbstate.watch_progs[j] = prog, i, expected[i]
+lambda_watchvalues = lambda: command_watchvalues
+
+
def command_stackid(cmd, extra):
frame = fetch_cur_frame()
if frame is not None and cmd.c_arg1 != 0: # parent_flag
@@ -440,3 +447,38 @@
w_obj = dbstate.w_future
set_metavar(index_metavar, w_obj)
lambda_attachid = lambda: command_attachid
+
+
+def command_compilewatch(cmd, expression):
+ space = dbstate.space
+ try:
+ code = compile(expression, 'eval')
+ marshalled_code = space.str_w(interp_marshal.dumps(
+ space, space.wrap(code),
+ space.wrap(interp_marshal.Py_MARSHAL_VERSION)))
+ except OperationError as e:
+ revdb.send_watch(e.errorstr(space), ok_flag=0)
+ else:
+ revdb.send_watch(marshalled_code, ok_flag=1)
+lambda_compilewatch = lambda: command_compilewatch
+
+def command_checkwatch(cmd, marshalled_code):
+ space = dbstate.space
+ try:
+ code = interp_marshal.loads(space, space.wrap(marshalled_code))
+ w_res = code.exec_code(space, space.builtin, space.builtin)
+ text = space.str_w(space.repr(w_res))
+ except OperationError as e:
+ revdb.send_watch(e.errorstr(space), ok_flag=0)
+ else:
+ revdb.send_watch(text, ok_flag=1)
+lambda_checkwatch = lambda: command_checkwatch
+
+def _run_watch(code):
+ space = dbstate.space
+ try:
+ w_res = code.exec_code(space, space.builtin, space.builtin)
+ text = space.str_w(space.repr(w_res))
+ except OperationError as e:
+ return e.errorstr(space)
+ return text
diff --git a/rpython/rlib/revdb.py b/rpython/rlib/revdb.py
--- a/rpython/rlib/revdb.py
+++ b/rpython/rlib/revdb.py
@@ -118,6 +118,25 @@
llop.revdb_watch_restore_state(lltype.Void, any_watch_point)
+def split_breakpoints_arg(breakpoints):
+ # RPython generator to help in splitting the string arg in CMD_BREAKPOINTS
+ n = 0
+ i = 0
+ while i < len(breakpoints):
+ kind = breakpoints[i]
+ i += 1
+ if kind != '\x00':
+ length = (ord(breakpoints[i]) |
+ (ord(breakpoints[i + 1]) << 8) |
+ (ord(breakpoints[i + 2]) << 16))
+ assert length >= 0
+ i += 3
+ yield n, kind, breakpoints[i : i + length]
+ i += length
+ n += 1
+ assert i == len(breakpoints)
+
+
# ____________________________________________________________
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
@@ -121,26 +121,32 @@
print ', '.join(lst)
def _bp_kind(self, num):
- name = self.pgroup.all_breakpoints.num2name.get(num, '??')
- if name[0] == 'B':
+ break_at = self.pgroup.all_breakpoints.num2break.get(num, '??')
+ if break_at[0] == 'B':
kind = 'breakpoint'
- name = name[1:]
- elif name[0] == 'W':
+ name = break_at[4:]
+ elif break_at[0] == 'W':
kind = 'watchpoint'
name = self.pgroup.all_breakpoints.sources.get(num, '??')
else:
kind = '?????point'
- name = repr(name)
+ name = repr(break_at)
return kind, name
- def _bp_new(self, break_at, nids=None, source_expr=None):
+ def _bp_new(self, source_expr, break_code, break_at, nids=None):
b = self.pgroup.edit_breakpoints()
new = 1
- while new in b.num2name:
+ while new in b.num2break:
new += 1
- b.num2name[new] = break_at
+ if len(break_at) > 0xFFFFFF:
+ raise OverflowError("break/watchpoint too complex")
+ b.num2break[new] = (break_code +
+ chr(len(break_at) & 0xFF) +
+ chr((len(break_at) >> 8) & 0xFF) +
+ chr(len(break_at) >> 16) +
+ break_at)
b.sources[new] = source_expr
- if break_at.startswith('W'):
+ if break_code == 'W':
b.watchvalues[new] = ''
if nids:
b.watchuids[new] = self.pgroup.nids_to_uids(nids)
@@ -149,7 +155,7 @@
def cmd_info_breakpoints(self):
"""List current breakpoints and watchpoints"""
- lst = self.pgroup.all_breakpoints.num2name.keys()
+ lst = self.pgroup.all_breakpoints.num2break.keys()
if lst:
for num in sorted(lst):
kind, name = self._bp_kind(num)
@@ -179,7 +185,7 @@
def hit_breakpoint(self, b, backward=False):
if b.num != -1:
- kind, name = self._bp_kind(d.num)
+ kind, name = self._bp_kind(b.num)
self.print_extra_pending_info = 'Hit %s %d: %s' % (kind, b.num,
name)
elif backward:
@@ -304,18 +310,18 @@
if not argument:
print "Break where?"
return
- self._bp_new('B' + argument)
+ self._bp_new(argument, 'B', argument)
command_b = command_break
def command_delete(self, argument):
"""Delete a breakpoint/watchpoint"""
arg = int(argument)
b = self.pgroup.edit_breakpoints()
- if arg not in b.num2name:
+ if arg not in b.num2break:
print "No breakpoint/watchpoint number %d" % (arg,)
else:
kind, name = self._bp_kind(arg)
- b.num2name.pop(arg, '')
+ b.num2break.pop(arg, '')
b.sources.pop(arg, '')
b.watchvalues.pop(arg, '')
b.watchuids.pop(arg, '')
@@ -340,5 +346,5 @@
print 'Watchpoint not added'
return
#
- self._bp_new('W' + compiled_code, nids=nids, source_expr=argument)
+ self._bp_new(argument, 'W', compiled_code, nids=nids)
self.pgroup.update_watch_values()
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
@@ -16,8 +16,8 @@
class AllBreakpoints(object):
def __init__(self):
- self.num2name = {} # {small number: break/watchpoint}
- self.sources = {} # {small number: src text or None}
+ self.num2break = {} # {small number: encoded break/watchpoint}
+ self.sources = {} # {small number: src text}
self.watchvalues = {} # {small number: resulting text}
self.watchuids = {} # {small number: [uid...]}
self.stack_id = 0 # breaks when leaving/entering a frame from/to
@@ -25,11 +25,11 @@
def __repr__(self):
return 'AllBreakpoints(%r, %r, %r, %r)' % (
- self.num2name, self.watchvalues, self.watchuids,
+ self.num2break, self.watchvalues, self.watchuids,
self.stack_id)
def compare(self, other):
- if (self.num2name == other.num2name and
+ if (self.num2break == other.num2break and
self.stack_id == other.stack_id):
if self.watchvalues == other.watchvalues:
return 2 # completely equal
@@ -39,11 +39,11 @@
return 0 # different
def is_empty(self):
- return len(self.num2name) == 0 and self.stack_id == 0
+ return len(self.num2break) == 0 and self.stack_id == 0
def duplicate(self):
a = AllBreakpoints()
- a.num2name.update(self.num2name)
+ a.num2break.update(self.num2break)
a.stack_id = self.stack_id
return a
@@ -362,24 +362,24 @@
# update the breakpoints/watchpoints
self.active.breakpoints_cache = None
- num2name = self.all_breakpoints.num2name
- N = (max(num2name) + 1) if num2name else 0
+ num2break = self.all_breakpoints.num2break
+ N = (max(num2break) + 1) if num2break else 0
if cmp == 0:
- flat = [num2name.get(n, '') for n in range(N)]
+ flat = [num2break.get(n, '\x00') for n in range(N)]
arg1 = self.all_breakpoints.stack_id
- extra = '\x00'.join(flat)
+ extra = ''.join(flat)
self.active.send(Message(CMD_BREAKPOINTS, arg1, extra=extra))
self.active.expect_ready()
else:
assert cmp == 1
# update the watchpoint values
- if any(name.startswith('W') for name in num2name.values()):
+ if any(name.startswith('W') for name in num2break.values()):
watchvalues = self.all_breakpoints.watchvalues
flat = []
for n in range(N):
text = ''
- name = num2name.get(n, '')
+ name = num2break.get(n, '')
if name.startswith('W'):
text = watchvalues[n]
flat.append(text)
@@ -392,13 +392,13 @@
def update_watch_values(self):
self._update_watchpoints_uids()
seen = set()
- for num, name in self.all_breakpoints.num2name.items():
+ for num, name in self.all_breakpoints.num2break.items():
if name.startswith('W'):
- _, text = self.check_watchpoint_expr(name[1:])
+ _, text = self.check_watchpoint_expr(name[4:])
if text != self.all_breakpoints.watchvalues[num]:
#print self.active.pid
print 'updating watchpoint value: %s => %s' % (
- name[1:], text)
+ self.all_breakpoints.sources[num], text)
self.all_breakpoints.watchvalues[num] = text
seen.add(num)
assert set(self.all_breakpoints.watchvalues) == seen
More information about the pypy-commit
mailing list