@@ -533,6 +533,22 @@ static void elf_init_ehframe(ELFObjectContext* ctx, int absolute_addr) {
533533 * These instructions describe how registers are saved and restored
534534 * during function calls. Each architecture has different calling
535535 * conventions and register usage patterns.
536+ *
537+ * GDB JIT invariant (absolute_addr == 1):
538+ *
539+ * We emit one synthetic FDE for the whole registered JIT region and
540+ * treat that region as one logical native frame while unwinding. This
541+ * relies on the generated executor stencils preserving the
542+ * frame-pointer register across the whole region (%rbp on x86_64,
543+ * x29 on AArch64). Individual stencils may still adjust SP or spill
544+ * temporaries, but they must not clobber the frame pointer or move
545+ * the recoverable caller state away from the frame layout described by
546+ * the steady-state CFI below.
547+ *
548+ * If code generation changes so that executor stencils start touching
549+ * the frame pointer, or the caller state is no longer recoverable from
550+ * this frame layout, then this synthetic GDB CFI must be updated
551+ * together with the stencil generator and tests.
536552 */
537553#ifdef __x86_64__
538554 /* x86_64 calling convention unwinding rules; keep CFA on %rbp */
@@ -547,6 +563,12 @@ static void elf_init_ehframe(ELFObjectContext* ctx, int absolute_addr) {
547563 DWRF_U8 (DWRF_CFA_advance_loc | 3 ); // Advance past mov %rsp,%rbp (3 bytes)
548564 DWRF_U8 (DWRF_CFA_def_cfa_register ); // def_cfa_register r6
549565 DWRF_UV (DWRF_REG_BP ); // Use base pointer register
566+ if (!absolute_addr ) {
567+ DWRF_U8 (DWRF_CFA_advance_loc | 3 ); // Advance past call *%rcx (2 bytes) + pop %rbp (1 byte) = 3
568+ DWRF_U8 (DWRF_CFA_def_cfa ); // def_cfa r7 ofs 8
569+ DWRF_UV (DWRF_REG_SP ); // Use stack pointer register
570+ DWRF_UV (8 ); // New offset: SP + 8
571+ }
550572#elif defined(__aarch64__ ) && defined(__AARCH64EL__ ) && !defined(__ILP32__ )
551573 /* AArch64 calling convention unwinding rules */
552574 DWRF_U8 (DWRF_CFA_advance_loc | 1 ); // Advance by 1 instruction (4 bytes)
@@ -562,14 +584,16 @@ static void elf_init_ehframe(ELFObjectContext* ctx, int absolute_addr) {
562584 DWRF_U8 (DWRF_CFA_def_cfa_offset ); // CFA = SP + 0 (stack restored)
563585 DWRF_UV (0 ); // Back to original stack position
564586
565- DWRF_U8 (DWRF_CFA_def_cfa_register ); // CFA = FP (x29)
566- DWRF_UV (DWRF_REG_FP );
567- DWRF_U8 (DWRF_CFA_def_cfa_offset ); // CFA = FP + 16
568- DWRF_UV (16 );
569- DWRF_U8 (DWRF_CFA_offset | DWRF_REG_FP ); // x29 saved
570- DWRF_UV (2 );
571- DWRF_U8 (DWRF_CFA_offset | DWRF_REG_RA ); // x30 saved
572- DWRF_UV (1 );
587+ if (absolute_addr ) {
588+ DWRF_U8 (DWRF_CFA_def_cfa_register ); // CFA = FP (x29)
589+ DWRF_UV (DWRF_REG_FP );
590+ DWRF_U8 (DWRF_CFA_def_cfa_offset ); // CFA = FP + 16
591+ DWRF_UV (16 );
592+ DWRF_U8 (DWRF_CFA_offset | DWRF_REG_FP ); // x29 saved
593+ DWRF_UV (2 );
594+ DWRF_U8 (DWRF_CFA_offset | DWRF_REG_RA ); // x30 saved
595+ DWRF_UV (1 );
596+ }
573597
574598#else
575599# error "Unsupported target architecture"
0 commit comments