2005-05-18 Daniel Berlin <dberlin@dberlin.org>
[official-gcc.git] / gcc / unwind-pe.h
blobce7d6943c0a3734724280efa40f9dd2d10e46c6c
1 /* Exception handling and frame unwind runtime interface routines.
2 Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
4 This file is part of GCC.
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.
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.)
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.
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. */
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. */
34 #ifndef GCC_UNWIND_PE_H
35 #define GCC_UNWIND_PE_H
37 /* Pointer encodings, from dwarf2.h. */
38 #define DW_EH_PE_absptr 0x00
39 #define DW_EH_PE_omit 0xff
41 #define DW_EH_PE_uleb128 0x01
42 #define DW_EH_PE_udata2 0x02
43 #define DW_EH_PE_udata4 0x03
44 #define DW_EH_PE_udata8 0x04
45 #define DW_EH_PE_sleb128 0x09
46 #define DW_EH_PE_sdata2 0x0A
47 #define DW_EH_PE_sdata4 0x0B
48 #define DW_EH_PE_sdata8 0x0C
49 #define DW_EH_PE_signed 0x08
51 #define DW_EH_PE_pcrel 0x10
52 #define DW_EH_PE_textrel 0x20
53 #define DW_EH_PE_datarel 0x30
54 #define DW_EH_PE_funcrel 0x40
55 #define DW_EH_PE_aligned 0x50
57 #define DW_EH_PE_indirect 0x80
60 #ifndef NO_SIZE_OF_ENCODED_VALUE
62 /* Given an encoding, return the number of bytes the format occupies.
63 This is only defined for fixed-size encodings, and so does not
64 include leb128. */
66 static unsigned int
67 size_of_encoded_value (unsigned char encoding)
69 if (encoding == DW_EH_PE_omit)
70 return 0;
72 switch (encoding & 0x07)
74 case DW_EH_PE_absptr:
75 return sizeof (void *);
76 case DW_EH_PE_udata2:
77 return 2;
78 case DW_EH_PE_udata4:
79 return 4;
80 case DW_EH_PE_udata8:
81 return 8;
82 default:
83 gcc_unreachable ();
87 #endif
89 #ifndef NO_BASE_OF_ENCODED_VALUE
91 /* Given an encoding and an _Unwind_Context, return the base to which
92 the encoding is relative. This base may then be passed to
93 read_encoded_value_with_base for use when the _Unwind_Context is
94 not available. */
96 static _Unwind_Ptr
97 base_of_encoded_value (unsigned char encoding, struct _Unwind_Context *context)
99 if (encoding == DW_EH_PE_omit)
100 return 0;
102 switch (encoding & 0x70)
104 case DW_EH_PE_absptr:
105 case DW_EH_PE_pcrel:
106 case DW_EH_PE_aligned:
107 return 0;
109 case DW_EH_PE_textrel:
110 return _Unwind_GetTextRelBase (context);
111 case DW_EH_PE_datarel:
112 return _Unwind_GetDataRelBase (context);
113 case DW_EH_PE_funcrel:
114 return _Unwind_GetRegionStart (context);
115 default:
116 gcc_unreachable ();
120 #endif
122 /* Read an unsigned leb128 value from P, store the value in VAL, return
123 P incremented past the value. We assume that a word is large enough to
124 hold any value so encoded; if it is smaller than a pointer on some target,
125 pointers should not be leb128 encoded on that target. */
127 static const unsigned char *
128 read_uleb128 (const unsigned char *p, _Unwind_Word *val)
130 unsigned int shift = 0;
131 unsigned char byte;
132 _Unwind_Word result;
134 result = 0;
137 byte = *p++;
138 result |= ((_Unwind_Word)byte & 0x7f) << shift;
139 shift += 7;
141 while (byte & 0x80);
143 *val = result;
144 return p;
147 /* Similar, but read a signed leb128 value. */
149 static const unsigned char *
150 read_sleb128 (const unsigned char *p, _Unwind_Sword *val)
152 unsigned int shift = 0;
153 unsigned char byte;
154 _Unwind_Word result;
156 result = 0;
159 byte = *p++;
160 result |= ((_Unwind_Word)byte & 0x7f) << shift;
161 shift += 7;
163 while (byte & 0x80);
165 /* Sign-extend a negative value. */
166 if (shift < 8 * sizeof(result) && (byte & 0x40) != 0)
167 result |= -(((_Unwind_Word)1L) << shift);
169 *val = (_Unwind_Sword) result;
170 return p;
173 /* Load an encoded value from memory at P. The value is returned in VAL;
174 The function returns P incremented past the value. BASE is as given
175 by base_of_encoded_value for this encoding in the appropriate context. */
177 static const unsigned char *
178 read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
179 const unsigned char *p, _Unwind_Ptr *val)
181 union unaligned
183 void *ptr;
184 unsigned u2 __attribute__ ((mode (HI)));
185 unsigned u4 __attribute__ ((mode (SI)));
186 unsigned u8 __attribute__ ((mode (DI)));
187 signed s2 __attribute__ ((mode (HI)));
188 signed s4 __attribute__ ((mode (SI)));
189 signed s8 __attribute__ ((mode (DI)));
190 } __attribute__((__packed__));
192 const union unaligned *u = (const union unaligned *) p;
193 _Unwind_Internal_Ptr result;
195 if (encoding == DW_EH_PE_aligned)
197 _Unwind_Internal_Ptr a = (_Unwind_Internal_Ptr) p;
198 a = (a + sizeof (void *) - 1) & - sizeof(void *);
199 result = *(_Unwind_Internal_Ptr *) a;
200 p = (const unsigned char *) (_Unwind_Internal_Ptr) (a + sizeof (void *));
202 else
204 switch (encoding & 0x0f)
206 case DW_EH_PE_absptr:
207 result = (_Unwind_Internal_Ptr) u->ptr;
208 p += sizeof (void *);
209 break;
211 case DW_EH_PE_uleb128:
213 _Unwind_Word tmp;
214 p = read_uleb128 (p, &tmp);
215 result = (_Unwind_Internal_Ptr) tmp;
217 break;
219 case DW_EH_PE_sleb128:
221 _Unwind_Sword tmp;
222 p = read_sleb128 (p, &tmp);
223 result = (_Unwind_Internal_Ptr) tmp;
225 break;
227 case DW_EH_PE_udata2:
228 result = u->u2;
229 p += 2;
230 break;
231 case DW_EH_PE_udata4:
232 result = u->u4;
233 p += 4;
234 break;
235 case DW_EH_PE_udata8:
236 result = u->u8;
237 p += 8;
238 break;
240 case DW_EH_PE_sdata2:
241 result = u->s2;
242 p += 2;
243 break;
244 case DW_EH_PE_sdata4:
245 result = u->s4;
246 p += 4;
247 break;
248 case DW_EH_PE_sdata8:
249 result = u->s8;
250 p += 8;
251 break;
253 default:
254 gcc_unreachable ();
257 if (result != 0)
259 result += ((encoding & 0x70) == DW_EH_PE_pcrel
260 ? (_Unwind_Internal_Ptr) u : base);
261 if (encoding & DW_EH_PE_indirect)
262 result = *(_Unwind_Internal_Ptr *) result;
266 *val = result;
267 return p;
270 #ifndef NO_BASE_OF_ENCODED_VALUE
272 /* Like read_encoded_value_with_base, but get the base from the context
273 rather than providing it directly. */
275 static inline const unsigned char *
276 read_encoded_value (struct _Unwind_Context *context, unsigned char encoding,
277 const unsigned char *p, _Unwind_Ptr *val)
279 return read_encoded_value_with_base (encoding,
280 base_of_encoded_value (encoding, context),
281 p, val);
284 #endif
286 #endif /* unwind-pe.h */