/* Signal frame backtracing support for SFrame on AMD, x86-64 and x86. Copyright (C) 2025 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see . */ /* This code is inspired from libgcc's MD_FALLBACK_FRAME_STATE_FOR implementation. See libgcc/config/i386/linux-unwind.h */ #include #include #ifdef __x86_64__ /* SFrame is only supported by x86_64 targets. */ #define MD_DECODE_SIGNAL_FRAME x86_64_decode_signal_frame #ifdef __LP64__ #define RT_SIGRETURN_SYSCALL 0x050f0000000fc0c7ULL #else #define RT_SIGRETURN_SYSCALL 0x050f40000201c0c7ULL #endif static _Unwind_Reason_Code x86_64_decode_signal_frame (frame *frame) { unsigned char *pc = (unsigned char *) frame->pc; mcontext_t *st; unsigned char pc0 = *(unsigned char *)(pc + 0); unsigned long long pc1; memcpy (&pc1, pc + 1, sizeof (unsigned long long)); /* movq $__NR_rt_sigreturn, %rax ; syscall. */ if ( pc0 == 0x48 && pc1 == RT_SIGRETURN_SYSCALL) { ucontext_t *uc_ = (ucontext_t *)frame->sp; st = &uc_->uc_mcontext; } else return _URC_END_OF_STACK; frame->pc = (_Unwind_Ptr) st->gregs[REG_RIP]; frame->sp = (_Unwind_Ptr) st->gregs[REG_RSP]; frame->fp = (_Unwind_Ptr) st->gregs[REG_RBP]; return _URC_NO_REASON; } #define MD_DETECT_OUTERMOST_FRAME x86_64_detect_outermost_frame static _Unwind_Reason_Code x86_64_detect_outermost_frame (frame *frame) { /* Outermost frame has the frame pointer cleared. */ if (frame->fp == 0) return _URC_END_OF_STACK; return _URC_NO_REASON; } #endif /* ifdef __x86_64__ */