Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-106597: Add debugging struct with offsets for out-of-process tools #106598

Merged
merged 3 commits into from
Jul 11, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions Include/internal/pycore_runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,66 @@ typedef struct _Py_AuditHookEntry {
void *userData;
} _Py_AuditHookEntry;

typedef struct _Py_DebugOffsets {
pablogsal marked this conversation as resolved.
Show resolved Hide resolved
pablogsal marked this conversation as resolved.
Show resolved Hide resolved
// 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;
} interpreter_state;

// Thread state offset;
struct _thread_state{
off_t prev;
off_t next;
off_t interp;
off_t cframe;
off_t thread_id;
} thread_state;

// Frame object offset;
struct _frame_object {
off_t previous;
off_t executable;
off_t prev_instr;
off_t localsplus;
off_t owner;
} frame_object;

// 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 co_code_adaptive;
} code_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 */
_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
Expand Down
39 changes: 38 additions & 1 deletion Include/internal/pycore_runtime_init.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,46 @@ 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 = { \
.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), \
}, \
.thread_state = { \
.prev = offsetof(PyThreadState, prev), \
.next = offsetof(PyThreadState, next), \
.interp = offsetof(PyThreadState, interp), \
.cframe = offsetof(PyThreadState, cframe), \
.thread_id = offsetof(PyThreadState, thread_id), \
}, \
.frame_object = { \
.previous = offsetof(_PyInterpreterFrame, previous), \
.executable = offsetof(_PyInterpreterFrame, f_executable), \
.prev_instr = offsetof(_PyInterpreterFrame, prev_instr), \
.localsplus = offsetof(_PyInterpreterFrame, localsplus), \
.owner = offsetof(_PyInterpreterFrame, owner), \
}, \
.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), \
.co_code_adaptive = offsetof(PyCodeObject, co_code_adaptive), \
}, \
}, \
.allocators = { \
.standard = _pymem_allocators_standard_INIT(runtime), \
.debug = _pymem_allocators_debug_INIT, \
Expand Down
Original file line number Diff line number Diff line change
@@ -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