]>
git.ipfire.org Git - thirdparty/gcc.git/blob - 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
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
)
114 op
= next_unwind_byte (uws
);
115 if (op
== CODE_FINISH
)
117 /* If we haven't already set pc then copy it from lr. */
120 _Unwind_VRS_Get (context
, _UVRSC_CORE
, R_LR
, _UVRSD_UINT32
,
122 _Unwind_VRS_Set (context
, _UVRSC_CORE
, R_PC
, _UVRSD_UINT32
,
126 /* Drop out of the loop. */
129 if ((op
& 0x80) == 0)
131 /* vsp = vsp +- (imm6 << 2 + 4). */
134 offset
= ((op
& 0x3f) << 2) + 4;
135 _Unwind_VRS_Get (context
, _UVRSC_CORE
, R_SP
, _UVRSD_UINT32
, ®
);
140 _Unwind_VRS_Set (context
, _UVRSC_CORE
, R_SP
, _UVRSD_UINT32
, ®
);
144 if ((op
& 0xf0) == 0x80)
146 op
= (op
<< 8) | next_unwind_byte (uws
);
149 /* Refuse to unwind. */
152 /* Pop r4-r15 under mask. */
153 op
= (op
<< 4) & 0xfff0;
154 if (_Unwind_VRS_Pop (context
, _UVRSC_CORE
, op
, _UVRSD_UINT32
)
157 if (op
& (1 << R_PC
))
161 if ((op
& 0xf0) == 0x90)
164 if (op
== 13 || op
== 15)
168 _Unwind_VRS_Get (context
, _UVRSC_CORE
, op
, _UVRSD_UINT32
, ®
);
169 _Unwind_VRS_Set (context
, _UVRSC_CORE
, R_SP
, _UVRSD_UINT32
, ®
);
172 if ((op
& 0xf0) == 0xa0)
174 /* Pop r4-r[4+nnn], [lr]. */
177 mask
= (0xff0 >> (7 - (op
& 7))) & 0xff0;
180 if (_Unwind_VRS_Pop (context
, _UVRSC_CORE
, mask
, _UVRSD_UINT32
)
185 if ((op
& 0xf0) == 0xb0)
187 /* op == 0xb0 already handled. */
190 op
= next_unwind_byte (uws
);
191 if (op
== 0 || ((op
& 0xf0) != 0))
194 /* Pop r0-r4 under mask. */
195 if (_Unwind_VRS_Pop (context
, _UVRSC_CORE
, op
, _UVRSD_UINT32
)
202 /* vsp = vsp + 0x204 + (uleb128 << 2). */
205 _Unwind_VRS_Get (context
, _UVRSC_CORE
, R_SP
, _UVRSD_UINT32
,
207 op
= next_unwind_byte (uws
);
211 reg
+= ((op
& 0x7f) << shift
);
213 op
= next_unwind_byte (uws
);
215 reg
+= ((op
& 0x7f) << shift
) + 0x204;
216 _Unwind_VRS_Set (context
, _UVRSC_CORE
, R_SP
, _UVRSD_UINT32
,
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
)
230 if ((op
& 0xfc) == 0xb4) /* Obsolete FPA. */
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
)
241 if ((op
& 0xf0) == 0xc0)
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
)
255 op
= next_unwind_byte (uws
);
256 if (op
== 0 || (op
& 0xf0) != 0)
259 /* Pop iWMMXt wCGR{3,2,1,0} under mask. */
260 if (_Unwind_VRS_Pop (context
, _UVRSC_WMMXC
, op
, _UVRSD_UINT32
)
265 if ((op
& 0xf8) == 0xc0)
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
)
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
)
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
)
297 if ((op
& 0xf8) == 0xd0)
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
)
313 /* Execute the unwinding instructions associated with a frame. UCBP and
314 CONTEXT are the current exception object and virtual CPU state
318 __gnu_unwind_frame (_Unwind_Control_Block
* ucbp
, _Unwind_Context
* context
)
321 __gnu_unwind_state uws
;
323 ptr
= (_uw
*) ucbp
->pr_cache
.ehtp
;
324 /* Skip over the personality routine address. */
326 /* Setup the unwinder state. */
327 uws
.data
= (*ptr
) << 8;
330 uws
.words_left
= ((*ptr
) >> 24) & 0xff;
332 return __gnu_unwind_execute (context
, &uws
);
335 /* Get the _Unwind_Control_Block from an _Unwind_Context. */
337 static inline _Unwind_Control_Block
*
338 unwind_UCB_from_context (_Unwind_Context
* context
)
340 return (_Unwind_Control_Block
*) _Unwind_GetGR (context
, R_IP
);
343 /* Get the start address of the function being unwound. */
346 _Unwind_GetRegionStart (_Unwind_Context
* context
)
348 _Unwind_Control_Block
*ucbp
;
350 ucbp
= unwind_UCB_from_context (context
);
351 return (_Unwind_Ptr
) ucbp
->pr_cache
.fnstart
;
354 /* Find the Language specific exception data. */
357 _Unwind_GetLanguageSpecificData (_Unwind_Context
* context
)
359 _Unwind_Control_Block
*ucbp
;
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. */
367 /* Skip the unwind opcodes. */
368 ptr
+= (((*ptr
) >> 24) & 0xff) + 1;
374 /* These two should never be used. */
377 _Unwind_GetDataRelBase (_Unwind_Context
*context
__attribute__ ((unused
)))
383 _Unwind_GetTextRelBase (_Unwind_Context
*context
__attribute__ ((unused
)))