diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index 5ed97e9715b2b0..33980e24d2833e 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -53,12 +53,56 @@ typedef struct _Py_AuditHookEntry { void *userData; } _Py_AuditHookEntry; +typedef struct _Py_DebugOffsets { + // Runtime state offset; + off_t rs_finalizing; + off_t rs_interpreters_head; + + // Interpreter state offset; + off_t is_next; + off_t is_threads_head; + off_t is_gc; + off_t is_imports_modules; + off_t is_sysdict; + off_t is_builtins; + off_t is_ceval_gil; + + // Thread state offset; + off_t ts_prev; + off_t ts_next; + off_t ts_interp; + off_t ts_cframe; + off_t ts_thread_id; + + // Frame object offset; + off_t fo_previous; + off_t fo_executable; + off_t fo_prev_instr; + off_t fo_localsplus; + off_t fo_owner; + + // Code object offset; + off_t co_filename; + off_t co_name; + off_t co_linetable; + off_t co_firstlineno; + off_t co_argcount; + off_t co_localsplusnames; + off_t co_co_code_adaptive; +} _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 */ + _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 b507de0437d9aa..f251f62c00c50b 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -21,9 +21,40 @@ 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 = { \ + .rs_finalizing = offsetof(_PyRuntimeState, _finalizing), \ + .rs_interpreters_head = offsetof(_PyRuntimeState, interpreters.head), \ + \ + .is_next = offsetof(PyInterpreterState, next), \ + .is_threads_head = offsetof(PyInterpreterState, threads.head), \ + .is_gc = offsetof(PyInterpreterState, gc), \ + .is_imports_modules = offsetof(PyInterpreterState, imports.modules), \ + .is_sysdict = offsetof(PyInterpreterState, sysdict), \ + .is_builtins = offsetof(PyInterpreterState, builtins), \ + .is_ceval_gil = offsetof(PyInterpreterState, ceval.gil), \ + \ + .ts_prev = offsetof(PyThreadState, prev), \ + .ts_next = offsetof(PyThreadState, next), \ + .ts_interp = offsetof(PyThreadState, interp), \ + .ts_cframe = offsetof(PyThreadState, cframe), \ + .ts_thread_id = offsetof(PyThreadState, thread_id), \ + \ + .fo_previous = offsetof(_PyInterpreterFrame, previous), \ + .fo_executable = offsetof(_PyInterpreterFrame, f_executable), \ + .fo_prev_instr = offsetof(_PyInterpreterFrame, prev_instr), \ + .fo_localsplus = offsetof(_PyInterpreterFrame, localsplus), \ + .fo_owner = offsetof(_PyInterpreterFrame, owner), \ + \ + .co_filename = offsetof(PyCodeObject, co_filename), \ + .co_name = offsetof(PyCodeObject, co_name), \ + .co_linetable = offsetof(PyCodeObject, co_linetable), \ + .co_firstlineno = offsetof(PyCodeObject, co_firstlineno), \ + .co_argcount = offsetof(PyCodeObject, co_argcount), \ + .co_localsplusnames = offsetof(PyCodeObject, co_localsplusnames), \ + .co_co_code_adaptive = offsetof(PyCodeObject, co_code_adaptive), \ + }, \ .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 00000000000000..bbe455d652f50e --- /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