Imported Upstream version 4.8.1
[platform/upstream/gcc48.git] / libgcc / config / sparc / sol2-unwind.h
1 /* DWARF2 EH unwinding support for SPARC Solaris.
2    Copyright (C) 2009-2013 Free Software Foundation, Inc.
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>
29 #include <sys/frame.h>
30 #include <sys/stack.h>
31
32 #ifdef __arch64__
33
34 #define IS_SIGHANDLER sparc64_is_sighandler
35
36 static int
37 sparc64_is_sighandler (unsigned int *pc, void *cfa, int *nframes)
38 {
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
43         Solaris 9.
44
45         <sigacthandler+24>:  sra  %i0, 0, %l1
46
47         Solaris 9 5/02:
48         <sigacthandler+28>:  ldx  [ %o2 + 0xf68 ], %g5
49         Solaris 9 9/05:
50         <sigacthandler+28>:  ldx  [ %o2 + 0xe50 ], %g5
51
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
59        /* skip pc[-6] */
60        && pc[-5] == 0x892c7003
61        && pc[-4] == 0x90100011
62        && pc[-3] == 0xe0590005
63        && pc[-2] == 0x9fc40000
64        && pc[-1] == 0x9410001a
65        && pc[ 0] == 0x80a46008))
66     {
67       /* We need to move up one frame:
68
69                 <signal handler>        <-- context->cfa
70                 sigacthandler
71                 <kernel>
72       */
73       *nframes = 1;
74       return 1;
75     }
76
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  */
86          pc[-5] == 0x9de3bf50
87       && pc[-4] == 0x90100018
88       && pc[-3] == 0x92100019
89       && pc[-2] == 0x9fc6c000
90       && pc[-1] == 0x9410001a
91       && pc[ 0] == 0x81c7e008
92       && pc[ 1] == 0x81e80000)
93     {
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);
102
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.  */
106         *nframes = 3;
107
108       else if (cuh_pattern == 0xd25fa7ef)
109         {
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);
114
115           if (sah_address && *(unsigned int *)(sah_address - 4) == 0x92100019)
116             /* This is the same setup as for Solaris 9, see below.  */
117             *nframes = 3;
118           else
119             /* The sigacthandler frame isn't present in the chain.
120                We need to move up two frames:
121
122                 <signal handler>        <-- context->cfa
123                 __sighndlr
124                 call_user_handler frame
125                 <kernel>
126             */
127             *nframes = 2;
128         }
129
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:
133
134                 <signal handler>        <-- context->cfa
135                 __sighndlr
136                 call_user_handler
137                 sigacthandler
138                 <kernel>
139         */
140         *nframes = 3;
141
142       return 1;
143     }
144
145   return 0;
146 }
147
148 #define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state
149
150 #define MD_FROB_UPDATE_CONTEXT sparc64_frob_update_context
151
152 static void
153 sparc64_frob_update_context (struct _Unwind_Context *context,
154                              _Unwind_FrameState *fs)
155 {
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)
164     {
165       long i;
166
167       context->cfa -= STACK_BIAS;
168
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);
173     }
174 }
175
176 #else
177
178 #define IS_SIGHANDLER sparc_is_sighandler
179
180 static int
181 sparc_is_sighandler (unsigned int *pc, void *cfa, int *nframes)
182 {
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].
187
188         <sigacthandler+16>:  add  %o1, %o7, %o3
189         <sigacthandler+20>:  mov  %i1, %o1
190
191         <sigacthandler+24>:  ld  [ %o3 + <offset> ], %o2
192
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  */
199          pc[-8] == 0x9602400f
200       && pc[-7] == 0x92100019
201       /* skip pc[-6] */
202       && pc[-5] == 0x912e2002
203       && pc[-4] == 0xe002000a
204       && pc[-3] == 0x90100018
205       && pc[-2] == 0x9fc40000
206       && pc[-1] == 0x9410001a
207       && pc[ 0] == 0x80a62008)
208     {
209       /* We need to move up one frame:
210
211                 <signal handler>        <-- context->cfa
212                 sigacthandler
213                 <kernel>
214       */
215       *nframes = 1;
216       return 1;
217     }
218
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  */
228         pc[-5] == 0x9de3bfa0
229      && pc[-4] == 0x90100018
230      && pc[-3] == 0x92100019
231      && pc[-2] == 0x9fc6c000
232      && pc[-1] == 0x9410001a
233      && pc[ 0] == 0x81c7e008
234      && pc[ 1] == 0x81e80000)
235     {
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);
244
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.  */
248         *nframes = 3;
249
250       else if (cuh_pattern == 0xd407a04c)
251         {
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);
256
257           if (sah_address && *(unsigned int *)(sah_address - 4) == 0x92100019)
258             /* This is the same setup as for Solaris 9, see below.  */
259             *nframes = 3;
260           else
261             /* The sigacthandler frame isn't present in the chain.
262                We need to move up two frames:
263
264                 <signal handler>        <-- context->cfa
265                 __sighndlr
266                 call_user_handler frame
267                 <kernel>
268             */
269             *nframes = 2;
270         }
271
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:
275
276                 <signal handler>        <-- context->cfa
277                 __sighndlr
278                 call_user_handler
279                 sigacthandler
280                 <kernel>
281         */
282         *nframes = 3;
283
284       return 1;
285     }
286
287   return 0;
288 }
289
290 #define MD_FALLBACK_FRAME_STATE_FOR sparc_fallback_frame_state
291
292 #endif
293
294 static _Unwind_Reason_Code
295 MD_FALLBACK_FRAME_STATE_FOR (struct _Unwind_Context *context,
296                              _Unwind_FrameState *fs)
297 {
298   void *pc = context->ra;
299   struct frame *fp = (struct frame *) context->cfa;
300   int nframes;
301   void *this_cfa = context->cfa;
302   long new_cfa;
303   void *ra_location, *shifted_ra_location;
304   mcontext_t *mctx;
305   int i;
306
307   /* Deal with frame-less function from which a signal was raised.  */
308   if (_Unwind_IsSignalFrame (context))
309     {
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;
314
315       /* This is the canonical RA column.  */
316       fs->retaddr_column = 15;
317
318       return _URC_NO_REASON;
319     }
320
321   if (IS_SIGHANDLER (pc, this_cfa, &nframes))
322     {
323       struct handler_args {
324         struct frame frwin;
325         ucontext_t ucontext;
326       } *handler_args;
327       ucontext_t *ucp;
328
329       /* context->cfa points into the frame after the saved frame pointer and
330          saved pc (struct frame).
331
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.  */
335
336       for (i = 0; i < nframes; i++)
337         fp = (struct frame *) ((char *)fp->fr_savfp + STACK_BIAS);
338
339       handler_args = (struct handler_args *) fp;
340       ucp = &handler_args->ucontext;
341       mctx = &ucp->uc_mcontext;
342     }
343
344   /* Exit if the pattern at the return address does not match the
345      previous three patterns.  */
346   else
347     return _URC_END_OF_STACK;
348
349   new_cfa = mctx->gregs[REG_SP];
350   /* The frame address is %sp + STACK_BIAS in 64-bit mode.  */
351   new_cfa += STACK_BIAS;
352
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;
356
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++)
360     {
361       /* We never restore %sp as everything is purely CFA-based.  */
362       if ((unsigned int) i == __builtin_dwarf_sp_column ())
363         continue;
364
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;
368     }
369
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++)
373     {
374       fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
375       fs->regs.reg[i + 16].loc.offset = i*sizeof(long);
376     }
377
378   /* Check whether we need to restore FPU registers.  */
379   if (mctx->fpregs.fpu_qcnt)
380     {
381       for (i = 0; i < 32; i++)
382         {
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;
386         }
387
388 #ifdef __arch64__
389       /* For 64-bit, fpu_fr.fpu_dregs contains 32 instead of 16 doubles.  */
390       for (i = 32; i < 64; i++)
391         {
392           if (i > 32 && (i & 1))
393             continue;
394
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;
398         }
399 #endif
400     }
401
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;
413
414   return _URC_NO_REASON;
415 }