[Python-checkins] gh-106597: Add debugging struct with offsets for out-of-process tools (#106598)
pablogsal
webhook-mailer at python.org
Tue Jul 11 15:35:45 EDT 2023
https://github.com/python/cpython/commit/b444bfb0a325dea8c29f7b1828233b00fbf4a1cb
commit: b444bfb0a325dea8c29f7b1828233b00fbf4a1cb
branch: main
author: Pablo Galindo Salgado <Pablogsal at gmail.com>
committer: pablogsal <Pablogsal at gmail.com>
date: 2023-07-11T20:35:41+01:00
summary:
gh-106597: Add debugging struct with offsets for out-of-process tools (#106598)
files:
A Misc/NEWS.d/next/Core and Builtins/2023-07-10-15-30-45.gh-issue-106597.WAZ14y.rst
M Include/internal/pycore_runtime.h
M Include/internal/pycore_runtime_init.h
diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h
index 5ed97e9715b2b..a16d4202b616d 100644
--- a/Include/internal/pycore_runtime.h
+++ b/Include/internal/pycore_runtime.h
@@ -53,12 +53,101 @@ typedef struct _Py_AuditHookEntry {
void *userData;
} _Py_AuditHookEntry;
+typedef struct _Py_DebugOffsets {
+ char cookie[8];
+ uint64_t version;
+ // Runtime state offset;
+ struct _runtime_state {
+ off_t finalizing;
+ off_t interpreters_head;
+ } runtime_state;
+
+ // Interpreter state offset;
+ struct _interpreter_state {
+ off_t next;
+ off_t threads_head;
+ off_t gc;
+ off_t imports_modules;
+ off_t sysdict;
+ off_t builtins;
+ off_t ceval_gil;
+ off_t gil_runtime_state_locked;
+ off_t gil_runtime_state_holder;
+ } interpreter_state;
+
+ // Thread state offset;
+ struct _thread_state{
+ off_t prev;
+ off_t next;
+ off_t interp;
+ off_t cframe;
+ off_t thread_id;
+ off_t native_thread_id;
+ } thread_state;
+
+ // InterpreterFrame offset;
+ struct _interpreter_frame {
+ off_t previous;
+ off_t executable;
+ off_t prev_instr;
+ off_t localsplus;
+ off_t owner;
+ } interpreter_frame;
+
+ // CFrame offset;
+ struct _cframe {
+ off_t current_frame;
+ off_t previous;
+ } cframe;
+
+ // Code object offset;
+ struct _code_object {
+ off_t filename;
+ off_t name;
+ off_t linetable;
+ off_t firstlineno;
+ off_t argcount;
+ off_t localsplusnames;
+ off_t localspluskinds;
+ off_t co_code_adaptive;
+ } code_object;
+
+ // PyObject offset;
+ struct _pyobject {
+ off_t ob_type;
+ } pyobject;
+
+ // PyTypeObject object offset;
+ struct _type_object {
+ off_t tp_name;
+ } type_object;
+
+ // PyTuple object offset;
+ struct _tuple_object {
+ off_t ob_item;
+ } tuple_object;
+} _Py_DebugOffsets;
+
/* Full Python runtime state */
/* _PyRuntimeState holds the global state for the CPython runtime.
That data is exposed in the internal API as a static variable (_PyRuntime).
*/
typedef struct pyruntimestate {
+ /* This field must be first to facilitate locating it by out of process
+ * debuggers. Out of process debuggers will use the offsets contained in this
+ * field to be able to locate other fields in several interpreter structures
+ * in a way that doesn't require them to know the exact layout of those
+ * structures.
+ *
+ * IMPORTANT:
+ * This struct is **NOT** backwards compatible between minor version of the
+ * interpreter and the members, order of members and size can change between
+ * minor versions. This struct is only guaranteed to be stable between patch
+ * versions for a given minor version of the interpreter.
+ */
+ _Py_DebugOffsets debug_offsets;
+
/* Has been initialized to a safe state.
In order to be effective, this must be set to 0 during or right
diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h
index b507de0437d9a..e72e7422c7207 100644
--- a/Include/internal/pycore_runtime_init.h
+++ b/Include/internal/pycore_runtime_init.h
@@ -21,9 +21,65 @@ extern PyTypeObject _PyExc_MemoryError;
/* The static initializers defined here should only be used
in the runtime init code (in pystate.c and pylifecycle.c). */
-
#define _PyRuntimeState_INIT(runtime) \
{ \
+ .debug_offsets = { \
+ .cookie = "xdebugpy", \
+ .version = PY_VERSION_HEX, \
+ .runtime_state = { \
+ .finalizing = offsetof(_PyRuntimeState, _finalizing), \
+ .interpreters_head = offsetof(_PyRuntimeState, interpreters.head), \
+ }, \
+ .interpreter_state = { \
+ .next = offsetof(PyInterpreterState, next), \
+ .threads_head = offsetof(PyInterpreterState, threads.head), \
+ .gc = offsetof(PyInterpreterState, gc), \
+ .imports_modules = offsetof(PyInterpreterState, imports.modules), \
+ .sysdict = offsetof(PyInterpreterState, sysdict), \
+ .builtins = offsetof(PyInterpreterState, builtins), \
+ .ceval_gil = offsetof(PyInterpreterState, ceval.gil), \
+ .gil_runtime_state_locked = offsetof(PyInterpreterState, _gil.locked), \
+ .gil_runtime_state_holder = offsetof(PyInterpreterState, _gil.last_holder), \
+ }, \
+ .thread_state = { \
+ .prev = offsetof(PyThreadState, prev), \
+ .next = offsetof(PyThreadState, next), \
+ .interp = offsetof(PyThreadState, interp), \
+ .cframe = offsetof(PyThreadState, cframe), \
+ .thread_id = offsetof(PyThreadState, thread_id), \
+ .native_thread_id = offsetof(PyThreadState, native_thread_id), \
+ }, \
+ .interpreter_frame = { \
+ .previous = offsetof(_PyInterpreterFrame, previous), \
+ .executable = offsetof(_PyInterpreterFrame, f_executable), \
+ .prev_instr = offsetof(_PyInterpreterFrame, prev_instr), \
+ .localsplus = offsetof(_PyInterpreterFrame, localsplus), \
+ .owner = offsetof(_PyInterpreterFrame, owner), \
+ }, \
+ .cframe = { \
+ .current_frame = offsetof(_PyCFrame, current_frame), \
+ .previous = offsetof(_PyCFrame, previous), \
+ }, \
+ .code_object = { \
+ .filename = offsetof(PyCodeObject, co_filename), \
+ .name = offsetof(PyCodeObject, co_name), \
+ .linetable = offsetof(PyCodeObject, co_linetable), \
+ .firstlineno = offsetof(PyCodeObject, co_firstlineno), \
+ .argcount = offsetof(PyCodeObject, co_argcount), \
+ .localsplusnames = offsetof(PyCodeObject, co_localsplusnames), \
+ .localspluskinds = offsetof(PyCodeObject, co_localspluskinds), \
+ .co_code_adaptive = offsetof(PyCodeObject, co_code_adaptive), \
+ }, \
+ .pyobject = { \
+ .ob_type = offsetof(PyObject, ob_type), \
+ }, \
+ .type_object = { \
+ .tp_name = offsetof(PyTypeObject, tp_name), \
+ }, \
+ .tuple_object = { \
+ .ob_item = offsetof(PyTupleObject, ob_item), \
+ }, \
+ }, \
.allocators = { \
.standard = _pymem_allocators_standard_INIT(runtime), \
.debug = _pymem_allocators_debug_INIT, \
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-10-15-30-45.gh-issue-106597.WAZ14y.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-10-15-30-45.gh-issue-106597.WAZ14y.rst
new file mode 100644
index 0000000000000..bbe455d652f50
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-10-15-30-45.gh-issue-106597.WAZ14y.rst
@@ -0,0 +1,5 @@
+A new debug structure of offsets has been added to the ``_PyRuntimeState``
+that will help out-of-process debuggers and profilers to obtain the offsets
+to relevant interpreter structures in a way that is agnostic of how Python
+was compiled and that doesn't require copying the headers. Patch by Pablo
+Galindo
More information about the Python-checkins
mailing list