OSDN Git Service

* config/arm/arm-protos.h (arm_print_operand): Delete.
[pf3gnuchains/gcc-fork.git] / gcc / config / arm / pr-support.c
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.  */
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)
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
352 static inline _Unwind_Control_Block *
353 unwind_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
371 void *
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 }