1 /* ARM EABI compliant unwinding routines
2 Copyright (C) 2004, 2005 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 2, or (at your option) any
10 In addition to the permissions in the GNU General Public License, the
11 Free Software Foundation gives you unlimited permission to link the
12 compiled version of this file into combinations with other programs,
13 and to distribute those combinations without any restriction coming
14 from the use of this file. (The General Public License restrictions
15 do apply in other respects; for example, they cover modification of
16 the file, and distribution when not linked into a combine
19 This file is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program; see the file COPYING. If not, write to
26 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
27 Boston, MA 02110-1301, USA. */
30 /* We add a prototype for abort here to avoid creating a dependency on
32 extern void abort (void);
34 typedef struct _ZSt9type_info type_info
; /* This names C++ type_info type */
42 #define uint32_highbit (((_uw) 1) << 31)
44 void __attribute__((weak
)) __cxa_call_unexpected(_Unwind_Control_Block
*ucbp
);
46 /* Unwind descriptors. */
60 /* Calculate the address encoded by a 31-bit self-relative offset at address
61 P. Copy of routine in unwind-arm.c. */
64 selfrel_offset31 (const _uw
*p
)
69 /* Sign extend to 32 bits. */
70 if (offset
& (1 << 30))
73 return offset
+ (_uw
) p
;
77 /* Personality routine helper functions. */
79 #define CODE_FINISH (0xb0)
81 /* Return the next byte of unwinding information, or CODE_FINISH if there is
84 next_unwind_byte (__gnu_unwind_state
* uws
)
88 if (uws
->bytes_left
== 0)
90 /* Load another word */
91 if (uws
->words_left
== 0)
92 return CODE_FINISH
; /* Nothing left. */
94 uws
->data
= *(uws
->next
++);
100 /* Extract the most significant byte. */
101 b
= (uws
->data
>> 24) & 0xff;
106 /* Execute the unwinding instructions described by UWS. */
108 __gnu_unwind_execute (_Unwind_Context
* context
, __gnu_unwind_state
* uws
)
117 op
= next_unwind_byte (uws
);
118 if (op
== CODE_FINISH
)
120 /* If we haven't already set pc then copy it from lr. */
123 _Unwind_VRS_Get (context
, _UVRSC_CORE
, R_LR
, _UVRSD_UINT32
,
125 _Unwind_VRS_Set (context
, _UVRSC_CORE
, R_PC
, _UVRSD_UINT32
,
129 /* Drop out of the loop. */
132 if ((op
& 0x80) == 0)
134 /* vsp = vsp +- (imm6 << 2 + 4). */
137 offset
= ((op
& 0x3f) << 2) + 4;
138 _Unwind_VRS_Get (context
, _UVRSC_CORE
, R_SP
, _UVRSD_UINT32
, ®
);
143 _Unwind_VRS_Set (context
, _UVRSC_CORE
, R_SP
, _UVRSD_UINT32
, ®
);
147 if ((op
& 0xf0) == 0x80)
149 op
= (op
<< 8) | next_unwind_byte (uws
);
152 /* Refuse to unwind. */
155 /* Pop r4-r15 under mask. */
156 op
= (op
<< 4) & 0xfff0;
157 if (_Unwind_VRS_Pop (context
, _UVRSC_CORE
, op
, _UVRSD_UINT32
)
160 if (op
& (1 << R_PC
))
164 if ((op
& 0xf0) == 0x90)
167 if (op
== 13 || op
== 15)
171 _Unwind_VRS_Get (context
, _UVRSC_CORE
, op
, _UVRSD_UINT32
, ®
);
172 _Unwind_VRS_Set (context
, _UVRSC_CORE
, R_SP
, _UVRSD_UINT32
, ®
);
175 if ((op
& 0xf0) == 0xa0)
177 /* Pop r4-r[4+nnn], [lr]. */
180 mask
= (0xff0 >> (7 - (op
& 7))) & 0xff0;
183 if (_Unwind_VRS_Pop (context
, _UVRSC_CORE
, mask
, _UVRSD_UINT32
)
188 if ((op
& 0xf0) == 0xb0)
190 /* op == 0xb0 already handled. */
193 op
= next_unwind_byte (uws
);
194 if (op
== 0 || ((op
& 0xf0) != 0))
197 /* Pop r0-r4 under mask. */
198 if (_Unwind_VRS_Pop (context
, _UVRSC_CORE
, op
, _UVRSD_UINT32
)
205 /* vsp = vsp + 0x204 + (uleb128 << 2). */
208 _Unwind_VRS_Get (context
, _UVRSC_CORE
, R_SP
, _UVRSD_UINT32
,
210 op
= next_unwind_byte (uws
);
214 reg
+= ((op
& 0x7f) << shift
);
216 op
= next_unwind_byte (uws
);
218 reg
+= ((op
& 0x7f) << shift
) + 0x204;
219 _Unwind_VRS_Set (context
, _UVRSC_CORE
, R_SP
, _UVRSD_UINT32
,
225 /* Pop VFP registers with fldmx. */
226 op
= next_unwind_byte (uws
);
227 op
= ((op
& 0xf0) << 12) | ((op
& 0xf) + 1);
228 if (_Unwind_VRS_Pop (context
, _UVRSC_VFP
, op
, _UVRSD_VFPX
)
233 if ((op
& 0xfc) == 0xb4)
235 /* Pop FPA E[4]-E[4+nn]. */
236 op
= 0x40000 | ((op
& 3) + 1);
237 if (_Unwind_VRS_Pop (context
, _UVRSC_FPA
, op
, _UVRSD_FPAX
)
242 /* op & 0xf8 == 0xb8. */
243 /* Pop VFP D[8]-D[8+nnn] with fldmx. */
244 op
= 0x80000 | ((op
& 7) + 1);
245 if (_Unwind_VRS_Pop (context
, _UVRSC_VFP
, op
, _UVRSD_VFPX
)
250 if ((op
& 0xf0) == 0xc0)
254 /* Pop iWMMXt D registers. */
255 op
= next_unwind_byte (uws
);
256 op
= ((op
& 0xf0) << 12) | ((op
& 0xf) + 1);
257 if (_Unwind_VRS_Pop (context
, _UVRSC_WMMXD
, op
, _UVRSD_UINT64
)
264 op
= next_unwind_byte (uws
);
265 if (op
== 0 || (op
& 0xf0) != 0)
268 /* Pop iWMMXt wCGR{3,2,1,0} under mask. */
269 if (_Unwind_VRS_Pop (context
, _UVRSC_WMMXC
, op
, _UVRSD_UINT32
)
274 if ((op
& 0xf8) == 0xc0)
276 /* Pop iWMMXt wR[10]-wR[10+nnn]. */
277 op
= 0xa0000 | ((op
& 0xf) + 1);
278 if (_Unwind_VRS_Pop (context
, _UVRSC_WMMXD
, op
, _UVRSD_UINT64
)
286 /* Pop FPA registers. */
287 op
= next_unwind_byte (uws
);
288 op
= ((op
& 0xf0) << 12) | ((op
& 0xf) + 1);
289 if (_Unwind_VRS_Pop (context
, _UVRSC_FPA
, op
, _UVRSD_FPAX
)
294 /* Pop VFPv3 registers D[16+ssss]-D[16+ssss+cccc] with vldm. */
295 op
= next_unwind_byte (uws
);
296 op
= (((op
& 0xf0) + 16) << 12) | ((op
& 0xf) + 1);
297 if (_Unwind_VRS_Pop (context
, _UVRSC_VFP
, op
, _UVRSD_DOUBLE
)
305 /* Pop VFP registers with fldmd. */
306 op
= next_unwind_byte (uws
);
307 op
= ((op
& 0xf0) << 12) | ((op
& 0xf) + 1);
308 if (_Unwind_VRS_Pop (context
, _UVRSC_VFP
, op
, _UVRSD_DOUBLE
)
316 if ((op
& 0xf8) == 0xd0)
318 /* Pop VFP D[8]-D[8+nnn] with fldmd. */
319 op
= 0x80000 | ((op
& 7) + 1);
320 if (_Unwind_VRS_Pop (context
, _UVRSC_VFP
, op
, _UVRSD_DOUBLE
)
332 /* Execute the unwinding instructions associated with a frame. UCBP and
333 CONTEXT are the current exception object and virtual CPU state
337 __gnu_unwind_frame (_Unwind_Control_Block
* ucbp
, _Unwind_Context
* context
)
340 __gnu_unwind_state uws
;
342 ptr
= (_uw
*) ucbp
->pr_cache
.ehtp
;
343 /* Skip over the personality routine address. */
345 /* Setup the unwinder state. */
346 uws
.data
= (*ptr
) << 8;
349 uws
.words_left
= ((*ptr
) >> 24) & 0xff;
351 return __gnu_unwind_execute (context
, &uws
);
354 /* Get the _Unwind_Control_Block from an _Unwind_Context. */
356 static inline _Unwind_Control_Block
*
357 unwind_UCB_from_context (_Unwind_Context
* context
)
359 return (_Unwind_Control_Block
*) _Unwind_GetGR (context
, R_IP
);
362 /* Get the start address of the function being unwound. */
365 _Unwind_GetRegionStart (_Unwind_Context
* context
)
367 _Unwind_Control_Block
*ucbp
;
369 ucbp
= unwind_UCB_from_context (context
);
370 return (_Unwind_Ptr
) ucbp
->pr_cache
.fnstart
;
373 /* Find the Language specific exception data. */
376 _Unwind_GetLanguageSpecificData (_Unwind_Context
* context
)
378 _Unwind_Control_Block
*ucbp
;
381 /* Get a pointer to the exception table entry. */
382 ucbp
= unwind_UCB_from_context (context
);
383 ptr
= (_uw
*) ucbp
->pr_cache
.ehtp
;
384 /* Skip the personality routine address. */
386 /* Skip the unwind opcodes. */
387 ptr
+= (((*ptr
) >> 24) & 0xff) + 1;
393 /* These two should never be used. */
396 _Unwind_GetDataRelBase (_Unwind_Context
*context
__attribute__ ((unused
)))
402 _Unwind_GetTextRelBase (_Unwind_Context
*context
__attribute__ ((unused
)))