Skip to content

Commit 46d9aaf

Browse files
Implement ni and si, do li and lli instead of assem
1 parent 67f6f41 commit 46d9aaf

File tree

2 files changed

+174
-45
lines changed

2 files changed

+174
-45
lines changed

Lib/bdb.py

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ def __init__(self, skip=None):
3232
self.skip = set(skip) if skip else None
3333
self.breaks = {}
3434
self.fncache = {}
35+
self._curframe = None
36+
self.lasti = -1
37+
self.trace_opcodes = False
3538
self.frame_returning = None
3639

3740
self._load_breaks()
@@ -84,6 +87,8 @@ def trace_dispatch(self, frame, event, arg):
8487
8588
The arg parameter depends on the previous event.
8689
"""
90+
self._curframe = frame
91+
8792
if self.quitting:
8893
return # None
8994
if event == 'line':
@@ -94,6 +99,8 @@ def trace_dispatch(self, frame, event, arg):
9499
return self.dispatch_return(frame, arg)
95100
if event == 'exception':
96101
return self.dispatch_exception(frame, arg)
102+
if event == 'opcode':
103+
return self.dispatch_opcode(frame)
97104
if event == 'c_call':
98105
return self.trace_dispatch
99106
if event == 'c_exception':
@@ -115,13 +122,30 @@ def dispatch_line(self, frame):
115122
if self.quitting: raise BdbQuit
116123
return self.trace_dispatch
117124

125+
def dispatch_opcode(self, frame):
126+
"""Invoke user function and return trace function for opcode event.
127+
128+
If the debugger stops on the current opcode, invoke
129+
self.user_opcode(). Raise BdbQuit if self.quitting is set.
130+
Return self.trace_dispatch to continue tracing in this scope.
131+
"""
132+
if self.stop_here(frame) or self.break_here(frame):
133+
self.user_opcode(frame)
134+
if self.quitting: raise BdbQuit
135+
return self.trace_dispatch
136+
118137
def dispatch_call(self, frame, arg):
119138
"""Invoke user function and return trace function for call event.
120139
121140
If the debugger stops on this function call, invoke
122141
self.user_call(). Raise BdbQuit if self.quitting is set.
123142
Return self.trace_dispatch to continue tracing in this scope.
124143
"""
144+
if self.trace_opcodes:
145+
frame.f_trace_opcodes = True
146+
else:
147+
frame.f_trace_opcodes = False
148+
125149
# XXX 'arg' is no longer used
126150
if self.botframe is None:
127151
# First call of dispatch since reset()
@@ -209,9 +233,15 @@ def stop_here(self, frame):
209233
if frame is self.stopframe:
210234
if self.stoplineno == -1:
211235
return False
212-
return frame.f_lineno >= self.stoplineno
236+
if self.trace_opcodes:
237+
return self.lasti != frame.f_lasti
238+
else:
239+
return frame.f_lineno >= self.stoplineno
213240
if not self.stopframe:
214-
return True
241+
if self.trace_opcodes:
242+
return self.lasti != frame.f_lasti
243+
else:
244+
return True
215245
return False
216246

217247
def break_here(self, frame):
@@ -272,7 +302,21 @@ def user_exception(self, frame, exc_info):
272302
"""Called when we stop on an exception."""
273303
pass
274304

275-
def _set_stopinfo(self, stopframe, returnframe, stoplineno=0):
305+
def user_opcode(self, frame):
306+
"""Called when we stop or break at a opcode."""
307+
pass
308+
309+
def _set_trace_opcodes(self, trace_opcodes):
310+
if trace_opcodes != self.trace_opcodes:
311+
self.trace_opcodes = trace_opcodes
312+
frame = self._curframe
313+
while frame is not None:
314+
frame.f_trace_opcodes = trace_opcodes
315+
if frame is self.botframe:
316+
break
317+
frame = frame.f_back
318+
319+
def _set_stopinfo(self, stopframe, returnframe, stoplineno=0, lasti=None):
276320
"""Set the attributes for stopping.
277321
278322
If stoplineno is greater than or equal to 0, then stop at line
@@ -285,6 +329,12 @@ def _set_stopinfo(self, stopframe, returnframe, stoplineno=0):
285329
# stoplineno >= 0 means: stop at line >= the stoplineno
286330
# stoplineno -1 means: don't stop at all
287331
self.stoplineno = stoplineno
332+
if lasti:
333+
# We are stopping at opcode level
334+
self._set_trace_opcodes(True)
335+
self.lasti = lasti
336+
else:
337+
self._set_trace_opcodes(False)
288338

289339
# Derived classes and clients can call the following methods
290340
# to affect the stepping state.
@@ -309,10 +359,26 @@ def set_step(self):
309359
caller_frame.f_trace = self.trace_dispatch
310360
self._set_stopinfo(None, None)
311361

362+
def set_stepinst(self, frame):
363+
"""Stop after one opcode."""
364+
# Issue #13183: pdb skips frames after hitting a breakpoint and running
365+
# step commands.
366+
# Restore the trace function in the caller (that may not have been set
367+
# for performance reasons) when returning from the current frame.
368+
if self.frame_returning:
369+
caller_frame = self.frame_returning.f_back
370+
if caller_frame and not caller_frame.f_trace:
371+
caller_frame.f_trace = self.trace_dispatch
372+
self._set_stopinfo(None, None, lasti=frame.f_lasti)
373+
312374
def set_next(self, frame):
313375
"""Stop on the next line in or below the given frame."""
314376
self._set_stopinfo(frame, None)
315377

378+
def set_nextinst(self, frame):
379+
"""Stop on the next line in or below the given frame."""
380+
self._set_stopinfo(frame, None, lasti=frame.f_lasti)
381+
316382
def set_return(self, frame):
317383
"""Stop when returning from the given frame."""
318384
if frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS:

0 commit comments

Comments
 (0)