@@ -337,6 +337,12 @@ class GhostStackImpl {
337337 tail, (unsigned long )entry.ip , (unsigned long )entry.return_address ,
338338 (void *)entry.location , (unsigned long )entry.stack_pointer );
339339
340+ // Always log the SP comparison for debugging
341+ fprintf (stderr, " [GS][TRAMP] tail=%zu expected_sp=0x%lx actual_sp=0x%lx diff=%ld match=%d\n " ,
342+ tail, (unsigned long )entry.stack_pointer , (unsigned long )sp,
343+ (long )((long )entry.stack_pointer - (long )sp),
344+ (int )(entry.stack_pointer == sp));
345+
340346 // Check for longjmp: if SP doesn't match expected, search backward
341347 // through shadow stack for matching entry (frames were skipped)
342348 if (sp != 0 && entry.stack_pointer != 0 && entry.stack_pointer != sp) {
@@ -421,14 +427,10 @@ class GhostStackImpl {
421427 unw_init_local (&cursor, &ctx);
422428 LOG_DEBUG (" Initialized libunwind cursor\n " );
423429
424- // Skip internal frames (platform-specific due to backtrace/libunwind differences)
425- #ifdef __APPLE__
426- // macOS: Skip fewer frames due to backtrace()/libunwind difference
427- for (int i = 0 ; i < 1 && unw_step (&cursor) > 0 ; ++i) {}
428- #else
429- // Linux: Skip internal frames (this function + backtrace)
430- for (int i = 0 ; i < 3 && unw_step (&cursor) > 0 ; ++i) {}
431- #endif
430+ // Skip the current frame to avoid patching our own return address
431+ if (unw_step (&cursor) > 0 ) {
432+ // Skipped internal frame
433+ }
432434
433435 // Process frames: read current frame, then step to next
434436 // Note: After skip loop, cursor is positioned AT the first frame we want
@@ -489,22 +491,10 @@ class GhostStackImpl {
489491 }
490492
491493 // Store the stack pointer that the trampoline will pass.
492- // This allows longjmp detection by comparing against the stored value.
493- //
494- // The trampoline passes different SP values depending on platform:
495- // - x86_64: RET pops return address, so trampoline sees ret_loc + 8
496- // - Linux ARM64: Trampoline passes SP after saving registers, which
497- // corresponds to actual_sp from libunwind
498- // - macOS ARM64: Trampoline passes ret_loc + 8 (similar to x86_64)
499- #if defined(GS_ARCH_AARCH64) && defined(__linux__)
500- // Linux ARM64: use actual SP from libunwind
494+ // Use libunwind's SP value directly.
501495 unw_word_t actual_sp;
502496 unw_get_reg (&cursor, UNW_REG_SP, &actual_sp);
503497 uintptr_t expected_sp = static_cast <uintptr_t >(actual_sp);
504- #else
505- // x86_64 and macOS ARM64: use ret_loc + sizeof(void*)
506- uintptr_t expected_sp = reinterpret_cast <uintptr_t >(ret_loc) + sizeof (void *);
507- #endif
508498 // Store both IP (for returning to caller) and return_address (for trampoline restoration)
509499 // Insert at beginning to reverse order (oldest at index 0, newest at end)
510500 new_entries.insert (new_entries.begin (), {ip, ret_addr, ret_loc, expected_sp});
0 commit comments