99#include "pycore_jit_unwind.h"
1010#include "pycore_lock.h"
1111
12+ #if defined(_Py_JIT ) && defined(__linux__ ) && defined(__ELF__ )
13+ # include "jit_unwind_info.h"
14+ # if !JIT_UNWIND_INFO_SUPPORTED
15+ # error "JIT unwind info was not generated for this target"
16+ # endif
17+ # define PY_HAVE_JIT_GDB_UNWIND 1
18+ #else
19+ # define PY_HAVE_JIT_GDB_UNWIND 0
20+ #endif
21+
1222#if defined(PY_HAVE_PERF_TRAMPOLINE ) || (defined(__linux__ ) && defined(__ELF__ ))
1323
1424#if defined(__linux__ )
@@ -205,11 +215,17 @@ static void elfctx_append_uleb128(ELFObjectContext* ctx, uint32_t v) {
205215// =============================================================================
206216
207217static void elf_init_ehframe_perf (ELFObjectContext * ctx );
218+ #if PY_HAVE_JIT_GDB_UNWIND
208219static void elf_init_ehframe_gdb (ELFObjectContext * ctx );
220+ #endif
209221
210222static inline void elf_init_ehframe (ELFObjectContext * ctx , int absolute_addr ) {
211223 if (absolute_addr ) {
224+ #if PY_HAVE_JIT_GDB_UNWIND
212225 elf_init_ehframe_gdb (ctx );
226+ #else
227+ Py_UNREACHABLE ();
228+ #endif
213229 }
214230 else {
215231 elf_init_ehframe_perf (ctx );
@@ -614,21 +630,15 @@ static void elf_init_ehframe_perf(ELFObjectContext* ctx) {
614630/*
615631 * Build .eh_frame data for the GDB JIT interface.
616632 *
617- * The CIE's initial CFI hard-codes the steady-state frame layout for the
618- * executor region:
619- *
620- * x86_64: CFA = %rbp + 16, return-to-_PyJIT_Entry PC at cfa-72
621- * AArch64: CFA = x29 + 96, caller x29 at cfa-96, caller x30 at cfa-88
622- *
623- * The executor runs inside the frame established by _PyJIT_Entry. On AArch64
624- * we collapse that state into a single synthetic executor frame that unwinds
625- * directly into _PyEval_*. On x86_64 the normal call into the executor leaves
626- * a real return slot back into _PyJIT_Entry, so the executor FDE materializes
627- * _PyJIT_Entry as the caller frame. Executor stencils never touch the frame
628- * pointer — enforced by Tools/jit/_optimizers.py _validate() and
629- * -mframe-pointer=reserved — so the steady-state rule is valid at every PC
630- * and the FDE body is empty.
633+ * The executor runs inside the frame established by _PyJIT_Entry, but the
634+ * synthetic executor FDE collapses that state into a single logical JIT frame
635+ * that unwinds directly into _PyEval_*. Executor stencils never touch the
636+ * frame pointer - enforced by Tools/jit/_optimizers.py _validate() and
637+ * -mframe-pointer=reserved - so the steady-state rule is valid at every PC
638+ * and the FDE body is empty. Tools/jit/_targets.py derives the initial CFI
639+ * rules from the row active at the executor call in the compiled shim object.
631640 */
641+ #if PY_HAVE_JIT_GDB_UNWIND
632642static void elf_init_ehframe_gdb (ELFObjectContext * ctx ) {
633643 int fde_ptr_enc = DWRF_EH_PE_absptr ;
634644 uint8_t * p = ctx -> p ;
@@ -638,34 +648,20 @@ static void elf_init_ehframe_gdb(ELFObjectContext* ctx) {
638648 DWRF_U32 (0 ); // CIE ID
639649 DWRF_U8 (DWRF_CIE_VERSION );
640650 DWRF_STR ("zR" ); // aug data length + FDE ptr encoding follow
641- #ifdef __x86_64__
642- DWRF_UV (1 ); // x86_64: 1 byte per instruction
643- #elif defined(__aarch64__ ) && defined(__AARCH64EL__ ) && !defined(__ILP32__ )
644- DWRF_UV (4 ); // AArch64: 4 bytes per instruction
645- #endif
646- DWRF_SV (- (int64_t )sizeof (uintptr_t ));
647- DWRF_U8 (DWRF_REG_RA );
651+ DWRF_UV (JIT_UNWIND_CODE_ALIGNMENT_FACTOR );
652+ DWRF_SV (JIT_UNWIND_DATA_ALIGNMENT_FACTOR );
653+ DWRF_U8 (JIT_UNWIND_RA_REG );
648654 DWRF_UV (1 ); // Augmentation data length
649655 DWRF_U8 (fde_ptr_enc ); // FDE pointer encoding
650656
651657 /* Executor steady-state rule (our invariant, not the compiler's). */
652- #ifdef __x86_64__
653- DWRF_U8 (DWRF_CFA_def_cfa ); // CFA = %rbp + 16
654- DWRF_UV (DWRF_REG_BP );
655- DWRF_UV (16 );
656- DWRF_U8 (DWRF_CFA_offset | DWRF_REG_RA );
657- DWRF_UV (9 ); // return-to-_PyJIT_Entry at cfa-72
658- #elif defined(__aarch64__ ) && defined(__AARCH64EL__ ) && !defined(__ILP32__ )
659- DWRF_U8 (DWRF_CFA_def_cfa ); // CFA = x29 + 96
660- DWRF_UV (DWRF_REG_FP );
661- DWRF_UV (96 );
662- DWRF_U8 (DWRF_CFA_offset | DWRF_REG_FP );
663- DWRF_UV (12 ); // caller x29 at cfa-96
664- DWRF_U8 (DWRF_CFA_offset | DWRF_REG_RA );
665- DWRF_UV (11 ); // caller x30 at cfa-88
666- #else
667- # error "Unsupported target architecture"
668- #endif
658+ DWRF_U8 (DWRF_CFA_def_cfa );
659+ DWRF_UV (JIT_UNWIND_CFA_REG );
660+ DWRF_UV (JIT_UNWIND_CFA_OFFSET );
661+ DWRF_U8 (DWRF_CFA_offset | JIT_UNWIND_FP_REG );
662+ DWRF_UV (JIT_UNWIND_FP_OFFSET );
663+ DWRF_U8 (DWRF_CFA_offset | JIT_UNWIND_RA_REG );
664+ DWRF_UV (JIT_UNWIND_RA_OFFSET );
669665 DWRF_ALIGNNOP (sizeof (uintptr_t ));
670666 )
671667
@@ -679,6 +675,7 @@ static void elf_init_ehframe_gdb(ELFObjectContext* ctx) {
679675
680676 ctx -> p = p ;
681677}
678+ #endif
682679
683680#if defined(__linux__ ) && defined(__ELF__ )
684681enum {
0 commit comments