]>
Commit | Line | Data |
---|---|---|
7590af71 | 1 | /* ARM EABI compliant unwinding routines |
fbd26352 | 2 | Copyright (C) 2004-2019 Free Software Foundation, Inc. |
7590af71 | 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 | |
6bc9506f | 7 | Free Software Foundation; either version 3, or (at your option) any |
7590af71 | 8 | later version. |
9 | ||
7590af71 | 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 | ||
6bc9506f | 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 | ||
7590af71 | 24 | #include "unwind.h" |
25 | ||
363d487e | 26 | /* We add a prototype for abort here to avoid creating a dependency on |
27 | target headers. */ | |
28 | extern void abort (void); | |
29 | ||
7590af71 | 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 | ®); | |
121 | _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, | |
122 | ®); | |
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, ®); | |
135 | if (op & 0x40) | |
136 | reg -= offset; | |
137 | else | |
138 | reg += offset; | |
139 | _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®); | |
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, ®); | |
168 | _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®); | |
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 | ®); | |
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 | ®); | |
217 | continue; | |
218 | } | |
219 | if (op == 0xb3) | |
220 | { | |
221 | /* Pop VFP registers with fldmx. */ | |
222 | op = next_unwind_byte (uws); | |
41c5a437 | 223 | op = ((op & 0xf0) << 12) | ((op & 0xf) + 1); |
7590af71 | 224 | if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_VFPX) |
225 | != _UVRSR_OK) | |
226 | return _URC_FAILURE; | |
227 | continue; | |
228 | } | |
6a11e52b | 229 | if ((op & 0xfc) == 0xb4) /* Obsolete FPA. */ |
230 | return _URC_FAILURE; | |
231 | ||
7590af71 | 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); | |
41c5a437 | 246 | op = ((op & 0xf0) << 12) | ((op & 0xf) + 1); |
7590af71 | 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 | { | |
382a2a57 | 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; | |
7590af71 | 282 | } |
283 | if (op == 0xc9) | |
284 | { | |
285 | /* Pop VFP registers with fldmd. */ | |
286 | op = next_unwind_byte (uws); | |
41c5a437 | 287 | op = ((op & 0xf0) << 12) | ((op & 0xf) + 1); |
7590af71 | 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 | ||
df5e9c68 | 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 | } |