GH-126910: Add GNU backtrace support for unwinding JIT frames

This commit is contained in:
Diego Russo 2026-04-24 14:47:34 +01:00
parent efcac6f281
commit db967dca64
14 changed files with 366 additions and 63 deletions

View file

@ -15,7 +15,7 @@
#include "pycore_interpframe.h"
#include "pycore_interpolation.h"
#include "pycore_intrinsics.h"
#include "pycore_jit_unwind.h"
#include "pycore_jit_publish.h"
#include "pycore_lazyimportobject.h"
#include "pycore_list.h"
#include "pycore_long.h"
@ -61,40 +61,6 @@ jit_error(const char *message)
PyErr_Format(PyExc_RuntimeWarning, "JIT %s (%d)", message, hint);
}
/*
* Publish JIT code to optional tooling backends.
*
* The return value is a backend-specific deregistration handle, not a
* success/failure indicator. NULL means there is nothing to unregister later:
* perf does not need a handle, and GDB registration failures are intentionally
* non-fatal because tooling support must not make JIT compilation fail.
*/
static void *
jit_record_code(const void *code_addr, size_t code_size,
const char *entry, const char *filename)
{
#ifdef PY_HAVE_PERF_TRAMPOLINE
_PyPerf_Callbacks callbacks;
_PyPerfTrampoline_GetCallbacks(&callbacks);
if (callbacks.write_state == _Py_perfmap_jit_callbacks.write_state) {
_PyPerfJit_WriteNamedCode(
code_addr, code_size, entry, filename);
return NULL;
}
#endif
#if defined(PY_HAVE_JIT_GDB_UNWIND)
return _PyJitUnwind_GdbRegisterCode(
code_addr, code_size, entry, filename);
#else
(void)code_addr;
(void)code_size;
(void)entry;
(void)filename;
return NULL;
#endif
}
static int
address_in_executor_array(_PyExecutorObject **ptrs, size_t count, uintptr_t addr)
{
@ -750,10 +716,11 @@ _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction trace[], siz
}
executor->jit_code = memory;
executor->jit_size = total_size;
executor->jit_gdb_handle = jit_record_code(memory,
code_size + state.trampolines.size,
"jit",
"executor");
executor->jit_registration = _PyJit_RegisterCode(
memory,
code_size + state.trampolines.size,
"jit",
"executor");
return 0;
}
@ -766,12 +733,8 @@ _PyJIT_Free(_PyExecutorObject *executor)
if (memory) {
executor->jit_code = NULL;
executor->jit_size = 0;
#if defined(PY_HAVE_JIT_GDB_UNWIND)
if (executor->jit_gdb_handle != NULL) {
_PyJitUnwind_GdbUnregisterCode(executor->jit_gdb_handle);
executor->jit_gdb_handle = NULL;
}
#endif
_PyJit_UnregisterCode(executor->jit_registration);
executor->jit_registration = NULL;
if (jit_free(memory, size)) {
PyErr_FormatUnraisable("Exception ignored while "
"freeing JIT memory");