1 /* ARM EABI compliant unwinding routines
2 Copyright (C) 2004-2017 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/>. */
26 /* We add a prototype for abort here to avoid creating a dependency on
28 extern void abort (void);
30 typedef struct _ZSt9type_info type_info
; /* This names C++ type_info type */
38 #define uint32_highbit (((_uw) 1) << 31)
40 void __attribute__((weak
)) __cxa_call_unexpected(_Unwind_Control_Block
*ucbp
);
42 /* Unwind descriptors. */
56 /* Calculate the address encoded by a 31-bit self-relative offset at address
57 P. Copy of routine in unwind-arm.c. */
60 selfrel_offset31 (const _uw
*p
)
65 /* Sign extend to 32 bits. */
66 if (offset
& (1 << 30))
69 return offset
+ (_uw
) p
;
73 /* Personality routine helper functions. */
75 #define CODE_FINISH (0xb0)
77 /* Return the next byte of unwinding information, or CODE_FINISH if there is
80 next_unwind_byte (__gnu_unwind_state
* uws
)
84 if (uws
->bytes_left
== 0)
86 /* Load another word */
87 if (uws
->words_left
== 0)
88 return CODE_FINISH
; /* Nothing left. */
90 uws
->data
= *(uws
->next
++);
96 /* Extract the most significant byte. */
97 b
= (uws
->data
>> 24) & 0xff;
102 /* Execute the unwinding instructions described by UWS. */
104 __gnu_unwind_execute (_Unwind_Context
* context
, __gnu_unwind_state
* uws
)
113 op
= next_unwind_byte (uws
);
114 if (op
== CODE_FINISH
)
116 /* If we haven't already set pc then copy it from lr. */
119 _Unwind_VRS_Get (context
, _UVRSC_CORE
, R_LR
, _UVRSD_UINT32
,
121 _Unwind_VRS_Set (context
, _UVRSC_CORE
, R_PC
, _UVRSD_UINT32
,
125 /* Drop out of the loop. */
128 if ((op
& 0x80) == 0)
130 /* vsp = vsp +- (imm6 << 2 + 4). */
133 offset
= ((op
& 0x3f) << 2) + 4;
134 _Unwind_VRS_Get (context
, _UVRSC_CORE
, R_SP
, _UVRSD_UINT32
, ®
);
139 _Unwind_VRS_Set (context
, _UVRSC_CORE
, R_SP
, _UVRSD_UINT32
, ®
);
143 if ((op
& 0xf0) == 0x80)
145 op
= (op
<< 8) | next_unwind_byte (uws
);
148 /* Refuse to unwind. */
151 /* Pop r4-r15 under mask. */
152 op
= (op
<< 4) & 0xfff0;
153 if (_Unwind_VRS_Pop (context
, _UVRSC_CORE
, op
, _UVRSD_UINT32
)
156 if (op
& (1 << R_PC
))
160 if ((op
& 0xf0) == 0x90)
163 if (op
== 13 || op
== 15)
167 _Unwind_VRS_Get (context
, _UVRSC_CORE
, op
, _UVRSD_UINT32
, ®
);
168 _Unwind_VRS_Set (context
, _UVRSC_CORE
, R_SP
, _UVRSD_UINT32
, ®
);
171 if ((op
& 0xf0) == 0xa0)
173 /* Pop r4-r[4+nnn], [lr]. */
176 mask
= (0xff0 >> (7 - (op
& 7))) & 0xff0;
179 if (_Unwind_VRS_Pop (context
, _UVRSC_CORE
, mask
, _UVRSD_UINT32
)
184 if ((op
& 0xf0) == 0xb0)
186 /* op == 0xb0 already handled. */
189 op
= next_unwind_byte (uws
);
190 if (op
== 0 || ((op
& 0xf0) != 0))
193 /* Pop r0-r4 under mask. */
194 if (_Unwind_VRS_Pop (context
, _UVRSC_CORE
, op
, _UVRSD_UINT32
)
201 /* vsp = vsp + 0x204 + (uleb128 << 2). */
204 _Unwind_VRS_Get (context
, _UVRSC_CORE
, R_SP
, _UVRSD_UINT32
,
206 op
= next_unwind_byte (uws
);
210 reg
+= ((op
& 0x7f) << shift
);
212 op
= next_unwind_byte (uws
);
214 reg
+= ((op
& 0x7f) << shift
) + 0x204;
215 _Unwind_VRS_Set (context
, _UVRSC_CORE
, R_SP
, _UVRSD_UINT32
,
221 /* Pop VFP registers with fldmx. */
222 op
= next_unwind_byte (uws
);
223 op
= ((op
& 0xf0) << 12) | ((op
& 0xf) + 1);
224 if (_Unwind_VRS_Pop (context
, _UVRSC_VFP
, op
, _UVRSD_VFPX
)
229 if ((op
& 0xfc) == 0xb4) /* Obsolete FPA. */
232 /* op & 0xf8 == 0xb8. */
233 /* Pop VFP D[8]-D[8+nnn] with fldmx. */
234 op
= 0x80000 | ((op
& 7) + 1);
235 if (_Unwind_VRS_Pop (context
, _UVRSC_VFP
, op
, _UVRSD_VFPX
)
240 if ((op
& 0xf0) == 0xc0)
244 /* Pop iWMMXt D registers. */
245 op
= next_unwind_byte (uws
);
246 op
= ((op
& 0xf0) << 12) | ((op
& 0xf) + 1);
247 if (_Unwind_VRS_Pop (context
, _UVRSC_WMMXD
, op
, _UVRSD_UINT64
)
254 op
= next_unwind_byte (uws
);
255 if (op
== 0 || (op
& 0xf0) != 0)
258 /* Pop iWMMXt wCGR{3,2,1,0} under mask. */
259 if (_Unwind_VRS_Pop (context
, _UVRSC_WMMXC
, op
, _UVRSD_UINT32
)
264 if ((op
& 0xf8) == 0xc0)
266 /* Pop iWMMXt wR[10]-wR[10+nnn]. */
267 op
= 0xa0000 | ((op
& 0xf) + 1);
268 if (_Unwind_VRS_Pop (context
, _UVRSC_WMMXD
, op
, _UVRSD_UINT64
)
275 /* Pop VFPv3 registers D[16+ssss]-D[16+ssss+cccc] with vldm. */
276 op
= next_unwind_byte (uws
);
277 op
= (((op
& 0xf0) + 16) << 12) | ((op
& 0xf) + 1);
278 if (_Unwind_VRS_Pop (context
, _UVRSC_VFP
, op
, _UVRSD_DOUBLE
)
285 /* Pop VFP registers with fldmd. */
286 op
= next_unwind_byte (uws
);
287 op
= ((op
& 0xf0) << 12) | ((op
& 0xf) + 1);
288 if (_Unwind_VRS_Pop (context
, _UVRSC_VFP
, op
, _UVRSD_DOUBLE
)
296 if ((op
& 0xf8) == 0xd0)
298 /* Pop VFP D[8]-D[8+nnn] with fldmd. */
299 op
= 0x80000 | ((op
& 7) + 1);
300 if (_Unwind_VRS_Pop (context
, _UVRSC_VFP
, op
, _UVRSD_DOUBLE
)
312 /* Execute the unwinding instructions associated with a frame. UCBP and
313 CONTEXT are the current exception object and virtual CPU state
317 __gnu_unwind_frame (_Unwind_Control_Block
* ucbp
, _Unwind_Context
* context
)
320 __gnu_unwind_state uws
;
322 ptr
= (_uw
*) ucbp
->pr_cache
.ehtp
;
323 /* Skip over the personality routine address. */
325 /* Setup the unwinder state. */
326 uws
.data
= (*ptr
) << 8;
329 uws
.words_left
= ((*ptr
) >> 24) & 0xff;
331 return __gnu_unwind_execute (context
, &uws
);
334 /* Get the _Unwind_Control_Block from an _Unwind_Context. */
336 static inline _Unwind_Control_Block
*
337 unwind_UCB_from_context (_Unwind_Context
* context
)
339 return (_Unwind_Control_Block
*) _Unwind_GetGR (context
, R_IP
);
342 /* Get the start address of the function being unwound. */
345 _Unwind_GetRegionStart (_Unwind_Context
* context
)
347 _Unwind_Control_Block
*ucbp
;
349 ucbp
= unwind_UCB_from_context (context
);
350 return (_Unwind_Ptr
) ucbp
->pr_cache
.fnstart
;
353 /* Find the Language specific exception data. */
356 _Unwind_GetLanguageSpecificData (_Unwind_Context
* context
)
358 _Unwind_Control_Block
*ucbp
;
361 /* Get a pointer to the exception table entry. */
362 ucbp
= unwind_UCB_from_context (context
);
363 ptr
= (_uw
*) ucbp
->pr_cache
.ehtp
;
364 /* Skip the personality routine address. */
366 /* Skip the unwind opcodes. */
367 ptr
+= (((*ptr
) >> 24) & 0xff) + 1;
373 /* These two should never be used. */
376 _Unwind_GetDataRelBase (_Unwind_Context
*context
__attribute__ ((unused
)))
382 _Unwind_GetTextRelBase (_Unwind_Context
*context
__attribute__ ((unused
)))