]> git.ipfire.org Git - thirdparty/gcc.git/blob - libgcc/config/arm/pr-support.c
Update copyright years.
[thirdparty/gcc.git] / libgcc / config / arm / pr-support.c
1 /* ARM EABI compliant unwinding routines
2 Copyright (C) 2004-2020 Free Software Foundation, Inc.
3 Contributed by Paul Brook
4
5 This file is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 3, or (at your option) any
8 later version.
9
10 This file is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 Under Section 7 of GPL version 3, you are granted additional
16 permissions described in the GCC Runtime Library Exception, version
17 3.1, as published by the Free Software Foundation.
18
19 You should have received a copy of the GNU General Public License and
20 a copy of the GCC Runtime Library Exception along with this program;
21 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
22 <http://www.gnu.org/licenses/>. */
23
24 #pragma GCC target ("general-regs-only")
25 #include "unwind.h"
26
27 /* We add a prototype for abort here to avoid creating a dependency on
28 target headers. */
29 extern void abort (void);
30
31 typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
32
33 /* Misc constants. */
34 #define R_IP 12
35 #define R_SP 13
36 #define R_LR 14
37 #define R_PC 15
38
39 #define uint32_highbit (((_uw) 1) << 31)
40
41 void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
42
43 /* Unwind descriptors. */
44
45 typedef struct
46 {
47 _uw16 length;
48 _uw16 offset;
49 } EHT16;
50
51 typedef struct
52 {
53 _uw length;
54 _uw offset;
55 } EHT32;
56
57 /* Calculate the address encoded by a 31-bit self-relative offset at address
58 P. Copy of routine in unwind-arm.c. */
59
60 static inline _uw
61 selfrel_offset31 (const _uw *p)
62 {
63 _uw offset;
64
65 offset = *p;
66 /* Sign extend to 32 bits. */
67 if (offset & (1 << 30))
68 offset |= 1u << 31;
69
70 return offset + (_uw) p;
71 }
72
73
74 /* Personality routine helper functions. */
75
76 #define CODE_FINISH (0xb0)
77
78 /* Return the next byte of unwinding information, or CODE_FINISH if there is
79 no data remaining. */
80 static inline _uw8
81 next_unwind_byte (__gnu_unwind_state * uws)
82 {
83 _uw8 b;
84
85 if (uws->bytes_left == 0)
86 {
87 /* Load another word */
88 if (uws->words_left == 0)
89 return CODE_FINISH; /* Nothing left. */
90 uws->words_left--;
91 uws->data = *(uws->next++);
92 uws->bytes_left = 3;
93 }
94 else
95 uws->bytes_left--;
96
97 /* Extract the most significant byte. */
98 b = (uws->data >> 24) & 0xff;
99 uws->data <<= 8;
100 return b;
101 }
102
103 /* Execute the unwinding instructions described by UWS. */
104 _Unwind_Reason_Code
105 __gnu_unwind_execute (_Unwind_Context * context, __gnu_unwind_state * uws)
106 {
107 _uw op;
108 int set_pc;
109 _uw reg;
110
111 set_pc = 0;
112 for (;;)
113 {
114 op = next_unwind_byte (uws);
115 if (op == CODE_FINISH)
116 {
117 /* If we haven't already set pc then copy it from lr. */
118 if (!set_pc)
119 {
120 _Unwind_VRS_Get (context, _UVRSC_CORE, R_LR, _UVRSD_UINT32,
121 &reg);
122 _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32,
123 &reg);
124 set_pc = 1;
125 }
126 /* Drop out of the loop. */
127 break;
128 }
129 if ((op & 0x80) == 0)
130 {
131 /* vsp = vsp +- (imm6 << 2 + 4). */
132 _uw offset;
133
134 offset = ((op & 0x3f) << 2) + 4;
135 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
136 if (op & 0x40)
137 reg -= offset;
138 else
139 reg += offset;
140 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
141 continue;
142 }
143
144 if ((op & 0xf0) == 0x80)
145 {
146 op = (op << 8) | next_unwind_byte (uws);
147 if (op == 0x8000)
148 {
149 /* Refuse to unwind. */
150 return _URC_FAILURE;
151 }
152 /* Pop r4-r15 under mask. */
153 op = (op << 4) & 0xfff0;
154 if (_Unwind_VRS_Pop (context, _UVRSC_CORE, op, _UVRSD_UINT32)
155 != _UVRSR_OK)
156 return _URC_FAILURE;
157 if (op & (1 << R_PC))
158 set_pc = 1;
159 continue;
160 }
161 if ((op & 0xf0) == 0x90)
162 {
163 op &= 0xf;
164 if (op == 13 || op == 15)
165 /* Reserved. */
166 return _URC_FAILURE;
167 /* vsp = r[nnnn]. */
168 _Unwind_VRS_Get (context, _UVRSC_CORE, op, _UVRSD_UINT32, &reg);
169 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
170 continue;
171 }
172 if ((op & 0xf0) == 0xa0)
173 {
174 /* Pop r4-r[4+nnn], [lr]. */
175 _uw mask;
176
177 mask = (0xff0 >> (7 - (op & 7))) & 0xff0;
178 if (op & 8)
179 mask |= (1 << R_LR);
180 if (_Unwind_VRS_Pop (context, _UVRSC_CORE, mask, _UVRSD_UINT32)
181 != _UVRSR_OK)
182 return _URC_FAILURE;
183 continue;
184 }
185 if ((op & 0xf0) == 0xb0)
186 {
187 /* op == 0xb0 already handled. */
188 if (op == 0xb1)
189 {
190 op = next_unwind_byte (uws);
191 if (op == 0 || ((op & 0xf0) != 0))
192 /* Spare. */
193 return _URC_FAILURE;
194 /* Pop r0-r4 under mask. */
195 if (_Unwind_VRS_Pop (context, _UVRSC_CORE, op, _UVRSD_UINT32)
196 != _UVRSR_OK)
197 return _URC_FAILURE;
198 continue;
199 }
200 if (op == 0xb2)
201 {
202 /* vsp = vsp + 0x204 + (uleb128 << 2). */
203 int shift;
204
205 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
206 &reg);
207 op = next_unwind_byte (uws);
208 shift = 2;
209 while (op & 0x80)
210 {
211 reg += ((op & 0x7f) << shift);
212 shift += 7;
213 op = next_unwind_byte (uws);
214 }
215 reg += ((op & 0x7f) << shift) + 0x204;
216 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
217 &reg);
218 continue;
219 }
220 if (op == 0xb3)
221 {
222 /* Pop VFP registers with fldmx. */
223 op = next_unwind_byte (uws);
224 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
225 if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_VFPX)
226 != _UVRSR_OK)
227 return _URC_FAILURE;
228 continue;
229 }
230 if ((op & 0xfc) == 0xb4) /* Obsolete FPA. */
231 return _URC_FAILURE;
232
233 /* op & 0xf8 == 0xb8. */
234 /* Pop VFP D[8]-D[8+nnn] with fldmx. */
235 op = 0x80000 | ((op & 7) + 1);
236 if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_VFPX)
237 != _UVRSR_OK)
238 return _URC_FAILURE;
239 continue;
240 }
241 if ((op & 0xf0) == 0xc0)
242 {
243 if (op == 0xc6)
244 {
245 /* Pop iWMMXt D registers. */
246 op = next_unwind_byte (uws);
247 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
248 if (_Unwind_VRS_Pop (context, _UVRSC_WMMXD, op, _UVRSD_UINT64)
249 != _UVRSR_OK)
250 return _URC_FAILURE;
251 continue;
252 }
253 if (op == 0xc7)
254 {
255 op = next_unwind_byte (uws);
256 if (op == 0 || (op & 0xf0) != 0)
257 /* Spare. */
258 return _URC_FAILURE;
259 /* Pop iWMMXt wCGR{3,2,1,0} under mask. */
260 if (_Unwind_VRS_Pop (context, _UVRSC_WMMXC, op, _UVRSD_UINT32)
261 != _UVRSR_OK)
262 return _URC_FAILURE;
263 continue;
264 }
265 if ((op & 0xf8) == 0xc0)
266 {
267 /* Pop iWMMXt wR[10]-wR[10+nnn]. */
268 op = 0xa0000 | ((op & 0xf) + 1);
269 if (_Unwind_VRS_Pop (context, _UVRSC_WMMXD, op, _UVRSD_UINT64)
270 != _UVRSR_OK)
271 return _URC_FAILURE;
272 continue;
273 }
274 if (op == 0xc8)
275 {
276 /* Pop VFPv3 registers D[16+ssss]-D[16+ssss+cccc] with vldm. */
277 op = next_unwind_byte (uws);
278 op = (((op & 0xf0) + 16) << 12) | ((op & 0xf) + 1);
279 if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
280 != _UVRSR_OK)
281 return _URC_FAILURE;
282 continue;
283 }
284 if (op == 0xc9)
285 {
286 /* Pop VFP registers with fldmd. */
287 op = next_unwind_byte (uws);
288 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
289 if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
290 != _UVRSR_OK)
291 return _URC_FAILURE;
292 continue;
293 }
294 /* Spare. */
295 return _URC_FAILURE;
296 }
297 if ((op & 0xf8) == 0xd0)
298 {
299 /* Pop VFP D[8]-D[8+nnn] with fldmd. */
300 op = 0x80000 | ((op & 7) + 1);
301 if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
302 != _UVRSR_OK)
303 return _URC_FAILURE;
304 continue;
305 }
306 /* Spare. */
307 return _URC_FAILURE;
308 }
309 return _URC_OK;
310 }
311
312
313 /* Execute the unwinding instructions associated with a frame. UCBP and
314 CONTEXT are the current exception object and virtual CPU state
315 respectively. */
316
317 _Unwind_Reason_Code
318 __gnu_unwind_frame (_Unwind_Control_Block * ucbp, _Unwind_Context * context)
319 {
320 _uw *ptr;
321 __gnu_unwind_state uws;
322
323 ptr = (_uw *) ucbp->pr_cache.ehtp;
324 /* Skip over the personality routine address. */
325 ptr++;
326 /* Setup the unwinder state. */
327 uws.data = (*ptr) << 8;
328 uws.next = ptr + 1;
329 uws.bytes_left = 3;
330 uws.words_left = ((*ptr) >> 24) & 0xff;
331
332 return __gnu_unwind_execute (context, &uws);
333 }
334
335 /* Get the _Unwind_Control_Block from an _Unwind_Context. */
336
337 static inline _Unwind_Control_Block *
338 unwind_UCB_from_context (_Unwind_Context * context)
339 {
340 return (_Unwind_Control_Block *) _Unwind_GetGR (context, R_IP);
341 }
342
343 /* Get the start address of the function being unwound. */
344
345 _Unwind_Ptr
346 _Unwind_GetRegionStart (_Unwind_Context * context)
347 {
348 _Unwind_Control_Block *ucbp;
349
350 ucbp = unwind_UCB_from_context (context);
351 return (_Unwind_Ptr) ucbp->pr_cache.fnstart;
352 }
353
354 /* Find the Language specific exception data. */
355
356 void *
357 _Unwind_GetLanguageSpecificData (_Unwind_Context * context)
358 {
359 _Unwind_Control_Block *ucbp;
360 _uw *ptr;
361
362 /* Get a pointer to the exception table entry. */
363 ucbp = unwind_UCB_from_context (context);
364 ptr = (_uw *) ucbp->pr_cache.ehtp;
365 /* Skip the personality routine address. */
366 ptr++;
367 /* Skip the unwind opcodes. */
368 ptr += (((*ptr) >> 24) & 0xff) + 1;
369
370 return ptr;
371 }
372
373
374 /* These two should never be used. */
375
376 _Unwind_Ptr
377 _Unwind_GetDataRelBase (_Unwind_Context *context __attribute__ ((unused)))
378 {
379 abort ();
380 }
381
382 _Unwind_Ptr
383 _Unwind_GetTextRelBase (_Unwind_Context *context __attribute__ ((unused)))
384 {
385 abort ();
386 }