2006-03-15 Paul Brook <paul@codesourcery.com>
[official-gcc.git] / gcc / config / arm / pr-support.c
blob072b4a98d5cd474d974d9527504ebf5085be32ae
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
8 later version.
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
17 executable.)
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. */
28 #include "unwind.h"
30 /* We add a prototype for abort here to avoid creating a dependency on
31 target headers. */
32 extern void abort (void);
34 typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
36 /* Misc constants. */
37 #define R_IP 12
38 #define R_SP 13
39 #define R_LR 14
40 #define R_PC 15
42 #define uint32_highbit (((_uw) 1) << 31)
44 void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
46 /* Unwind descriptors. */
48 typedef struct
50 _uw16 length;
51 _uw16 offset;
52 } EHT16;
54 typedef struct
56 _uw length;
57 _uw offset;
58 } EHT32;
60 /* Calculate the address encoded by a 31-bit self-relative offset at address
61 P. Copy of routine in unwind-arm.c. */
63 static inline _uw
64 selfrel_offset31 (const _uw *p)
66 _uw offset;
68 offset = *p;
69 /* Sign extend to 32 bits. */
70 if (offset & (1 << 30))
71 offset |= 1u << 31;
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
82 no data remaining. */
83 static inline _uw8
84 next_unwind_byte (__gnu_unwind_state * uws)
86 _uw8 b;
88 if (uws->bytes_left == 0)
90 /* Load another word */
91 if (uws->words_left == 0)
92 return CODE_FINISH; /* Nothing left. */
93 uws->words_left--;
94 uws->data = *(uws->next++);
95 uws->bytes_left = 3;
97 else
98 uws->bytes_left--;
100 /* Extract the most significant byte. */
101 b = (uws->data >> 24) & 0xff;
102 uws->data <<= 8;
103 return b;
106 /* Execute the unwinding instructions described by UWS. */
107 _Unwind_Reason_Code
108 __gnu_unwind_execute (_Unwind_Context * context, __gnu_unwind_state * uws)
110 _uw op;
111 int set_pc;
112 _uw reg;
114 set_pc = 0;
115 for (;;)
117 op = next_unwind_byte (uws);
118 if (op == CODE_FINISH)
120 /* If we haven't already set pc then copy it from lr. */
121 if (!set_pc)
123 _Unwind_VRS_Get (context, _UVRSC_CORE, R_LR, _UVRSD_UINT32,
124 &reg);
125 _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32,
126 &reg);
127 set_pc = 1;
129 /* Drop out of the loop. */
130 break;
132 if ((op & 0x80) == 0)
134 /* vsp = vsp +- (imm6 << 2 + 4). */
135 _uw offset;
137 offset = ((op & 0x3f) << 2) + 4;
138 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
139 if (op & 0x40)
140 reg -= offset;
141 else
142 reg += offset;
143 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
144 continue;
147 if ((op & 0xf0) == 0x80)
149 op = (op << 8) | next_unwind_byte (uws);
150 if (op == 0x8000)
152 /* Refuse to unwind. */
153 return _URC_FAILURE;
155 /* Pop r4-r15 under mask. */
156 op = (op << 4) & 0xfff0;
157 if (_Unwind_VRS_Pop (context, _UVRSC_CORE, op, _UVRSD_UINT32)
158 != _UVRSR_OK)
159 return _URC_FAILURE;
160 if (op & (1 << R_PC))
161 set_pc = 1;
162 continue;
164 if ((op & 0xf0) == 0x90)
166 op &= 0xf;
167 if (op == 13 || op == 15)
168 /* Reserved. */
169 return _URC_FAILURE;
170 /* vsp = r[nnnn]. */
171 _Unwind_VRS_Get (context, _UVRSC_CORE, op, _UVRSD_UINT32, &reg);
172 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
173 continue;
175 if ((op & 0xf0) == 0xa0)
177 /* Pop r4-r[4+nnn], [lr]. */
178 _uw mask;
180 mask = (0xff0 >> (7 - (op & 7))) & 0xff0;
181 if (op & 8)
182 mask |= (1 << R_LR);
183 if (_Unwind_VRS_Pop (context, _UVRSC_CORE, mask, _UVRSD_UINT32)
184 != _UVRSR_OK)
185 return _URC_FAILURE;
186 continue;
188 if ((op & 0xf0) == 0xb0)
190 /* op == 0xb0 already handled. */
191 if (op == 0xb1)
193 op = next_unwind_byte (uws);
194 if (op == 0 || ((op & 0xf0) != 0))
195 /* Spare. */
196 return _URC_FAILURE;
197 /* Pop r0-r4 under mask. */
198 if (_Unwind_VRS_Pop (context, _UVRSC_CORE, op, _UVRSD_UINT32)
199 != _UVRSR_OK)
200 return _URC_FAILURE;
201 continue;
203 if (op == 0xb2)
205 /* vsp = vsp + 0x204 + (uleb128 << 2). */
206 int shift;
208 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
209 &reg);
210 op = next_unwind_byte (uws);
211 shift = 2;
212 while (op & 0x80)
214 reg += ((op & 0x7f) << shift);
215 shift += 7;
216 op = next_unwind_byte (uws);
218 reg += ((op & 0x7f) << shift) + 0x204;
219 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
220 &reg);
221 continue;
223 if (op == 0xb3)
225 /* Pop VFP registers with fldmx. */
226 op = next_unwind_byte (uws);
227 op = ((op & 0xf0) << 12) | (op & 0xf);
228 if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_VFPX)
229 != _UVRSR_OK)
230 return _URC_FAILURE;
231 continue;
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)
238 != _UVRSR_OK)
239 return _URC_FAILURE;
240 continue;
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)
246 != _UVRSR_OK)
247 return _URC_FAILURE;
248 continue;
250 if ((op & 0xf0) == 0xc0)
252 if (op == 0xc6)
254 /* Pop iWMMXt D registers. */
255 op = next_unwind_byte (uws);
256 op = ((op & 0xf0) << 12) | (op & 0xf);
257 if (_Unwind_VRS_Pop (context, _UVRSC_WMMXD, op, _UVRSD_UINT64)
258 != _UVRSR_OK)
259 return _URC_FAILURE;
260 continue;
262 if (op == 0xc7)
264 op = next_unwind_byte (uws);
265 if (op == 0 || (op & 0xf0) != 0)
266 /* Spare. */
267 return _URC_FAILURE;
268 /* Pop iWMMXt wCGR{3,2,1,0} under mask. */
269 if (_Unwind_VRS_Pop (context, _UVRSC_WMMXC, op, _UVRSD_UINT32)
270 != _UVRSR_OK)
271 return _URC_FAILURE;
272 continue;
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)
279 != _UVRSR_OK)
280 return _URC_FAILURE;
281 continue;
283 if (op == 0xc8)
285 /* Pop FPA registers. */
286 op = next_unwind_byte (uws);
287 op = ((op & 0xf0) << 12) | (op & 0xf);
288 if (_Unwind_VRS_Pop (context, _UVRSC_FPA, op, _UVRSD_FPAX)
289 != _UVRSR_OK)
290 return _URC_FAILURE;
291 continue;
293 if (op == 0xc9)
295 /* Pop VFP registers with fldmd. */
296 op = next_unwind_byte (uws);
297 op = ((op & 0xf0) << 12) | (op & 0xf);
298 if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
299 != _UVRSR_OK)
300 return _URC_FAILURE;
301 continue;
303 /* Spare. */
304 return _URC_FAILURE;
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)
311 != _UVRSR_OK)
312 return _URC_FAILURE;
313 continue;
315 /* Spare. */
316 return _URC_FAILURE;
318 return _URC_OK;
322 /* Execute the unwinding instructions associated with a frame. UCBP and
323 CONTEXT are the current exception object and virtual CPU state
324 respectively. */
326 _Unwind_Reason_Code
327 __gnu_unwind_frame (_Unwind_Control_Block * ucbp, _Unwind_Context * context)
329 _uw *ptr;
330 __gnu_unwind_state uws;
332 ptr = (_uw *) ucbp->pr_cache.ehtp;
333 /* Skip over the personality routine address. */
334 ptr++;
335 /* Setup the unwinder state. */
336 uws.data = (*ptr) << 8;
337 uws.next = ptr + 1;
338 uws.bytes_left = 3;
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. */
354 _Unwind_Ptr
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. */
365 void *
366 _Unwind_GetLanguageSpecificData (_Unwind_Context * context)
368 _Unwind_Control_Block *ucbp;
369 _uw *ptr;
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. */
375 ptr++;
376 /* Skip the unwind opcodes. */
377 ptr += (((*ptr) >> 24) & 0xff) + 1;
379 return ptr;