OSDN Git Service

2003-10-03 Paolo Carlini <pcarlini@unitus.it>
[pf3gnuchains/gcc-fork.git] / gcc / unwind-pe.h
1 /* Exception handling and frame unwind runtime interface routines.
2    Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
3
4    This file is part of GCC.
5
6    GCC is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2, or (at your option)
9    any later version.
10
11    In addition to the permissions in the GNU General Public License, the
12    Free Software Foundation gives you unlimited permission to link the
13    compiled version of this file into combinations with other programs,
14    and to distribute those combinations without any restriction coming
15    from the use of this file.  (The General Public License restrictions
16    do apply in other respects; for example, they cover modification of
17    the file, and distribution when not linked into a combined
18    executable.)
19
20    GCC is distributed in the hope that it will be useful, but WITHOUT
21    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
23    License for more details.
24
25    You should have received a copy of the GNU General Public License
26    along with GCC; see the file COPYING.  If not, write to the Free
27    Software Foundation, 59 Temple Place - Suite 330, Boston, MA
28    02111-1307, USA.  */
29
30 /* @@@ Really this should be out of line, but this also causes link
31    compatibility problems with the base ABI.  This is slightly better
32    than duplicating code, however.  */
33
34 /* If using C++, references to abort have to be qualified with std::.  */
35 #if __cplusplus
36 #define __gxx_abort std::abort
37 #else
38 #define __gxx_abort abort
39 #endif
40
41 /* Pointer encodings, from dwarf2.h.  */
42 #define DW_EH_PE_absptr         0x00
43 #define DW_EH_PE_omit           0xff
44
45 #define DW_EH_PE_uleb128        0x01
46 #define DW_EH_PE_udata2         0x02
47 #define DW_EH_PE_udata4         0x03
48 #define DW_EH_PE_udata8         0x04
49 #define DW_EH_PE_sleb128        0x09
50 #define DW_EH_PE_sdata2         0x0A
51 #define DW_EH_PE_sdata4         0x0B
52 #define DW_EH_PE_sdata8         0x0C
53 #define DW_EH_PE_signed         0x08
54
55 #define DW_EH_PE_pcrel          0x10
56 #define DW_EH_PE_textrel        0x20
57 #define DW_EH_PE_datarel        0x30
58 #define DW_EH_PE_funcrel        0x40
59 #define DW_EH_PE_aligned        0x50
60
61 #define DW_EH_PE_indirect       0x80
62 \f
63
64 #ifndef NO_SIZE_OF_ENCODED_VALUE
65
66 /* Given an encoding, return the number of bytes the format occupies.
67    This is only defined for fixed-size encodings, and so does not
68    include leb128.  */
69
70 static unsigned int
71 size_of_encoded_value (unsigned char encoding)
72 {
73   if (encoding == DW_EH_PE_omit)
74     return 0;
75
76   switch (encoding & 0x07)
77     {
78     case DW_EH_PE_absptr:
79       return sizeof (void *);
80     case DW_EH_PE_udata2:
81       return 2;
82     case DW_EH_PE_udata4:
83       return 4;
84     case DW_EH_PE_udata8:
85       return 8;
86     }
87   __gxx_abort ();
88 }
89
90 #endif
91
92 #ifndef NO_BASE_OF_ENCODED_VALUE
93
94 /* Given an encoding and an _Unwind_Context, return the base to which
95    the encoding is relative.  This base may then be passed to
96    read_encoded_value_with_base for use when the _Unwind_Context is
97    not available.  */
98
99 static _Unwind_Ptr
100 base_of_encoded_value (unsigned char encoding, struct _Unwind_Context *context)
101 {
102   if (encoding == DW_EH_PE_omit)
103     return 0;
104
105   switch (encoding & 0x70)
106     {
107     case DW_EH_PE_absptr:
108     case DW_EH_PE_pcrel:
109     case DW_EH_PE_aligned:
110       return 0;
111
112     case DW_EH_PE_textrel:
113       return _Unwind_GetTextRelBase (context);
114     case DW_EH_PE_datarel:
115       return _Unwind_GetDataRelBase (context);
116     case DW_EH_PE_funcrel:
117       return _Unwind_GetRegionStart (context);
118     }
119   __gxx_abort ();
120 }
121
122 #endif
123
124 /* Read an unsigned leb128 value from P, store the value in VAL, return
125    P incremented past the value.  We assume that a word is large enough to
126    hold any value so encoded; if it is smaller than a pointer on some target,
127    pointers should not be leb128 encoded on that target.  */
128
129 static const unsigned char *
130 read_uleb128 (const unsigned char *p, _Unwind_Word *val)
131 {
132   unsigned int shift = 0;
133   unsigned char byte;
134   _Unwind_Word result;
135
136   result = 0;
137   do
138     {
139       byte = *p++;
140       result |= (byte & 0x7f) << shift;
141       shift += 7;
142     }
143   while (byte & 0x80);
144
145   *val = result;
146   return p;
147 }
148
149 /* Similar, but read a signed leb128 value.  */
150
151 static const unsigned char *
152 read_sleb128 (const unsigned char *p, _Unwind_Sword *val)
153 {
154   unsigned int shift = 0;
155   unsigned char byte;
156   _Unwind_Word result;
157
158   result = 0;
159   do
160     {
161       byte = *p++;
162       result |= (byte & 0x7f) << shift;
163       shift += 7;
164     }
165   while (byte & 0x80);
166
167   /* Sign-extend a negative value.  */
168   if (shift < 8 * sizeof(result) && (byte & 0x40) != 0)
169     result |= -(1L << shift);
170
171   *val = (_Unwind_Sword) result;
172   return p;
173 }
174
175 /* Load an encoded value from memory at P.  The value is returned in VAL;
176    The function returns P incremented past the value.  BASE is as given
177    by base_of_encoded_value for this encoding in the appropriate context.  */
178
179 static const unsigned char *
180 read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
181                               const unsigned char *p, _Unwind_Ptr *val)
182 {
183   union unaligned
184     {
185       void *ptr;
186       unsigned u2 __attribute__ ((mode (HI)));
187       unsigned u4 __attribute__ ((mode (SI)));
188       unsigned u8 __attribute__ ((mode (DI)));
189       signed s2 __attribute__ ((mode (HI)));
190       signed s4 __attribute__ ((mode (SI)));
191       signed s8 __attribute__ ((mode (DI)));
192     } __attribute__((__packed__));
193
194   const union unaligned *u = (const union unaligned *) p;
195   _Unwind_Internal_Ptr result;
196
197   if (encoding == DW_EH_PE_aligned)
198     {
199       _Unwind_Internal_Ptr a = (_Unwind_Internal_Ptr) p;
200       a = (a + sizeof (void *) - 1) & - sizeof(void *);
201       result = *(_Unwind_Internal_Ptr *) a;
202       p = (const unsigned char *) (a + sizeof (void *));
203     }
204   else
205     {
206       switch (encoding & 0x0f)
207         {
208         case DW_EH_PE_absptr:
209           result = (_Unwind_Internal_Ptr) u->ptr;
210           p += sizeof (void *);
211           break;
212
213         case DW_EH_PE_uleb128:
214           {
215             _Unwind_Word tmp;
216             p = read_uleb128 (p, &tmp);
217             result = (_Unwind_Internal_Ptr) tmp;
218           }
219           break;
220
221         case DW_EH_PE_sleb128:
222           {
223             _Unwind_Sword tmp;
224             p = read_sleb128 (p, &tmp);
225             result = (_Unwind_Internal_Ptr) tmp;
226           }
227           break;
228
229         case DW_EH_PE_udata2:
230           result = u->u2;
231           p += 2;
232           break;
233         case DW_EH_PE_udata4:
234           result = u->u4;
235           p += 4;
236           break;
237         case DW_EH_PE_udata8:
238           result = u->u8;
239           p += 8;
240           break;
241
242         case DW_EH_PE_sdata2:
243           result = u->s2;
244           p += 2;
245           break;
246         case DW_EH_PE_sdata4:
247           result = u->s4;
248           p += 4;
249           break;
250         case DW_EH_PE_sdata8:
251           result = u->s8;
252           p += 8;
253           break;
254
255         default:
256           __gxx_abort ();
257         }
258
259       if (result != 0)
260         {
261           result += ((encoding & 0x70) == DW_EH_PE_pcrel
262                      ? (_Unwind_Internal_Ptr) u : base);
263           if (encoding & DW_EH_PE_indirect)
264             result = *(_Unwind_Internal_Ptr *) result;
265         }
266     }
267
268   *val = result;
269   return p;
270 }
271
272 #ifndef NO_BASE_OF_ENCODED_VALUE
273
274 /* Like read_encoded_value_with_base, but get the base from the context
275    rather than providing it directly.  */
276
277 static inline const unsigned char *
278 read_encoded_value (struct _Unwind_Context *context, unsigned char encoding,
279                     const unsigned char *p, _Unwind_Ptr *val)
280 {
281   return read_encoded_value_with_base (encoding,
282                 base_of_encoded_value (encoding, context),
283                 p, val);
284 }
285
286 #endif