diff --git a/src/pystack/_pystack/process.cpp b/src/pystack/_pystack/process.cpp index f068df2..040d75e 100644 --- a/src/pystack/_pystack/process.cpp +++ b/src/pystack/_pystack/process.cpp @@ -63,84 +63,6 @@ class DirectoryReader } // namespace namespace pystack { -namespace { // unnamed - -template -void -warnIfOffsetsAreMismatchedImpl( - const PyDebugOffsets& debug_offsets, - const pystack::python_v& pystack_offsets) -{ - // Note: It's OK for pystack's size to be smaller, but not larger. -#define compare_size(offset_struct, pystack_struct) \ - if (debug_offsets.offset_struct.size < (uint64_t)pystack_offsets.pystack_struct.size) { \ - LOG(WARNING) << "Debug offsets mismatch: debug_offsets." #offset_struct ".size < " \ - << "pystack_offsets." #pystack_struct ".size" \ - << " (" << debug_offsets.offset_struct.size << " < " \ - << pystack_offsets.pystack_struct.size << ")"; \ - } else \ - do { \ - } while (0) - -#define compare_offset(offset_field, pystack_field) \ - if (debug_offsets.offset_field != (uint64_t)pystack_offsets.pystack_field.offset) { \ - LOG(WARNING) << "Debug offsets mismatch: debug_offsets." #offset_field \ - << " != pystack_offsets." #pystack_field ".offset" \ - << " (" << debug_offsets.offset_field \ - << " != " << pystack_offsets.pystack_field.offset << ")"; \ - } else \ - do { \ - } while (0) - - compare_size(runtime_state, py_runtime); - compare_offset(runtime_state.finalizing, py_runtime.o_finalizing); - compare_offset(runtime_state.interpreters_head, py_runtime.o_interp_head); - - compare_size(interpreter_state, py_is); - compare_offset(interpreter_state.next, py_is.o_next); - compare_offset(interpreter_state.threads_head, py_is.o_tstate_head); - compare_offset(interpreter_state.gc, py_is.o_gc); - compare_offset(interpreter_state.imports_modules, py_is.o_modules); - compare_offset(interpreter_state.sysdict, py_is.o_sysdict); - compare_offset(interpreter_state.builtins, py_is.o_builtins); - compare_offset(interpreter_state.ceval_gil, py_is.o_gil_runtime_state); - - compare_size(thread_state, py_thread); - compare_offset(thread_state.prev, py_thread.o_prev); - compare_offset(thread_state.next, py_thread.o_next); - compare_offset(thread_state.interp, py_thread.o_interp); - compare_offset(thread_state.current_frame, py_thread.o_frame); - compare_offset(thread_state.thread_id, py_thread.o_thread_id); - compare_offset(thread_state.native_thread_id, py_thread.o_native_thread_id); - - compare_size(interpreter_frame, py_frame); - compare_offset(interpreter_frame.previous, py_frame.o_back); - compare_offset(interpreter_frame.executable, py_frame.o_code); - compare_offset(interpreter_frame.instr_ptr, py_frame.o_prev_instr); - compare_offset(interpreter_frame.localsplus, py_frame.o_localsplus); - compare_offset(interpreter_frame.owner, py_frame.o_owner); - - compare_size(code_object, py_code); - compare_offset(code_object.filename, py_code.o_filename); - compare_offset(code_object.name, py_code.o_name); - compare_offset(code_object.linetable, py_code.o_lnotab); - compare_offset(code_object.firstlineno, py_code.o_firstlineno); - compare_offset(code_object.argcount, py_code.o_argcount); - compare_offset(code_object.localsplusnames, py_code.o_varnames); - compare_offset(code_object.co_code_adaptive, py_code.o_code_adaptive); - - compare_size(type_object, py_type); - compare_offset(type_object.tp_name, py_type.o_tp_name); - - compare_size(gc, py_gc); - compare_offset(gc.collecting, py_gc.o_collecting); - -#undef compare_size -#undef compare_offset -} - -} // unnamed namespace - static std::vector getProcessTids(pid_t pid) { @@ -700,7 +622,74 @@ AbstractProcessManager::warnIfOffsetsAreMismatched() const return; } - return warnIfOffsetsAreMismatchedImpl(py_runtime.v3_13.debug_offsets, offsets()); + // Note: It's OK for pystack's size to be smaller, but not larger. +#define compare_size(size_offset, pystack_struct) \ + if (getFieldOffset(size_offset) \ + && ((uint64_t)offsets().pystack_struct.size > getField(py_runtime, size_offset))) \ + { \ + LOG(WARNING) << "Debug offsets mismatch: " #pystack_struct ".size " \ + << offsets().pystack_struct.size << " > " << getField(py_runtime, size_offset) \ + << " reported by CPython"; \ + } else \ + do { \ + } while (0) + +#define compare_offset(field_offset_offset, pystack_field) \ + if (getFieldOffset(field_offset_offset) \ + && (uint64_t)offsets().pystack_field.offset != getField(py_runtime, field_offset_offset)) \ + { \ + LOG(WARNING) << "Debug offsets mismatch: " #pystack_field << " " \ + << offsets().pystack_field.offset \ + << " != " << getField(py_runtime, field_offset_offset) << " reported by CPython"; \ + } else \ + do { \ + } while (0) + + compare_size(&py_runtime_v::o_dbg_off_runtime_state_struct_size, py_runtime); + compare_offset(&py_runtime_v::o_dbg_off_runtime_state_finalizing, py_runtime.o_finalizing); + compare_offset(&py_runtime_v::o_dbg_off_runtime_state_interpreters_head, py_runtime.o_interp_head); + + compare_size(&py_runtime_v::o_dbg_off_interpreter_state_struct_size, py_is); + compare_offset(&py_runtime_v::o_dbg_off_interpreter_state_next, py_is.o_next); + compare_offset(&py_runtime_v::o_dbg_off_interpreter_state_threads_head, py_is.o_tstate_head); + compare_offset(&py_runtime_v::o_dbg_off_interpreter_state_gc, py_is.o_gc); + compare_offset(&py_runtime_v::o_dbg_off_interpreter_state_imports_modules, py_is.o_modules); + compare_offset(&py_runtime_v::o_dbg_off_interpreter_state_sysdict, py_is.o_sysdict); + compare_offset(&py_runtime_v::o_dbg_off_interpreter_state_builtins, py_is.o_builtins); + compare_offset(&py_runtime_v::o_dbg_off_interpreter_state_ceval_gil, py_is.o_gil_runtime_state); + + compare_size(&py_runtime_v::o_dbg_off_thread_state_struct_size, py_thread); + compare_offset(&py_runtime_v::o_dbg_off_thread_state_prev, py_thread.o_prev); + compare_offset(&py_runtime_v::o_dbg_off_thread_state_next, py_thread.o_next); + compare_offset(&py_runtime_v::o_dbg_off_thread_state_interp, py_thread.o_interp); + compare_offset(&py_runtime_v::o_dbg_off_thread_state_current_frame, py_thread.o_frame); + compare_offset(&py_runtime_v::o_dbg_off_thread_state_thread_id, py_thread.o_thread_id); + compare_offset(&py_runtime_v::o_dbg_off_thread_state_native_thread_id, py_thread.o_native_thread_id); + + compare_size(&py_runtime_v::o_dbg_off_interpreter_frame_struct_size, py_frame); + compare_offset(&py_runtime_v::o_dbg_off_interpreter_frame_previous, py_frame.o_back); + compare_offset(&py_runtime_v::o_dbg_off_interpreter_frame_executable, py_frame.o_code); + compare_offset(&py_runtime_v::o_dbg_off_interpreter_frame_instr_ptr, py_frame.o_prev_instr); + compare_offset(&py_runtime_v::o_dbg_off_interpreter_frame_localsplus, py_frame.o_localsplus); + compare_offset(&py_runtime_v::o_dbg_off_interpreter_frame_owner, py_frame.o_owner); + + compare_size(&py_runtime_v::o_dbg_off_code_object_struct_size, py_code); + compare_offset(&py_runtime_v::o_dbg_off_code_object_filename, py_code.o_filename); + compare_offset(&py_runtime_v::o_dbg_off_code_object_name, py_code.o_name); + compare_offset(&py_runtime_v::o_dbg_off_code_object_linetable, py_code.o_lnotab); + compare_offset(&py_runtime_v::o_dbg_off_code_object_firstlineno, py_code.o_firstlineno); + compare_offset(&py_runtime_v::o_dbg_off_code_object_argcount, py_code.o_argcount); + compare_offset(&py_runtime_v::o_dbg_off_code_object_localsplusnames, py_code.o_varnames); + compare_offset(&py_runtime_v::o_dbg_off_code_object_co_code_adaptive, py_code.o_code_adaptive); + + compare_size(&py_runtime_v::o_dbg_off_type_object_struct_size, py_type); + compare_offset(&py_runtime_v::o_dbg_off_type_object_tp_name, py_type.o_tp_name); + + compare_size(&py_runtime_v::o_dbg_off_gc_struct_size, py_gc); + compare_offset(&py_runtime_v::o_dbg_off_gc_collecting, py_gc.o_collecting); + +#undef compare_size +#undef compare_offset } bool diff --git a/src/pystack/_pystack/version.cpp b/src/pystack/_pystack/version.cpp index d115c51..9307be7 100644 --- a/src/pystack/_pystack/version.cpp +++ b/src/pystack/_pystack/version.cpp @@ -216,6 +216,64 @@ py_runtimev312() }; } +template +constexpr py_runtime_v +py_runtimev313() +{ + return { + sizeof(T), + offsetof(T, finalizing), + offsetof(T, interpreters.head), + {}, + {}, + offsetof(T, debug_offsets.runtime_state.size), + offsetof(T, debug_offsets.runtime_state.finalizing), + offsetof(T, debug_offsets.runtime_state.interpreters_head), + offsetof(T, debug_offsets.interpreter_state.size), + offsetof(T, debug_offsets.interpreter_state.id), + offsetof(T, debug_offsets.interpreter_state.next), + offsetof(T, debug_offsets.interpreter_state.threads_head), + offsetof(T, debug_offsets.interpreter_state.gc), + offsetof(T, debug_offsets.interpreter_state.imports_modules), + offsetof(T, debug_offsets.interpreter_state.sysdict), + offsetof(T, debug_offsets.interpreter_state.builtins), + offsetof(T, debug_offsets.interpreter_state.ceval_gil), + offsetof(T, debug_offsets.interpreter_state.gil_runtime_state_locked), + offsetof(T, debug_offsets.interpreter_state.gil_runtime_state_holder), + offsetof(T, debug_offsets.thread_state.size), + offsetof(T, debug_offsets.thread_state.prev), + offsetof(T, debug_offsets.thread_state.next), + offsetof(T, debug_offsets.thread_state.interp), + offsetof(T, debug_offsets.thread_state.current_frame), + offsetof(T, debug_offsets.thread_state.thread_id), + offsetof(T, debug_offsets.thread_state.native_thread_id), + offsetof(T, debug_offsets.thread_state.datastack_chunk), + offsetof(T, debug_offsets.thread_state.status), + offsetof(T, debug_offsets.interpreter_frame.size), + offsetof(T, debug_offsets.interpreter_frame.previous), + offsetof(T, debug_offsets.interpreter_frame.executable), + offsetof(T, debug_offsets.interpreter_frame.instr_ptr), + offsetof(T, debug_offsets.interpreter_frame.localsplus), + offsetof(T, debug_offsets.interpreter_frame.owner), + offsetof(T, debug_offsets.code_object.size), + offsetof(T, debug_offsets.code_object.filename), + offsetof(T, debug_offsets.code_object.name), + offsetof(T, debug_offsets.code_object.qualname), + offsetof(T, debug_offsets.code_object.linetable), + offsetof(T, debug_offsets.code_object.firstlineno), + offsetof(T, debug_offsets.code_object.argcount), + offsetof(T, debug_offsets.code_object.localsplusnames), + offsetof(T, debug_offsets.code_object.localspluskinds), + offsetof(T, debug_offsets.code_object.co_code_adaptive), + offsetof(T, debug_offsets.pyobject.size), + offsetof(T, debug_offsets.pyobject.ob_type), + offsetof(T, debug_offsets.type_object.size), + offsetof(T, debug_offsets.type_object.tp_name), + offsetof(T, debug_offsets.gc.size), + offsetof(T, debug_offsets.gc.collecting), + }; +} + template constexpr py_type_v py_type() @@ -345,7 +403,7 @@ python_v python_v3_13 = { py_framev312(), py_threadv313(), py_isv312(), - py_runtimev312(), + py_runtimev313(), py_gc(), py_cframe(), }; diff --git a/src/pystack/_pystack/version.h b/src/pystack/_pystack/version.h index 846b390..d1455af 100644 --- a/src/pystack/_pystack/version.h +++ b/src/pystack/_pystack/version.h @@ -64,6 +64,59 @@ struct py_runtime_v FieldOffset o_interp_head; FieldOffset o_gc; FieldOffset o_tstate_current; + + FieldOffset o_dbg_off_runtime_state_struct_size; + FieldOffset o_dbg_off_runtime_state_finalizing; + FieldOffset o_dbg_off_runtime_state_interpreters_head; + + FieldOffset o_dbg_off_interpreter_state_struct_size; + FieldOffset o_dbg_off_interpreter_state_id; + FieldOffset o_dbg_off_interpreter_state_next; + FieldOffset o_dbg_off_interpreter_state_threads_head; + FieldOffset o_dbg_off_interpreter_state_gc; + FieldOffset o_dbg_off_interpreter_state_imports_modules; + FieldOffset o_dbg_off_interpreter_state_sysdict; + FieldOffset o_dbg_off_interpreter_state_builtins; + FieldOffset o_dbg_off_interpreter_state_ceval_gil; + FieldOffset o_dbg_off_interpreter_state_gil_runtime_state_locked; + FieldOffset o_dbg_off_interpreter_state_gil_runtime_state_holder; + + FieldOffset o_dbg_off_thread_state_struct_size; + FieldOffset o_dbg_off_thread_state_prev; + FieldOffset o_dbg_off_thread_state_next; + FieldOffset o_dbg_off_thread_state_interp; + FieldOffset o_dbg_off_thread_state_current_frame; + FieldOffset o_dbg_off_thread_state_thread_id; + FieldOffset o_dbg_off_thread_state_native_thread_id; + FieldOffset o_dbg_off_thread_state_datastack_chunk; + FieldOffset o_dbg_off_thread_state_status; + + FieldOffset o_dbg_off_interpreter_frame_struct_size; + FieldOffset o_dbg_off_interpreter_frame_previous; + FieldOffset o_dbg_off_interpreter_frame_executable; + FieldOffset o_dbg_off_interpreter_frame_instr_ptr; + FieldOffset o_dbg_off_interpreter_frame_localsplus; + FieldOffset o_dbg_off_interpreter_frame_owner; + + FieldOffset o_dbg_off_code_object_struct_size; + FieldOffset o_dbg_off_code_object_filename; + FieldOffset o_dbg_off_code_object_name; + FieldOffset o_dbg_off_code_object_qualname; + FieldOffset o_dbg_off_code_object_linetable; + FieldOffset o_dbg_off_code_object_firstlineno; + FieldOffset o_dbg_off_code_object_argcount; + FieldOffset o_dbg_off_code_object_localsplusnames; + FieldOffset o_dbg_off_code_object_localspluskinds; + FieldOffset o_dbg_off_code_object_co_code_adaptive; + + FieldOffset o_dbg_off_pyobject_struct_size; + FieldOffset o_dbg_off_pyobject_ob_type; + + FieldOffset o_dbg_off_type_object_struct_size; + FieldOffset o_dbg_off_type_object_tp_name; + + FieldOffset o_dbg_off_gc_struct_size; + FieldOffset o_dbg_off_gc_collecting; }; struct py_type_v