Skip to content

Commit c77eb4f

Browse files
godlygeekpablogsal
authored andcommitted
Leverage new debug offsets added in 3.13rc2
Some offsets that we previously needed to infer or make assumptions about are now provided by the interpreter itself. Start using them. Signed-off-by: Matt Wozniski <[email protected]>
1 parent 5942474 commit c77eb4f

File tree

3 files changed

+111
-61
lines changed

3 files changed

+111
-61
lines changed

src/pystack/_pystack/process.cpp

Lines changed: 66 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -839,9 +839,31 @@ AbstractProcessManager::warnIfOffsetsAreMismatched(remote_addr_t runtime_addr) c
839839

840840
compare_size(&py_runtime_v::o_dbg_off_type_object_struct_size, py_type);
841841
compare_offset(&py_runtime_v::o_dbg_off_type_object_tp_name, py_type.o_tp_name);
842+
compare_offset(&py_runtime_v::o_dbg_off_type_object_tp_repr, py_type.o_tp_repr);
843+
compare_offset(&py_runtime_v::o_dbg_off_type_object_tp_flags, py_type.o_tp_flags);
842844

843845
compare_size(&py_runtime_v::o_dbg_off_tuple_object_struct_size, py_tuple);
844846
compare_offset(&py_runtime_v::o_dbg_off_tuple_object_ob_item, py_tuple.o_ob_item);
847+
compare_offset(&py_runtime_v::o_dbg_off_tuple_object_ob_size, py_tuple.o_ob_size);
848+
849+
compare_size(&py_runtime_v::o_dbg_off_list_object_struct_size, py_list);
850+
compare_offset(&py_runtime_v::o_dbg_off_list_object_ob_item, py_list.o_ob_item);
851+
compare_offset(&py_runtime_v::o_dbg_off_list_object_ob_size, py_list.o_ob_size);
852+
853+
compare_size(&py_runtime_v::o_dbg_off_dict_object_struct_size, py_dict);
854+
compare_offset(&py_runtime_v::o_dbg_off_dict_object_ma_keys, py_dict.o_ma_keys);
855+
compare_offset(&py_runtime_v::o_dbg_off_dict_object_ma_values, py_dict.o_ma_values);
856+
857+
compare_size(&py_runtime_v::o_dbg_off_float_object_struct_size, py_float);
858+
compare_offset(&py_runtime_v::o_dbg_off_float_object_ob_fval, py_float.o_ob_fval);
859+
860+
compare_size(&py_runtime_v::o_dbg_off_long_object_struct_size, py_long);
861+
compare_offset(&py_runtime_v::o_dbg_off_long_object_lv_tag, py_long.o_ob_size);
862+
compare_offset(&py_runtime_v::o_dbg_off_long_object_ob_digit, py_long.o_ob_digit);
863+
864+
compare_size(&py_runtime_v::o_dbg_off_bytes_object_struct_size, py_bytes);
865+
compare_offset(&py_runtime_v::o_dbg_off_bytes_object_ob_size, py_bytes.o_ob_size);
866+
compare_offset(&py_runtime_v::o_dbg_off_bytes_object_ob_sval, py_bytes.o_ob_sval);
845867

