Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
fabioz committed Nov 11, 2023
1 parent ee16be2 commit 71c36d0
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ def _handle_exception(self, frame, event, arg, exception_type):
except:
pydev_log.exception()

main_debugger.set_trace_for_frame_and_parents(frame)
main_debugger.set_trace_for_frame_and_parents(thread, frame)
finally:
# Make sure the user cannot see the '__exception__' we added after we leave the suspend state.
remove_exception_from_frame(frame)
Expand Down Expand Up @@ -1218,7 +1218,7 @@ def trace_dispatch(self, frame, event, arg):
# other parent) has to be traced and it's not currently, we wouldn't stop where
# we should anymore (so, a step in/over/return may not stop anywhere if no parent is traced).
# Related test: _debugger_case17a.py
main_debugger.set_trace_for_frame_and_parents(back)
main_debugger.set_trace_for_frame_and_parents(thread, back)
return None if is_call else NO_FTRACE

if back is not None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def suspend_all_threads(py_db, except_thread):
# Reset the tracing as in this case as it could've set scopes to be untraced.
if frame is not None:
try:
py_db.set_trace_for_frame_and_parents(frame)
py_db.set_trace_for_frame_and_parents(t, frame)
finally:
frame = None

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,24 +198,28 @@ def _get_code_line_info(code_obj):
return _CodeLineInfo(line_to_offset, first_line, last_line)


code_to_func_code_info: Dict[CodeType, 'FuncCodeInfo'] = {}
_code_to_func_code_info_cache: Dict[CodeType, 'FuncCodeInfo'] = {}


def get_func_code_info(thread_info: ThreadInfo, code_obj, code_to_func_code_info=code_to_func_code_info) -> FuncCodeInfo:
def get_func_code_info(code_obj) -> FuncCodeInfo:
'''
Provides code-object related info.
Note that it contains informations on the breakpoints for a given function.
If breakpoints change a new FuncCodeInfo instance will be created.
Note that this can be called by any thread.
'''
py_db = GlobalDebuggerHolder.global_dbg

func_code_info_obj = code_to_func_code_info.get(code_obj)
if func_code_info_obj is not None:
if func_code_info_obj.breakpoints_mtime == py_db.mtime:
func_code_info = _code_to_func_code_info_cache.get(code_obj)
if func_code_info is not None:
if func_code_info.breakpoints_mtime == py_db.mtime:
# if DEBUG:
# print('get_func_code_info: matched mtime', f_code.co_name, f_code.co_filename)
return func_code_info_obj
# print('get_func_code_info: matched mtime', key, code_obj)
return func_code_info

# print('get_func_code_info: new (mtime did not match)', key, code_obj)

