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