rs6000.md (fseldfsf4): Add TARGET_SINGLE_FLOAT condition.
[gcc.git] / gcc / unwind-pe.h
1 /* Exception handling and frame unwind runtime interface routines.
2 Copyright (C) 2001, 2002, 2003, 2004 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, 51 Franklin Street, Fifth Floor, Boston, MA
28 02110-1301, 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 #ifndef GCC_UNWIND_PE_H
35 #define GCC_UNWIND_PE_H
36
37 /* If using C++, references to abort have to be qualified with std::. */
38 #if __cplusplus
39 #define __gxx_abort std::abort
40 #else
41 #define __gxx_abort abort
42 #endif
43
44 /* Pointer encodings, from dwarf2.h. */
45 #define DW_EH_PE_absptr 0x00
46 #define DW_EH_PE_omit 0xff
47
48 #define DW_EH_PE_uleb128 0x01
49 #define DW_EH_PE_udata2 0x02
50 #define DW_EH_PE_udata4 0x03
51 #define DW_EH_PE_udata8 0x04
52 #define DW_EH_PE_sleb128 0x09
53 #define DW_EH_PE_sdata2 0x0A
54 #define DW_EH_PE_sdata4 0x0B
55 #define DW_EH_PE_sdata8 0x0C
56 #define DW_EH_PE_signed 0x08
57
58 #define DW_EH_PE_pcrel 0x10
59 #define DW_EH_PE_textrel 0x20
60 #define DW_EH_PE_datarel 0x30
61 #define DW_EH_PE_funcrel 0x40
62 #define DW_EH_PE_aligned 0x50
63
64 #define DW_EH_PE_indirect 0x80
65 \f
66
67 #ifndef NO_SIZE_OF_ENCODED_VALUE
68
69 /* Given an encoding, return the number of bytes the format occupies.
70 This is only defined for fixed-size encodings, and so does not
71 include leb128. */
72
73 static unsigned int
74 size_of_encoded_value (unsigned char encoding) __attribute__ ((unused));
75
76 static unsigned int
77 size_of_encoded_value (unsigned char encoding)
78 {
79 if (encoding == DW_EH_PE_omit)
80 return 0;
81
82 switch (encoding & 0x07)
83 {
84 case DW_EH_PE_absptr:
85 return sizeof (void *);
86 case DW_EH_PE_udata2:
87 return 2;
88 case DW_EH_PE_udata4:
89 return 4;
90 case DW_EH_PE_udata8:
91 return 8;
92 }
93 __gxx_abort ();
94 }
95
96 #endif
97
98 #ifndef NO_BASE_OF_ENCODED_VALUE
99
100 /* Given an encoding and an _Unwind_Context, return the base to which
101 the encoding is relative. This base may then be passed to
102 read_encoded_value_with_base for use when the _Unwind_Context is
103 not available. */
104
105 static _Unwind_Ptr
106 base_of_encoded_value (unsigned char encoding, struct _Unwind_Context *context)
107 {
108 if (encoding == DW_EH_PE_omit)
109 return 0;
110
111 switch (encoding & 0x70)
112 {
113 case DW_EH_PE_absptr:
114 case DW_EH_PE_pcrel:
115 case DW_EH_PE_aligned:
116 return 0;
117
118 case DW_EH_PE_textrel:
119 return _Unwind_GetTextRelBase (context);
120 case DW_EH_PE_datarel:
121 return _Unwind_GetDataRelBase (context);
122 case DW_EH_PE_funcrel:
123 return _Unwind_GetRegionStart (context);
124 }
125 __gxx_abort ();
126 }
127
128 #endif
129
130 /* Read an unsigned leb128 value from P, store the value in VAL, return
131 P incremented past the value. We assume that a word is large enough to
132 hold any value so encoded; if it is smaller than a pointer on some target,
133 pointers should not be leb128 encoded on that target. */
134
135 static const unsigned char *
136 read_uleb128 (const unsigned char *p, _uleb128_t *val)
137 {
138 unsigned int shift = 0;
139 unsigned char byte;
140 _uleb128_t result;
141
142 result = 0;
143 do
144 {
145 byte = *p++;
146 result |= ((_uleb128_t)byte & 0x7f) << shift;
147 shift += 7;
148 }
149 while (byte & 0x80);
150
151 *val = result;
152 return p;
153 }
154
155 /* Similar, but read a signed leb128 value. */
156
157 static const unsigned char *
158 read_sleb128 (const unsigned char *p, _sleb128_t *val)
159 {
160 unsigned int shift = 0;
161 unsigned char byte;
162 _uleb128_t result;
163
164 result = 0;
165 do
166 {
167 byte = *p++;
168 result |= ((_uleb128_t)byte & 0x7f) << shift;
169 shift += 7;
170 }
171 while (byte & 0x80);
172
173 /* Sign-extend a negative value. */
174 if (shift < 8 * sizeof(result) && (byte & 0x40) != 0)
175 result |= -(((_uleb128_t)1L) << shift);
176
177 *val = (_sleb128_t) result;
178 return p;
179 }
180
181 /* Load an encoded value from memory at P. The value is returned in VAL;
182 The function returns P incremented past the value. BASE is as given
183 by base_of_encoded_value for this encoding in the appropriate context. */
184
185 static const unsigned char *
186 read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
187 const unsigned char *p, _Unwind_Ptr *val)
188 {
189 union unaligned
190 {
191 void *ptr;
192 unsigned u2 __attribute__ ((mode (HI)));
193 unsigned u4 __attribute__ ((mode (SI)));
194 unsigned u8 __attribute__ ((mode (DI)));
195 signed s2 __attribute__ ((mode (HI)));
196 signed s4 __attribute__ ((mode (SI)));
197 signed s8 __attribute__ ((mode (DI)));
198 } __attribute__((__packed__));
199
200 const union unaligned *u = (const union unaligned *) p;
201 _Unwind_Internal_Ptr result;
202
203 if (encoding == DW_EH_PE_aligned)
204 {
205 _Unwind_Internal_Ptr a = (_Unwind_Internal_Ptr) p;
206 a = (a + sizeof (void *) - 1) & - sizeof(void *);
207 result = *(_Unwind_Internal_Ptr *) a;
208 p = (const unsigned char *) (_Unwind_Internal_Ptr) (a + sizeof (void *));
209 }
210 else
211 {
212 switch (encoding & 0x0f)
213 {
214 case DW_EH_PE_absptr:
215 result = (_Unwind_Internal_Ptr) u->ptr;
216 p += sizeof (void *);
217 break;
218
219 case DW_EH_PE_uleb128:
220 {
221 _uleb128_t tmp;
222 p = read_uleb128 (p, &tmp);
223 result = (_Unwind_Internal_Ptr) tmp;
224 }
225 break;
226
227 case DW_EH_PE_sleb128:
228 {
229 _sleb128_t tmp;
230 p = read_sleb128 (p, &tmp);
231 result = (_Unwind_Internal_Ptr) tmp;
232 }
233 break;
234
235 case DW_EH_PE_udata2:
236 result = u->u2;
237 p += 2;
238 break;
239 case DW_EH_PE_udata4:
240 result = u->u4;
241 p += 4;
242 break;
243 case DW_EH_PE_udata8:
244 result = u->u8;
245 p += 8;
246 break;
247
248 case DW_EH_PE_sdata2:
249 result = u->s2;
250 p += 2;
251 break;
252 case DW_EH_PE_sdata4:
253 result = u->s4;
254 p += 4;
255 break;
256 case DW_EH_PE_sdata8:
257 result = u->s8;
258 p += 8;
259 break;
260
261 default:
262 __gxx_abort ();
263 }
264
265 if (result != 0)
266 {
267 result += ((encoding & 0x70) == DW_EH_PE_pcrel
268 ? (_Unwind_Internal_Ptr) u : base);
269 if (encoding & DW_EH_PE_indirect)
270 result = *(_Unwind_Internal_Ptr *) result;
271 }
272 }
273
274 *val = result;
275 return p;
276 }
277
278 #ifndef NO_BASE_OF_ENCODED_VALUE
279
280 /* Like read_encoded_value_with_base, but get the base from the context
281 rather than providing it directly. */
282
283 static inline const unsigned char *
284 read_encoded_value (struct _Unwind_Context *context, unsigned char encoding,
285 const unsigned char *p, _Unwind_Ptr *val)
286 {
287 return read_encoded_value_with_base (encoding,
288 base_of_encoded_value (encoding, context),
289 p, val);
290 }
291
292 #endif
293
294 #endif /* unwind-pe.h */