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
)
285 /* Pop FPA registers. */
286 op
= next_unwind_byte (uws
);
287 op
= ((op
& 0xf0) << 12) | ((op
& 0xf) + 1);
288 if (_Unwind_VRS_Pop (context
, _UVRSC_FPA
, op
, _UVRSD_FPAX
)
295 /* Pop VFP registers with fldmd. */
296 op
= next_unwind_byte (uws
);
297 op
= ((op
& 0xf0) << 12) | ((op
& 0xf) + 1);
298 if (_Unwind_VRS_Pop (context
, _UVRSC_VFP
, op
, _UVRSD_DOUBLE
)
306 if ((op
& 0xf8) == 0xd0)
308 /* Pop VFP D[8]-D[8+nnn] with fldmd. */
309 op
= 0x80000 | ((op
& 7) + 1);
310 if (_Unwind_VRS_Pop (context
, _UVRSC_VFP
, op
, _UVRSD_DOUBLE
)
322 /* Execute the unwinding instructions associated with a frame. UCBP and
323 CONTEXT are the current exception object and virtual CPU state
327 __gnu_unwind_frame (_Unwind_Control_Block
* ucbp
, _Unwind_Context
* context
)
330 __gnu_unwind_state uws
;
332 ptr
= (_uw
*) ucbp
->pr_cache
.ehtp
;
333 /* Skip over the personality routine address. */
335 /* Setup the unwinder state. */
336 uws
.data
= (*ptr
) << 8;
339 uws
.words_left
= ((*ptr
) >> 24) & 0xff;
341 return __gnu_unwind_execute (context
, &uws
);
344 /* Get the _Unwind_Control_Block from an _Unwind_Context. */
346 static inline _Unwind_Control_Block
*
347 unwind_UCB_from_context (_Unwind_Context
* context
)
349 return (_Unwind_Control_Block
*) _Unwind_GetGR (context
, R_IP
);
352 /* Get the start address of the function being unwound. */
355 _Unwind_GetRegionStart (_Unwind_Context
* context
)
357 _Unwind_Control_Block
*ucbp
;
359 ucbp
= unwind_UCB_from_context (context
);
360 return (_Unwind_Ptr
) ucbp
->pr_cache
.fnstart
;
363 /* Find the Language specific exception data. */
366 _Unwind_GetLanguageSpecificData (_Unwind_Context
* context
)
368 _Unwind_Control_Block
*ucbp
;
371 /* Get a pointer to the exception table entry. */
372 ucbp
= unwind_UCB_from_context (context
);
373 ptr
= (_uw
*) ucbp
->pr_cache
.ehtp
;
374 /* Skip the personality routine address. */
376 /* Skip the unwind opcodes. */
377 ptr
+= (((*ptr
) >> 24) & 0xff) + 1;