846868
compare_size(&py_runtime_v::o_dbg_off_unicode_object_struct_size, py_unicode);
847869
compare_offset(&py_runtime_v::o_dbg_off_unicode_object_state, py_unicode.o_state);
@@ -896,12 +918,8 @@ bool
896918
AbstractProcessManager::copyDebugOffsets(Structure<py_runtime_v>& py_runtime, python_v& debug_offsets)
897919
const
898920
{
899-
// Fill in a temporary python_v with the offsets from the remote.
900-
// For fields that aren't in _Py_DebugOffsets, make some assumptions, based
901-
// in part on the size delta between the sizeof(PyObject) baked into our
902-
// static offsets and the sizeof(PyObject) in the remote process/core.
903-
Py_ssize_t new_pyobject_size = py_runtime.getField(&py_runtime_v::o_dbg_off_pyobject_struct_size);
904-
Py_ssize_t pyobject_size_delta = -d_py_v->py_object.size + new_pyobject_size;
921+
// Fill in a temporary python_v with the offsets from the remote. For fields
922+
// that aren't in _Py_DebugOffsets, assume our static offsets are correct.
905923

906924
#define set_size(pystack_struct, size_offset) \
907925
debug_offsets.pystack_struct.size = py_runtime.getField(size_offset)
@@ -951,19 +969,35 @@ AbstractProcessManager::copyDebugOffsets(Structure<py_runtime_v>& py_runtime, py
951969

952970
set_size(py_type, &py_runtime_v::o_dbg_off_type_object_struct_size);
953971
set_offset(py_type.o_tp_name, &py_runtime_v::o_dbg_off_type_object_tp_name);
954-
// Assume our static offsets are correct about the distance from tp_name to the other fields
955-
debug_offsets.py_type.o_tp_repr = {
956-
d_py_v->py_type.o_tp_repr.offset - d_py_v->py_type.o_tp_name.offset
957-
+ debug_offsets.py_type.o_tp_name.offset};
958-
debug_offsets.py_type.o_tp_flags = {
959-
d_py_v->py_type.o_tp_flags.offset - d_py_v->py_type.o_tp_name.offset
960-
+ debug_offsets.py_type.o_tp_name.offset};
972+
set_offset(py_type.o_tp_repr, &py_runtime_v::o_dbg_off_type_object_tp_repr);
973+
set_offset(py_type.o_tp_flags, &py_runtime_v::o_dbg_off_type_object_tp_flags);
961974

962975
set_size(py_tuple, &py_runtime_v::o_dbg_off_tuple_object_struct_size);
963-
// Assume ob_base is the first field of PyVarObject and ob_size is the second
964-
static_assert(sizeof(PyTupleObject::ob_base.ob_base) == offsetof(PyTupleObject, ob_base.ob_size));
965-
debug_offsets.py_tuple.o_ob_size = {(offset_t)new_pyobject_size};
966976
set_offset(py_tuple.o_ob_item, &py_runtime_v::o_dbg_off_tuple_object_ob_item);
977+
set_offset(py_tuple.o_ob_size, &py_runtime_v::o_dbg_off_tuple_object_ob_size);
978+
979+
set_size(py_list, &py_runtime_v::o_dbg_off_list_object_struct_size);
980+
set_offset(py_list.o_ob_item, &py_runtime_v::o_dbg_off_list_object_ob_item);
981+
set_offset(py_list.o_ob_size, &py_runtime_v::o_dbg_off_list_object_ob_size);
982+
983+
set_size(py_dict, &py_runtime_v::o_dbg_off_dict_object_struct_size);
984+
set_offset(py_dict.o_ma_keys, &py_runtime_v::o_dbg_off_dict_object_ma_keys);
985+
set_offset(py_dict.o_ma_values, &py_runtime_v::o_dbg_off_dict_object_ma_values);
986+
987+
// Assume our static offsets for dict keys and values are correct
988+
debug_offsets.py_dictkeys = d_py_v->py_dictkeys;
989+
debug_offsets.py_dictvalues = d_py_v->py_dictvalues;
990+
991+
set_size(py_float, &py_runtime_v::o_dbg_off_float_object_struct_size);
992+
set_offset(py_float.o_ob_fval, &py_runtime_v::o_dbg_off_float_object_ob_fval);
993+
994+
set_size(py_long, &py_runtime_v::o_dbg_off_long_object_struct_size);
995+
set_offset(py_long.o_ob_size, &py_runtime_v::o_dbg_off_long_object_lv_tag);
996+
set_offset(py_long.o_ob_digit, &py_runtime_v::o_dbg_off_long_object_ob_digit);
997+
998+
set_size(py_bytes, &py_runtime_v::o_dbg_off_bytes_object_struct_size);
999+
set_offset(py_bytes.o_ob_size, &py_runtime_v::o_dbg_off_bytes_object_ob_size);
1000+
set_offset(py_bytes.o_ob_sval, &py_runtime_v::o_dbg_off_bytes_object_ob_sval);
9671001

9681002
set_size(py_unicode, &py_runtime_v::o_dbg_off_unicode_object_struct_size);
9691003
set_offset(py_unicode.o_state, &py_runtime_v::o_dbg_off_unicode_object_state);
@@ -973,54 +1007,25 @@ AbstractProcessManager::copyDebugOffsets(Structure<py_runtime_v>& py_runtime, py
9731007
set_size(py_gc, &py_runtime_v::o_dbg_off_gc_struct_size);
9741008
set_offset(py_gc.o_collecting, &py_runtime_v::o_dbg_off_gc_collecting);
9751009

976-
// Assume ob_size and ob_item are at the same location for list as for tuple
977-
static_assert(
978-
offsetof(PyListObject, ob_item) + sizeof(PyListObject::ob_item) <= sizeof(PyTupleObject));
979-
debug_offsets.py_list.size = debug_offsets.py_tuple.size;
980-
981-
static_assert(offsetof(PyListObject, ob_base.ob_size) == offsetof(PyTupleObject, ob_base.ob_size));
982-
debug_offsets.py_list.o_ob_size = debug_offsets.py_tuple.o_ob_size;
983-
984-
static_assert(offsetof(PyListObject, ob_item) == offsetof(PyTupleObject, ob_item));
985-
debug_offsets.py_list.o_ob_item = {debug_offsets.py_tuple.o_ob_item.offset};
986-
987-
// Assume our static offsets for dict are correct save possibly for sizeof(PyObject) changing
988-
debug_offsets.py_dictkeys = d_py_v->py_dictkeys;
989-
debug_offsets.py_dictvalues = d_py_v->py_dictvalues;
990-
debug_offsets.py_dict = d_py_v->py_dict;
991-
debug_offsets.py_dict.size += pyobject_size_delta;
992-
debug_offsets.py_dict.o_ma_keys.offset += pyobject_size_delta;
993-
debug_offsets.py_dict.o_ma_values.offset += pyobject_size_delta;
994-
995-
// Assume our static offsets for float are correct save possibly for sizeof(PyObject) changing
996-
debug_offsets.py_float = d_py_v->py_float;
997-
debug_offsets.py_float.size += pyobject_size_delta;
998-
debug_offsets.py_float.o_ob_fval.offset += pyobject_size_delta;
999-
1000-
// Assume our static offsets for long are correct save possibly for sizeof(PyObject) changing
1001-
debug_offsets.py_long = d_py_v->py_long;
1002-
debug_offsets.py_long.size += pyobject_size_delta;
1003-
debug_offsets.py_long.o_ob_size.offset += pyobject_size_delta;
1004-
debug_offsets.py_long.o_ob_digit.offset += pyobject_size_delta;
1005-
1006-
// Assume our static offsets for bytes are correct save possibly for sizeof(PyObject) changing
1007-
debug_offsets.py_bytes = d_py_v->py_bytes;
1008-
debug_offsets.py_bytes.size += pyobject_size_delta;
1009-
debug_offsets.py_bytes.o_ob_size.offset += pyobject_size_delta;
1010-
debug_offsets.py_bytes.o_ob_sval.offset += pyobject_size_delta;
1011-
10121010
// Assume our static offsets for cframe are all correct
10131011
debug_offsets.py_cframe = d_py_v->py_cframe;
10141012

1015-
// Assume our static offsets for gilruntimestate are off by 8 bytes in a free-threading build.
1016-
// This is quite a hack...
1017-
debug_offsets.py_gilruntimestate = d_py_v->py_gilruntimestate;
1018-
bool is_free_threading = static_cast<size_t>(debug_offsets.py_object.size) > 2 * sizeof(void*);
1019-
if (is_free_threading) {
1020-
debug_offsets.py_gilruntimestate.size += 8;
1021-
debug_offsets.py_gilruntimestate.o_last_holder.offset += 8;
1022-
debug_offsets.py_gilruntimestate.o_locked.offset += 8;
1023-
}
1013+
size_t gilruntimestate_start =
1014+
py_runtime.getField(&py_runtime_v::o_dbg_off_interpreter_state_gil_runtime_state);
1015+
1016+
size_t gilruntimestate_locked_offset =
1017+
py_runtime.getField(&py_runtime_v::o_dbg_off_interpreter_state_gil_runtime_state_locked)
1018+
- gilruntimestate_start;
1019+
size_t gilruntimestate_holder_offset =
1020+
py_runtime.getField(&py_runtime_v::o_dbg_off_interpreter_state_gil_runtime_state_holder)
1021+
- gilruntimestate_start;
1022+
1023+
debug_offsets.py_gilruntimestate.size = std::max(
1024+
{gilruntimestate_locked_offset + sizeof(decltype(py_gilruntimestate_v::o_locked)::Type),
1025+
gilruntimestate_holder_offset
1026+
+ sizeof(decltype(py_gilruntimestate_v::o_last_holder)::Type)});
1027+
debug_offsets.py_gilruntimestate.o_locked.offset = gilruntimestate_locked_offset;
1028+
debug_offsets.py_gilruntimestate.o_last_holder.offset = gilruntimestate_holder_offset;
10241029

10251030
#undef set_size
10261031
#undef set_offset

src/pystack/_pystack/version.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ py_runtimev313()
239239
{},
240240
offsetof(T, debug_offsets.cookie),
241241
offsetof(T, debug_offsets.version),
242+
offsetof(T, debug_offsets.free_threaded),
242243
offsetof(T, debug_offsets.runtime_state.size),
243244
offsetof(T, debug_offsets.runtime_state.finalizing),
244245
offsetof(T, debug_offsets.runtime_state.interpreters_head),
@@ -251,6 +252,8 @@ py_runtimev313()
251252
offsetof(T, debug_offsets.interpreter_state.sysdict),
252253
offsetof(T, debug_offsets.interpreter_state.builtins),
253254
offsetof(T, debug_offsets.interpreter_state.ceval_gil),
255+
offsetof(T, debug_offsets.interpreter_state.gil_runtime_state),
256+
offsetof(T, debug_offsets.interpreter_state.gil_runtime_state_enabled),
254257
offsetof(T, debug_offsets.interpreter_state.gil_runtime_state_locked),
255258
offsetof(T, debug_offsets.interpreter_state.gil_runtime_state_holder),
256259
offsetof(T, debug_offsets.thread_state.size),
@@ -282,8 +285,25 @@ py_runtimev313()
282285
offsetof(T, debug_offsets.pyobject.ob_type),
283286
offsetof(T, debug_offsets.type_object.size),
284287
offsetof(T, debug_offsets.type_object.tp_name),
288+
offsetof(T, debug_offsets.type_object.tp_repr),
289+
offsetof(T, debug_offsets.type_object.tp_flags),
285290
offsetof(T, debug_offsets.tuple_object.size),
286291
offsetof(T, debug_offsets.tuple_object.ob_item),
292+
offsetof(T, debug_offsets.tuple_object.ob_size),
293+
offsetof(T, debug_offsets.list_object.size),
294+
offsetof(T, debug_offsets.list_object.ob_item),
295+
offsetof(T, debug_offsets.list_object.ob_size),
296+
offsetof(T, debug_offsets.dict_object.size),
297+
offsetof(T, debug_offsets.dict_object.ma_keys),
298+
offsetof(T, debug_offsets.dict_object.ma_values),
299+
offsetof(T, debug_offsets.float_object.size),
300+
offsetof(T, debug_offsets.float_object.ob_fval),
301+
offsetof(T, debug_offsets.long_object.size),
302+
offsetof(T, debug_offsets.long_object.lv_tag),
303+
offsetof(T, debug_offsets.long_object.ob_digit),
304+
offsetof(T, debug_offsets.bytes_object.size),
305+
offsetof(T, debug_offsets.bytes_object.ob_size),
306+
offsetof(T, debug_offsets.bytes_object.ob_sval),
287307
offsetof(T, debug_offsets.unicode_object.size),
288308
offsetof(T, debug_offsets.unicode_object.state),
289309
offsetof(T, debug_offsets.unicode_object.length),

src/pystack/_pystack/version.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ struct py_runtime_v
134134

135135
FieldOffset<char[8]> o_dbg_off_cookie;
136136
FieldOffset<uint64_t> o_dbg_off_py_version_hex;
137+
FieldOffset<uint64_t> o_dbg_off_free_threaded;
137138

138139
FieldOffset<uint64_t> o_dbg_off_runtime_state_struct_size;
139140
FieldOffset<uint64_t> o_dbg_off_runtime_state_finalizing;
@@ -148,6 +149,8 @@ struct py_runtime_v
148149
FieldOffset<uint64_t> o_dbg_off_interpreter_state_sysdict;
149150
FieldOffset<uint64_t> o_dbg_off_interpreter_state_builtins;
150151
FieldOffset<uint64_t> o_dbg_off_interpreter_state_ceval_gil;
152+
FieldOffset<uint64_t> o_dbg_off_interpreter_state_gil_runtime_state;
153+
FieldOffset<uint64_t> o_dbg_off_interpreter_state_gil_runtime_state_enabled;
151154
FieldOffset<uint64_t> o_dbg_off_interpreter_state_gil_runtime_state_locked;
152155
FieldOffset<uint64_t> o_dbg_off_interpreter_state_gil_runtime_state_holder;
153156

@@ -184,9 +187,31 @@ struct py_runtime_v
184187

185188
FieldOffset<uint64_t> o_dbg_off_type_object_struct_size;
186189
FieldOffset<uint64_t> o_dbg_off_type_object_tp_name;
190+
FieldOffset<uint64_t> o_dbg_off_type_object_tp_repr;
191+
FieldOffset<uint64_t> o_dbg_off_type_object_tp_flags;
187192

188193
FieldOffset<uint64_t> o_dbg_off_tuple_object_struct_size;
189194
FieldOffset<uint64_t> o_dbg_off_tuple_object_ob_item;
195+
FieldOffset<uint64_t> o_dbg_off_tuple_object_ob_size;
196+
197+
FieldOffset<uint64_t> o_dbg_off_list_object_struct_size;
198+
FieldOffset<uint64_t> o_dbg_off_list_object_ob_item;
199+
FieldOffset<uint64_t> o_dbg_off_list_object_ob_size;
200+
201+
FieldOffset<uint64_t> o_dbg_off_dict_object_struct_size;
202+
FieldOffset<uint64_t> o_dbg_off_dict_object_ma_keys;
203+
FieldOffset<uint64_t> o_dbg_off_dict_object_ma_values;
204+
205+
FieldOffset<uint64_t> o_dbg_off_float_object_struct_size;
206+
FieldOffset<uint64_t> o_dbg_off_float_object_ob_fval;
207+
208+
FieldOffset<uint64_t> o_dbg_off_long_object_struct_size;
209+
FieldOffset<uint64_t> o_dbg_off_long_object_lv_tag;
210+
FieldOffset<uint64_t> o_dbg_off_long_object_ob_digit;
211+
212+
FieldOffset<uint64_t> o_dbg_off_bytes_object_struct_size;
213+
FieldOffset<uint64_t> o_dbg_off_bytes_object_ob_size;
214+
FieldOffset<uint64_t> o_dbg_off_bytes_object_ob_sval;
190215

191216
FieldOffset<uint64_t> o_dbg_off_unicode_object_struct_size;
192217
FieldOffset<uint64_t> o_dbg_off_unicode_object_state;

0 commit comments

Comments
 (0)