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