]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/gcc/config/arm/pr-support.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / gcc / config / arm / pr-support.c
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.  */
32 extern void abort (void);
33
34 typedef 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
44 void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
45
46 /* Unwind descriptors.  */
47
48 typedef struct
49 {
50   _uw16 length;
51   _uw16 offset;
52 } EHT16;
53
54 typedef 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
63 static inline _uw
64 selfrel_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.  */
83 static inline _uw8
84 next_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
346 static inline _Unwind_Control_Block *
347 unwind_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
365 void *
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