OSDN Git Service

* except.c (eh_data_format_name): Move to ...
[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 /* Pointer encodings, from dwarf2.h.  */
26 #define DW_EH_PE_absptr         0x00
27 #define DW_EH_PE_omit           0xff
28
29 #define DW_EH_PE_uleb128        0x01
30 #define DW_EH_PE_udata2         0x02
31 #define DW_EH_PE_udata4         0x03
32 #define DW_EH_PE_udata8         0x04
33 #define DW_EH_PE_sleb128        0x09
34 #define DW_EH_PE_sdata2         0x0A
35 #define DW_EH_PE_sdata4         0x0B
36 #define DW_EH_PE_sdata8         0x0C
37 #define DW_EH_PE_signed         0x08
38
39 #define DW_EH_PE_pcrel          0x10
40 #define DW_EH_PE_textrel        0x20
41 #define DW_EH_PE_datarel        0x30
42 #define DW_EH_PE_funcrel        0x40
43
44 #define DW_EH_PE_indirect       0x80
45 \f
46
47 /* Given an encoding, return the number of bytes the format occupies.
48    This is only defined for fixed-size encodings, and so does not 
49    include leb128.  */
50
51 static unsigned int
52 size_of_encoded_value (unsigned char encoding)
53 {
54   if (encoding == DW_EH_PE_omit)
55     return 0;
56
57   switch (encoding & 0x07)
58     {
59     case DW_EH_PE_absptr:
60       return sizeof (void *);
61     case DW_EH_PE_udata2:
62       return 2;
63     case DW_EH_PE_udata4:
64       return 4;
65     case DW_EH_PE_udata8:
66       return 8;
67     }
68   abort ();
69 }
70
71 /* Given an encoding and an _Unwind_Context, return the base to which
72    the encoding is relative.  This base may then be passed to 
73    read_encoded_value_with_base for use when the _Unwind_Context is
74    not available.  */
75
76 static _Unwind_Ptr
77 base_of_encoded_value (unsigned char encoding, struct _Unwind_Context *context)
78 {
79   if (encoding == DW_EH_PE_omit)
80     return 0;
81
82   switch (encoding & 0x70)
83     {
84     case DW_EH_PE_absptr:
85     case DW_EH_PE_pcrel:
86       return 0;
87
88     case DW_EH_PE_textrel:
89       return _Unwind_GetTextRelBase (context);
90     case DW_EH_PE_datarel:
91       return _Unwind_GetDataRelBase (context);
92     case DW_EH_PE_funcrel:
93       return _Unwind_GetRegionStart (context);
94     }
95   abort ();
96 }
97
98 /* Load an encoded value from memory at P.  The value is returned in VAL;
99    The function returns P incremented past the value.  BASE is as given
100    by base_of_encoded_value for this encoding in the appropriate context.  */
101
102 static const unsigned char *
103 read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
104                               const unsigned char *p, _Unwind_Ptr *val)
105 {
106   union unaligned
107     {
108       void *ptr;
109       unsigned u2 __attribute__ ((mode (HI)));
110       unsigned u4 __attribute__ ((mode (SI)));
111       unsigned u8 __attribute__ ((mode (DI)));
112       signed s2 __attribute__ ((mode (HI)));
113       signed s4 __attribute__ ((mode (SI)));
114       signed s8 __attribute__ ((mode (DI)));
115     } __attribute__((__packed__));
116
117   union unaligned *u = (union unaligned *) p;
118   _Unwind_Ptr result;
119
120   switch (encoding & 0x0f)
121     {
122     case DW_EH_PE_absptr:
123       result = (_Unwind_Ptr) u->ptr;
124       p += sizeof (void *);
125       break;
126
127     case DW_EH_PE_uleb128:
128       {
129         unsigned int shift = 0;
130         unsigned char byte;
131
132         result = 0;
133         do
134           {
135             byte = *p++;
136             result |= (_Unwind_Ptr)(byte & 0x7f) << shift;
137             shift += 7;
138           }
139         while (byte & 0x80);
140       }
141       break;
142
143     case DW_EH_PE_sleb128:
144       {
145         unsigned int shift = 0;
146         unsigned char byte;
147
148         result = 0;
149         do
150           {
151             byte = *p++;
152             result |= (_Unwind_Ptr)(byte & 0x7f) << shift;
153             shift += 7;
154           }
155         while (byte & 0x80);
156
157         if (shift < 8 * sizeof(result) && (byte & 0x40) != 0)
158           result |= -(1L << shift);
159       }
160       break;
161
162     case DW_EH_PE_udata2:
163       result = u->u2;
164       p += 2;
165       break;
166     case DW_EH_PE_udata4:
167       result = u->u4;
168       p += 4;
169       break;
170     case DW_EH_PE_udata8:
171       result = u->u8;
172       p += 8;
173       break;
174
175     case DW_EH_PE_sdata2:
176       result = u->s2;
177       p += 2;
178       break;
179     case DW_EH_PE_sdata4:
180       result = u->s4;
181       p += 4;
182       break;
183     case DW_EH_PE_sdata8:
184       result = u->s8;
185       p += 8;
186       break;
187
188     default:
189       abort ();
190     }
191
192   if (result != 0)
193     {
194       result += ((encoding & 0x70) == DW_EH_PE_pcrel ? (_Unwind_Ptr)u : base);
195       if (encoding & DW_EH_PE_indirect)
196         result = *(_Unwind_Ptr *)result;
197     }
198
199   *val = result;
200   return p;
201 }
202
203 /* Like read_encoded_value_with_base, but get the base from the context
204    rather than providing it directly.  */
205
206 static inline const unsigned char *
207 read_encoded_value (struct _Unwind_Context *context, unsigned char encoding,
208                     const unsigned char *p, _Unwind_Ptr *val)
209 {
210   return read_encoded_value_with_base (encoding, 
211                 base_of_encoded_value (encoding, context),
212                 p, val);
213 }
214
215 /* Read an unsigned leb128 value from P, store the value in VAL, return
216    P incremented past the value.  */
217
218 static inline const unsigned char *
219 read_uleb128 (const unsigned char *p, _Unwind_Ptr *val)
220 {
221   return read_encoded_value_with_base (DW_EH_PE_uleb128, 0, p, val);
222 }
223
224 /* Similar, but read a signed leb128 value.  */
225
226 static inline const unsigned char *
227 read_sleb128 (const unsigned char *p, _Unwind_Ptr *val)
228 {
229   return read_encoded_value_with_base (DW_EH_PE_sleb128, 0, p, val);
230 }