]>
git.ipfire.org Git - thirdparty/gcc.git/blob - libgcc/config/arm/pr-support.c
1 /* ARM EABI compliant unwinding routines
2 Copyright (C) 2004-2023 Free Software Foundation, Inc.
3 Contributed by Paul Brook
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
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.
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.
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/>. */
24 #pragma GCC target ("general-regs-only")
27 /* We add a prototype for abort here to avoid creating a dependency on
29 extern void abort (void);
31 typedef struct _ZSt9type_info type_info
; /* This names C++ type_info type */
39 #define uint32_highbit (((_uw) 1) << 31)
41 void __attribute__((weak
)) __cxa_call_unexpected(_Unwind_Control_Block
*ucbp
);
43 /* Unwind descriptors. */
57 /* Calculate the address encoded by a 31-bit self-relative offset at address
58 P. Copy of routine in unwind-arm.c. */
61 selfrel_offset31 (const _uw
*p
)
66 /* Sign extend to 32 bits. */
67 if (offset
& (1 << 30))
70 return offset
+ (_uw
) p
;
74 /* Personality routine helper functions. */
76 #define CODE_FINISH (0xb0)
78 /* Return the next byte of unwinding information, or CODE_FINISH if there is
81 next_unwind_byte (__gnu_unwind_state
* uws
)
85 if (uws
->bytes_left
== 0)
87 /* Load another word */
88 if (uws
->words_left
== 0)
89 return CODE_FINISH
; /* Nothing left. */
91 uws
->data
= *(uws
->next
++);
97 /* Extract the most significant byte. */
98 b
= (uws
->data
>> 24) & 0xff;
103 /* Execute the unwinding instructions described by UWS. */
105 __gnu_unwind_execute (_Unwind_Context
* context
, __gnu_unwind_state
* uws
)
109 #if defined(TARGET_HAVE_PACBTI)
119 op
= next_unwind_byte (uws
);
120 if (op
== CODE_FINISH
)
122 /* When we reach end, we have to authenticate R12 we just popped
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)
134 _Unwind_VRS_Get (context
, _UVRSC_CORE
, R_SP
, _UVRSD_UINT32
,
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
);
140 ("autg %0, %1, %2" : : "r"(pac
), "r"(lr
), "r"(sp
) :);
144 /* If we haven't already set pc then copy it from lr. */
147 _Unwind_VRS_Get (context
, _UVRSC_CORE
, R_LR
, _UVRSD_UINT32
,
149 _Unwind_VRS_Set (context
, _UVRSC_CORE
, R_PC
, _UVRSD_UINT32
,
153 /* Drop out of the loop. */
156 if ((op
& 0x80) == 0)
158 /* vsp = vsp +- (imm6 << 2 + 4). */
161 offset
= ((op
& 0x3f) << 2) + 4;
162 _Unwind_VRS_Get (context
, _UVRSC_CORE
, R_SP
, _UVRSD_UINT32
, ®
);
167 _Unwind_VRS_Set (context
, _UVRSC_CORE
, R_SP
, _UVRSD_UINT32
, ®
);
171 if ((op
& 0xf0) == 0x80)
173 op
= (op
<< 8) | next_unwind_byte (uws
);
176 /* Refuse to unwind. */
179 /* Pop r4-r15 under mask. */
180 op
= (op
<< 4) & 0xfff0;
181 if (_Unwind_VRS_Pop (context
, _UVRSC_CORE
, op
, _UVRSD_UINT32
)
184 if (op
& (1 << R_PC
))
188 if ((op
& 0xf0) == 0x90)
191 if (op
== 13 || op
== 15)
195 _Unwind_VRS_Get (context
, _UVRSC_CORE
, op
, _UVRSD_UINT32
, ®
);
196 _Unwind_VRS_Set (context
, _UVRSC_CORE
, R_SP
, _UVRSD_UINT32
, ®
);
199 if ((op
& 0xf0) == 0xa0)
201 /* Pop r4-r[4+nnn], [lr]. */
204 mask
= (0xff0 >> (7 - (op
& 7))) & 0xff0;
207 if (_Unwind_VRS_Pop (context
, _UVRSC_CORE
, mask
, _UVRSD_UINT32
)
212 if ((op
& 0xf0) == 0xb0)
214 /* op == 0xb0 already handled. */
217 op
= next_unwind_byte (uws
);
218 if (op
== 0 || ((op
& 0xf0) != 0))
221 /* Pop r0-r4 under mask. */
222 if (_Unwind_VRS_Pop (context
, _UVRSC_CORE
, op
, _UVRSD_UINT32
)
229 /* vsp = vsp + 0x204 + (uleb128 << 2). */
232 _Unwind_VRS_Get (context
, _UVRSC_CORE
, R_SP
, _UVRSD_UINT32
,
234 op
= next_unwind_byte (uws
);
238 reg
+= ((op
& 0x7f) << shift
);
240 op
= next_unwind_byte (uws
);
242 reg
+= ((op
& 0x7f) << shift
) + 0x204;
243 _Unwind_VRS_Set (context
, _UVRSC_CORE
, R_SP
, _UVRSD_UINT32
,
249 /* Pop VFP registers with fldmx. */
250 op
= next_unwind_byte (uws
);
251 op
= ((op
& 0xf0) << 12) | ((op
& 0xf) + 1);
252 if (_Unwind_VRS_Pop (context
, _UVRSC_VFP
, op
, _UVRSD_VFPX
)
257 /* Pop PAC off the stack into VRS pseudo.pac. */
260 if (_Unwind_VRS_Pop (context
, _UVRSC_PAC
, 0, _UVRSD_UINT32
)
263 #if defined(TARGET_HAVE_PACBTI)
269 /* Use current VSP as modifier in PAC validation. */
272 _Unwind_VRS_Get (context
, _UVRSC_CORE
, R_SP
, _UVRSD_UINT32
, &sp
);
273 #if defined(TARGET_HAVE_PACBTI)
279 if ((op
& 0xfc) == 0xb4) /* Obsolete FPA. */
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
)
290 if ((op
& 0xf0) == 0xc0)
294 /* Pop iWMMXt D registers. */
295 op
= next_unwind_byte (uws
);
296 op
= ((op
& 0xf0) << 12) | ((op
& 0xf) + 1);
297 if (_Unwind_VRS_Pop (context
, _UVRSC_WMMXD
, op
, _UVRSD_UINT64
)
304 op
= next_unwind_byte (uws
);
305 if (op
== 0 || (op
& 0xf0) != 0)
308 /* Pop iWMMXt wCGR{3,2,1,0} under mask. */
309 if (_Unwind_VRS_Pop (context
, _UVRSC_WMMXC
, op
, _UVRSD_UINT32
)
314 if ((op
& 0xf8) == 0xc0)
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
)
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
)
335 /* Pop VFP registers with fldmd. */
336 op
= next_unwind_byte (uws
);
337 op
= ((op
& 0xf0) << 12) | ((op
& 0xf) + 1);
338 if (_Unwind_VRS_Pop (context
, _UVRSC_VFP
, op
, _UVRSD_DOUBLE
)
346 if ((op
& 0xf8) == 0xd0)
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
)
362 /* Execute the unwinding instructions associated with a frame. UCBP and
363 CONTEXT are the current exception object and virtual CPU state
367 __gnu_unwind_frame (_Unwind_Control_Block
* ucbp
, _Unwind_Context
* context
)
370 __gnu_unwind_state uws
;
372 ptr
= (_uw
*) ucbp
->pr_cache
.ehtp
;
373 /* Skip over the personality routine address. */
375 /* Setup the unwinder state. */
376 uws
.data
= (*ptr
) << 8;
379 uws
.words_left
= ((*ptr
) >> 24) & 0xff;
381 return __gnu_unwind_execute (context
, &uws
);
384 /* Get the _Unwind_Control_Block from an _Unwind_Context. */
386 static inline _Unwind_Control_Block
*
387 unwind_UCB_from_context (_Unwind_Context
* context
)
389 return (_Unwind_Control_Block
*) _Unwind_GetGR (context
, R_IP
);
392 /* Get the start address of the function being unwound. */
395 _Unwind_GetRegionStart (_Unwind_Context
* context
)
397 _Unwind_Control_Block
*ucbp
;
399 ucbp
= unwind_UCB_from_context (context
);
400 return (_Unwind_Ptr
) ucbp
->pr_cache
.fnstart
;
403 /* Find the Language specific exception data. */
406 _Unwind_GetLanguageSpecificData (_Unwind_Context
* context
)
408 _Unwind_Control_Block
*ucbp
;
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. */
416 /* Skip the unwind opcodes. */
417 ptr
+= (((*ptr
) >> 24) & 0xff) + 1;
423 /* These two should never be used. */
426 _Unwind_GetDataRelBase (_Unwind_Context
*context
__attribute__ ((unused
)))
432 _Unwind_GetTextRelBase (_Unwind_Context
*context
__attribute__ ((unused
)))