@@ -136,20 +136,19 @@ A new structure is added to PyThreadState to support remote debugging:
136136
137137 typedef struct _remote_debugger_support {
138138 int debugger_pending_call;
139- char debugger_script[MAX_SCRIPT_SIZE ];
139+ char debugger_script_path[MAX_SCRIPT_PATH_SIZE ];
140140 } _PyRemoteDebuggerSupport;
141141
142-
143142 This structure is appended to ``PyThreadState ``, adding only a few fields that
144143are **never accessed during normal execution **. The ``debugger_pending_call `` field
145144indicates when a debugger has requested execution, while ``debugger_script ``
146145provides Python code to be executed when the interpreter reaches a safe point.
147146
148- The value for ``MAX_SCRIPT_SIZE `` will be a trade-off between binary size and
149- how big debugging scripts can be. As most of the logic should be in libraries
150- and arbitrary code can be executed with very short amount of Python we are
151- proposing to start with 4kb initially. This value can be extended in the future
152- if we ever need to.
147+ The value for ``MAX_SCRIPT_PATH_SIZE `` will be a trade-off between binary size
148+ and how big debugging scripts' paths can be. To limit the memory overhead per
149+ thread we will be limiting this to 512 bytes. This size will also be provided as
150+ part of the debugger support structure so debuggers know how much they can
151+ write. This value can be extended in the future if we ever need to.
153152
154153
155154Debug Offsets Table
@@ -168,18 +167,20 @@ debugger support:
168167.. code-block :: C
169168
170169 struct _debugger_support {
171- uint64_t eval_breaker; // Location of the eval breaker flag
172- uint64_t remote_debugger_support; // Offset to our support structure
173- uint64_t debugger_pending_call; // Where to write the pending flag
174- uint64_t debugger_script; // Where to write the script path
170+ uint64_t eval_breaker; // Location of the eval breaker flag
171+ uint64_t remote_debugger_support; // Offset to our support structure
172+ uint64_t debugger_pending_call; // Where to write the pending flag
173+ uint64_t debugger_script_path; // Where to write the script path
174+ uint64_t debugger_script_path_size; // Size of the script path buffer
175175 } debugger_support;
176176
177177 These offsets allow debuggers to locate critical debugging control structures in
178178the target process's memory space. The ``eval_breaker `` and ``remote_debugger_support ``
179179offsets are relative to each ``PyThreadState ``, while the ``debugger_pending_call ``
180180and ``debugger_script `` offsets are relative to each ``_PyRemoteDebuggerSupport ``
181181structure, allowing the new structure and its fields to be found regardless of
182- where they are in memory.
182+ where they are in memory. ``debugger_script_path_size `` informs the attaching
183+ tool of the size of the buffer.
183184
184185Attachment Protocol
185186-------------------
@@ -201,7 +202,7 @@ When a debugger wants to attach to a Python process, it follows these steps:
201202
202203 - Write a filename containing Python code to be executed into the
203204 ``debugger_script `` field in ``_PyRemoteDebuggerSupport ``.
204- - Set ``debugger_pending_call `` flag in ``_PyRemoteDebuggerSupport ``
205+ - Set ``debugger_pending_call `` flag in ``_PyRemoteDebuggerSupport `` to 1
205206 - Set ``_PY_EVAL_PLEASE_STOP_BIT `` in the ``eval_breaker `` field
206207
207208Once the interpreter reaches the next safe point, it will execute the script
@@ -224,6 +225,9 @@ the interpreter will execute the provided debugging code at the next safe point.
224225This all happens in a completely safe context, since the interpreter is
225226guaranteed to be in a consistent state whenever the eval breaker is checked.
226227
228+ The only valid values for ``debugger_pending_call `` will initially be 0 and 1
229+ and other values are reserved for future use.
230+
227231An audit event will be raised before the code is executed, allowing this mechanism
228232to be audited or disabled if desired by a system's administrator.
229233
@@ -464,6 +468,21 @@ in the file path to point to somewhere attacker controlled, this would allow
464468them to force their malicious code to be executed rather than the code the
465469debugger intends to run.
466470
471+ Using a Single Runtime Buffer
472+ -----------------------------
473+
474+ During the review of this PEP it has been suggested using a single
475+ shared buffer at the runtime level for all debugger communications. While this
476+ appeared simpler and required less memory, we discovered it would actually prevent scenarios
477+ where multiple debuggers need to coordinate operations across different threads,
478+ or where a single debugger needs to orchestrate complex debugging operations. A
479+ single shared buffer would force serialization of all debugging operations,
480+ making it impossible for debuggers to work independently on different threads.
481+
482+ The per-thread buffer approach, despite its memory overhead in highly threaded
483+ applications, enables these important debugging scenarios by allowing each
484+ debugger to communicate independently with its target thread.
485+
467486Thanks
468487======
469488
0 commit comments