]>
Commit | Line | Data |
---|---|---|
ad5818ae | 1 | /* Exception handling and frame unwind runtime interface routines. |
2 | Copyright (C) 2001 Free Software Foundation, Inc. | |
3 | ||
f12b58b3 | 4 | This file is part of GCC. |
ad5818ae | 5 | |
f12b58b3 | 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 | |
ad5818ae | 8 | the Free Software Foundation; either version 2, or (at your option) |
9 | any later version. | |
10 | ||
f12b58b3 | 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. | |
ad5818ae | 15 | |
16 | You should have received a copy of the GNU General Public License | |
f12b58b3 | 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. */ | |
ad5818ae | 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 | ||
60527644 | 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 | ||
ad5818ae | 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 | |
9a4d22ba | 50 | #define DW_EH_PE_aligned 0x50 |
ad5818ae | 51 | |
52 | #define DW_EH_PE_indirect 0x80 | |
73eaf1ba | 53 | \f |
54 | ||
55 | /* Given an encoding, return the number of bytes the format occupies. | |
9a4d22ba | 56 | This is only defined for fixed-size encodings, and so does not |
73eaf1ba | 57 | include leb128. */ |
ad5818ae | 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 | } | |
60527644 | 76 | __gxx_abort (); |
ad5818ae | 77 | } |
78 | ||
8e7f75ad | 79 | #ifndef NO_BASE_OF_ENCODED_VALUE |
80 | ||
73eaf1ba | 81 | /* Given an encoding and an _Unwind_Context, return the base to which |
9a4d22ba | 82 | the encoding is relative. This base may then be passed to |
73eaf1ba | 83 | read_encoded_value_with_base for use when the _Unwind_Context is |
84 | not available. */ | |
85 | ||
ad5818ae | 86 | static _Unwind_Ptr |
9b84bf7d | 87 | base_of_encoded_value (unsigned char encoding, struct _Unwind_Context *context) |
ad5818ae | 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: | |
9a4d22ba | 96 | case DW_EH_PE_aligned: |
ad5818ae | 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 | } | |
60527644 | 106 | __gxx_abort (); |
ad5818ae | 107 | } |
108 | ||
8e7f75ad | 109 | #endif |
110 | ||
73eaf1ba | 111 | /* Load an encoded value from memory at P. The value is returned in VAL; |
112 | The function returns P incremented past the value. BASE is as given | |
113 | by base_of_encoded_value for this encoding in the appropriate context. */ | |
114 | ||
ad5818ae | 115 | static const unsigned char * |
116 | read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base, | |
117 | const unsigned char *p, _Unwind_Ptr *val) | |
118 | { | |
119 | union unaligned | |
120 | { | |
121 | void *ptr; | |
122 | unsigned u2 __attribute__ ((mode (HI))); | |
123 | unsigned u4 __attribute__ ((mode (SI))); | |
124 | unsigned u8 __attribute__ ((mode (DI))); | |
125 | signed s2 __attribute__ ((mode (HI))); | |
126 | signed s4 __attribute__ ((mode (SI))); | |
127 | signed s8 __attribute__ ((mode (DI))); | |
128 | } __attribute__((__packed__)); | |
129 | ||
130 | union unaligned *u = (union unaligned *) p; | |
131 | _Unwind_Ptr result; | |
132 | ||
9a4d22ba | 133 | if (encoding == DW_EH_PE_aligned) |
ad5818ae | 134 | { |
9a4d22ba | 135 | _Unwind_Ptr a = (_Unwind_Ptr)p; |
136 | a = (a + sizeof (void *) - 1) & - sizeof(void *); | |
137 | result = *(_Unwind_Ptr *) a; | |
138 | p = (const unsigned char *)(a + sizeof (void *)); | |
139 | } | |
140 | else | |
141 | { | |
142 | switch (encoding & 0x0f) | |
143 | { | |
144 | case DW_EH_PE_absptr: | |
145 | result = (_Unwind_Ptr) u->ptr; | |
146 | p += sizeof (void *); | |
147 | break; | |
148 | ||
149 | case DW_EH_PE_uleb128: | |
ad5818ae | 150 | { |
9a4d22ba | 151 | unsigned int shift = 0; |
152 | unsigned char byte; | |
153 | ||
154 | result = 0; | |
155 | do | |
156 | { | |
157 | byte = *p++; | |
158 | result |= (_Unwind_Ptr)(byte & 0x7f) << shift; | |
159 | shift += 7; | |
160 | } | |
161 | while (byte & 0x80); | |
ad5818ae | 162 | } |
9a4d22ba | 163 | break; |
ad5818ae | 164 | |
9a4d22ba | 165 | case DW_EH_PE_sleb128: |
ad5818ae | 166 | { |
9a4d22ba | 167 | unsigned int shift = 0; |
168 | unsigned char byte; | |
169 | ||
170 | result = 0; | |
171 | do | |
172 | { | |
173 | byte = *p++; | |
174 | result |= (_Unwind_Ptr)(byte & 0x7f) << shift; | |
175 | shift += 7; | |
176 | } | |
177 | while (byte & 0x80); | |
178 | ||
179 | if (shift < 8 * sizeof(result) && (byte & 0x40) != 0) | |
180 | result |= -(1L << shift); | |
ad5818ae | 181 | } |
9a4d22ba | 182 | break; |
183 | ||
184 | case DW_EH_PE_udata2: | |
185 | result = u->u2; | |
186 | p += 2; | |
187 | break; | |
188 | case DW_EH_PE_udata4: | |
189 | result = u->u4; | |
190 | p += 4; | |
191 | break; | |
192 | case DW_EH_PE_udata8: | |
193 | result = u->u8; | |
194 | p += 8; | |
195 | break; | |
196 | ||
197 | case DW_EH_PE_sdata2: | |
198 | result = u->s2; | |
199 | p += 2; | |
200 | break; | |
201 | case DW_EH_PE_sdata4: | |
202 | result = u->s4; | |
203 | p += 4; | |
204 | break; | |
205 | case DW_EH_PE_sdata8: | |
206 | result = u->s8; | |
207 | p += 8; | |
208 | break; | |
209 | ||
210 | default: | |
60527644 | 211 | __gxx_abort (); |
9a4d22ba | 212 | } |
213 | ||
214 | if (result != 0) | |
215 | { | |
216 | result += ((encoding & 0x70) == DW_EH_PE_pcrel | |
217 | ? (_Unwind_Ptr)u : base); | |
218 | if (encoding & DW_EH_PE_indirect) | |
219 | result = *(_Unwind_Ptr *)result; | |
220 | } | |
ad5818ae | 221 | } |
222 | ||
223 | *val = result; | |
224 | return p; | |
225 | } | |
226 | ||
8e7f75ad | 227 | #ifndef NO_BASE_OF_ENCODED_VALUE |
228 | ||
73eaf1ba | 229 | /* Like read_encoded_value_with_base, but get the base from the context |
230 | rather than providing it directly. */ | |
231 | ||
ad5818ae | 232 | static inline const unsigned char * |
9b84bf7d | 233 | read_encoded_value (struct _Unwind_Context *context, unsigned char encoding, |
ad5818ae | 234 | const unsigned char *p, _Unwind_Ptr *val) |
235 | { | |
9a4d22ba | 236 | return read_encoded_value_with_base (encoding, |
ad5818ae | 237 | base_of_encoded_value (encoding, context), |
238 | p, val); | |
239 | } | |
240 | ||
8e7f75ad | 241 | #endif |
242 | ||
73eaf1ba | 243 | /* Read an unsigned leb128 value from P, store the value in VAL, return |
244 | P incremented past the value. */ | |
245 | ||
ad5818ae | 246 | static inline const unsigned char * |
247 | read_uleb128 (const unsigned char *p, _Unwind_Ptr *val) | |
248 | { | |
249 | return read_encoded_value_with_base (DW_EH_PE_uleb128, 0, p, val); | |
250 | } | |
251 | ||
73eaf1ba | 252 | /* Similar, but read a signed leb128 value. */ |
253 | ||
ad5818ae | 254 | static inline const unsigned char * |
255 | read_sleb128 (const unsigned char *p, _Unwind_Ptr *val) | |
256 | { | |
257 | return read_encoded_value_with_base (DW_EH_PE_sleb128, 0, p, val); | |
258 | } |