]>
Commit | Line | Data |
---|---|---|
2a1ee410 | 1 | /* Exception handling and frame unwind runtime interface routines. |
3ef42a0c | 2 | Copyright (C) 2001, 2002 Free Software Foundation, Inc. |
2a1ee410 | 3 | |
1322177d | 4 | This file is part of GCC. |
2a1ee410 | 5 | |
1322177d LB |
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 | |
2a1ee410 RH |
8 | the Free Software Foundation; either version 2, or (at your option) |
9 | any later version. | |
10 | ||
1322177d LB |
11 | GCC is distributed in the hope that it will be useful, but WITHOUT |
12 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
13 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public | |
14 | License for more details. | |
2a1ee410 RH |
15 | |
16 | You should have received a copy of the GNU General Public License | |
1322177d LB |
17 | along with GCC; see the file COPYING. If not, write to the Free |
18 | Software Foundation, 59 Temple Place - Suite 330, Boston, MA | |
19 | 02111-1307, USA. */ | |
2a1ee410 RH |
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 | ||
3ef42a0c | 25 | /* If using C++, references to abort have to be qualified with std::. */ |
f71c6542 BK |
26 | #if __cplusplus |
27 | #define __gxx_abort std::abort | |
28 | #else | |
29 | #define __gxx_abort abort | |
30 | #endif | |
31 | ||
2a1ee410 RH |
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 | |
099c8b17 | 50 | #define DW_EH_PE_aligned 0x50 |
2a1ee410 RH |
51 | |
52 | #define DW_EH_PE_indirect 0x80 | |
c9ec8f32 RH |
53 | \f |
54 | ||
55 | /* Given an encoding, return the number of bytes the format occupies. | |
099c8b17 | 56 | This is only defined for fixed-size encodings, and so does not |
c9ec8f32 | 57 | include leb128. */ |
2a1ee410 RH |
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 | } | |
f71c6542 | 76 | __gxx_abort (); |
2a1ee410 RH |
77 | } |
78 | ||
bda33a6e MK |
79 | #ifndef NO_BASE_OF_ENCODED_VALUE |
80 | ||
c9ec8f32 | 81 | /* Given an encoding and an _Unwind_Context, return the base to which |
099c8b17 | 82 | the encoding is relative. This base may then be passed to |
c9ec8f32 RH |
83 | read_encoded_value_with_base for use when the _Unwind_Context is |
84 | not available. */ | |
85 | ||
2a1ee410 | 86 | static _Unwind_Ptr |
e1f9550a | 87 | base_of_encoded_value (unsigned char encoding, struct _Unwind_Context *context) |
2a1ee410 RH |
88 | { |
89 | if (encoding == DW_EH_PE_omit) | |
90 | return 0; | |
91 | ||
92 | switch (encoding & 0x70) | |
93 | { | |
94 | case DW_EH_PE_absptr: | |
95 | case DW_EH_PE_pcrel: | |
099c8b17 | 96 | case DW_EH_PE_aligned: |
2a1ee410 RH |
97 | return 0; |
98 | ||
99 | case DW_EH_PE_textrel: | |
100 | return _Unwind_GetTextRelBase (context); | |
101 | case DW_EH_PE_datarel: | |
102 | return _Unwind_GetDataRelBase (context); | |
103 | case DW_EH_PE_funcrel: | |
104 | return _Unwind_GetRegionStart (context); | |
105 | } | |
f71c6542 | 106 | __gxx_abort (); |
2a1ee410 RH |
107 | } |
108 | ||
bda33a6e MK |
109 | #endif |
110 | ||
a9985a92 JM |
111 | /* Read an unsigned leb128 value from P, store the value in VAL, return |
112 | P incremented past the value. We assume that a word is large enough to | |
113 | hold any value so encoded; if it is smaller than a pointer on some target, | |
114 | pointers should not be leb128 encoded on that target. */ | |
115 | ||
116 | static const unsigned char * | |
117 | read_uleb128 (const unsigned char *p, _Unwind_Word *val) | |
118 | { | |
119 | unsigned int shift = 0; | |
120 | unsigned char byte; | |
121 | _Unwind_Word result; | |
122 | ||
123 | result = 0; | |
124 | do | |
125 | { | |
126 | byte = *p++; | |
127 | result |= (byte & 0x7f) << shift; | |
128 | shift += 7; | |
129 | } | |
130 | while (byte & 0x80); | |
131 | ||
132 | *val = result; | |
133 | return p; | |
134 | } | |
135 | ||
136 | /* Similar, but read a signed leb128 value. */ | |
137 | ||
138 | static const unsigned char * | |
139 | read_sleb128 (const unsigned char *p, _Unwind_Sword *val) | |
140 | { | |
141 | unsigned int shift = 0; | |
142 | unsigned char byte; | |
143 | _Unwind_Word result; | |
144 | ||
145 | result = 0; | |
146 | do | |
147 | { | |
148 | byte = *p++; | |
149 | result |= (byte & 0x7f) << shift; | |
150 | shift += 7; | |
151 | } | |
152 | while (byte & 0x80); | |
153 | ||
154 | /* Sign-extend a negative value. */ | |
155 | if (shift < 8 * sizeof(result) && (byte & 0x40) != 0) | |
156 | result |= -(1L << shift); | |
157 | ||
158 | *val = (_Unwind_Sword) result; | |
159 | return p; | |
160 | } | |
161 | ||
c9ec8f32 RH |
162 | /* Load an encoded value from memory at P. The value is returned in VAL; |
163 | The function returns P incremented past the value. BASE is as given | |
164 | by base_of_encoded_value for this encoding in the appropriate context. */ | |
165 | ||
2a1ee410 RH |
166 | static const unsigned char * |
167 | read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base, | |
168 | const unsigned char *p, _Unwind_Ptr *val) | |
169 | { | |
170 | union unaligned | |
171 | { | |
172 | void *ptr; | |
173 | unsigned u2 __attribute__ ((mode (HI))); | |
174 | unsigned u4 __attribute__ ((mode (SI))); | |
175 | unsigned u8 __attribute__ ((mode (DI))); | |
176 | signed s2 __attribute__ ((mode (HI))); | |
177 | signed s4 __attribute__ ((mode (SI))); | |
178 | signed s8 __attribute__ ((mode (DI))); | |
179 | } __attribute__((__packed__)); | |
180 | ||
181 | union unaligned *u = (union unaligned *) p; | |
182 | _Unwind_Ptr result; | |
183 | ||
099c8b17 | 184 | if (encoding == DW_EH_PE_aligned) |
2a1ee410 | 185 | { |
e9d1b155 | 186 | _Unwind_Ptr a = (_Unwind_Ptr) p; |
099c8b17 RH |
187 | a = (a + sizeof (void *) - 1) & - sizeof(void *); |
188 | result = *(_Unwind_Ptr *) a; | |
e9d1b155 | 189 | p = (const unsigned char *) (a + sizeof (void *)); |
099c8b17 RH |
190 | } |
191 | else | |
192 | { | |
193 | switch (encoding & 0x0f) | |
194 | { | |
195 | case DW_EH_PE_absptr: | |
196 | result = (_Unwind_Ptr) u->ptr; | |
197 | p += sizeof (void *); | |
198 | break; | |
199 | ||
200 | case DW_EH_PE_uleb128: | |
2a1ee410 | 201 | { |
a9985a92 JM |
202 | _Unwind_Word tmp; |
203 | p = read_uleb128 (p, &tmp); | |
e9d1b155 | 204 | result = (_Unwind_Ptr) tmp; |
2a1ee410 | 205 | } |
099c8b17 | 206 | break; |
2a1ee410 | 207 | |
099c8b17 | 208 | case DW_EH_PE_sleb128: |
2a1ee410 | 209 | { |
a9985a92 JM |
210 | _Unwind_Sword tmp; |
211 | p = read_sleb128 (p, &tmp); | |
e9d1b155 | 212 | result = (_Unwind_Ptr) tmp; |
2a1ee410 | 213 | } |
099c8b17 RH |
214 | break; |
215 | ||
216 | case DW_EH_PE_udata2: | |
217 | result = u->u2; | |
218 | p += 2; | |
219 | break; | |
220 | case DW_EH_PE_udata4: | |
221 | result = u->u4; | |
222 | p += 4; | |
223 | break; | |
224 | case DW_EH_PE_udata8: | |
225 | result = u->u8; | |
226 | p += 8; | |
227 | break; | |
228 | ||
229 | case DW_EH_PE_sdata2: | |
230 | result = u->s2; | |
231 | p += 2; | |
232 | break; | |
233 | case DW_EH_PE_sdata4: | |
234 | result = u->s4; | |
235 | p += 4; | |
236 | break; | |
237 | case DW_EH_PE_sdata8: | |
238 | result = u->s8; | |
239 | p += 8; | |
240 | break; | |
241 | ||
242 | default: | |
f71c6542 | 243 | __gxx_abort (); |
099c8b17 RH |
244 | } |
245 | ||
246 | if (result != 0) | |
247 | { | |
248 | result += ((encoding & 0x70) == DW_EH_PE_pcrel | |
e9d1b155 | 249 | ? (_Unwind_Ptr) u : base); |
099c8b17 | 250 | if (encoding & DW_EH_PE_indirect) |
e9d1b155 | 251 | result = *(_Unwind_Ptr *) result; |
099c8b17 | 252 | } |
2a1ee410 RH |
253 | } |
254 | ||
255 | *val = result; | |
256 | return p; | |
257 | } | |
258 | ||
bda33a6e MK |
259 | #ifndef NO_BASE_OF_ENCODED_VALUE |
260 | ||
c9ec8f32 RH |
261 | /* Like read_encoded_value_with_base, but get the base from the context |
262 | rather than providing it directly. */ | |
263 | ||
2a1ee410 | 264 | static inline const unsigned char * |
e1f9550a | 265 | read_encoded_value (struct _Unwind_Context *context, unsigned char encoding, |
2a1ee410 RH |
266 | const unsigned char *p, _Unwind_Ptr *val) |
267 | { | |
099c8b17 | 268 | return read_encoded_value_with_base (encoding, |
2a1ee410 RH |
269 | base_of_encoded_value (encoding, context), |
270 | p, val); | |
271 | } | |
272 | ||
bda33a6e | 273 | #endif |