1/* ARM EABI compliant unwinding routines
2   Copyright (C) 2004, 2005, 2009 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.  */
28extern void abort (void);
29
30typedef 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
40void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
41
42/* Unwind descriptors.  */
43
44typedef struct
45{
46  _uw16 length;
47  _uw16 offset;
48} EHT16;
49
50typedef 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
59static inline _uw
60selfrel_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.  */
79static inline _uw8
80next_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)
230	    {
231	      /* Pop FPA E[4]-E[4+nn].  */
232	      op = 0x40000 | ((op & 3) + 1);
233	      if (_Unwind_VRS_Pop (context, _UVRSC_FPA, op, _UVRSD_FPAX)
234		  != _UVRSR_OK)
235		return _URC_FAILURE;
236	      continue;
237	    }
238	  /* op & 0xf8 == 0xb8.  */
239	  /* Pop VFP D[8]-D[8+nnn] with fldmx.  */
240	  op = 0x80000 | ((op & 7) + 1);
241	  if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_VFPX)
242	      != _UVRSR_OK)
243	    return _URC_FAILURE;
244	  continue;
245	}
246      if ((op & 0xf0) == 0xc0)
247	{
248	  if (op == 0xc6)
249	    {
250	      /* Pop iWMMXt D registers.  */
251	      op = next_unwind_byte (uws);
252	      op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
253	      if (_Unwind_VRS_Pop (context, _UVRSC_WMMXD, op, _UVRSD_UINT64)
254		  != _UVRSR_OK)
255		return _URC_FAILURE;
256	      continue;
257	    }
258	  if (op == 0xc7)
259	    {
260	      op = next_unwind_byte (uws);
261	      if (op == 0 || (op & 0xf0) != 0)
262		/* Spare.  */
263		return _URC_FAILURE;
264	      /* Pop iWMMXt wCGR{3,2,1,0} under mask.  */
265	      if (_Unwind_VRS_Pop (context, _UVRSC_WMMXC, op, _UVRSD_UINT32)
266		  != _UVRSR_OK)
267		return _URC_FAILURE;
268	      continue;
269	    }
270	  if ((op & 0xf8) == 0xc0)
271	    {
272	      /* Pop iWMMXt wR[10]-wR[10+nnn].  */
273	      op = 0xa0000 | ((op & 0xf) + 1);
274	      if (_Unwind_VRS_Pop (context, _UVRSC_WMMXD, op, _UVRSD_UINT64)
275		  != _UVRSR_OK)
276		return _URC_FAILURE;
277	      continue;
278	    }
279	  if (op == 0xc8)
280	    {
281#ifndef __VFP_FP__
282 	      /* Pop FPA registers.  */
283 	      op = next_unwind_byte (uws);
284	      op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
285 	      if (_Unwind_VRS_Pop (context, _UVRSC_FPA, op, _UVRSD_FPAX)
286 		  != _UVRSR_OK)
287 		return _URC_FAILURE;
288 	      continue;
289#else
290              /* Pop VFPv3 registers D[16+ssss]-D[16+ssss+cccc] with vldm.  */
291              op = next_unwind_byte (uws);
292              op = (((op & 0xf0) + 16) << 12) | ((op & 0xf) + 1);
293              if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
294                  != _UVRSR_OK)
295                return _URC_FAILURE;
296              continue;
297#endif
298	    }
299	  if (op == 0xc9)
300	    {
301	      /* Pop VFP registers with fldmd.  */
302	      op = next_unwind_byte (uws);
303	      op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
304	      if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
305		  != _UVRSR_OK)
306		return _URC_FAILURE;
307	      continue;
308	    }
309	  /* Spare.  */
310	  return _URC_FAILURE;
311	}
312      if ((op & 0xf8) == 0xd0)
313	{
314	  /* Pop VFP D[8]-D[8+nnn] with fldmd.  */
315	  op = 0x80000 | ((op & 7) + 1);
316	  if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
317	      != _UVRSR_OK)
318	    return _URC_FAILURE;
319	  continue;
320	}
321      /* Spare.  */
322      return _URC_FAILURE;
323    }
324  return _URC_OK;
325}
326
327
328/* Execute the unwinding instructions associated with a frame.  UCBP and
329   CONTEXT are the current exception object and virtual CPU state
330   respectively.  */
331
332_Unwind_Reason_Code
333__gnu_unwind_frame (_Unwind_Control_Block * ucbp, _Unwind_Context * context)
334{
335  _uw *ptr;
336  __gnu_unwind_state uws;
337
338  ptr = (_uw *) ucbp->pr_cache.ehtp;
339  /* Skip over the personality routine address.  */
340  ptr++;
341  /* Setup the unwinder state.  */
342  uws.data = (*ptr) << 8;
343  uws.next = ptr + 1;
344  uws.bytes_left = 3;
345  uws.words_left = ((*ptr) >> 24) & 0xff;
346
347  return __gnu_unwind_execute (context, &uws);
348}
349
350/* Get the _Unwind_Control_Block from an _Unwind_Context.  */
351
352static inline _Unwind_Control_Block *
353unwind_UCB_from_context (_Unwind_Context * context)
354{
355  return (_Unwind_Control_Block *) _Unwind_GetGR (context, R_IP);
356}
357
358/* Get the start address of the function being unwound.  */
359
360_Unwind_Ptr
361_Unwind_GetRegionStart (_Unwind_Context * context)
362{
363  _Unwind_Control_Block *ucbp;
364
365  ucbp = unwind_UCB_from_context (context);
366  return (_Unwind_Ptr) ucbp->pr_cache.fnstart;
367}
368
369/* Find the Language specific exception data.  */
370
371void *
372_Unwind_GetLanguageSpecificData (_Unwind_Context * context)
373{
374  _Unwind_Control_Block *ucbp;
375  _uw *ptr;
376
377  /* Get a pointer to the exception table entry.  */
378  ucbp = unwind_UCB_from_context (context);
379  ptr = (_uw *) ucbp->pr_cache.ehtp;
380  /* Skip the personality routine address.  */
381  ptr++;
382  /* Skip the unwind opcodes.  */
383  ptr += (((*ptr) >> 24) & 0xff) + 1;
384
385  return ptr;
386}
387
388
389/* These two should never be used.  */
390
391_Unwind_Ptr
392_Unwind_GetDataRelBase (_Unwind_Context *context __attribute__ ((unused)))
393{
394  abort ();
395}
396
397_Unwind_Ptr
398_Unwind_GetTextRelBase (_Unwind_Context *context __attribute__ ((unused)))
399{
400  abort ();
401}
402