xref: /openbsd/gnu/gcc/gcc/unwind-pe.h (revision 404b540a)
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 
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
size_of_encoded_value(unsigned char encoding)74 size_of_encoded_value (unsigned char encoding)
75 {
76   if (encoding == DW_EH_PE_omit)
77     return 0;
78 
79   switch (encoding & 0x07)
80     {
81     case DW_EH_PE_absptr:
82       return sizeof (void *);
83     case DW_EH_PE_udata2:
84       return 2;
85     case DW_EH_PE_udata4:
86       return 4;
87     case DW_EH_PE_udata8:
88       return 8;
89     }
90   __gxx_abort ();
91 }
92 
93 #endif
94 
95 #ifndef NO_BASE_OF_ENCODED_VALUE
96 
97 /* Given an encoding and an _Unwind_Context, return the base to which
98    the encoding is relative.  This base may then be passed to
99    read_encoded_value_with_base for use when the _Unwind_Context is
100    not available.  */
101 
102 static _Unwind_Ptr
base_of_encoded_value(unsigned char encoding,struct _Unwind_Context * context)103 base_of_encoded_value (unsigned char encoding, struct _Unwind_Context *context)
104 {
105   if (encoding == DW_EH_PE_omit)
106     return 0;
107 
108   switch (encoding & 0x70)
109     {
110     case DW_EH_PE_absptr:
111     case DW_EH_PE_pcrel:
112     case DW_EH_PE_aligned:
113       return 0;
114 
115     case DW_EH_PE_textrel:
116       return _Unwind_GetTextRelBase (context);
117     case DW_EH_PE_datarel:
118       return _Unwind_GetDataRelBase (context);
119     case DW_EH_PE_funcrel:
120       return _Unwind_GetRegionStart (context);
121     }
122   __gxx_abort ();
123 }
124 
125 #endif
126 
127 /* Read an unsigned leb128 value from P, store the value in VAL, return
128    P incremented past the value.  We assume that a word is large enough to
129    hold any value so encoded; if it is smaller than a pointer on some target,
130    pointers should not be leb128 encoded on that target.  */
131 
132 static const unsigned char *
read_uleb128(const unsigned char * p,_Unwind_Word * val)133 read_uleb128 (const unsigned char *p, _Unwind_Word *val)
134 {
135   unsigned int shift = 0;
136   unsigned char byte;
137   _Unwind_Word result;
138 
139   result = 0;
140   do
141     {
142       byte = *p++;
143       result |= ((_Unwind_Word)byte & 0x7f) << shift;
144       shift += 7;
145     }
146   while (byte & 0x80);
147 
148   *val = result;
149   return p;
150 }
151 
152 /* Similar, but read a signed leb128 value.  */
153 
154 static const unsigned char *
read_sleb128(const unsigned char * p,_Unwind_Sword * val)155 read_sleb128 (const unsigned char *p, _Unwind_Sword *val)
156 {
157   unsigned int shift = 0;
158   unsigned char byte;
159   _Unwind_Word result;
160 
161   result = 0;
162   do
163     {
164       byte = *p++;
165       result |= ((_Unwind_Word)byte & 0x7f) << shift;
166       shift += 7;
167     }
168   while (byte & 0x80);
169 
170   /* Sign-extend a negative value.  */
171   if (shift < 8 * sizeof(result) && (byte & 0x40) != 0)
172     result |= -(((_Unwind_Word)1L) << shift);
173 
174   *val = (_Unwind_Sword) result;
175   return p;
176 }
177 
178 /* Load an encoded value from memory at P.  The value is returned in VAL;
179    The function returns P incremented past the value.  BASE is as given
180    by base_of_encoded_value for this encoding in the appropriate context.  */
181 
182 static const unsigned char *
read_encoded_value_with_base(unsigned char encoding,_Unwind_Ptr base,const unsigned char * p,_Unwind_Ptr * val)183 read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
184 			      const unsigned char *p, _Unwind_Ptr *val)
185 {
186   union unaligned
187     {
188       void *ptr;
189       unsigned u2 __attribute__ ((mode (HI)));
190       unsigned u4 __attribute__ ((mode (SI)));
191       unsigned u8 __attribute__ ((mode (DI)));
192       signed s2 __attribute__ ((mode (HI)));
193       signed s4 __attribute__ ((mode (SI)));
194       signed s8 __attribute__ ((mode (DI)));
195     } __attribute__((__packed__));
196 
197   const union unaligned *u = (const union unaligned *) p;
198   _Unwind_Internal_Ptr result;
199 
200   if (encoding == DW_EH_PE_aligned)
201     {
202       _Unwind_Internal_Ptr a = (_Unwind_Internal_Ptr) p;
203       a = (a + sizeof (void *) - 1) & - sizeof(void *);
204       result = *(_Unwind_Internal_Ptr *) a;
205       p = (const unsigned char *) (_Unwind_Internal_Ptr) (a + sizeof (void *));
206     }
207   else
208     {
209       switch (encoding & 0x0f)
210 	{
211 	case DW_EH_PE_absptr:
212 	  result = (_Unwind_Internal_Ptr) u->ptr;
213 	  p += sizeof (void *);
214 	  break;
215 
216 	case DW_EH_PE_uleb128:
217 	  {
218 	    _Unwind_Word tmp;
219 	    p = read_uleb128 (p, &tmp);
220 	    result = (_Unwind_Internal_Ptr) tmp;
221 	  }
222 	  break;
223 
224 	case DW_EH_PE_sleb128:
225 	  {
226 	    _Unwind_Sword tmp;
227 	    p = read_sleb128 (p, &tmp);
228 	    result = (_Unwind_Internal_Ptr) tmp;
229 	  }
230 	  break;
231 
232 	case DW_EH_PE_udata2:
233 	  result = u->u2;
234 	  p += 2;
235 	  break;
236 	case DW_EH_PE_udata4:
237 	  result = u->u4;
238 	  p += 4;
239 	  break;
240 	case DW_EH_PE_udata8:
241 	  result = u->u8;
242 	  p += 8;
243 	  break;
244 
245 	case DW_EH_PE_sdata2:
246 	  result = u->s2;
247 	  p += 2;
248 	  break;
249 	case DW_EH_PE_sdata4:
250 	  result = u->s4;
251 	  p += 4;
252 	  break;
253 	case DW_EH_PE_sdata8:
254 	  result = u->s8;
255 	  p += 8;
256 	  break;
257 
258 	default:
259 	  __gxx_abort ();
260 	}
261 
262       if (result != 0)
263 	{
264 	  result += ((encoding & 0x70) == DW_EH_PE_pcrel
265 		     ? (_Unwind_Internal_Ptr) u : base);
266 	  if (encoding & DW_EH_PE_indirect)
267 	    result = *(_Unwind_Internal_Ptr *) result;
268 	}
269     }
270 
271   *val = result;
272   return p;
273 }
274 
275 #ifndef NO_BASE_OF_ENCODED_VALUE
276 
277 /* Like read_encoded_value_with_base, but get the base from the context
278    rather than providing it directly.  */
279 
280 static inline const unsigned char *
read_encoded_value(struct _Unwind_Context * context,unsigned char encoding,const unsigned char * p,_Unwind_Ptr * val)281 read_encoded_value (struct _Unwind_Context *context, unsigned char encoding,
282 		    const unsigned char *p, _Unwind_Ptr *val)
283 {
284   return read_encoded_value_with_base (encoding,
285 		base_of_encoded_value (encoding, context),
286 		p, val);
287 }
288 
289 #endif
290 
291 #endif /* unwind-pe.h */
292