8000 gh-103049: Support instruction level debugging in pdb by gaogaotiantian · Pull Request #103050 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-103049: Support instruction level debugging in pdb #103050

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Prev Previous commit
Next Next commit
Fix docstrings and commands
Used stepi instead of stepinst(other commands too)

Abstracted a function to restore caller trace function
  • Loading branch information
gaogaotiantian committed Apr 8, 2023
commit 4016fd44f09e4615e892e8bb7fc7dafd165c6ecf
35 changes: 16 additions & 19 deletions Lib/bdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ def trace_dispatch(self, frame, event, arg):
is entered.
return: A function or other code block is about to return.
exception: An exception has occurred.
opcode: An opcode is going to be executed.
c_call: A C function is about to be called.
c_return: A C function has returned.
c_exception: A C function has raised an exception.
Expand Down Expand Up @@ -303,7 +304,7 @@ def user_exception(self, frame, exc_info):
pass

def user_opcode(self, frame):
"""Called when we stop or break at an opcode."""
"""Called when we are about to execute an opcode."""
pass

def _set_trace_opcodes(self, trace_opcodes):
Expand Down Expand Up @@ -336,6 +337,16 @@ def _set_stopinfo(self, stopframe, returnframe, stoplineno=0, lasti=None):
else:
self._set_trace_opcodes(False)

def _set_caller_tracefunc(self):
# Issue #13183: pdb skips frames after hitting a breakpoint and running
# step commands.
# Restore the trace function in the caller (that may not have been set
# for performance reasons) when returning from the current frame.
if self.frame_returning:
caller_frame = self.frame_returning.f_back
if caller_frame and not caller_frame.f_trace:
caller_frame.f_trace = self.trace_dispatch

# Derived classes and clients can call the following methods
# to affect the stepping state.

Expand All @@ -349,33 +360,19 @@ def set_until(self, frame, lineno=None):

def set_step(self):
"""Stop after one line of code."""
# Issue #13183: pdb skips frames after hitting a breakpoint and running
# step commands.
# Restore the trace function in the caller (that may not have been set
# for performance reasons) when returning from the current frame.
if self.frame_returning:
caller_frame = self.frame_returning.f_back
if caller_frame and not caller_frame.f_trace:
caller_frame.f_trace = self.trace_dispatch
self._set_caller_tracefunc()
self._set_stopinfo(None, None)

def set_stepinst(self, frame):
def set_stepi(self, frame):
"""Stop after one opcode."""
# Issue #13183: pdb skips frames after hitting a breakpoint and running
# step commands.
# Restore the trace function in the caller (that may not have been set
# for performance reasons) when returning from the current frame.
if self.frame_returning:
caller_frame = self.frame_returning.f_back
if caller_frame and not caller_frame.f_trace:
caller_frame.f_trace = self.trace_dispatch
self._set_caller_tracefunc()
self._set_stopinfo(None, None, lasti=frame.f_lasti)

def set_next(self, frame):
"""Stop on the next line in or below the given frame."""
self._set_stopinfo(frame, None)

def set_nextinst(self, frame):
def set_nexti(self, frame):
"""Stop on the next line in or below the given frame."""
self._set_stopinfo(frame, None, lasti=frame.f_lasti)

Expand Down
48 changes: 26 additions & 22 deletions Lib/pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ def user_line(self, frame):
self.interaction(frame, None)

def user_opcode(self, frame):
"""This function is called when we are about to execute an opcode."""
if self._wait_for_mainpyfile:
if (self.mainpyfile != self.canonic(frame.f_code.co_filename)
or frame.f_lineno <= 0):
Expand Down Expand Up @@ -1098,15 +1099,15 @@ def do_step(self, arg):
return 1
do_s = do_step

def do_stepinst(self, arg):
def do_stepi(self, arg):
"""s(tep)
Execute the current line, stop at the first possible occasion
(either in a function that is called or in the current
function).
"""
self.set_stepinst(self.curframe)
self.set_stepi(self.curframe)
return 1
do_si = do_stepinst
do_si = do_stepi

def do_next(self, arg):
"""n(ext)
Expand All @@ -1117,14 +1118,14 @@ def do_next(self, arg):
return 1
do_n = do_next

def do_nextinst(self, arg):
def do_nexti(self, arg):
"""n(ext)
Continue execution until the next line in the current function
is reached or it returns.
"""
self.set_nextinst(self.curframe)
self.set_nexti(self.curframe)
return 1
do_ni = do_nextinst
do_ni = do_nexti

def do_run(self, arg):
"""run [args...]
Expand Down Expand Up @@ -1380,17 +1381,19 @@ def do_list(self, arg):
self._do_list(arg, False)
do_l = do_list

def do_listinst(self, arg):
"""listinst | li [first[, last] | .]
def do_listi(self, arg):
"""listi | li [first[, last] | .]

List source code for the current file with instructions.

Without arguments, list 11 lines around the current line or
continue the previous listing. With . as argument, list 11
lines around the current line. With one argument, list 11
lines starting at that line. With two arguments, list the
given range; if the second argument is less than the first,
it is a count.
Without arguments, list 11 lines with their corresponding
instructions around the current line or continue the
previous listing. With . as argument, list 11 lines with
their corresponding instructions around the current line.
With one argument, list 11 lines with their corresponding
instructions starting at that line. With two arguments,
list the given range; if the second argument is less than
the first, it is a count.

The current line in the current frame is indicated by "->".
The current instruction is indicated by "-->"
Expand All @@ -1399,7 +1402,7 @@ def do_listinst(self, arg):
">>", if it differs from the current line.
"""
self._do_list(arg, True)
do_li = do_listinst
do_li = do_listi

def _do_longlist(self, arg, show_instructions=False):
filename = self.curframe.f_code.co_filename
Expand All @@ -1421,14 +1424,14 @@ def do_longlist(self, arg):
self._do_longlist(arg, False)
do_ll = do_longlist

def do_longlistinst(self, arg):
"""longlistinst | lli
def do_longlisti(self, arg):
"""longlisti | lli

List the whole source code with instructions for the current
function or frame.
"""
self._do_longlist(arg, True)
do_lli = do_longlistinst
do_lli = do_longlisti

def do_source(self, arg):
"""source expression
Expand Down Expand Up @@ -1763,10 +1766,11 @@ def _compile_error_message(self, expr):
# unfortunately we can't guess this order from the class definition
_help_order = [
'help', 'where', 'down', 'up', 'break', 'tbreak', 'clear', 'disable',
'enable', 'ignore', 'condition', 'commands', 'step', 'stepinst',
'next', 'nextinst', 'until', 'jump', 'return', 'retval', 'run',
'continue', 'list', 'longlist', 'args', 'p', 'pp', 'whatis', 'source',
'display', 'undisplay', 'interact', 'alias', 'unalias', 'debug', 'quit',
'enable', 'ignore', 'condition', 'commands', 'step', 'stepi',
'next', 'nexti', 'until', 'jump', 'return', 'retval', 'run',
'continue', 'list', 'listi', 'longlist', 'longlisti', 'args', 'p',
'pp', 'whatis', 'source', 'display', 'undisplay', 'interact', 'alias',
'unalias', 'debug', 'quit',
]

for _command in _help_order:
Expand Down
0