]>
Commit | Line | Data |
---|---|---|
f6aa7063 | 1 | /* DWARF2 EH unwinding support for SPARC Solaris. |
fbd26352 | 2 | Copyright (C) 2009-2019 Free Software Foundation, Inc. |
f6aa7063 | 3 | |
4 | This file is part of GCC. | |
5 | ||
6 | GCC is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 3, or (at your option) | |
9 | any later version. | |
10 | ||
11 | GCC is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | Under Section 7 of GPL version 3, you are granted additional | |
17 | permissions described in the GCC Runtime Library Exception, version | |
18 | 3.1, as published by the Free Software Foundation. | |
19 | ||
20 | You should have received a copy of the GNU General Public License and | |
21 | a copy of the GCC Runtime Library Exception along with this program; | |
22 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
23 | <http://www.gnu.org/licenses/>. */ | |
24 | ||
25 | /* Do code reading to identify a signal frame, and set the frame | |
26 | state data appropriately. See unwind-dw2.c for the structs. */ | |
27 | ||
28 | #include <ucontext.h> | |
96727600 | 29 | #include <sys/frame.h> |
30 | #include <sys/stack.h> | |
f6aa7063 | 31 | |
18e6a060 | 32 | #ifdef __arch64__ |
f6aa7063 | 33 | |
96727600 | 34 | #define IS_SIGHANDLER sparc64_is_sighandler |
f6aa7063 | 35 | |
96727600 | 36 | static int |
af185b18 | 37 | sparc64_is_sighandler (unsigned int *pc, void *cfa, int *nframes) |
f6aa7063 | 38 | { |
96727600 | 39 | if (/* Solaris 8+ - multi-threaded |
40 | ---------------------------- | |
41 | <__sighndlr>: save %sp, -176, %sp | |
42 | <__sighndlr+4>: mov %i0, %o0 | |
43 | <__sighndlr+8>: mov %i1, %o1 | |
44 | <__sighndlr+12>: call %i3 | |
45 | <__sighndlr+16>: mov %i2, %o2 | |
46 | <__sighndlr+20>: ret <--- PC | |
47 | <__sighndlr+24>: restore */ | |
48 | pc[-5] == 0x9de3bf50 | |
49 | && pc[-4] == 0x90100018 | |
50 | && pc[-3] == 0x92100019 | |
51 | && pc[-2] == 0x9fc6c000 | |
52 | && pc[-1] == 0x9410001a | |
53 | && pc[ 0] == 0x81c7e008 | |
54 | && pc[ 1] == 0x81e80000) | |
f6aa7063 | 55 | { |
af185b18 | 56 | /* We have observed different calling frames among different |
57 | versions of the operating system, so that we need to | |
58 | discriminate using the upper frame. We look for the return | |
59 | address of the caller frame (there is an offset of 15 double | |
60 | words between the frame address and the place where this return | |
61 | address is stored) in order to do some more pattern matching. */ | |
62 | unsigned int cuh_pattern | |
63 | = *(unsigned int *)(*(unsigned long *)(cfa + 15*8) - 4); | |
64 | ||
99e0a0ad | 65 | if (cuh_pattern == 0x92100019) |
3efb5d22 | 66 | /* This matches the call_user_handler pattern in Solaris 11 |
67 | libc.so.1: | |
68 | ||
69 | <call_user_handler+864>: mov %i1, %o1 | |
70 | <call_user_handler+868>: call __sighndlr | |
71 | ||
72 | This is the same setup as for Solaris 10, see below. */ | |
99e0a0ad | 73 | *nframes = 3; |
74 | ||
75 | else if (cuh_pattern == 0xd25fa7ef) | |
51c81e49 | 76 | { |
3efb5d22 | 77 | /* This matches the call_user_handler pattern in Solaris 10 |
78 | libc.so.1: | |
79 | ||
80 | <call_user_handler+988>: ldx [ %fp + 0x7ef ], %o1 | |
81 | <call_user_handler+992>: call __sighndlr | |
82 | ||
af185b18 | 83 | There are 2 cases so we look for the return address of the |
84 | caller's caller frame in order to do more pattern matching. */ | |
6e647e51 | 85 | unsigned long sah_address = *(unsigned long *)(cfa + 176 + 15*8); |
af185b18 | 86 | |
6e647e51 | 87 | if (sah_address && *(unsigned int *)(sah_address - 4) == 0x92100019) |
3efb5d22 | 88 | /* We need to move up three frames: |
89 | ||
90 | <signal handler> <-- context->cfa | |
91 | __sighndlr | |
92 | call_user_handler | |
93 | sigacthandler | |
94 | <kernel> */ | |
af185b18 | 95 | *nframes = 3; |
96 | else | |
97 | /* The sigacthandler frame isn't present in the chain. | |
98 | We need to move up two frames: | |
96727600 | 99 | |
100 | <signal handler> <-- context->cfa | |
101 | __sighndlr | |
3efb5d22 | 102 | call_user_handler |
103 | <kernel> */ | |
af185b18 | 104 | *nframes = 2; |
51c81e49 | 105 | } |
99e0a0ad | 106 | |
3efb5d22 | 107 | else if (cuh_pattern == 0x9410001a || cuh_pattern == 0x9410001b) |
108 | /* This matches the call_user_handler pattern in Solaris 9 | |
109 | libthread.so.1: | |
96727600 | 110 | |
3efb5d22 | 111 | <call_user_handler+600>: mov %i2, %o2 |
112 | <call_user_handler+604>: call __sighndlr | |
113 | ||
114 | This is the same setup as for Solaris 10, see above. */ | |
af185b18 | 115 | *nframes = 3; |
99e0a0ad | 116 | |
96727600 | 117 | return 1; |
f6aa7063 | 118 | } |
119 | ||
96727600 | 120 | return 0; |
f6aa7063 | 121 | } |
122 | ||
96727600 | 123 | #define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state |
124 | ||
f6aa7063 | 125 | #define MD_FROB_UPDATE_CONTEXT sparc64_frob_update_context |
126 | ||
127 | static void | |
128 | sparc64_frob_update_context (struct _Unwind_Context *context, | |
129 | _Unwind_FrameState *fs) | |
130 | { | |
131 | /* The column of %sp contains the old CFA, not the old value of %sp. | |
132 | The CFA offset already comprises the stack bias so, when %sp is the | |
34a60aa2 | 133 | CFA register, we must avoid counting the stack bias twice. */ |
f6aa7063 | 134 | if (fs->regs.cfa_reg == __builtin_dwarf_sp_column () |
135 | && fs->regs.cfa_how == CFA_REG_OFFSET | |
34a60aa2 | 136 | && fs->regs.cfa_offset != 0) |
47529489 | 137 | { |
138 | long i; | |
139 | ||
140 | context->cfa -= STACK_BIAS; | |
141 | ||
325b8c3c | 142 | for (i = 0; i < __LIBGCC_DWARF_FRAME_REGISTERS__ + 1; ++i) |
47529489 | 143 | if (fs->regs.reg[i].how == REG_SAVED_OFFSET) |
144 | _Unwind_SetGRPtr (context, i, | |
145 | _Unwind_GetGRPtr (context, i) - STACK_BIAS); | |
146 | } | |
f6aa7063 | 147 | } |
148 | ||
149 | #else | |
150 | ||
96727600 | 151 | #define IS_SIGHANDLER sparc_is_sighandler |
152 | ||
153 | static int | |
af185b18 | 154 | sparc_is_sighandler (unsigned int *pc, void *cfa, int *nframes) |
96727600 | 155 | { |
96727600 | 156 | if(/* Solaris 8+ - multi-threaded |
157 | ---------------------------- | |
158 | <__sighndlr>: save %sp, -96, %sp | |
159 | <__sighndlr+4>: mov %i0, %o0 | |
160 | <__sighndlr+8>: mov %i1, %o1 | |
161 | <__sighndlr+12>: call %i3 | |
162 | <__sighndlr+16>: mov %i2, %o2 | |
163 | <__sighndlr+20>: ret <--- PC | |
164 | <__sighndlr+24>: restore */ | |
165 | pc[-5] == 0x9de3bfa0 | |
166 | && pc[-4] == 0x90100018 | |
167 | && pc[-3] == 0x92100019 | |
168 | && pc[-2] == 0x9fc6c000 | |
169 | && pc[-1] == 0x9410001a | |
170 | && pc[ 0] == 0x81c7e008 | |
171 | && pc[ 1] == 0x81e80000) | |
172 | { | |
af185b18 | 173 | /* We have observed different calling frames among different |
174 | versions of the operating system, so that we need to | |
175 | discriminate using the upper frame. We look for the return | |
176 | address of the caller frame (there is an offset of 15 words | |
177 | between the frame address and the place where this return | |
178 | address is stored) in order to do some more pattern matching. */ | |
179 | unsigned int cuh_pattern | |
180 | = *(unsigned int *)(*(unsigned int *)(cfa + 15*4) - 4); | |
181 | ||
99e0a0ad | 182 | if (cuh_pattern == 0x92100019) |
3efb5d22 | 183 | /* This matches the call_user_handler pattern in Solaris 11 |
184 | libc.so.1: | |
185 | ||
186 | <call_user_handler+876>: mov %i1, %o1 | |
187 | <call_user_handler+880>: call __sighndlr | |
188 | ||
189 | This is the same setup as for Solaris 10, see below. */ | |
99e0a0ad | 190 | *nframes = 3; |
191 | ||
192 | else if (cuh_pattern == 0xd407a04c) | |
96727600 | 193 | { |
3efb5d22 | 194 | /* This matches the call_user_handler pattern in Solaris 10 |
195 | libc.so.1: | |
196 | ||
197 | <call_user_handler+948>: ld [ %fp + 0x4c ], %o2 | |
198 | <call_user_handler+952>: call __sighndlr | |
199 | ||
af185b18 | 200 | There are 2 cases so we look for the return address of the |
201 | caller's caller frame in order to do more pattern matching. */ | |
6e647e51 | 202 | unsigned int sah_address = *(unsigned int *)(cfa + 96 + 15*4); |
af185b18 | 203 | |
6e647e51 | 204 | if (sah_address && *(unsigned int *)(sah_address - 4) == 0x92100019) |
3efb5d22 | 205 | /* We need to move up three frames: |
206 | ||
207 | <signal handler> <-- context->cfa | |
208 | __sighndlr | |
209 | call_user_handler | |
210 | sigacthandler | |
211 | <kernel> */ | |
af185b18 | 212 | *nframes = 3; |
213 | else | |
214 | /* The sigacthandler frame isn't present in the chain. | |
215 | We need to move up two frames: | |
96727600 | 216 | |
217 | <signal handler> <-- context->cfa | |
218 | __sighndlr | |
3efb5d22 | 219 | call_user_handler |
220 | <kernel> */ | |
af185b18 | 221 | *nframes = 2; |
96727600 | 222 | } |
99e0a0ad | 223 | |
af185b18 | 224 | else if (cuh_pattern == 0x9410001a || cuh_pattern == 0x9410001b) |
3efb5d22 | 225 | /* This matches the call_user_handler pattern in Solaris 9 |
226 | libthread.so.1: | |
96727600 | 227 | |
3efb5d22 | 228 | <call_user_handler+560>: mov %i2, %o2 |
229 | <call_user_handler+564>: call __sighndlr | |
230 | ||
231 | This is the same setup as for Solaris 10, see above. */ | |
af185b18 | 232 | *nframes = 3; |
99e0a0ad | 233 | |
96727600 | 234 | return 1; |
235 | } | |
236 | ||
237 | return 0; | |
238 | } | |
239 | ||
f6aa7063 | 240 | #define MD_FALLBACK_FRAME_STATE_FOR sparc_fallback_frame_state |
241 | ||
96727600 | 242 | #endif |
243 | ||
f6aa7063 | 244 | static _Unwind_Reason_Code |
96727600 | 245 | MD_FALLBACK_FRAME_STATE_FOR (struct _Unwind_Context *context, |
246 | _Unwind_FrameState *fs) | |
f6aa7063 | 247 | { |
248 | void *pc = context->ra; | |
249 | void *this_cfa = context->cfa; | |
34a60aa2 | 250 | int nframes = 0; |
96727600 | 251 | long new_cfa; |
252 | void *ra_location, *shifted_ra_location; | |
253 | mcontext_t *mctx; | |
f6aa7063 | 254 | int i; |
255 | ||
f6aa7063 | 256 | /* Deal with frame-less function from which a signal was raised. */ |
257 | if (_Unwind_IsSignalFrame (context)) | |
258 | { | |
259 | /* The CFA is by definition unmodified in this case. */ | |
260 | fs->regs.cfa_how = CFA_REG_OFFSET; | |
261 | fs->regs.cfa_reg = __builtin_dwarf_sp_column (); | |
262 | fs->regs.cfa_offset = 0; | |
263 | ||
264 | /* This is the canonical RA column. */ | |
265 | fs->retaddr_column = 15; | |
266 | ||
267 | return _URC_NO_REASON; | |
268 | } | |
269 | ||
34a60aa2 | 270 | /* Do some pattern matching at the return address. */ |
af185b18 | 271 | if (IS_SIGHANDLER (pc, this_cfa, &nframes)) |
f6aa7063 | 272 | { |
34a60aa2 | 273 | struct frame *fp = (struct frame *) this_cfa; |
96727600 | 274 | struct handler_args { |
275 | struct frame frwin; | |
276 | ucontext_t ucontext; | |
277 | } *handler_args; | |
278 | ucontext_t *ucp; | |
279 | ||
34a60aa2 | 280 | /* this_cfa points into the frame after the saved frame pointer and |
96727600 | 281 | saved pc (struct frame). |
282 | ||
283 | The ucontext_t structure is in the kernel frame after a struct | |
284 | frame. Since the frame sizes vary even within OS releases, we | |
285 | need to walk the stack to get there. */ | |
96727600 | 286 | for (i = 0; i < nframes; i++) |
287 | fp = (struct frame *) ((char *)fp->fr_savfp + STACK_BIAS); | |
288 | ||
289 | handler_args = (struct handler_args *) fp; | |
290 | ucp = &handler_args->ucontext; | |
291 | mctx = &ucp->uc_mcontext; | |
f6aa7063 | 292 | } |
f6aa7063 | 293 | else |
294 | return _URC_END_OF_STACK; | |
295 | ||
96727600 | 296 | /* The frame address is %sp + STACK_BIAS in 64-bit mode. */ |
34a60aa2 | 297 | new_cfa = mctx->gregs[REG_SP] + STACK_BIAS; |
96727600 | 298 | |
f6aa7063 | 299 | fs->regs.cfa_how = CFA_REG_OFFSET; |
300 | fs->regs.cfa_reg = __builtin_dwarf_sp_column (); | |
34a60aa2 | 301 | fs->regs.cfa_offset = new_cfa - (long) this_cfa + STACK_BIAS; |
f6aa7063 | 302 | |
303 | /* Restore global and out registers (in this order) from the | |
304 | ucontext_t structure, uc_mcontext.gregs field. */ | |
305 | for (i = 1; i < 16; i++) | |
306 | { | |
307 | /* We never restore %sp as everything is purely CFA-based. */ | |
308 | if ((unsigned int) i == __builtin_dwarf_sp_column ()) | |
309 | continue; | |
310 | ||
96727600 | 311 | /* First the global registers and then the out registers. */ |
f6aa7063 | 312 | fs->regs.reg[i].how = REG_SAVED_OFFSET; |
96727600 | 313 | fs->regs.reg[i].loc.offset = (long)&mctx->gregs[REG_Y + i] - new_cfa; |
f6aa7063 | 314 | } |
315 | ||
96727600 | 316 | /* Just above the stack pointer there are 16 extended words in which |
317 | the register window (in and local registers) was saved. */ | |
f6aa7063 | 318 | for (i = 0; i < 16; i++) |
319 | { | |
320 | fs->regs.reg[i + 16].how = REG_SAVED_OFFSET; | |
34a60aa2 | 321 | fs->regs.reg[i + 16].loc.offset = i * sizeof(long); |
f6aa7063 | 322 | } |
323 | ||
51c81e49 | 324 | /* Check whether we need to restore FPU registers. */ |
96727600 | 325 | if (mctx->fpregs.fpu_qcnt) |
f6aa7063 | 326 | { |
327 | for (i = 0; i < 32; i++) | |
328 | { | |
329 | fs->regs.reg[i + 32].how = REG_SAVED_OFFSET; | |
330 | fs->regs.reg[i + 32].loc.offset | |
96727600 | 331 | = (long)&mctx->fpregs.fpu_fr.fpu_regs[i] - new_cfa; |
332 | } | |
333 | ||
334 | #ifdef __arch64__ | |
335 | /* For 64-bit, fpu_fr.fpu_dregs contains 32 instead of 16 doubles. */ | |
336 | for (i = 32; i < 64; i++) | |
337 | { | |
338 | if (i > 32 && (i & 1)) | |
339 | continue; | |
340 | ||
341 | fs->regs.reg[i + 32].how = REG_SAVED_OFFSET; | |
342 | fs->regs.reg[i + 32].loc.offset | |
343 | = (long)&mctx->fpregs.fpu_fr.fpu_dregs[i/2] - new_cfa; | |
f6aa7063 | 344 | } |
96727600 | 345 | #endif |
f6aa7063 | 346 | } |
347 | ||
348 | /* State the rules to find the kernel's code "return address", which is | |
349 | the address of the active instruction when the signal was caught. | |
350 | On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we | |
351 | need to preventively subtract it from the purported return address. */ | |
96727600 | 352 | ra_location = &mctx->gregs[REG_PC]; |
353 | shifted_ra_location = &mctx->gregs[REG_Y]; | |
f6aa7063 | 354 | *(void **)shifted_ra_location = *(void **)ra_location - 8; |
355 | fs->retaddr_column = 0; | |
356 | fs->regs.reg[0].how = REG_SAVED_OFFSET; | |
96727600 | 357 | fs->regs.reg[0].loc.offset = (long)shifted_ra_location - new_cfa; |
aad33226 | 358 | |
359 | /* SIGFPE for IEEE-754 exceptions is delivered after the faulting insn | |
360 | rather than before it, so don't set fs->signal_frame in that case. | |
361 | We test whether the cexc field of the FSR is zero. */ | |
362 | if ((mctx->fpregs.fpu_fsr & 0x1f) == 0) | |
363 | fs->signal_frame = 1; | |
f6aa7063 | 364 | |
365 | return _URC_NO_REASON; | |
96727600 | 366 | } |