co_filename: str = code_obj.co_filename
co_name: str = code_obj.co_name
Expand Down Expand Up @@ -280,7 +284,7 @@ def get_func_code_info(thread_info: ThreadInfo, code_obj, code_to_func_code_info
func_code_info.breakpoint_found = bool(bp_line_to_breakpoint or function_breakpoint)
func_code_info.bp_line_to_breakpoint = bp_line_to_breakpoint

code_to_func_code_info[code_obj] = func_code_info_obj
_code_to_func_code_info_cache[code_obj] = func_code_info

return func_code_info

Expand All @@ -301,33 +305,39 @@ def disable_code_tracing(code):
monitor.set_local_events(DEBUGGER_ID, code, 0)


def enable_code_tracing(code, frame):
def enable_code_tracing(thread, code, frame):
print('enable code tracing', code)
return _enable_code_tracing(code, frame)
return _enable_code_tracing(thread, code, frame)


def _enable_code_tracing(code, frame):
try:
thread_info = _thread_local_info.thread_info
except:
thread_info = get_thread_info(code, True)
if thread_info is None:
return

def _enable_code_tracing(thread, code, frame):
py_db: object = GlobalDebuggerHolder.global_dbg
if py_db is None or py_db.pydb_disposed:
return monitor.DISABLE

if not thread_info.trace or thread_info.thread._is_stopped:
# For thread-related stuff we can't disable the code tracing because other
# threads may still want it...
return

func_code_info: FuncCodeInfo = get_func_code_info(thread_info, code)
func_code_info: FuncCodeInfo = get_func_code_info(code)
if func_code_info.always_skip_code:
return monitor.DISABLE

info = thread_info.additional_info
if func_code_info.breakpoint_found:
enable_line_tracing(code)
elif py_db.has_plugin_line_breaks or py_db.has_plugin_exception_breaks:
can_skip = py_db.plugin.can_skip(py_db, frame)

if not can_skip:
if py_db.has_plugin_line_breaks:
enable_line_tracing(code)

# if py_db.has_plugin_exception_breaks:
# enable_exception_tracing(code)

try:
# thread could be None here.
info = thread.additional_info
except:
# Cannot set based on stepping
return

step_cmd = info.pydev_step_cmd

if step_cmd in (CMD_STEP_INTO, CMD_STEP_INTO_MY_CODE, CMD_STEP_INTO_COROUTINE, CMD_SMART_STEP_INTO):
Expand All @@ -350,23 +360,6 @@ def _enable_code_tracing(code, frame):
# if py_db.signature_factory:
# pass

func_code_info: FuncCodeInfo = get_func_code_info(thread_info, code)
# if DEBUG:
# print('get_bytecode_while_frame_eval always skip', func_code_info.always_skip_code)
if not func_code_info.always_skip_code:
if py_db.has_plugin_line_breaks or py_db.has_plugin_exception_breaks:
can_skip = py_db.plugin.can_skip(py_db, frame)

if not can_skip:
if py_db.has_plugin_line_breaks:
enable_line_tracing(code)

# if py_db.has_plugin_exception_breaks:
# enable_exception_tracing(code)

if func_code_info.breakpoint_found:
enable_line_tracing(code)


def _return_event(code, instruction, retval):
try:
Expand All @@ -385,7 +378,7 @@ def _return_event(code, instruction, retval):
# threads may still want it...
return

func_code_info: FuncCodeInfo = get_func_code_info(thread_info, code)
func_code_info: FuncCodeInfo = get_func_code_info(code)
if func_code_info.always_skip_code:
return monitor.DISABLE

Expand Down Expand Up @@ -423,7 +416,7 @@ def _stop_on_return(py_db, thread_info, info, step_cmd, frame, retval):
# other parent) has to be traced and it's not currently, we wouldn't stop where
# we should anymore (so, a step in/over/return may not stop anywhere if no parent is traced).
# Related test: _debugger_case17a.py
py_db.set_trace_for_frame_and_parents(back)
py_db.set_trace_for_frame_and_parents(thread_info.thread, back)
return

if back is not None:
Expand Down Expand Up @@ -460,7 +453,7 @@ def _line_event(code, line):
# threads may still want it...
return

func_code_info: FuncCodeInfo = get_func_code_info(thread_info, code)
func_code_info: FuncCodeInfo = get_func_code_info(code)
if func_code_info.always_skip_code:
return monitor.DISABLE

Expand Down Expand Up @@ -657,8 +650,24 @@ def _line_event(code, line):


def _start_method(code, instruction_offset):
try:
thread_info = _thread_local_info.thread_info
except:
thread_info = get_thread_info(code, True)
if thread_info is None:
return

py_db: object = GlobalDebuggerHolder.global_dbg
if py_db is None or py_db.pydb_disposed:
return monitor.DISABLE

if not thread_info.trace or thread_info.thread._is_stopped:
# For thread-related stuff we can't disable the code tracing because other
# threads may still want it...
return

frame = sys._getframe(1)
_enable_code_tracing(code, frame)
_enable_code_tracing(thread_info.thread, code, frame)


def start_monitoring(all_threads=False):
Expand Down
33 changes: 19 additions & 14 deletions plugins/org.python.pydev.core/pysrc/pydevd.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
# Import this first as it'll check for shadowed modules and will make sure that we import
# things as needed for gevent.
from _pydevd_bundle import pydevd_constants
from typing import Optional

import atexit
import dis
Expand Down Expand Up @@ -1187,7 +1188,8 @@ def set_tracing_for_untraced_contexts(self):

for thread_id, frame in tid_to_frame.items():
if thread_id not in ignore_thread_ids:
self.set_trace_for_frame_and_parents(frame)
t = threading._active.get(thread_id)
self.set_trace_for_frame_and_parents(t, frame)

else:
try:
Expand All @@ -1200,7 +1202,7 @@ def set_tracing_for_untraced_contexts(self):
frame = additional_info.get_topmost_frame(t)
try:
if frame is not None:
self.set_trace_for_frame_and_parents(frame)
self.set_trace_for_frame_and_parents(t, frame)
finally:
frame = None
finally:
Expand Down Expand Up @@ -1921,7 +1923,7 @@ def set_suspend(self, thread, stop_reason, suspend_other_threads=False, is_pause
frame = info.get_topmost_frame(thread)
if frame is not None:
try:
self.set_trace_for_frame_and_parents(frame)
self.set_trace_for_frame_and_parents(thread, frame)
finally:
frame = None

Expand Down Expand Up @@ -2167,18 +2169,18 @@ def _do_wait_suspend(self, thread, frame, event, arg, suspend_type, from_this_th
# When in a coroutine we switch to CMD_STEP_INTO_COROUTINE.
info.pydev_step_cmd = CMD_STEP_INTO_COROUTINE
info.pydev_step_stop = frame
self.set_trace_for_frame_and_parents(frame)
self.set_trace_for_frame_and_parents(thread, frame)
else:
info.pydev_step_stop = None
self.set_trace_for_frame_and_parents(frame)
self.set_trace_for_frame_and_parents(thread, frame)

elif info.pydev_step_cmd in (CMD_STEP_OVER, CMD_STEP_OVER_MY_CODE, CMD_SMART_STEP_INTO):
info.pydev_step_stop = frame
self.set_trace_for_frame_and_parents(frame)
self.set_trace_for_frame_and_parents(thread, frame)

elif info.pydev_step_cmd == CMD_RUN_TO_LINE or info.pydev_step_cmd == CMD_SET_NEXT_STATEMENT:
info.pydev_step_stop = None
self.set_trace_for_frame_and_parents(frame)
self.set_trace_for_frame_and_parents(thread, frame)
stop = False
response_msg = ""
try:
Expand Down Expand Up @@ -2225,7 +2227,7 @@ def _do_wait_suspend(self, thread, frame, event, arg, suspend_type, from_this_th
if back_frame is not None:
# steps back to the same frame (in a return call it will stop in the 'back frame' for the user)
info.pydev_step_stop = frame
self.set_trace_for_frame_and_parents(frame)
self.set_trace_for_frame_and_parents(thread, frame)
else:
# No back frame?!? -- this happens in jython when we have some frame created from an awt event
# (the previous frame would be the awt event, but this doesn't make part of 'jython', only 'java')
Expand Down Expand Up @@ -2280,7 +2282,11 @@ def do_stop_on_unhandled_exception(self, thread, frame, frames_byid, arg):
remove_exception_from_frame(frame)
frame = None

def set_trace_for_frame_and_parents(self, frame, **kwargs):
def set_trace_for_frame_and_parents(self, thread: Optional[threading.Thread], frame, **kwargs):
'''
Note that the thread may be None for c/c++ threads (for which threading.current_thread
was never requested) or for threads which are no longer active.
'''
disable = kwargs.pop('disable', False)
assert not kwargs

Expand All @@ -2295,7 +2301,7 @@ def set_trace_for_frame_and_parents(self, frame, **kwargs):

else:
pydev_log.debug('Set tracing of frame: %s - %s', frame.f_code.co_filename, frame.f_code.co_name)
pydevd_sys_monitoring.enable_code_tracing(frame.f_code, frame)
pydevd_sys_monitoring.enable_code_tracing(thread, frame.f_code, frame)
else:
pydev_log.debug('SKIP set tracing of frame: %s - %s', frame.f_code.co_filename, frame.f_code.co_name)
else:
Expand Down Expand Up @@ -3014,11 +3020,11 @@ def _locked_settrace(
# As this is the first connection, also set tracing for any untraced threads
py_db.set_tracing_for_untraced_contexts()

py_db.set_trace_for_frame_and_parents(get_frame().f_back)
py_db.set_trace_for_frame_and_parents(t, get_frame().f_back)

with CustomFramesContainer.custom_frames_lock: # @UndefinedVariable
for _frameId, custom_frame in CustomFramesContainer.custom_frames.items():
py_db.set_trace_for_frame_and_parents(custom_frame.frame)
py_db.set_trace_for_frame_and_parents(None, custom_frame.frame)

else:
# ok, we're already in debug mode, with all set, so, let's just set the break
Expand All @@ -3027,9 +3033,8 @@ def _locked_settrace(
if client_access_token is not None:
py_db.authentication.client_access_token = client_access_token

py_db.set_trace_for_frame_and_parents(get_frame().f_back)

t = threadingCurrentThread()
py_db.set_trace_for_frame_and_parents(t, get_frame().f_back)
additional_info = set_additional_thread_info(t)

if trace_only_current_thread:
Expand Down

0 comments on commit 71c36d0

Please sign in to comment.