OSDN Git Service

* config/ia64/ia64.c (ia64_register_move_cost): Fix argument types.
[pf3gnuchains/gcc-fork.git] / gcc / config / sparc / linux-unwind.h
1 /* DWARF2 EH unwinding support for SPARC Linux.
2    Copyright 2004, 2005, 2009 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 #if defined(__arch64__)
29
30 /* 64-bit SPARC version */
31 #define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state
32
33 static _Unwind_Reason_Code
34 sparc64_fallback_frame_state (struct _Unwind_Context *context,
35                               _Unwind_FrameState *fs)
36 {
37   unsigned int *pc = context->ra;
38   long this_cfa = (long) context->cfa;
39   long new_cfa, ra_location, shifted_ra_location;
40   long regs_off, fpu_save_off;
41   long fpu_save;
42   int i;
43
44   if (pc[0] != 0x82102065       /* mov NR_rt_sigreturn, %g1 */
45       || pc[1] != 0x91d0206d)   /* ta 0x6d */
46     return _URC_END_OF_STACK;
47
48   regs_off = 192 + 128;
49   fpu_save_off = regs_off + (16 * 8) + (3 * 8) + (2 * 4);
50
51   new_cfa = *(long *)(this_cfa + regs_off + (14 * 8));
52   new_cfa += 2047; /* Stack bias */
53   fpu_save = *(long *)(this_cfa + fpu_save_off);
54   fs->regs.cfa_how = CFA_REG_OFFSET;
55   fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
56   fs->regs.cfa_offset = new_cfa - this_cfa;
57
58   for (i = 1; i < 16; i++)
59     {
60       /* We never restore %sp as everything is purely CFA-based.  */
61       if ((unsigned int) i == __builtin_dwarf_sp_column ())
62         continue;
63
64       fs->regs.reg[i].how = REG_SAVED_OFFSET;
65       fs->regs.reg[i].loc.offset
66         = this_cfa + regs_off + (i * 8) - new_cfa;
67     }
68   for (i = 0; i < 16; i++)
69     {
70       fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
71       fs->regs.reg[i + 16].loc.offset
72         = this_cfa + (i * 8) - new_cfa;
73     }
74   if (fpu_save)
75     {
76       for (i = 0; i < 64; i++)
77         {
78           if (i > 32 && (i & 0x1))
79             continue;
80           fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
81           fs->regs.reg[i + 32].loc.offset
82             = fpu_save + (i * 4) - new_cfa;
83         }
84     }
85
86   /* State the rules to find the kernel's code "return address", which is
87      the address of the active instruction when the signal was caught.
88      On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we
89      need to preventively subtract it from the purported return address.  */
90   ra_location = this_cfa + regs_off + 17 * 8;
91   shifted_ra_location = this_cfa + regs_off + 19 * 8; /* Y register */
92   *(long *)shifted_ra_location = *(long *)ra_location - 8;
93   fs->retaddr_column = 0;
94   fs->regs.reg[0].how = REG_SAVED_OFFSET;
95   fs->regs.reg[0].loc.offset = shifted_ra_location - new_cfa;
96   fs->signal_frame = 1;
97
98   return _URC_NO_REASON;
99 }
100
101 #define MD_FROB_UPDATE_CONTEXT sparc64_frob_update_context
102
103 static void
104 sparc64_frob_update_context (struct _Unwind_Context *context,
105                              _Unwind_FrameState *fs)
106 {
107   /* The column of %sp contains the old CFA, not the old value of %sp.
108      The CFA offset already comprises the stack bias so, when %sp is the
109      CFA register, we must avoid counting the stack bias twice.  Do not
110      do that for signal frames as the offset is artificial for them.  */
111   if (fs->regs.cfa_reg == __builtin_dwarf_sp_column ()
112       && fs->regs.cfa_how == CFA_REG_OFFSET
113       && fs->regs.cfa_offset != 0
114       && !fs->signal_frame)
115     context->cfa -= 2047;
116 }
117
118 #else
119
120 /* 32-bit SPARC version */
121 #define MD_FALLBACK_FRAME_STATE_FOR sparc_fallback_frame_state
122
123 static _Unwind_Reason_Code
124 sparc_fallback_frame_state (struct _Unwind_Context *context,
125                             _Unwind_FrameState *fs)
126 {
127   unsigned int *pc = context->ra;
128   int this_cfa = (int) context->cfa;
129   int new_cfa, ra_location, shifted_ra_location;
130   int regs_off, fpu_save_off;
131   int fpu_save;
132   int old_style, i;
133
134   if (pc[1] != 0x91d02010)      /* ta 0x10 */
135     return _URC_END_OF_STACK;
136
137   if (pc[0] == 0x821020d8)      /* mov NR_sigreturn, %g1 */
138     old_style = 1;
139   else if (pc[0] == 0x82102065) /* mov NR_rt_sigreturn, %g1 */
140     old_style = 0;
141   else
142     return _URC_END_OF_STACK;
143
144   if (old_style)
145     {
146       regs_off = 96;
147       fpu_save_off = regs_off + (4 * 4) + (16 * 4);
148     }
149   else
150     {
151       regs_off = 96 + 128;
152       fpu_save_off = regs_off + (4 * 4) + (16 * 4) + (2 * 4);
153     }
154
155   new_cfa = *(int *)(this_cfa + regs_off + (4 * 4) + (14 * 4));
156   fpu_save = *(int *)(this_cfa + fpu_save_off);
157   fs->regs.cfa_how = CFA_REG_OFFSET;
158   fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
159   fs->regs.cfa_offset = new_cfa - this_cfa;
160
161   for (i = 1; i < 16; i++)
162     {
163       /* We never restore %sp as everything is purely CFA-based.  */
164       if ((unsigned int) i == __builtin_dwarf_sp_column ())
165         continue;
166
167       fs->regs.reg[i].how = REG_SAVED_OFFSET;
168       fs->regs.reg[i].loc.offset
169         = this_cfa + regs_off + (4 * 4) + (i * 4) - new_cfa;
170     }
171   for (i = 0; i < 16; i++)
172     {
173       fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
174       fs->regs.reg[i + 16].loc.offset
175         = this_cfa + (i * 4) - new_cfa;
176     }
177   if (fpu_save)
178     {
179       for (i = 0; i < 32; i++)
180         {
181           fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
182           fs->regs.reg[i + 32].loc.offset
183             = fpu_save + (i * 4) - new_cfa;
184         }
185     }
186
187   /* State the rules to find the kernel's code "return address", which is
188      the address of the active instruction when the signal was caught.
189      On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we
190      need to preventively subtract it from the purported return address.  */
191   ra_location = this_cfa + regs_off + 4;
192   shifted_ra_location = this_cfa + regs_off + 3 * 4; /* Y register */
193   *(int *)shifted_ra_location = *(int *)ra_location - 8;
194   fs->retaddr_column = 0;
195   fs->regs.reg[0].how = REG_SAVED_OFFSET;
196   fs->regs.reg[0].loc.offset = shifted_ra_location - new_cfa;
197   fs->signal_frame = 1;
198
199   return _URC_NO_REASON;
200 }
201
202 #endif