]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/config/arm/pr-support.c
arm: Fix warning in libgcc/config/arm/pr-support.c
[thirdparty/gcc.git] / libgcc / config / arm / pr-support.c
CommitLineData
2a75c0b6 1/* ARM EABI compliant unwinding routines
83ffe9cd 2 Copyright (C) 2004-2023 Free Software Foundation, Inc.
2a75c0b6
PB
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
748086b7 7 Free Software Foundation; either version 3, or (at your option) any
2a75c0b6
PB
8 later version.
9
2a75c0b6
PB
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
748086b7
JJ
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
48528842 24#pragma GCC target ("general-regs-only")
2a75c0b6
PB
25#include "unwind.h"
26
74d9c39f
DJ
27/* We add a prototype for abort here to avoid creating a dependency on
28 target headers. */
29extern void abort (void);
30
2a75c0b6
PB
31typedef 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
41void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
42
43/* Unwind descriptors. */
44
45typedef struct
46{
47 _uw16 length;
48 _uw16 offset;
49} EHT16;
50
51typedef 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
60static inline _uw
61selfrel_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. */
80static inline _uw8
81next_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;
3dba5b2c 109#if defined(TARGET_HAVE_PACBTI)
7161afc7 110 int set_pac = 0;
55a2d809 111 int set_pac_sp = 0;
3dba5b2c 112#endif
2a75c0b6 113 _uw reg;
55a2d809 114 _uw sp;
2a75c0b6
PB
115
116 set_pc = 0;
117 for (;;)
118 {
119 op = next_unwind_byte (uws);
120 if (op == CODE_FINISH)
121 {
7161afc7
AC
122 /* When we reach end, we have to authenticate R12 we just popped
123 earlier.
124
125 Note: while the check provides additional security against a
126 corrupted unwind chain, it isn't essential for correct unwinding
127 of an uncorrupted chain. */
128#if defined(TARGET_HAVE_PACBTI)
129 if (set_pac)
130 {
7161afc7
AC
131 _uw lr;
132 _uw pac;
55a2d809
SP
133 if (!set_pac_sp)
134 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
135 &sp);
7161afc7
AC
136 _Unwind_VRS_Get (context, _UVRSC_CORE, R_LR, _UVRSD_UINT32, &lr);
137 _Unwind_VRS_Get (context, _UVRSC_PAC, R_IP,
138 _UVRSD_UINT32, &pac);
139 __asm__ __volatile__
140 ("autg %0, %1, %2" : : "r"(pac), "r"(lr), "r"(sp) :);
141 }
142#endif
143
2a75c0b6
PB
144 /* If we haven't already set pc then copy it from lr. */
145 if (!set_pc)
146 {
147 _Unwind_VRS_Get (context, _UVRSC_CORE, R_LR, _UVRSD_UINT32,
148 &reg);
149 _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32,
150 &reg);
151 set_pc = 1;
152 }
153 /* Drop out of the loop. */
154 break;
155 }
156 if ((op & 0x80) == 0)
157 {
158 /* vsp = vsp +- (imm6 << 2 + 4). */
159 _uw offset;
160
161 offset = ((op & 0x3f) << 2) + 4;
162 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
163 if (op & 0x40)
164 reg -= offset;
165 else
166 reg += offset;
167 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
168 continue;
169 }
170
171 if ((op & 0xf0) == 0x80)
172 {
173 op = (op << 8) | next_unwind_byte (uws);
174 if (op == 0x8000)
175 {
176 /* Refuse to unwind. */
177 return _URC_FAILURE;
178 }
179 /* Pop r4-r15 under mask. */
180 op = (op << 4) & 0xfff0;
181 if (_Unwind_VRS_Pop (context, _UVRSC_CORE, op, _UVRSD_UINT32)
182 != _UVRSR_OK)
183 return _URC_FAILURE;
184 if (op & (1 << R_PC))
185 set_pc = 1;
186 continue;
187 }
188 if ((op & 0xf0) == 0x90)
189 {
190 op &= 0xf;
191 if (op == 13 || op == 15)
192 /* Reserved. */
193 return _URC_FAILURE;
194 /* vsp = r[nnnn]. */
195 _Unwind_VRS_Get (context, _UVRSC_CORE, op, _UVRSD_UINT32, &reg);
196 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
197 continue;
198 }
199 if ((op & 0xf0) == 0xa0)
200 {
201 /* Pop r4-r[4+nnn], [lr]. */
202 _uw mask;
203
204 mask = (0xff0 >> (7 - (op & 7))) & 0xff0;
205 if (op & 8)
206 mask |= (1 << R_LR);
207 if (_Unwind_VRS_Pop (context, _UVRSC_CORE, mask, _UVRSD_UINT32)
208 != _UVRSR_OK)
209 return _URC_FAILURE;
210 continue;
211 }
212 if ((op & 0xf0) == 0xb0)
213 {
214 /* op == 0xb0 already handled. */
215 if (op == 0xb1)
216 {
217 op = next_unwind_byte (uws);
218 if (op == 0 || ((op & 0xf0) != 0))
219 /* Spare. */
220 return _URC_FAILURE;
221 /* Pop r0-r4 under mask. */
222 if (_Unwind_VRS_Pop (context, _UVRSC_CORE, op, _UVRSD_UINT32)
223 != _UVRSR_OK)
224 return _URC_FAILURE;
225 continue;
226 }
227 if (op == 0xb2)
228 {
229 /* vsp = vsp + 0x204 + (uleb128 << 2). */
230 int shift;
231
232 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
233 &reg);
234 op = next_unwind_byte (uws);
235 shift = 2;
236 while (op & 0x80)
237 {
238 reg += ((op & 0x7f) << shift);
239 shift += 7;
240 op = next_unwind_byte (uws);
241 }
242 reg += ((op & 0x7f) << shift) + 0x204;
243 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
244 &reg);
245 continue;
246 }
247 if (op == 0xb3)
248 {
249 /* Pop VFP registers with fldmx. */
250 op = next_unwind_byte (uws);
08a557f6 251 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
2a75c0b6
PB
252 if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_VFPX)
253 != _UVRSR_OK)
254 return _URC_FAILURE;
255 continue;
256 }
7161afc7
AC
257 /* Pop PAC off the stack into VRS pseudo.pac. */
258 if (op == 0xb4)
259 {
260 if (_Unwind_VRS_Pop (context, _UVRSC_PAC, 0, _UVRSD_UINT32)
261 != _UVRSR_OK)
262 return _URC_FAILURE;
3dba5b2c 263#if defined(TARGET_HAVE_PACBTI)
7161afc7 264 set_pac = 1;
3dba5b2c 265#endif
7161afc7
AC
266 continue;
267 }
268
55a2d809
SP
269 /* Use current VSP as modifier in PAC validation. */
270 if (op == 0xb5)
271 {
272 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &sp);
3dba5b2c 273#if defined(TARGET_HAVE_PACBTI)
55a2d809 274 set_pac_sp = 1;
3dba5b2c 275#endif
55a2d809
SP
276 continue;
277 }
278
5005fe22
RE
279 if ((op & 0xfc) == 0xb4) /* Obsolete FPA. */
280 return _URC_FAILURE;
281
2a75c0b6
PB
282 /* op & 0xf8 == 0xb8. */
283 /* Pop VFP D[8]-D[8+nnn] with fldmx. */
284 op = 0x80000 | ((op & 7) + 1);
285 if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_VFPX)
286 != _UVRSR_OK)
287 return _URC_FAILURE;
288 continue;
289 }
290 if ((op & 0xf0) == 0xc0)
291 {
292 if (op == 0xc6)
293 {
294 /* Pop iWMMXt D registers. */
295 op = next_unwind_byte (uws);
08a557f6 296 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
2a75c0b6
PB
297 if (_Unwind_VRS_Pop (context, _UVRSC_WMMXD, op, _UVRSD_UINT64)
298 != _UVRSR_OK)
299 return _URC_FAILURE;
300 continue;
301 }
302 if (op == 0xc7)
303 {
304 op = next_unwind_byte (uws);
305 if (op == 0 || (op & 0xf0) != 0)
306 /* Spare. */
307 return _URC_FAILURE;
308 /* Pop iWMMXt wCGR{3,2,1,0} under mask. */
309 if (_Unwind_VRS_Pop (context, _UVRSC_WMMXC, op, _UVRSD_UINT32)
310 != _UVRSR_OK)
311 return _URC_FAILURE;
312 continue;
313 }
314 if ((op & 0xf8) == 0xc0)
315 {
316 /* Pop iWMMXt wR[10]-wR[10+nnn]. */
317 op = 0xa0000 | ((op & 0xf) + 1);
318 if (_Unwind_VRS_Pop (context, _UVRSC_WMMXD, op, _UVRSD_UINT64)
319 != _UVRSR_OK)
320 return _URC_FAILURE;
321 continue;
322 }
323 if (op == 0xc8)
324 {
8edfc4cc
MS
325 /* Pop VFPv3 registers D[16+ssss]-D[16+ssss+cccc] with vldm. */
326 op = next_unwind_byte (uws);
327 op = (((op & 0xf0) + 16) << 12) | ((op & 0xf) + 1);
328 if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
329 != _UVRSR_OK)
330 return _URC_FAILURE;
331 continue;
2a75c0b6
PB
332 }
333 if (op == 0xc9)
334 {
335 /* Pop VFP registers with fldmd. */
336 op = next_unwind_byte (uws);
08a557f6 337 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
2a75c0b6
PB
338 if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
339 != _UVRSR_OK)
340 return _URC_FAILURE;
341 continue;
342 }
343 /* Spare. */
344 return _URC_FAILURE;
345 }
346 if ((op & 0xf8) == 0xd0)
347 {
348 /* Pop VFP D[8]-D[8+nnn] with fldmd. */
349 op = 0x80000 | ((op & 7) + 1);
350 if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
351 != _UVRSR_OK)
352 return _URC_FAILURE;
353 continue;
354 }
355 /* Spare. */
356 return _URC_FAILURE;
357 }
358 return _URC_OK;
359}
360
361
362/* Execute the unwinding instructions associated with a frame. UCBP and
363 CONTEXT are the current exception object and virtual CPU state
364 respectively. */
365
366_Unwind_Reason_Code
367__gnu_unwind_frame (_Unwind_Control_Block * ucbp, _Unwind_Context * context)
368{
369 _uw *ptr;
370 __gnu_unwind_state uws;
371
372 ptr = (_uw *) ucbp->pr_cache.ehtp;
373 /* Skip over the personality routine address. */
374 ptr++;
375 /* Setup the unwinder state. */
376 uws.data = (*ptr) << 8;
377 uws.next = ptr + 1;
378 uws.bytes_left = 3;
379 uws.words_left = ((*ptr) >> 24) & 0xff;
380
381 return __gnu_unwind_execute (context, &uws);
382}
383
384/* Get the _Unwind_Control_Block from an _Unwind_Context. */
385
386static inline _Unwind_Control_Block *
387unwind_UCB_from_context (_Unwind_Context * context)
388{
389 return (_Unwind_Control_Block *) _Unwind_GetGR (context, R_IP);
390}
391
392/* Get the start address of the function being unwound. */
393
394_Unwind_Ptr
395_Unwind_GetRegionStart (_Unwind_Context * context)
396{
397 _Unwind_Control_Block *ucbp;
398
399 ucbp = unwind_UCB_from_context (context);
400 return (_Unwind_Ptr) ucbp->pr_cache.fnstart;
401}
402
403/* Find the Language specific exception data. */
404
405void *
406_Unwind_GetLanguageSpecificData (_Unwind_Context * context)
407{
408 _Unwind_Control_Block *ucbp;
409 _uw *ptr;
410
411 /* Get a pointer to the exception table entry. */
412 ucbp = unwind_UCB_from_context (context);
413 ptr = (_uw *) ucbp->pr_cache.ehtp;
414 /* Skip the personality routine address. */
415 ptr++;
416 /* Skip the unwind opcodes. */
417 ptr += (((*ptr) >> 24) & 0xff) + 1;
418
419 return ptr;
420}
421
66403286
PB
422
423/* These two should never be used. */
424
425_Unwind_Ptr
426_Unwind_GetDataRelBase (_Unwind_Context *context __attribute__ ((unused)))
427{
428 abort ();
429}
430
431_Unwind_Ptr
432_Unwind_GetTextRelBase (_Unwind_Context *context __attribute__ ((unused)))
433{
434 abort ();
435}