OSDN Git Service

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