1 /* DWARF2 EH unwinding support for SPARC Solaris.
2 Copyright (C) 2009-2013 Free Software Foundation, Inc.
4 This file is part of GCC.
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)
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.
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.
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/>. */
25 /* Do code reading to identify a signal frame, and set the frame
26 state data appropriately. See unwind-dw2.c for the structs. */
29 #include <sys/frame.h>
30 #include <sys/stack.h>
34 #define IS_SIGHANDLER sparc64_is_sighandler
37 sparc64_is_sighandler (unsigned int *pc, void *cfa, int *nframes)
39 if (/* Solaris 9 - single-threaded
40 ----------------------------
41 The pattern changes slightly in different versions of the
42 operating system, so we skip the comparison against pc[-6] for
45 <sigacthandler+24>: sra %i0, 0, %l1
48 <sigacthandler+28>: ldx [ %o2 + 0xf68 ], %g5
50 <sigacthandler+28>: ldx [ %o2 + 0xe50 ], %g5
52 <sigacthandler+32>: sllx %l1, 3, %g4
53 <sigacthandler+36>: mov %l1, %o0
54 <sigacthandler+40>: ldx [ %g4 + %g5 ], %l0
55 <sigacthandler+44>: call %l0
56 <sigacthandler+48>: mov %i2, %o2
57 <sigacthandler+52>: cmp %l1, 8 <--- PC */
58 ( pc[-7] == 0xa33e2000
60 && pc[-5] == 0x892c7003
61 && pc[-4] == 0x90100011
62 && pc[-3] == 0xe0590005
63 && pc[-2] == 0x9fc40000
64 && pc[-1] == 0x9410001a
65 && pc[ 0] == 0x80a46008))
67 /* We need to move up one frame:
69 <signal handler> <-- context->cfa
77 if (/* Solaris 8+ - multi-threaded
78 ----------------------------
79 <__sighndlr>: save %sp, -176, %sp
80 <__sighndlr+4>: mov %i0, %o0
81 <__sighndlr+8>: mov %i1, %o1
82 <__sighndlr+12>: call %i3
83 <__sighndlr+16>: mov %i2, %o2
84 <__sighndlr+20>: ret <--- PC
85 <__sighndlr+24>: restore */
87 && pc[-4] == 0x90100018
88 && pc[-3] == 0x92100019
89 && pc[-2] == 0x9fc6c000
90 && pc[-1] == 0x9410001a
91 && pc[ 0] == 0x81c7e008
92 && pc[ 1] == 0x81e80000)
94 /* We have observed different calling frames among different
95 versions of the operating system, so that we need to
96 discriminate using the upper frame. We look for the return
97 address of the caller frame (there is an offset of 15 double
98 words between the frame address and the place where this return
99 address is stored) in order to do some more pattern matching. */
100 unsigned int cuh_pattern
101 = *(unsigned int *)(*(unsigned long *)(cfa + 15*8) - 4);
103 if (cuh_pattern == 0x92100019)
104 /* This matches the call_user_handler pattern for Solaris 11.
105 This is the same setup as for Solaris 9, see below. */
108 else if (cuh_pattern == 0xd25fa7ef)
110 /* This matches the call_user_handler pattern for Solaris 10.
111 There are 2 cases so we look for the return address of the
112 caller's caller frame in order to do more pattern matching. */
113 unsigned long sah_address = *(unsigned long *)(cfa + 176 + 15*8);
115 if (sah_address && *(unsigned int *)(sah_address - 4) == 0x92100019)
116 /* This is the same setup as for Solaris 9, see below. */
119 /* The sigacthandler frame isn't present in the chain.
120 We need to move up two frames:
122 <signal handler> <-- context->cfa
124 call_user_handler frame
130 else if (cuh_pattern == 0x9410001a || cuh_pattern == 0x94100013)
131 /* This matches the call_user_handler pattern for Solaris 9.
132 We need to move up three frames:
134 <signal handler> <-- context->cfa
148 #define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state
150 #define MD_FROB_UPDATE_CONTEXT sparc64_frob_update_context
153 sparc64_frob_update_context (struct _Unwind_Context *context,
154 _Unwind_FrameState *fs)
156 /* The column of %sp contains the old CFA, not the old value of %sp.
157 The CFA offset already comprises the stack bias so, when %sp is the
158 CFA register, we must avoid counting the stack bias twice. Do not
159 do that for signal frames as the offset is artificial for them. */
160 if (fs->regs.cfa_reg == __builtin_dwarf_sp_column ()
161 && fs->regs.cfa_how == CFA_REG_OFFSET
162 && fs->regs.cfa_offset != 0
163 && !fs->signal_frame)
167 context->cfa -= STACK_BIAS;
169 for (i = 0; i < DWARF_FRAME_REGISTERS + 1; ++i)
170 if (fs->regs.reg[i].how == REG_SAVED_OFFSET)
171 _Unwind_SetGRPtr (context, i,
172 _Unwind_GetGRPtr (context, i) - STACK_BIAS);
178 #define IS_SIGHANDLER sparc_is_sighandler
181 sparc_is_sighandler (unsigned int *pc, void *cfa, int *nframes)
183 if (/* Solaris 9 - single-threaded
184 ----------------------------
185 The pattern changes slightly in different versions of the operating
186 system, so we skip the comparison against pc[-6].
188 <sigacthandler+16>: add %o1, %o7, %o3
189 <sigacthandler+20>: mov %i1, %o1
191 <sigacthandler+24>: ld [ %o3 + <offset> ], %o2
193 <sigacthandler+28>: sll %i0, 2, %o0
194 <sigacthandler+32>: ld [ %o0 + %o2 ], %l0
195 <sigacthandler+36>: mov %i0, %o0
196 <sigacthandler+40>: call %l0
197 <sigacthandler+44>: mov %i2, %o2
198 <sigacthandler+48>: cmp %i0, 8 <--- PC */
200 && pc[-7] == 0x92100019
202 && pc[-5] == 0x912e2002
203 && pc[-4] == 0xe002000a
204 && pc[-3] == 0x90100018
205 && pc[-2] == 0x9fc40000
206 && pc[-1] == 0x9410001a
207 && pc[ 0] == 0x80a62008)
209 /* We need to move up one frame:
211 <signal handler> <-- context->cfa
219 if(/* Solaris 8+ - multi-threaded
220 ----------------------------
221 <__sighndlr>: save %sp, -96, %sp
222 <__sighndlr+4>: mov %i0, %o0
223 <__sighndlr+8>: mov %i1, %o1
224 <__sighndlr+12>: call %i3
225 <__sighndlr+16>: mov %i2, %o2
226 <__sighndlr+20>: ret <--- PC
227 <__sighndlr+24>: restore */
229 && pc[-4] == 0x90100018
230 && pc[-3] == 0x92100019
231 && pc[-2] == 0x9fc6c000
232 && pc[-1] == 0x9410001a
233 && pc[ 0] == 0x81c7e008
234 && pc[ 1] == 0x81e80000)
236 /* We have observed different calling frames among different
237 versions of the operating system, so that we need to
238 discriminate using the upper frame. We look for the return
239 address of the caller frame (there is an offset of 15 words
240 between the frame address and the place where this return
241 address is stored) in order to do some more pattern matching. */
242 unsigned int cuh_pattern
243 = *(unsigned int *)(*(unsigned int *)(cfa + 15*4) - 4);
245 if (cuh_pattern == 0x92100019)
246 /* This matches the call_user_handler pattern for Solaris 11.
247 This is the same setup as for Solaris 9, see below. */
250 else if (cuh_pattern == 0xd407a04c)
252 /* This matches the call_user_handler pattern for Solaris 10.
253 There are 2 cases so we look for the return address of the
254 caller's caller frame in order to do more pattern matching. */
255 unsigned int sah_address = *(unsigned int *)(cfa + 96 + 15*4);
257 if (sah_address && *(unsigned int *)(sah_address - 4) == 0x92100019)
258 /* This is the same setup as for Solaris 9, see below. */
261 /* The sigacthandler frame isn't present in the chain.
262 We need to move up two frames:
264 <signal handler> <-- context->cfa
266 call_user_handler frame
272 else if (cuh_pattern == 0x9410001a || cuh_pattern == 0x9410001b)
273 /* This matches the call_user_handler pattern for Solaris 9.
274 We need to move up three frames:
276 <signal handler> <-- context->cfa
290 #define MD_FALLBACK_FRAME_STATE_FOR sparc_fallback_frame_state
294 static _Unwind_Reason_Code
295 MD_FALLBACK_FRAME_STATE_FOR (struct _Unwind_Context *context,
296 _Unwind_FrameState *fs)
298 void *pc = context->ra;
299 struct frame *fp = (struct frame *) context->cfa;
301 void *this_cfa = context->cfa;
303 void *ra_location, *shifted_ra_location;
307 /* Deal with frame-less function from which a signal was raised. */
308 if (_Unwind_IsSignalFrame (context))
310 /* The CFA is by definition unmodified in this case. */
311 fs->regs.cfa_how = CFA_REG_OFFSET;
312 fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
313 fs->regs.cfa_offset = 0;
315 /* This is the canonical RA column. */
316 fs->retaddr_column = 15;
318 return _URC_NO_REASON;
321 if (IS_SIGHANDLER (pc, this_cfa, &nframes))
323 struct handler_args {
329 /* context->cfa points into the frame after the saved frame pointer and
330 saved pc (struct frame).
332 The ucontext_t structure is in the kernel frame after a struct
333 frame. Since the frame sizes vary even within OS releases, we
334 need to walk the stack to get there. */
336 for (i = 0; i < nframes; i++)
337 fp = (struct frame *) ((char *)fp->fr_savfp + STACK_BIAS);
339 handler_args = (struct handler_args *) fp;
340 ucp = &handler_args->ucontext;
341 mctx = &ucp->uc_mcontext;
344 /* Exit if the pattern at the return address does not match the
345 previous three patterns. */
347 return _URC_END_OF_STACK;
349 new_cfa = mctx->gregs[REG_SP];
350 /* The frame address is %sp + STACK_BIAS in 64-bit mode. */
351 new_cfa += STACK_BIAS;
353 fs->regs.cfa_how = CFA_REG_OFFSET;
354 fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
355 fs->regs.cfa_offset = new_cfa - (long) this_cfa;
357 /* Restore global and out registers (in this order) from the
358 ucontext_t structure, uc_mcontext.gregs field. */
359 for (i = 1; i < 16; i++)
361 /* We never restore %sp as everything is purely CFA-based. */
362 if ((unsigned int) i == __builtin_dwarf_sp_column ())
365 /* First the global registers and then the out registers. */
366 fs->regs.reg[i].how = REG_SAVED_OFFSET;
367 fs->regs.reg[i].loc.offset = (long)&mctx->gregs[REG_Y + i] - new_cfa;
370 /* Just above the stack pointer there are 16 extended words in which
371 the register window (in and local registers) was saved. */
372 for (i = 0; i < 16; i++)
374 fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
375 fs->regs.reg[i + 16].loc.offset = i*sizeof(long);
378 /* Check whether we need to restore FPU registers. */
379 if (mctx->fpregs.fpu_qcnt)
381 for (i = 0; i < 32; i++)
383 fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
384 fs->regs.reg[i + 32].loc.offset
385 = (long)&mctx->fpregs.fpu_fr.fpu_regs[i] - new_cfa;
389 /* For 64-bit, fpu_fr.fpu_dregs contains 32 instead of 16 doubles. */
390 for (i = 32; i < 64; i++)
392 if (i > 32 && (i & 1))
395 fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
396 fs->regs.reg[i + 32].loc.offset
397 = (long)&mctx->fpregs.fpu_fr.fpu_dregs[i/2] - new_cfa;
402 /* State the rules to find the kernel's code "return address", which is
403 the address of the active instruction when the signal was caught.
404 On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we
405 need to preventively subtract it from the purported return address. */
406 ra_location = &mctx->gregs[REG_PC];
407 shifted_ra_location = &mctx->gregs[REG_Y];
408 *(void **)shifted_ra_location = *(void **)ra_location - 8;
409 fs->retaddr_column = 0;
410 fs->regs.reg[0].how = REG_SAVED_OFFSET;
411 fs->regs.reg[0].loc.offset = (long)shifted_ra_location - new_cfa;
412 fs->signal_frame = 1;
414 return _URC_NO_REASON;