linux-unwind.h revision 1.1.1.3.4.2 1 1.1 mrg /* DWARF2 EH unwinding support for SPARC Linux.
2 1.1.1.3.4.2 martin Copyright (C) 2004-2018 Free Software Foundation, Inc.
3 1.1 mrg
4 1.1 mrg This file is part of GCC.
5 1.1 mrg
6 1.1 mrg GCC is free software; you can redistribute it and/or modify
7 1.1 mrg it under the terms of the GNU General Public License as published by
8 1.1 mrg the Free Software Foundation; either version 3, or (at your option)
9 1.1 mrg any later version.
10 1.1 mrg
11 1.1 mrg GCC is distributed in the hope that it will be useful,
12 1.1 mrg but WITHOUT ANY WARRANTY; without even the implied warranty of
13 1.1 mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 1.1 mrg GNU General Public License for more details.
15 1.1 mrg
16 1.1 mrg Under Section 7 of GPL version 3, you are granted additional
17 1.1 mrg permissions described in the GCC Runtime Library Exception, version
18 1.1 mrg 3.1, as published by the Free Software Foundation.
19 1.1 mrg
20 1.1 mrg You should have received a copy of the GNU General Public License and
21 1.1 mrg a copy of the GCC Runtime Library Exception along with this program;
22 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 1.1 mrg <http://www.gnu.org/licenses/>. */
24 1.1 mrg
25 1.1 mrg /* Do code reading to identify a signal frame, and set the frame
26 1.1 mrg state data appropriately. See unwind-dw2.c for the structs. */
27 1.1 mrg
28 1.1 mrg #if defined(__arch64__)
29 1.1 mrg
30 1.1 mrg #undef STACK_BIAS
31 1.1 mrg #define STACK_BIAS 2047
32 1.1 mrg
33 1.1 mrg /* 64-bit SPARC version */
34 1.1 mrg #define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state
35 1.1 mrg
36 1.1 mrg static _Unwind_Reason_Code
37 1.1 mrg sparc64_fallback_frame_state (struct _Unwind_Context *context,
38 1.1 mrg _Unwind_FrameState *fs)
39 1.1 mrg {
40 1.1 mrg unsigned int *pc = context->ra;
41 1.1 mrg long this_cfa = (long) context->cfa;
42 1.1 mrg long new_cfa, ra_location, shifted_ra_location;
43 1.1 mrg long regs_off, fpu_save_off;
44 1.1 mrg long fpu_save;
45 1.1 mrg int i;
46 1.1 mrg
47 1.1 mrg if (pc[0] != 0x82102065 /* mov NR_rt_sigreturn, %g1 */
48 1.1 mrg || pc[1] != 0x91d0206d) /* ta 0x6d */
49 1.1 mrg return _URC_END_OF_STACK;
50 1.1 mrg
51 1.1 mrg regs_off = 192 + 128;
52 1.1 mrg fpu_save_off = regs_off + (16 * 8) + (3 * 8) + (2 * 4);
53 1.1 mrg
54 1.1 mrg new_cfa = *(long *)(this_cfa + regs_off + (14 * 8));
55 1.1 mrg /* The frame address is %sp + STACK_BIAS in 64-bit mode. */
56 1.1 mrg new_cfa += STACK_BIAS;
57 1.1 mrg fpu_save = *(long *)(this_cfa + fpu_save_off);
58 1.1 mrg fs->regs.cfa_how = CFA_REG_OFFSET;
59 1.1 mrg fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
60 1.1 mrg fs->regs.cfa_offset = new_cfa - this_cfa;
61 1.1 mrg
62 1.1 mrg for (i = 1; i < 16; i++)
63 1.1 mrg {
64 1.1 mrg /* We never restore %sp as everything is purely CFA-based. */
65 1.1 mrg if ((unsigned int) i == __builtin_dwarf_sp_column ())
66 1.1 mrg continue;
67 1.1 mrg
68 1.1 mrg fs->regs.reg[i].how = REG_SAVED_OFFSET;
69 1.1 mrg fs->regs.reg[i].loc.offset
70 1.1 mrg = this_cfa + regs_off + (i * 8) - new_cfa;
71 1.1 mrg }
72 1.1 mrg for (i = 0; i < 16; i++)
73 1.1 mrg {
74 1.1 mrg fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
75 1.1 mrg fs->regs.reg[i + 16].loc.offset
76 1.1 mrg = this_cfa + (i * 8) - new_cfa;
77 1.1 mrg }
78 1.1 mrg if (fpu_save)
79 1.1 mrg {
80 1.1 mrg for (i = 0; i < 64; i++)
81 1.1 mrg {
82 1.1 mrg if (i > 32 && (i & 0x1))
83 1.1 mrg continue;
84 1.1 mrg fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
85 1.1 mrg fs->regs.reg[i + 32].loc.offset
86 1.1 mrg = fpu_save + (i * 4) - new_cfa;
87 1.1 mrg }
88 1.1 mrg }
89 1.1 mrg
90 1.1 mrg /* State the rules to find the kernel's code "return address", which is
91 1.1 mrg the address of the active instruction when the signal was caught.
92 1.1 mrg On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we
93 1.1 mrg need to preventively subtract it from the purported return address. */
94 1.1 mrg ra_location = this_cfa + regs_off + 17 * 8;
95 1.1 mrg shifted_ra_location = this_cfa + regs_off + 19 * 8; /* Y register */
96 1.1 mrg *(long *)shifted_ra_location = *(long *)ra_location - 8;
97 1.1 mrg fs->retaddr_column = 0;
98 1.1 mrg fs->regs.reg[0].how = REG_SAVED_OFFSET;
99 1.1 mrg fs->regs.reg[0].loc.offset = shifted_ra_location - new_cfa;
100 1.1 mrg fs->signal_frame = 1;
101 1.1 mrg
102 1.1 mrg return _URC_NO_REASON;
103 1.1 mrg }
104 1.1 mrg
105 1.1 mrg #define MD_FROB_UPDATE_CONTEXT sparc64_frob_update_context
106 1.1 mrg
107 1.1 mrg static void
108 1.1 mrg sparc64_frob_update_context (struct _Unwind_Context *context,
109 1.1 mrg _Unwind_FrameState *fs)
110 1.1 mrg {
111 1.1 mrg /* The column of %sp contains the old CFA, not the old value of %sp.
112 1.1 mrg The CFA offset already comprises the stack bias so, when %sp is the
113 1.1 mrg CFA register, we must avoid counting the stack bias twice. Do not
114 1.1 mrg do that for signal frames as the offset is artificial for them. */
115 1.1 mrg if (fs->regs.cfa_reg == __builtin_dwarf_sp_column ()
116 1.1 mrg && fs->regs.cfa_how == CFA_REG_OFFSET
117 1.1 mrg && fs->regs.cfa_offset != 0
118 1.1 mrg && !fs->signal_frame)
119 1.1 mrg {
120 1.1 mrg long i;
121 1.1 mrg
122 1.1 mrg context->cfa -= STACK_BIAS;
123 1.1 mrg
124 1.1.1.2 mrg for (i = 0; i < __LIBGCC_DWARF_FRAME_REGISTERS__ + 1; ++i)
125 1.1 mrg if (fs->regs.reg[i].how == REG_SAVED_OFFSET)
126 1.1 mrg _Unwind_SetGRPtr (context, i,
127 1.1 mrg _Unwind_GetGRPtr (context, i) - STACK_BIAS);
128 1.1 mrg }
129 1.1 mrg }
130 1.1 mrg
131 1.1 mrg #else
132 1.1 mrg
133 1.1 mrg /* 32-bit SPARC version */
134 1.1 mrg #define MD_FALLBACK_FRAME_STATE_FOR sparc_fallback_frame_state
135 1.1 mrg
136 1.1 mrg static _Unwind_Reason_Code
137 1.1 mrg sparc_fallback_frame_state (struct _Unwind_Context *context,
138 1.1 mrg _Unwind_FrameState *fs)
139 1.1 mrg {
140 1.1 mrg unsigned int *pc = context->ra;
141 1.1 mrg int this_cfa = (int) context->cfa;
142 1.1 mrg int new_cfa, ra_location, shifted_ra_location;
143 1.1 mrg int regs_off, fpu_save_off;
144 1.1 mrg int fpu_save;
145 1.1 mrg int old_style, i;
146 1.1 mrg
147 1.1 mrg if (pc[1] != 0x91d02010) /* ta 0x10 */
148 1.1 mrg return _URC_END_OF_STACK;
149 1.1 mrg
150 1.1 mrg if (pc[0] == 0x821020d8) /* mov NR_sigreturn, %g1 */
151 1.1 mrg old_style = 1;
152 1.1 mrg else if (pc[0] == 0x82102065) /* mov NR_rt_sigreturn, %g1 */
153 1.1 mrg old_style = 0;
154 1.1 mrg else
155 1.1 mrg return _URC_END_OF_STACK;
156 1.1 mrg
157 1.1 mrg if (old_style)
158 1.1 mrg {
159 1.1 mrg regs_off = 96;
160 1.1 mrg fpu_save_off = regs_off + (4 * 4) + (16 * 4);
161 1.1 mrg }
162 1.1 mrg else
163 1.1 mrg {
164 1.1 mrg regs_off = 96 + 128;
165 1.1 mrg fpu_save_off = regs_off + (4 * 4) + (16 * 4) + (2 * 4);
166 1.1 mrg }
167 1.1 mrg
168 1.1 mrg new_cfa = *(int *)(this_cfa + regs_off + (4 * 4) + (14 * 4));
169 1.1 mrg fpu_save = *(int *)(this_cfa + fpu_save_off);
170 1.1 mrg fs->regs.cfa_how = CFA_REG_OFFSET;
171 1.1 mrg fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
172 1.1 mrg fs->regs.cfa_offset = new_cfa - this_cfa;
173 1.1 mrg
174 1.1 mrg for (i = 1; i < 16; i++)
175 1.1 mrg {
176 1.1 mrg /* We never restore %sp as everything is purely CFA-based. */
177 1.1 mrg if ((unsigned int) i == __builtin_dwarf_sp_column ())
178 1.1 mrg continue;
179 1.1 mrg
180 1.1 mrg fs->regs.reg[i].how = REG_SAVED_OFFSET;
181 1.1 mrg fs->regs.reg[i].loc.offset
182 1.1 mrg = this_cfa + regs_off + (4 * 4) + (i * 4) - new_cfa;
183 1.1 mrg }
184 1.1 mrg for (i = 0; i < 16; i++)
185 1.1 mrg {
186 1.1 mrg fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
187 1.1 mrg fs->regs.reg[i + 16].loc.offset
188 1.1 mrg = this_cfa + (i * 4) - new_cfa;
189 1.1 mrg }
190 1.1 mrg if (fpu_save)
191 1.1 mrg {
192 1.1 mrg for (i = 0; i < 32; i++)
193 1.1 mrg {
194 1.1 mrg fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
195 1.1 mrg fs->regs.reg[i + 32].loc.offset
196 1.1 mrg = fpu_save + (i * 4) - new_cfa;
197 1.1 mrg }
198 1.1 mrg }
199 1.1 mrg
200 1.1 mrg /* State the rules to find the kernel's code "return address", which is
201 1.1 mrg the address of the active instruction when the signal was caught.
202 1.1 mrg On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we
203 1.1 mrg need to preventively subtract it from the purported return address. */
204 1.1 mrg ra_location = this_cfa + regs_off + 4;
205 1.1 mrg shifted_ra_location = this_cfa + regs_off + 3 * 4; /* Y register */
206 1.1 mrg *(int *)shifted_ra_location = *(int *)ra_location - 8;
207 1.1 mrg fs->retaddr_column = 0;
208 1.1 mrg fs->regs.reg[0].how = REG_SAVED_OFFSET;
209 1.1 mrg fs->regs.reg[0].loc.offset = shifted_ra_location - new_cfa;
210 1.1 mrg fs->signal_frame = 1;
211 1.1 mrg
212 1.1 mrg return _URC_NO_REASON;
213 1.1 mrg }
214 1.1 mrg
215 1.1 mrg #endif
216