]> git.ipfire.org Git - thirdparty/gcc.git/blob - libgcc/config/arm/pr-support.c
Update copyright years.
[thirdparty/gcc.git] / libgcc / config / arm / pr-support.c
1 /* ARM EABI compliant unwinding routines
2 Copyright (C) 2004-2015 Free Software Foundation, Inc.
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
7 Free Software Foundation; either version 3, or (at your option) any
8 later version.
9
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
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
24 #include "unwind.h"
25
26 /* We add a prototype for abort here to avoid creating a dependency on
27 target headers. */
28 extern void abort (void);
29
30 typedef 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
40 void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
41
42 /* Unwind descriptors. */
43
44 typedef struct
45 {
46 _uw16 length;
47 _uw16 offset;
48 } EHT16;
49
50 typedef 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
59 static inline _uw
60 selfrel_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. */
79 static inline _uw8
80 next_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);
223 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
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) /* Obsolete FPA. */
230 return _URC_FAILURE;
231
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)
236 != _UVRSR_OK)
237 return _URC_FAILURE;
238 continue;
239 }
240 if ((op & 0xf0) == 0xc0)
241 {
242 if (op == 0xc6)
243 {
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)
248 != _UVRSR_OK)
249 return _URC_FAILURE;
250 continue;
251 }
252 if (op == 0xc7)
253 {
254 op = next_unwind_byte (uws);
255 if (op == 0 || (op & 0xf0) != 0)
256 /* Spare. */
257 return _URC_FAILURE;
258 /* Pop iWMMXt wCGR{3,2,1,0} under mask. */
259 if (_Unwind_VRS_Pop (context, _UVRSC_WMMXC, op, _UVRSD_UINT32)
260 != _UVRSR_OK)
261 return _URC_FAILURE;
262 continue;
263 }
264 if ((op & 0xf8) == 0xc0)
265 {
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)
269 != _UVRSR_OK)
270 return _URC_FAILURE;
271 continue;
272 }
273 if (op == 0xc8)
274 {
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)
279 != _UVRSR_OK)
280 return _URC_FAILURE;
281 continue;
282 }
283 if (op == 0xc9)
284 {
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)
289 != _UVRSR_OK)
290 return _URC_FAILURE;
291 continue;
292 }
293 /* Spare. */
294 return _URC_FAILURE;
295 }
296 if ((op & 0xf8) == 0xd0)
297 {
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)
301 != _UVRSR_OK)
302 return _URC_FAILURE;
303 continue;
304 }
305 /* Spare. */
306 return _URC_FAILURE;
307 }
308 return _URC_OK;
309 }
310
311
312 /* Execute the unwinding instructions associated with a frame. UCBP and
313 CONTEXT are the current exception object and virtual CPU state
314 respectively. */
315
316 _Unwind_Reason_Code
317 __gnu_unwind_frame (_Unwind_Control_Block * ucbp, _Unwind_Context * context)
318 {
319 _uw *ptr;
320 __gnu_unwind_state uws;
321
322 ptr = (_uw *) ucbp->pr_cache.ehtp;
323 /* Skip over the personality routine address. */
324 ptr++;
325 /* Setup the unwinder state. */
326 uws.data = (*ptr) << 8;
327 uws.next = ptr + 1;
328 uws.bytes_left = 3;
329 uws.words_left = ((*ptr) >> 24) & 0xff;
330
331 return __gnu_unwind_execute (context, &uws);
332 }
333
334 /* Get the _Unwind_Control_Block from an _Unwind_Context. */
335
336 static inline _Unwind_Control_Block *
337 unwind_UCB_from_context (_Unwind_Context * context)
338 {
339 return (_Unwind_Control_Block *) _Unwind_GetGR (context, R_IP);
340 }
341
342 /* Get the start address of the function being unwound. */
343
344 _Unwind_Ptr
345 _Unwind_GetRegionStart (_Unwind_Context * context)
346 {
347 _Unwind_Control_Block *ucbp;
348
349 ucbp = unwind_UCB_from_context (context);
350 return (_Unwind_Ptr) ucbp->pr_cache.fnstart;
351 }
352
353 /* Find the Language specific exception data. */
354
355 void *
356 _Unwind_GetLanguageSpecificData (_Unwind_Context * context)
357 {
358 _Unwind_Control_Block *ucbp;
359 _uw *ptr;
360
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. */
365 ptr++;
366 /* Skip the unwind opcodes. */
367 ptr += (((*ptr) >> 24) & 0xff) + 1;
368
369 return ptr;
370 }
371
372
373 /* These two should never be used. */
374
375 _Unwind_Ptr
376 _Unwind_GetDataRelBase (_Unwind_Context *context __attribute__ ((unused)))
377 {
378 abort ();
379 }
380
381 _Unwind_Ptr
382 _Unwind_GetTextRelBase (_Unwind_Context *context __attribute__ ((unused)))
383 {
384 abort ();
385 }