mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Make set next statement work properly for frame eval debugger (PY-26101)
This commit is contained in:
committed by
Elizaveta Shashkova
parent
f9fcc6f846
commit
e9af010573
@@ -560,7 +560,7 @@ class PyDBFrame:
|
||||
breakpoint = breakpoints_for_file[line]
|
||||
new_frame = frame
|
||||
stop = True
|
||||
if step_cmd == CMD_STEP_OVER and stop_frame is frame and (is_line or is_return):
|
||||
if (step_cmd == CMD_STEP_OVER or step_cmd == CMD_SET_NEXT_STATEMENT) and stop_frame is frame and (is_line or is_return):
|
||||
stop = False #we don't stop on breakpoint if we have to stop by step-over (it will be processed later)
|
||||
elif plugin_manager is not None and main_debugger.has_plugin_line_breaks:
|
||||
result = plugin_manager.get_breakpoint(main_debugger, self, frame, event, self._args)
|
||||
|
||||
@@ -3,7 +3,7 @@ from _pydev_imps._pydev_saved_modules import threading
|
||||
from _pydevd_bundle.pydevd_additional_thread_info import PyDBAdditionalThreadInfo
|
||||
from _pydevd_bundle.pydevd_comm import get_global_debugger
|
||||
from _pydevd_bundle.pydevd_dont_trace_files import DONT_TRACE
|
||||
from _pydevd_frame_eval.pydevd_frame_tracing import pydev_trace_code_wrapper, update_globals_dict, dummy_tracing_holder
|
||||
from _pydevd_frame_eval.pydevd_frame_tracing import create_code_wrapper, update_globals_dict, dummy_tracing_holder
|
||||
from _pydevd_frame_eval.pydevd_modify_bytecode import insert_code
|
||||
from pydevd_file_utils import get_abs_path_real_path_and_base_from_frame, NORM_PATHS_AND_BASE_CONTAINER
|
||||
|
||||
@@ -107,13 +107,16 @@ cdef PyObject* get_bytecode_while_frame_eval(PyFrameObject *frame_obj, int exc):
|
||||
code_object = frame.f_code
|
||||
if breakpoints:
|
||||
breakpoints_to_update = []
|
||||
injected_code_size = 0
|
||||
for offset, line in dis.findlinestarts(code_object):
|
||||
if line in breakpoints:
|
||||
breakpoint = breakpoints[line]
|
||||
if code_object not in breakpoint.code_objects:
|
||||
# This check is needed for generator functions, because after each yield the new frame is created
|
||||
# but the former code object is used
|
||||
success, new_code = insert_code(frame.f_code, pydev_trace_code_wrapper.__code__, line)
|
||||
injected_code = create_code_wrapper(offset + injected_code_size)
|
||||
success, new_code = insert_code(frame.f_code, injected_code , line)
|
||||
injected_code_size += len(injected_code.co_code)
|
||||
if success:
|
||||
breakpoints_to_update.append(breakpoint)
|
||||
Py_INCREF(new_code)
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
from types import CodeType
|
||||
|
||||
import sys
|
||||
|
||||
from _pydev_bundle import pydev_log
|
||||
from _pydev_imps._pydev_saved_modules import threading
|
||||
from _pydevd_bundle.pydevd_comm import get_global_debugger, CMD_SET_BREAK
|
||||
from _pydevd_bundle.pydevd_comm import get_global_debugger, CMD_SET_BREAK, CMD_SET_NEXT_STATEMENT
|
||||
from pydevd_file_utils import get_abs_path_real_path_and_base_from_frame, NORM_PATHS_AND_BASE_CONTAINER
|
||||
from _pydevd_bundle.pydevd_frame import handle_breakpoint_condition, handle_breakpoint_expression
|
||||
|
||||
|
||||
import opcode
|
||||
class DummyTracingHolder:
|
||||
dummy_trace_func = None
|
||||
|
||||
@@ -54,7 +56,7 @@ def _pydev_stop_at_break():
|
||||
frame = sys._getframe(1)
|
||||
t = threading.currentThread()
|
||||
if t.additional_info.is_tracing:
|
||||
return
|
||||
return False
|
||||
|
||||
if t.additional_info.pydev_step_cmd == -1 and frame.f_trace in (None, dummy_tracing_holder.dummy_trace_func):
|
||||
# do not handle breakpoints while stepping, because they're handled by old tracing function
|
||||
@@ -74,16 +76,40 @@ def _pydev_stop_at_break():
|
||||
except KeyError:
|
||||
pydev_log.debug("Couldn't find breakpoint in the file {} on line {}".format(frame.f_code.co_filename, line))
|
||||
t.additional_info.is_tracing = False
|
||||
return
|
||||
return False
|
||||
if breakpoint and handle_breakpoint(frame, t, debugger, breakpoint):
|
||||
pydev_log.debug("Suspending at breakpoint in file: {} on line {}".format(frame.f_code.co_filename, line))
|
||||
debugger.set_suspend(t, CMD_SET_BREAK)
|
||||
debugger.do_wait_suspend(t, frame, 'line', None, "frame_eval")
|
||||
|
||||
t.additional_info.is_tracing = False
|
||||
return t.additional_info.pydev_step_cmd == CMD_SET_NEXT_STATEMENT
|
||||
return False
|
||||
|
||||
|
||||
def pydev_trace_code_wrapper():
|
||||
# import this module again, because it's inserted inside user's code
|
||||
global _pydev_stop_at_break
|
||||
_pydev_stop_at_break()
|
||||
return _pydev_stop_at_break()
|
||||
|
||||
|
||||
|
||||
def create_code_wrapper(offset):
|
||||
co = pydev_trace_code_wrapper.__code__
|
||||
# 0 + offset LOAD_GLOBAL 0 (_pydev_stop_at_break)
|
||||
# 2 + offset CALL_FUNCTION 0
|
||||
# 4 + offset POP_JUMP_IF_TRUE offset
|
||||
byte_code = [116, 0, 131, 0]
|
||||
if offset > 0xFF:
|
||||
byte_code += [opcode.EXTENDED_ARG, offset >> 8]
|
||||
byte_code += [115, offset & 0xFF]
|
||||
|
||||
#below code is just function trailer and gets removed
|
||||
byte_code += [100, 0, 83, 0]
|
||||
return CodeType(
|
||||
co.co_argcount, co.co_kwonlyargcount, co.co_nlocals,
|
||||
co.co_stacksize,
|
||||
co.co_flags,
|
||||
bytes(byte_code),
|
||||
co.co_consts, co.co_names, co.co_varnames, co.co_filename,
|
||||
co.co_name, co.co_firstlineno, co.co_lnotab, co.co_freevars,
|
||||
co.co_cellvars)
|
||||
@@ -750,14 +750,10 @@ class PyDB:
|
||||
|
||||
if curr_func_name == func_name:
|
||||
line = next_line
|
||||
if frame.f_lineno == line:
|
||||
stop = True
|
||||
else:
|
||||
if frame.f_trace is None:
|
||||
frame.f_trace = self.trace_dispatch
|
||||
frame.f_lineno = line
|
||||
frame.f_trace = None
|
||||
stop = True
|
||||
if frame.f_trace is None:
|
||||
frame.f_trace = self.trace_dispatch
|
||||
frame.f_lineno = line
|
||||
stop = True
|
||||
else:
|
||||
response_msg = "jump is available only within the bottom frame"
|
||||
return stop, old_line, response_msg
|
||||
@@ -856,14 +852,15 @@ class PyDB:
|
||||
info.pydev_message = ''
|
||||
|
||||
if stop:
|
||||
info.pydev_state = STATE_RUN
|
||||
# `f_line` should be assigned within a tracing function, so, we can't assign it here
|
||||
# for the frame evaluation debugger. For tracing debugger it will be assigned, but we should
|
||||
# revert the previous value, because both debuggers should behave the same way
|
||||
try:
|
||||
self.set_next_statement(frame, event, info.pydev_func_name, old_line)
|
||||
except:
|
||||
pass
|
||||
cmd = self.cmd_factory.make_thread_run_message(get_thread_id(thread), info.pydev_step_cmd)
|
||||
self.writer.add_command(cmd)
|
||||
if suspend_type == "trace":
|
||||
info.pydev_state = STATE_SUSPEND
|
||||
thread.stop_reason= CMD_SET_NEXT_STATEMENT
|
||||
self.do_wait_suspend(thread, frame, event, arg, "trace")
|
||||
else:
|
||||
info.pydev_step_stop = frame
|
||||
return
|
||||
else:
|
||||
info.pydev_step_cmd = -1
|
||||
info.pydev_state = STATE_SUSPEND
|
||||
|
||||
Reference in New Issue
Block a user