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