Skip to content

Commit

Permalink
Add debug offsets for free threaded builds (#123041)
Browse files Browse the repository at this point in the history
  • Loading branch information
pablogsal authored Aug 15, 2024
1 parent b15b81e commit d7a3df9
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 5 deletions.
51 changes: 50 additions & 1 deletion Include/internal/pycore_runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ struct _gilstate_runtime_state {

/* Runtime audit hook state */

#define _Py_Debug_Cookie "xdebugpy"

#ifdef Py_GIL_DISABLED
# define _Py_Debug_gilruntimestate_enabled offsetof(struct _gil_runtime_state, enabled)
# define _Py_Debug_Free_Threaded 1
#else
# define _Py_Debug_gilruntimestate_enabled 0
# define _Py_Debug_Free_Threaded 0
#endif
typedef struct _Py_AuditHookEntry {
struct _Py_AuditHookEntry *next;
Py_AuditHookFunction hookCFunction;
Expand All @@ -53,6 +62,7 @@ typedef struct _Py_AuditHookEntry {
typedef struct _Py_DebugOffsets {
char cookie[8];
uint64_t version;
uint64_t free_threaded;
// Runtime state offset;
struct _runtime_state {
uint64_t size;
Expand All @@ -71,6 +81,8 @@ typedef struct _Py_DebugOffsets {
uint64_t sysdict;
uint64_t builtins;
uint64_t ceval_gil;
uint64_t gil_runtime_state;
uint64_t gil_runtime_state_enabled;
uint64_t gil_runtime_state_locked;
uint64_t gil_runtime_state_holder;
} interpreter_state;
Expand Down Expand Up @@ -122,20 +134,57 @@ typedef struct _Py_DebugOffsets {
struct _type_object {
uint64_t size;
uint64_t tp_name;
uint64_t tp_repr;
uint64_t tp_flags;
} type_object;

// PyTuple object offset;
struct _tuple_object {
uint64_t size;
uint64_t ob_item;
uint64_t ob_size;
} tuple_object;

// PyList object offset;
struct _list_object {
uint64_t size;
uint64_t ob_item;
uint64_t ob_size;
} list_object;

// PyDict object offset;
struct _dict_object {
uint64_t size;
uint64_t ma_keys;
uint64_t ma_values;
} dict_object;

// PyFloat object offset;
struct _float_object {
uint64_t size;
uint64_t ob_fval;
} float_object;

// PyLong object offset;
struct _long_object {
uint64_t size;
uint64_t lv_tag;
uint64_t ob_digit;
} long_object;

// PyBytes object offset;
struct _bytes_object {
uint64_t size;
uint64_t ob_size;
uint64_t ob_sval;
} bytes_object;

// Unicode object offset;
struct _unicode_object {
uint64_t size;
uint64_t state;
uint64_t length;
size_t asciiobject_size;
uint64_t asciiobject_size;
} unicode_object;

// GC runtime state offset;
Expand Down
34 changes: 32 additions & 2 deletions Include/internal/pycore_runtime_init.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,12 @@ 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) \
#define _PyRuntimeState_INIT(runtime, debug_cookie) \
{ \
.debug_offsets = { \
.cookie = "xdebugpy", \
.cookie = debug_cookie, \
.version = PY_VERSION_HEX, \
.free_threaded = _Py_Debug_Free_Threaded, \
.runtime_state = { \
.size = sizeof(_PyRuntimeState), \
.finalizing = offsetof(_PyRuntimeState, _finalizing), \
Expand All @@ -49,6 +50,8 @@ extern PyTypeObject _PyExc_MemoryError;
.sysdict = offsetof(PyInterpreterState, sysdict), \
.builtins = offsetof(PyInterpreterState, builtins), \
.ceval_gil = offsetof(PyInterpreterState, ceval.gil), \
.gil_runtime_state = offsetof(PyInterpreterState, _gil), \
.gil_runtime_state_enabled = _Py_Debug_gilruntimestate_enabled, \
.gil_runtime_state_locked = offsetof(PyInterpreterState, _gil.locked), \
.gil_runtime_state_holder = offsetof(PyInterpreterState, _gil.last_holder), \
}, \
Expand Down Expand Up @@ -90,10 +93,37 @@ extern PyTypeObject _PyExc_MemoryError;
.type_object = { \
.size = sizeof(PyTypeObject), \
.tp_name = offsetof(PyTypeObject, tp_name), \
.tp_repr = offsetof(PyTypeObject, tp_repr), \
.tp_flags = offsetof(PyTypeObject, tp_flags), \
}, \
.tuple_object = { \
.size = sizeof(PyTupleObject), \
.ob_item = offsetof(PyTupleObject, ob_item), \
.ob_size = offsetof(PyTupleObject, ob_base.ob_size), \
}, \
.list_object = { \
.size = sizeof(PyListObject), \
.ob_item = offsetof(PyListObject, ob_item), \
.ob_size = offsetof(PyListObject, ob_base.ob_size), \
}, \
.dict_object = { \
.size = sizeof(PyDictObject), \
.ma_keys = offsetof(PyDictObject, ma_keys), \
.ma_values = offsetof(PyDictObject, ma_values), \
}, \
.float_object = { \
.size = sizeof(PyFloatObject), \
.ob_fval = offsetof(PyFloatObject, ob_fval), \
}, \
.long_object = { \
.size = sizeof(PyLongObject), \
.lv_tag = offsetof(_PyLongValue, lv_tag), \
.ob_digit = offsetof(_PyLongValue, ob_digit), \
}, \
.bytes_object = { \
.size = sizeof(PyBytesObject), \
.ob_size = offsetof(PyBytesObject, ob_base.ob_size), \
.ob_sval = offsetof(PyBytesObject, ob_sval), \
}, \
.unicode_object = { \
.size = sizeof(PyUnicodeObject), \
Expand Down
2 changes: 1 addition & 1 deletion Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ _PyRuntimeState _PyRuntime
#if defined(__linux__) && (defined(__GNUC__) || defined(__clang__))
__attribute__ ((section (".PyRuntime")))
#endif
= _PyRuntimeState_INIT(_PyRuntime);
= _PyRuntimeState_INIT(_PyRuntime, _Py_Debug_Cookie);
_Py_COMP_DIAG_POP

static int runtime_initialized = 0;
Expand Down
4 changes: 3 additions & 1 deletion Python/pystate.c
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ _Py_COMP_DIAG_IGNORE_DEPR_DECLS
Note that we initialize "initial" relative to _PyRuntime,
to ensure pre-initialized pointers point to the active
runtime state (and not "initial"). */
static const _PyRuntimeState initial = _PyRuntimeState_INIT(_PyRuntime);
static const _PyRuntimeState initial = _PyRuntimeState_INIT(_PyRuntime, "");
_Py_COMP_DIAG_POP

#define LOCKS_INIT(runtime) \
Expand Down Expand Up @@ -455,6 +455,8 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime)
// Py_Initialize() must be running again.
// Reset to _PyRuntimeState_INIT.
memcpy(runtime, &initial, sizeof(*runtime));
// Preserve the cookie from the original runtime.
memcpy(runtime->debug_offsets.cookie, _Py_Debug_Cookie, 8);
assert(!runtime->_initialized);
}

Expand Down

0 comments on commit d7a3df9

Please sign in to comment.