xref: /netbsd-src/external/gpl3/gcc.old/dist/libgcc/config/arm/pr-support.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /* ARM EABI compliant unwinding routines
2    Copyright (C) 2004-2015 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.  */
28 extern void abort (void);
29 
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 			       &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)  /* Obsolete FPA.  */
230 	    return _URC_FAILURE;
231 
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);
246 	      op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
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 	    {
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;
282 	    }
283 	  if (op == 0xc9)
284 	    {
285 	      /* Pop VFP registers with fldmd.  */
286 	      op = next_unwind_byte (uws);
287 	      op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
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 _Unwind_Ptr
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 (_Unwind_Ptr) ptr;
370 }
371 
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 }
386