f8b99027247b89379c6105504f89908d989a381c
1 /* DWARF2 EH unwinding support for SPARC Solaris.
2 Copyright (C) 2009, 2010, 2011 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>
32 #if defined(__arch64__)
34 #define IS_SIGHANDLER sparc64_is_sighandler
37 sparc64_is_sighandler (unsigned int *pc
, unsigned int *savpc
, int *nframes
)
39 if (/* Solaris 8 - single-threaded
40 ----------------------------
41 <sigacthandler+24>: add %g5, %o7, %o2
42 <sigacthandler+28>: ldx [ %o2 + 0xfa0 ], %g5
43 <sigacthandler+32>: sra %i0, 0, %o0
44 <sigacthandler+36>: sllx %o0, 3, %g4
45 <sigacthandler+40>: ldx [ %g4 + %g5 ], %l0
46 <sigacthandler+44>: call %l0
47 <sigacthandler+48>: mov %i2, %o2
48 <sigacthandler+52>: cmp %i3, 8 <--- PC */
49 ( pc
[-7] == 0x9401400f
50 && pc
[-6] == 0xca5aafa0
51 && pc
[-5] == 0x913e2000
52 && pc
[-4] == 0x892a3003
53 && pc
[-3] == 0xe0590005
54 && pc
[-2] == 0x9fc40000
55 && pc
[-1] == 0x9410001a
56 && pc
[ 0] == 0x80a6e008)
58 || /* Solaris 9 - single-threaded
59 ----------------------------
60 The pattern changes slightly in different versions of the
61 operating system, so we skip the comparison against pc[-6] for
64 <sigacthandler+24>: sra %i0, 0, %l1
67 <sigacthandler+28>: ldx [ %o2 + 0xf68 ], %g5
69 <sigacthandler+28>: ldx [ %o2 + 0xe50 ], %g5
71 <sigacthandler+32>: sllx %l1, 3, %g4
72 <sigacthandler+36>: mov %l1, %o0
73 <sigacthandler+40>: ldx [ %g4 + %g5 ], %l0
74 <sigacthandler+44>: call %l0
75 <sigacthandler+48>: mov %i2, %o2
76 <sigacthandler+52>: cmp %l1, 8 <--- PC */
77 ( pc
[-7] == 0xa33e2000
79 && pc
[-5] == 0x892c7003
80 && pc
[-4] == 0x90100011
81 && pc
[-3] == 0xe0590005
82 && pc
[-2] == 0x9fc40000
83 && pc
[-1] == 0x9410001a
84 && pc
[ 0] == 0x80a46008))
86 /* We need to move up one frame:
88 <signal handler> <-- context->cfa
96 if (/* Solaris 8+ - multi-threaded
97 ----------------------------
98 <__sighndlr>: save %sp, -176, %sp
99 <__sighndlr+4>: mov %i0, %o0
100 <__sighndlr+8>: mov %i1, %o1
101 <__sighndlr+12>: call %i3
102 <__sighndlr+16>: mov %i2, %o2
103 <__sighndlr+20>: ret <--- PC
104 <__sighndlr+24>: restore */
106 && pc
[-4] == 0x90100018
107 && pc
[-3] == 0x92100019
108 && pc
[-2] == 0x9fc6c000
109 && pc
[-1] == 0x9410001a
110 && pc
[ 0] == 0x81c7e008
111 && pc
[ 1] == 0x81e80000)
113 if (/* Solaris 8 /usr/lib/sparcv9/libthread.so.1
114 ------------------------------------------
115 Before patch 108827-08:
116 <sigacthandler+1760>: st %g4, [ %i1 + 0x1c ]
118 Since patch 108827-08:
119 <sigacthandler+1816>: st %l0, [ %i4 + 0x10 ] */
120 savpc
[-1] == 0xc826601c
121 || savpc
[-1] == 0xe0272010)
123 /* We need to move up three frames:
125 <signal handler> <-- context->cfa
132 else /* Solaris 8 /usr/lib/lwp/sparcv9/libthread.so.1, Solaris 9+
133 ---------------------------------------------------------- */
135 /* We need to move up three frames:
137 <signal handler> <-- context->cfa
151 #define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state
153 #define MD_FROB_UPDATE_CONTEXT sparc64_frob_update_context
156 sparc64_frob_update_context (struct _Unwind_Context
*context
,
157 _Unwind_FrameState
*fs
)
159 /* The column of %sp contains the old CFA, not the old value of %sp.
160 The CFA offset already comprises the stack bias so, when %sp is the
161 CFA register, we must avoid counting the stack bias twice. Do not
162 do that for signal frames as the offset is artificial for them. */
163 if (fs
->regs
.cfa_reg
== __builtin_dwarf_sp_column ()
164 && fs
->regs
.cfa_how
== CFA_REG_OFFSET
165 && fs
->regs
.cfa_offset
!= 0
166 && !fs
->signal_frame
)
167 context
->cfa
-= STACK_BIAS
;
172 #define IS_SIGHANDLER sparc_is_sighandler
175 sparc_is_sighandler (unsigned int *pc
, unsigned int * savpc
, int *nframes
)
177 if (/* Solaris 8, 9 - single-threaded
178 -------------------------------
179 The pattern changes slightly in different versions of the operating
180 system, so we skip the comparison against pc[-6].
182 <sigacthandler+16>: add %o1, %o7, %o3
183 <sigacthandler+20>: mov %i1, %o1
185 <sigacthandler+24>: ld [ %o3 + <offset> ], %o2
187 <sigacthandler+28>: sll %i0, 2, %o0
188 <sigacthandler+32>: ld [ %o0 + %o2 ], %l0
189 <sigacthandler+36>: mov %i0, %o0
190 <sigacthandler+40>: call %l0
191 <sigacthandler+44>: mov %i2, %o2
192 <sigacthandler+48>: cmp %i0, 8 <--- PC */
194 && pc
[-7] == 0x92100019
196 && pc
[-5] == 0x912e2002
197 && pc
[-4] == 0xe002000a
198 && pc
[-3] == 0x90100018
199 && pc
[-2] == 0x9fc40000
200 && pc
[-1] == 0x9410001a
201 && pc
[ 0] == 0x80a62008)
203 /* Need to move up one frame:
205 <signal handler> <-- context->cfa
213 if (/* Solaris 8 - multi-threaded
214 ---------------------------
215 <__libthread_segvhdlr+212>: clr %o2
216 <__libthread_segvhdlr+216>: ld [ %fp + -28 ], %l0
217 <__libthread_segvhdlr+220>: mov %i4, %o0
218 <__libthread_segvhdlr+224>: mov %i1, %o1
219 <__libthread_segvhdlr+228>: call %l0
220 <__libthread_segvhdlr+232>: mov %i2, %o2
221 <__libthread_segvhdlr+236>: ret <--- PC
222 <__libthread_segvhdlr+240>: restore
223 <__libthread_segvhdlr+244>: cmp %o1, 0 */
225 && pc
[-5] == 0xe007bfe4
226 && pc
[-4] == 0x9010001c
227 && pc
[-3] == 0x92100019
228 && pc
[-2] == 0x9fc40000
229 && pc
[-1] == 0x9410001a
230 && pc
[ 0] == 0x81c7e008
231 && pc
[ 1] == 0x81e80000
232 && pc
[ 2] == 0x80a26000)
234 /* Need to move up one frame:
236 <signal handler> <-- context->cfa
244 if(/* Solaris 8+ - multi-threaded
245 ----------------------------
246 <__sighndlr>: save %sp, -96, %sp
247 <__sighndlr+4>: mov %i0, %o0
248 <__sighndlr+8>: mov %i1, %o1
249 <__sighndlr+12>: call %i3
250 <__sighndlr+16>: mov %i2, %o2
251 <__sighndlr+20>: ret <--- PC
252 <__sighndlr+24>: restore */
254 && pc
[-4] == 0x90100018
255 && pc
[-3] == 0x92100019
256 && pc
[-2] == 0x9fc6c000
257 && pc
[-1] == 0x9410001a
258 && pc
[ 0] == 0x81c7e008
259 && pc
[ 1] == 0x81e80000)
261 if (/* Solaris 8 /usr/lib/libthread.so.1
262 ----------------------------------
263 <sigacthandler+1796>: mov %i0, %o0 */
264 savpc
[-1] == 0x90100018)
266 /* We need to move up two frames:
268 <signal handler> <-- context->cfa
275 else /* Solaris 8 /usr/lib/lwp/libthread.so.1, Solaris 9+
276 -------------------------------------------------- */
278 /* We need to move up three frames:
280 <signal handler> <-- context->cfa
294 #define MD_FALLBACK_FRAME_STATE_FOR sparc_fallback_frame_state
298 static _Unwind_Reason_Code
299 MD_FALLBACK_FRAME_STATE_FOR (struct _Unwind_Context
*context
,
300 _Unwind_FrameState
*fs
)
302 void *pc
= context
->ra
;
303 struct frame
*fp
= (struct frame
*) context
->cfa
;
305 void *this_cfa
= context
->cfa
;
307 void *ra_location
, *shifted_ra_location
;
311 /* Deal with frame-less function from which a signal was raised. */
312 if (_Unwind_IsSignalFrame (context
))
314 /* The CFA is by definition unmodified in this case. */
315 fs
->regs
.cfa_how
= CFA_REG_OFFSET
;
316 fs
->regs
.cfa_reg
= __builtin_dwarf_sp_column ();
317 fs
->regs
.cfa_offset
= 0;
319 /* This is the canonical RA column. */
320 fs
->retaddr_column
= 15;
322 return _URC_NO_REASON
;
325 if (IS_SIGHANDLER (pc
, (unsigned int *)fp
->fr_savpc
, &nframes
))
327 struct handler_args
{
333 /* context->cfa points into the frame after the saved frame pointer and
334 saved pc (struct frame).
336 The ucontext_t structure is in the kernel frame after a struct
337 frame. Since the frame sizes vary even within OS releases, we
338 need to walk the stack to get there. */
340 for (i
= 0; i
< nframes
; i
++)
341 fp
= (struct frame
*) ((char *)fp
->fr_savfp
+ STACK_BIAS
);
343 handler_args
= (struct handler_args
*) fp
;
344 ucp
= &handler_args
->ucontext
;
345 mctx
= &ucp
->uc_mcontext
;
348 /* Exit if the pattern at the return address does not match the
349 previous three patterns. */
351 return _URC_END_OF_STACK
;
353 new_cfa
= mctx
->gregs
[REG_SP
];
354 /* The frame address is %sp + STACK_BIAS in 64-bit mode. */
355 new_cfa
+= STACK_BIAS
;
357 fs
->regs
.cfa_how
= CFA_REG_OFFSET
;
358 fs
->regs
.cfa_reg
= __builtin_dwarf_sp_column ();
359 fs
->regs
.cfa_offset
= new_cfa
- (long) this_cfa
;
361 /* Restore global and out registers (in this order) from the
362 ucontext_t structure, uc_mcontext.gregs field. */
363 for (i
= 1; i
< 16; i
++)
365 /* We never restore %sp as everything is purely CFA-based. */
366 if ((unsigned int) i
== __builtin_dwarf_sp_column ())
369 /* First the global registers and then the out registers. */
370 fs
->regs
.reg
[i
].how
= REG_SAVED_OFFSET
;
371 fs
->regs
.reg
[i
].loc
.offset
= (long)&mctx
->gregs
[REG_Y
+ i
] - new_cfa
;
374 /* Just above the stack pointer there are 16 extended words in which
375 the register window (in and local registers) was saved. */
376 for (i
= 0; i
< 16; i
++)
378 fs
->regs
.reg
[i
+ 16].how
= REG_SAVED_OFFSET
;
379 fs
->regs
.reg
[i
+ 16].loc
.offset
= i
*sizeof(long);
382 /* Check whether we need to restore FPU registers. */
383 if (mctx
->fpregs
.fpu_qcnt
)
385 for (i
= 0; i
< 32; i
++)
387 fs
->regs
.reg
[i
+ 32].how
= REG_SAVED_OFFSET
;
388 fs
->regs
.reg
[i
+ 32].loc
.offset
389 = (long)&mctx
->fpregs
.fpu_fr
.fpu_regs
[i
] - new_cfa
;
393 /* For 64-bit, fpu_fr.fpu_dregs contains 32 instead of 16 doubles. */
394 for (i
= 32; i
< 64; i
++)
396 if (i
> 32 && (i
& 1))
399 fs
->regs
.reg
[i
+ 32].how
= REG_SAVED_OFFSET
;
400 fs
->regs
.reg
[i
+ 32].loc
.offset
401 = (long)&mctx
->fpregs
.fpu_fr
.fpu_dregs
[i
/2] - new_cfa
;
406 /* State the rules to find the kernel's code "return address", which is
407 the address of the active instruction when the signal was caught.
408 On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we
409 need to preventively subtract it from the purported return address. */
410 ra_location
= &mctx
->gregs
[REG_PC
];
411 shifted_ra_location
= &mctx
->gregs
[REG_Y
];
412 *(void **)shifted_ra_location
= *(void **)ra_location
- 8;
413 fs
->retaddr_column
= 0;
414 fs
->regs
.reg
[0].how
= REG_SAVED_OFFSET
;
415 fs
->regs
.reg
[0].loc
.offset
= (long)shifted_ra_location
- new_cfa
;
416 fs
->signal_frame
= 1;
418 return _URC_NO_REASON
;