1 1.1 mrg /* DWARF2 EH unwinding support for AMD x86-64 and x86. 2 1.1.1.13 mrg Copyright (C) 2004-2024 Free Software Foundation, Inc. 3 1.1 mrg 4 1.1 mrg This file is part of GCC. 5 1.1 mrg 6 1.1 mrg GCC is free software; you can redistribute it and/or modify 7 1.1 mrg it under the terms of the GNU General Public License as published by 8 1.1 mrg the Free Software Foundation; either version 3, or (at your option) 9 1.1 mrg any later version. 10 1.1 mrg 11 1.1 mrg GCC is distributed in the hope that it will be useful, 12 1.1 mrg but WITHOUT ANY WARRANTY; without even the implied warranty of 13 1.1 mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 1.1 mrg GNU General Public License for more details. 15 1.1 mrg 16 1.1 mrg Under Section 7 of GPL version 3, you are granted additional 17 1.1 mrg permissions described in the GCC Runtime Library Exception, version 18 1.1 mrg 3.1, as published by the Free Software Foundation. 19 1.1 mrg 20 1.1 mrg You should have received a copy of the GNU General Public License and 21 1.1 mrg a copy of the GCC Runtime Library Exception along with this program; 22 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 1.1 mrg <http://www.gnu.org/licenses/>. */ 24 1.1 mrg 25 1.1.1.9 mrg /* Unwind shadow stack for -fcf-protection -mshstk. */ 26 1.1.1.9 mrg #if defined __SHSTK__ && defined __CET__ && (__CET__ & 2) != 0 27 1.1.1.9 mrg # include "config/i386/shadow-stack-unwind.h" 28 1.1.1.9 mrg #endif 29 1.1.1.9 mrg 30 1.1 mrg /* Do code reading to identify a signal frame, and set the frame 31 1.1 mrg state data appropriately. See unwind-dw2.c for the structs. 32 1.1 mrg Don't use this at all if inhibit_libc is used. */ 33 1.1 mrg 34 1.1 mrg #ifndef inhibit_libc 35 1.1 mrg 36 1.1 mrg /* There's no sys/ucontext.h for glibc 2.0, so no 37 1.1 mrg signal-turned-exceptions for them. There's also no configure-run for 38 1.1 mrg the target, so we can't check on (e.g.) HAVE_SYS_UCONTEXT_H. Using the 39 1.1 mrg target libc version macro should be enough. */ 40 1.1 mrg #if defined __GLIBC__ && !(__GLIBC__ == 2 && __GLIBC_MINOR__ == 0) 41 1.1 mrg 42 1.1 mrg #include <signal.h> 43 1.1 mrg #include <sys/ucontext.h> 44 1.1 mrg 45 1.1 mrg #ifdef __x86_64__ 46 1.1 mrg 47 1.1 mrg #define MD_FALLBACK_FRAME_STATE_FOR x86_64_fallback_frame_state 48 1.1 mrg 49 1.1 mrg static _Unwind_Reason_Code 50 1.1 mrg x86_64_fallback_frame_state (struct _Unwind_Context *context, 51 1.1 mrg _Unwind_FrameState *fs) 52 1.1 mrg { 53 1.1 mrg unsigned char *pc = context->ra; 54 1.1 mrg struct sigcontext *sc; 55 1.1 mrg long new_cfa; 56 1.1 mrg 57 1.1 mrg /* movq $__NR_rt_sigreturn, %rax ; syscall. */ 58 1.1 mrg #ifdef __LP64__ 59 1.1 mrg #define RT_SIGRETURN_SYSCALL 0x050f0000000fc0c7ULL 60 1.1 mrg #else 61 1.1 mrg #define RT_SIGRETURN_SYSCALL 0x050f40000201c0c7ULL 62 1.1 mrg #endif 63 1.1 mrg if (*(unsigned char *)(pc+0) == 0x48 64 1.1 mrg && *(unsigned long long *)(pc+1) == RT_SIGRETURN_SYSCALL) 65 1.1 mrg { 66 1.1.1.5 mrg ucontext_t *uc_ = context->cfa; 67 1.1 mrg /* The void * cast is necessary to avoid an aliasing warning. 68 1.1 mrg The aliasing warning is correct, but should not be a problem 69 1.1 mrg because it does not alias anything. */ 70 1.1 mrg sc = (struct sigcontext *) (void *) &uc_->uc_mcontext; 71 1.1 mrg } 72 1.1 mrg else 73 1.1 mrg return _URC_END_OF_STACK; 74 1.1 mrg 75 1.1 mrg new_cfa = sc->rsp; 76 1.1 mrg fs->regs.cfa_how = CFA_REG_OFFSET; 77 1.1 mrg /* Register 7 is rsp */ 78 1.1 mrg fs->regs.cfa_reg = 7; 79 1.1 mrg fs->regs.cfa_offset = new_cfa - (long) context->cfa; 80 1.1 mrg 81 1.1 mrg /* The SVR4 register numbering macros aren't usable in libgcc. */ 82 1.1.1.13 mrg fs->regs.how[0] = REG_SAVED_OFFSET; 83 1.1 mrg fs->regs.reg[0].loc.offset = (long)&sc->rax - new_cfa; 84 1.1.1.13 mrg fs->regs.how[1] = REG_SAVED_OFFSET; 85 1.1 mrg fs->regs.reg[1].loc.offset = (long)&sc->rdx - new_cfa; 86 1.1.1.13 mrg fs->regs.how[2] = REG_SAVED_OFFSET; 87 1.1 mrg fs->regs.reg[2].loc.offset = (long)&sc->rcx - new_cfa; 88 1.1.1.13 mrg fs->regs.how[3] = REG_SAVED_OFFSET; 89 1.1 mrg fs->regs.reg[3].loc.offset = (long)&sc->rbx - new_cfa; 90 1.1.1.13 mrg fs->regs.how[4] = REG_SAVED_OFFSET; 91 1.1 mrg fs->regs.reg[4].loc.offset = (long)&sc->rsi - new_cfa; 92 1.1.1.13 mrg fs->regs.how[5] = REG_SAVED_OFFSET; 93 1.1 mrg fs->regs.reg[5].loc.offset = (long)&sc->rdi - new_cfa; 94 1.1.1.13 mrg fs->regs.how[6] = REG_SAVED_OFFSET; 95 1.1 mrg fs->regs.reg[6].loc.offset = (long)&sc->rbp - new_cfa; 96 1.1.1.13 mrg fs->regs.how[8] = REG_SAVED_OFFSET; 97 1.1 mrg fs->regs.reg[8].loc.offset = (long)&sc->r8 - new_cfa; 98 1.1.1.13 mrg fs->regs.how[9] = REG_SAVED_OFFSET; 99 1.1 mrg fs->regs.reg[9].loc.offset = (long)&sc->r9 - new_cfa; 100 1.1.1.13 mrg fs->regs.how[10] = REG_SAVED_OFFSET; 101 1.1 mrg fs->regs.reg[10].loc.offset = (long)&sc->r10 - new_cfa; 102 1.1.1.13 mrg fs->regs.how[11] = REG_SAVED_OFFSET; 103 1.1 mrg fs->regs.reg[11].loc.offset = (long)&sc->r11 - new_cfa; 104 1.1.1.13 mrg fs->regs.how[12] = REG_SAVED_OFFSET; 105 1.1 mrg fs->regs.reg[12].loc.offset = (long)&sc->r12 - new_cfa; 106 1.1.1.13 mrg fs->regs.how[13] = REG_SAVED_OFFSET; 107 1.1 mrg fs->regs.reg[13].loc.offset = (long)&sc->r13 - new_cfa; 108 1.1.1.13 mrg fs->regs.how[14] = REG_SAVED_OFFSET; 109 1.1 mrg fs->regs.reg[14].loc.offset = (long)&sc->r14 - new_cfa; 110 1.1.1.13 mrg fs->regs.how[15] = REG_SAVED_OFFSET; 111 1.1 mrg fs->regs.reg[15].loc.offset = (long)&sc->r15 - new_cfa; 112 1.1.1.13 mrg fs->regs.how[16] = REG_SAVED_OFFSET; 113 1.1 mrg fs->regs.reg[16].loc.offset = (long)&sc->rip - new_cfa; 114 1.1 mrg fs->retaddr_column = 16; 115 1.1 mrg fs->signal_frame = 1; 116 1.1 mrg return _URC_NO_REASON; 117 1.1 mrg } 118 1.1 mrg 119 1.1 mrg #else /* ifdef __x86_64__ */ 120 1.1 mrg 121 1.1 mrg #define MD_FALLBACK_FRAME_STATE_FOR x86_fallback_frame_state 122 1.1 mrg 123 1.1 mrg static _Unwind_Reason_Code 124 1.1 mrg x86_fallback_frame_state (struct _Unwind_Context *context, 125 1.1 mrg _Unwind_FrameState *fs) 126 1.1 mrg { 127 1.1 mrg unsigned char *pc = context->ra; 128 1.1 mrg struct sigcontext *sc; 129 1.1 mrg long new_cfa; 130 1.1 mrg 131 1.1 mrg /* popl %eax ; movl $__NR_sigreturn,%eax ; int $0x80 */ 132 1.1 mrg if (*(unsigned short *)(pc+0) == 0xb858 133 1.1 mrg && *(unsigned int *)(pc+2) == 119 134 1.1 mrg && *(unsigned short *)(pc+6) == 0x80cd) 135 1.1 mrg sc = context->cfa + 4; 136 1.1 mrg /* movl $__NR_rt_sigreturn,%eax ; int $0x80 */ 137 1.1 mrg else if (*(unsigned char *)(pc+0) == 0xb8 138 1.1 mrg && *(unsigned int *)(pc+1) == 173 139 1.1 mrg && *(unsigned short *)(pc+5) == 0x80cd) 140 1.1 mrg { 141 1.1 mrg struct rt_sigframe { 142 1.1 mrg int sig; 143 1.1 mrg siginfo_t *pinfo; 144 1.1 mrg void *puc; 145 1.1 mrg siginfo_t info; 146 1.1.1.5 mrg ucontext_t uc; 147 1.1 mrg } *rt_ = context->cfa; 148 1.1 mrg /* The void * cast is necessary to avoid an aliasing warning. 149 1.1 mrg The aliasing warning is correct, but should not be a problem 150 1.1 mrg because it does not alias anything. */ 151 1.1 mrg sc = (struct sigcontext *) (void *) &rt_->uc.uc_mcontext; 152 1.1 mrg } 153 1.1 mrg else 154 1.1 mrg return _URC_END_OF_STACK; 155 1.1 mrg 156 1.1 mrg new_cfa = sc->esp; 157 1.1 mrg fs->regs.cfa_how = CFA_REG_OFFSET; 158 1.1 mrg fs->regs.cfa_reg = 4; 159 1.1 mrg fs->regs.cfa_offset = new_cfa - (long) context->cfa; 160 1.1 mrg 161 1.1 mrg /* The SVR4 register numbering macros aren't usable in libgcc. */ 162 1.1.1.13 mrg fs->regs.how[0] = REG_SAVED_OFFSET; 163 1.1 mrg fs->regs.reg[0].loc.offset = (long)&sc->eax - new_cfa; 164 1.1.1.13 mrg fs->regs.how[3] = REG_SAVED_OFFSET; 165 1.1 mrg fs->regs.reg[3].loc.offset = (long)&sc->ebx - new_cfa; 166 1.1.1.13 mrg fs->regs.how[1] = REG_SAVED_OFFSET; 167 1.1 mrg fs->regs.reg[1].loc.offset = (long)&sc->ecx - new_cfa; 168 1.1.1.13 mrg fs->regs.how[2] = REG_SAVED_OFFSET; 169 1.1 mrg fs->regs.reg[2].loc.offset = (long)&sc->edx - new_cfa; 170 1.1.1.13 mrg fs->regs.how[6] = REG_SAVED_OFFSET; 171 1.1 mrg fs->regs.reg[6].loc.offset = (long)&sc->esi - new_cfa; 172 1.1.1.13 mrg fs->regs.how[7] = REG_SAVED_OFFSET; 173 1.1 mrg fs->regs.reg[7].loc.offset = (long)&sc->edi - new_cfa; 174 1.1.1.13 mrg fs->regs.how[5] = REG_SAVED_OFFSET; 175 1.1 mrg fs->regs.reg[5].loc.offset = (long)&sc->ebp - new_cfa; 176 1.1.1.13 mrg fs->regs.how[8] = REG_SAVED_OFFSET; 177 1.1 mrg fs->regs.reg[8].loc.offset = (long)&sc->eip - new_cfa; 178 1.1 mrg fs->retaddr_column = 8; 179 1.1 mrg fs->signal_frame = 1; 180 1.1 mrg return _URC_NO_REASON; 181 1.1 mrg } 182 1.1 mrg 183 1.1 mrg #define MD_FROB_UPDATE_CONTEXT x86_frob_update_context 184 1.1 mrg 185 1.1 mrg /* Fix up for kernels that have vDSO, but don't have S flag in it. */ 186 1.1 mrg 187 1.1 mrg static void 188 1.1 mrg x86_frob_update_context (struct _Unwind_Context *context, 189 1.1 mrg _Unwind_FrameState *fs ATTRIBUTE_UNUSED) 190 1.1 mrg { 191 1.1 mrg unsigned char *pc = context->ra; 192 1.1 mrg 193 1.1 mrg /* movl $__NR_rt_sigreturn,%eax ; {int $0x80 | syscall} */ 194 1.1 mrg if (*(unsigned char *)(pc+0) == 0xb8 195 1.1 mrg && *(unsigned int *)(pc+1) == 173 196 1.1 mrg && (*(unsigned short *)(pc+5) == 0x80cd 197 1.1 mrg || *(unsigned short *)(pc+5) == 0x050f)) 198 1.1 mrg _Unwind_SetSignalFrame (context, 1); 199 1.1 mrg } 200 1.1 mrg 201 1.1 mrg #endif /* ifdef __x86_64__ */ 202 1.1 mrg #endif /* not glibc 2.0 */ 203 1.1 mrg #endif /* ifdef inhibit_libc */ 204