linux-unwind.h revision 1.1.1.13 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