]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/config/arm/pr-support.c
Makefile.in (UNWIND_H): Remove.
[thirdparty/gcc.git] / libgcc / config / arm / pr-support.c
CommitLineData
2a75c0b6 1/* ARM EABI compliant unwinding routines
748086b7 2 Copyright (C) 2004, 2005, 2009 Free Software Foundation, Inc.
2a75c0b6
PB
3 Contributed by Paul Brook
4
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
748086b7 7 Free Software Foundation; either version 3, or (at your option) any
2a75c0b6
PB
8 later version.
9
2a75c0b6
PB
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.
14
748086b7
JJ
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.
18
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/>. */
23
2a75c0b6
PB
24#include "unwind.h"
25
74d9c39f
DJ
26/* We add a prototype for abort here to avoid creating a dependency on
27 target headers. */
28extern void abort (void);
29
2a75c0b6
PB
30typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
31
32/* Misc constants. */
33#define R_IP 12
34#define R_SP 13
35#define R_LR 14
36#define R_PC 15
37
38#define uint32_highbit (((_uw) 1) << 31)
39
40void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
41
42/* Unwind descriptors. */
43
44typedef struct
45{
46 _uw16 length;
47 _uw16 offset;
48} EHT16;
49
50typedef struct
51{
52 _uw length;
53 _uw offset;
54} EHT32;
55
56/* Calculate the address encoded by a 31-bit self-relative offset at address
57 P. Copy of routine in unwind-arm.c. */
58
59static inline _uw
60selfrel_offset31 (const _uw *p)
61{
62 _uw offset;
63
64 offset = *p;
65 /* Sign extend to 32 bits. */
66 if (offset & (1 << 30))
67 offset |= 1u << 31;
68
69 return offset + (_uw) p;
70}
71
72
73/* Personality routine helper functions. */
74
75#define CODE_FINISH (0xb0)
76
77/* Return the next byte of unwinding information, or CODE_FINISH if there is
78 no data remaining. */
79static inline _uw8
80next_unwind_byte (__gnu_unwind_state * uws)
81{
82 _uw8 b;
83
84 if (uws->bytes_left == 0)
85 {
86 /* Load another word */
87 if (uws->words_left == 0)
88 return CODE_FINISH; /* Nothing left. */
89 uws->words_left--;
90 uws->data = *(uws->next++);
91 uws->bytes_left = 3;
92 }
93 else
94 uws->bytes_left--;
95
96 /* Extract the most significant byte. */
97 b = (uws->data >> 24) & 0xff;
98 uws->data <<= 8;
99 return b;
100}
101
102/* Execute the unwinding instructions described by UWS. */
103_Unwind_Reason_Code
104__gnu_unwind_execute (_Unwind_Context * context, __gnu_unwind_state * uws)
105{
106 _uw op;
107 int set_pc;
108 _uw reg;
109
110 set_pc = 0;
111 for (;;)
112 {
113 op = next_unwind_byte (uws);
114 if (op == CODE_FINISH)
115 {
116 /* If we haven't already set pc then copy it from lr. */
117 if (!set_pc)
118 {
119 _Unwind_VRS_Get (context, _UVRSC_CORE, R_LR, _UVRSD_UINT32,
120 &reg);
121 _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32,
122 &reg);
123 set_pc = 1;
124 }
125 /* Drop out of the loop. */
126 break;
127 }
128 if ((op & 0x80) == 0)
129 {
130 /* vsp = vsp +- (imm6 << 2 + 4). */
131 _uw offset;
132
133 offset = ((op & 0x3f) << 2) + 4;
134 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
135 if (op & 0x40)
136 reg -= offset;
137 else
138 reg += offset;
139 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
140 continue;
141 }
142
143 if ((op & 0xf0) == 0x80)
144 {
145 op = (op << 8) | next_unwind_byte (uws);
146 if (op == 0x8000)
147 {
148 /* Refuse to unwind. */
149 return _URC_FAILURE;
150 }
151 /* Pop r4-r15 under mask. */
152 op = (op << 4) & 0xfff0;
153 if (_Unwind_VRS_Pop (context, _UVRSC_CORE, op, _UVRSD_UINT32)
154 != _UVRSR_OK)
155 return _URC_FAILURE;
156 if (op & (1 << R_PC))
157 set_pc = 1;
158 continue;
159 }
160 if ((op & 0xf0) == 0x90)
161 {
162 op &= 0xf;
163 if (op == 13 || op == 15)
164 /* Reserved. */
165 return _URC_FAILURE;
166 /* vsp = r[nnnn]. */
167 _Unwind_VRS_Get (context, _UVRSC_CORE, op, _UVRSD_UINT32, &reg);
168 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
169 continue;
170 }
171 if ((op & 0xf0) == 0xa0)
172 {
173 /* Pop r4-r[4+nnn], [lr]. */
174 _uw mask;
175
176 mask = (0xff0 >> (7 - (op & 7))) & 0xff0;
177 if (op & 8)
178 mask |= (1 << R_LR);
179 if (_Unwind_VRS_Pop (context, _UVRSC_CORE, mask, _UVRSD_UINT32)
180 != _UVRSR_OK)
181 return _URC_FAILURE;
182 continue;
183 }
184 if ((op & 0xf0) == 0xb0)
185 {
186 /* op == 0xb0 already handled. */
187 if (op == 0xb1)
188 {
189 op = next_unwind_byte (uws);
190 if (op == 0 || ((op & 0xf0) != 0))
191 /* Spare. */
192 return _URC_FAILURE;
193 /* Pop r0-r4 under mask. */
194 if (_Unwind_VRS_Pop (context, _UVRSC_CORE, op, _UVRSD_UINT32)
195 != _UVRSR_OK)
196 return _URC_FAILURE;
197 continue;
198 }
199 if (op == 0xb2)
200 {
201 /* vsp = vsp + 0x204 + (uleb128 << 2). */
202 int shift;
203
204 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
205 &reg);
206 op = next_unwind_byte (uws);
207 shift = 2;
208 while (op & 0x80)
209 {
210 reg += ((op & 0x7f) << shift);
211 shift += 7;
212 op = next_unwind_byte (uws);
213 }
214 reg += ((op & 0x7f) << shift) + 0x204;
215 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
216 &reg);
217 continue;
218 }
219 if (op == 0xb3)
220 {
221 /* Pop VFP registers with fldmx. */
222 op = next_unwind_byte (uws);
08a557f6 223 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
2a75c0b6
PB
224 if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_VFPX)
225 != _UVRSR_OK)
226 return _URC_FAILURE;
227 continue;
228 }
229 if ((op & 0xfc) == 0xb4)
230 {
231 /* Pop FPA E[4]-E[4+nn]. */
232 op = 0x40000 | ((op & 3) + 1);
233 if (_Unwind_VRS_Pop (context, _UVRSC_FPA, op, _UVRSD_FPAX)
234 != _UVRSR_OK)
235 return _URC_FAILURE;
236 continue;
237 }
238 /* op & 0xf8 == 0xb8. */
239 /* Pop VFP D[8]-D[8+nnn] with fldmx. */
240 op = 0x80000 | ((op & 7) + 1);
241 if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_VFPX)
242 != _UVRSR_OK)
243 return _URC_FAILURE;
244 continue;
245 }
246 if ((op & 0xf0) == 0xc0)
247 {
248 if (op == 0xc6)
249 {
250 /* Pop iWMMXt D registers. */
251 op = next_unwind_byte (uws);
08a557f6 252 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
2a75c0b6
PB
253 if (_Unwind_VRS_Pop (context, _UVRSC_WMMXD, op, _UVRSD_UINT64)
254 != _UVRSR_OK)
255 return _URC_FAILURE;
256 continue;
257 }
258 if (op == 0xc7)
259 {
260 op = next_unwind_byte (uws);
261 if (op == 0 || (op & 0xf0) != 0)
262 /* Spare. */
263 return _URC_FAILURE;
264 /* Pop iWMMXt wCGR{3,2,1,0} under mask. */
265 if (_Unwind_VRS_Pop (context, _UVRSC_WMMXC, op, _UVRSD_UINT32)
266 != _UVRSR_OK)
267 return _URC_FAILURE;
268 continue;
269 }
270 if ((op & 0xf8) == 0xc0)
271 {
272 /* Pop iWMMXt wR[10]-wR[10+nnn]. */
273 op = 0xa0000 | ((op & 0xf) + 1);
274 if (_Unwind_VRS_Pop (context, _UVRSC_WMMXD, op, _UVRSD_UINT64)
275 != _UVRSR_OK)
276 return _URC_FAILURE;
277 continue;
278 }
279 if (op == 0xc8)
280 {
8edfc4cc
MS
281#ifndef __VFP_FP__
282 /* Pop FPA registers. */
283 op = next_unwind_byte (uws);
08a557f6 284 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
8edfc4cc
MS
285 if (_Unwind_VRS_Pop (context, _UVRSC_FPA, op, _UVRSD_FPAX)
286 != _UVRSR_OK)
287 return _URC_FAILURE;
288 continue;
289#else
290 /* Pop VFPv3 registers D[16+ssss]-D[16+ssss+cccc] with vldm. */
291 op = next_unwind_byte (uws);
292 op = (((op & 0xf0) + 16) << 12) | ((op & 0xf) + 1);
293 if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
294 != _UVRSR_OK)
295 return _URC_FAILURE;
296 continue;
297#endif
2a75c0b6
PB
298 }
299 if (op == 0xc9)
300 {
301 /* Pop VFP registers with fldmd. */
302 op = next_unwind_byte (uws);
08a557f6 303 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
2a75c0b6
PB
304 if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
305 != _UVRSR_OK)
306 return _URC_FAILURE;
307 continue;
308 }
309 /* Spare. */
310 return _URC_FAILURE;
311 }
312 if ((op & 0xf8) == 0xd0)
313 {
314 /* Pop VFP D[8]-D[8+nnn] with fldmd. */
315 op = 0x80000 | ((op & 7) + 1);
316 if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
317 != _UVRSR_OK)
318 return _URC_FAILURE;
319 continue;
320 }
321 /* Spare. */
322 return _URC_FAILURE;
323 }
324 return _URC_OK;
325}
326
327
328/* Execute the unwinding instructions associated with a frame. UCBP and
329 CONTEXT are the current exception object and virtual CPU state
330 respectively. */
331
332_Unwind_Reason_Code
333__gnu_unwind_frame (_Unwind_Control_Block * ucbp, _Unwind_Context * context)
334{
335 _uw *ptr;
336 __gnu_unwind_state uws;
337
338 ptr = (_uw *) ucbp->pr_cache.ehtp;
339 /* Skip over the personality routine address. */
340 ptr++;
341 /* Setup the unwinder state. */
342 uws.data = (*ptr) << 8;
343 uws.next = ptr + 1;
344 uws.bytes_left = 3;
345 uws.words_left = ((*ptr) >> 24) & 0xff;
346
347 return __gnu_unwind_execute (context, &uws);
348}
349
350/* Get the _Unwind_Control_Block from an _Unwind_Context. */
351
352static inline _Unwind_Control_Block *
353unwind_UCB_from_context (_Unwind_Context * context)
354{
355 return (_Unwind_Control_Block *) _Unwind_GetGR (context, R_IP);
356}
357
358/* Get the start address of the function being unwound. */
359
360_Unwind_Ptr
361_Unwind_GetRegionStart (_Unwind_Context * context)
362{
363 _Unwind_Control_Block *ucbp;
364
365 ucbp = unwind_UCB_from_context (context);
366 return (_Unwind_Ptr) ucbp->pr_cache.fnstart;
367}
368
369/* Find the Language specific exception data. */
370
371void *
372_Unwind_GetLanguageSpecificData (_Unwind_Context * context)
373{
374 _Unwind_Control_Block *ucbp;
375 _uw *ptr;
376
377 /* Get a pointer to the exception table entry. */
378 ucbp = unwind_UCB_from_context (context);
379 ptr = (_uw *) ucbp->pr_cache.ehtp;
380 /* Skip the personality routine address. */
381 ptr++;
382 /* Skip the unwind opcodes. */
383 ptr += (((*ptr) >> 24) & 0xff) + 1;
384
385 return ptr;
386}
387
66403286
PB
388
389/* These two should never be used. */
390
391_Unwind_Ptr
392_Unwind_GetDataRelBase (_Unwind_Context *context __attribute__ ((unused)))
393{
394 abort ();
395}
396
397_Unwind_Ptr
398_Unwind_GetTextRelBase (_Unwind_Context *context __attribute__ ((unused)))
399{
400 abort ();
401}