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 			       &reg);
122af526226Smrg 	      _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32,
123af526226Smrg 			       &reg);
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, &reg);
136af526226Smrg 	  if (op & 0x40)
137af526226Smrg 	    reg -= offset;
138af526226Smrg 	  else
139af526226Smrg 	    reg += offset;
140af526226Smrg 	  _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
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, &reg);
169af526226Smrg 	  _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
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 			       &reg);
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 			       &reg);
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