]>
Commit | Line | Data |
---|---|---|
74bd2300 | 1 | /* Exception handling and frame unwind runtime interface routines. |
04277e02 | 2 | Copyright (C) 2001-2019 Free Software Foundation, Inc. |
74bd2300 | 3 | |
df5fd414 RM |
4 | This file is part of the GNU C Library. |
5 | ||
6 | The GNU C Library is free software; you can redistribute it and/or | |
7 | modify it under the terms of the GNU Lesser General Public | |
8 | License as published by the Free Software Foundation; either | |
9 | version 2.1 of the License, or (at your option) any later version. | |
10 | ||
11 | The GNU C Library 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 GNU | |
14 | Lesser General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU Lesser General Public | |
59ba27a6 | 17 | License along with the GNU C Library; if not, see |
5a82c748 | 18 | <https://www.gnu.org/licenses/>. */ |
74bd2300 UD |
19 | |
20 | /* @@@ Really this should be out of line, but this also causes link | |
21 | compatibility problems with the base ABI. This is slightly better | |
22 | than duplicating code, however. */ | |
23 | ||
6180ac2f | 24 | /* If using C++, references to abort have to be qualified with std::. */ |
6680738a | 25 | #ifdef __cplusplus |
74bd2300 UD |
26 | #define __gxx_abort std::abort |
27 | #else | |
28 | #define __gxx_abort abort | |
29 | #endif | |
30 | ||
31 | /* Pointer encodings, from dwarf2.h. */ | |
32 | #define DW_EH_PE_absptr 0x00 | |
33 | #define DW_EH_PE_omit 0xff | |
34 | ||
35 | #define DW_EH_PE_uleb128 0x01 | |
36 | #define DW_EH_PE_udata2 0x02 | |
37 | #define DW_EH_PE_udata4 0x03 | |
38 | #define DW_EH_PE_udata8 0x04 | |
39 | #define DW_EH_PE_sleb128 0x09 | |
40 | #define DW_EH_PE_sdata2 0x0A | |
41 | #define DW_EH_PE_sdata4 0x0B | |
42 | #define DW_EH_PE_sdata8 0x0C | |
43 | #define DW_EH_PE_signed 0x08 | |
44 | ||
45 | #define DW_EH_PE_pcrel 0x10 | |
46 | #define DW_EH_PE_textrel 0x20 | |
47 | #define DW_EH_PE_datarel 0x30 | |
48 | #define DW_EH_PE_funcrel 0x40 | |
49 | #define DW_EH_PE_aligned 0x50 | |
50 | ||
51 | #define DW_EH_PE_indirect 0x80 | |
52 | \f | |
53 | ||
78678039 UD |
54 | #if defined(_LIBC) |
55 | ||
7f0244de | 56 | /* Prototypes. */ |
78678039 UD |
57 | extern unsigned int size_of_encoded_value (unsigned char encoding) |
58 | attribute_hidden; | |
59 | ||
7f0244de AJ |
60 | extern const unsigned char *read_encoded_value_with_base |
61 | (unsigned char encoding, _Unwind_Ptr base, | |
78678039 UD |
62 | const unsigned char *p, _Unwind_Ptr *val) |
63 | attribute_hidden; | |
64 | ||
65 | extern const unsigned char * read_encoded_value | |
66 | (struct _Unwind_Context *context, unsigned char encoding, | |
67 | const unsigned char *p, _Unwind_Ptr *val) | |
68 | attribute_hidden; | |
7f0244de | 69 | |
78678039 UD |
70 | extern const unsigned char * read_uleb128 (const unsigned char *p, |
71 | _Unwind_Word *val) | |
72 | attribute_hidden; | |
73 | extern const unsigned char * read_sleb128 (const unsigned char *p, | |
74 | _Unwind_Sword *val) | |
75 | attribute_hidden; | |
76 | ||
77 | #endif | |
78 | #if defined(_LIBC) && defined(_LIBC_DEFINITIONS) | |
79 | ||
80 | #ifdef _LIBC | |
81 | #define STATIC | |
06c15096 | 82 | #else |
78678039 UD |
83 | #define STATIC static |
84 | #endif | |
7f0244de | 85 | |
74bd2300 UD |
86 | /* Given an encoding, return the number of bytes the format occupies. |
87 | This is only defined for fixed-size encodings, and so does not | |
88 | include leb128. */ | |
89 | ||
78678039 | 90 | STATIC unsigned int |
74bd2300 | 91 | size_of_encoded_value (unsigned char encoding) |
74bd2300 UD |
92 | { |
93 | if (encoding == DW_EH_PE_omit) | |
94 | return 0; | |
95 | ||
96 | switch (encoding & 0x07) | |
97 | { | |
98 | case DW_EH_PE_absptr: | |
99 | return sizeof (void *); | |
100 | case DW_EH_PE_udata2: | |
101 | return 2; | |
102 | case DW_EH_PE_udata4: | |
103 | return 4; | |
104 | case DW_EH_PE_udata8: | |
105 | return 8; | |
106 | } | |
107 | __gxx_abort (); | |
108 | } | |
74bd2300 UD |
109 | |
110 | #ifndef NO_BASE_OF_ENCODED_VALUE | |
111 | ||
112 | /* Given an encoding and an _Unwind_Context, return the base to which | |
113 | the encoding is relative. This base may then be passed to | |
114 | read_encoded_value_with_base for use when the _Unwind_Context is | |
115 | not available. */ | |
116 | ||
78678039 | 117 | STATIC _Unwind_Ptr |
74bd2300 UD |
118 | base_of_encoded_value (unsigned char encoding, struct _Unwind_Context *context) |
119 | { | |
120 | if (encoding == DW_EH_PE_omit) | |
121 | return 0; | |
122 | ||
123 | switch (encoding & 0x70) | |
124 | { | |
125 | case DW_EH_PE_absptr: | |
126 | case DW_EH_PE_pcrel: | |
127 | case DW_EH_PE_aligned: | |
128 | return 0; | |
129 | ||
130 | case DW_EH_PE_textrel: | |
131 | return _Unwind_GetTextRelBase (context); | |
132 | case DW_EH_PE_datarel: | |
133 | return _Unwind_GetDataRelBase (context); | |
134 | case DW_EH_PE_funcrel: | |
135 | return _Unwind_GetRegionStart (context); | |
136 | } | |
137 | __gxx_abort (); | |
138 | } | |
139 | ||
140 | #endif | |
141 | ||
6180ac2f UD |
142 | /* Read an unsigned leb128 value from P, store the value in VAL, return |
143 | P incremented past the value. We assume that a word is large enough to | |
144 | hold any value so encoded; if it is smaller than a pointer on some target, | |
145 | pointers should not be leb128 encoded on that target. */ | |
146 | ||
78678039 | 147 | STATIC const unsigned char * |
6180ac2f UD |
148 | read_uleb128 (const unsigned char *p, _Unwind_Word *val) |
149 | { | |
150 | unsigned int shift = 0; | |
151 | unsigned char byte; | |
152 | _Unwind_Word result; | |
153 | ||
154 | result = 0; | |
155 | do | |
156 | { | |
157 | byte = *p++; | |
158 | result |= (byte & 0x7f) << shift; | |
159 | shift += 7; | |
160 | } | |
161 | while (byte & 0x80); | |
162 | ||
163 | *val = result; | |
164 | return p; | |
165 | } | |
166 | ||
167 | /* Similar, but read a signed leb128 value. */ | |
168 | ||
78678039 | 169 | STATIC const unsigned char * |
6180ac2f UD |
170 | read_sleb128 (const unsigned char *p, _Unwind_Sword *val) |
171 | { | |
172 | unsigned int shift = 0; | |
173 | unsigned char byte; | |
174 | _Unwind_Word result; | |
175 | ||
176 | result = 0; | |
177 | do | |
178 | { | |
179 | byte = *p++; | |
180 | result |= (byte & 0x7f) << shift; | |
181 | shift += 7; | |
182 | } | |
183 | while (byte & 0x80); | |
184 | ||
185 | /* Sign-extend a negative value. */ | |
c4f50205 | 186 | if (shift < 8 * sizeof (result) && (byte & 0x40) != 0) |
6180ac2f UD |
187 | result |= -(1L << shift); |
188 | ||
189 | *val = (_Unwind_Sword) result; | |
190 | return p; | |
191 | } | |
192 | ||
74bd2300 UD |
193 | /* Load an encoded value from memory at P. The value is returned in VAL; |
194 | The function returns P incremented past the value. BASE is as given | |
195 | by base_of_encoded_value for this encoding in the appropriate context. */ | |
196 | ||
78678039 | 197 | STATIC const unsigned char * |
74bd2300 UD |
198 | read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base, |
199 | const unsigned char *p, _Unwind_Ptr *val) | |
74bd2300 UD |
200 | { |
201 | union unaligned | |
202 | { | |
203 | void *ptr; | |
204 | unsigned u2 __attribute__ ((mode (HI))); | |
205 | unsigned u4 __attribute__ ((mode (SI))); | |
206 | unsigned u8 __attribute__ ((mode (DI))); | |
207 | signed s2 __attribute__ ((mode (HI))); | |
208 | signed s4 __attribute__ ((mode (SI))); | |
209 | signed s8 __attribute__ ((mode (DI))); | |
210 | } __attribute__((__packed__)); | |
211 | ||
212 | union unaligned *u = (union unaligned *) p; | |
6180ac2f | 213 | _Unwind_Internal_Ptr result; |
74bd2300 UD |
214 | |
215 | if (encoding == DW_EH_PE_aligned) | |
216 | { | |
6180ac2f | 217 | _Unwind_Internal_Ptr a = (_Unwind_Internal_Ptr) p; |
c4f50205 | 218 | a = (a + sizeof (void *) - 1) & - sizeof (void *); |
6180ac2f UD |
219 | result = *(_Unwind_Internal_Ptr *) a; |
220 | p = (const unsigned char *) (a + sizeof (void *)); | |
74bd2300 UD |
221 | } |
222 | else | |
223 | { | |
224 | switch (encoding & 0x0f) | |
225 | { | |
226 | case DW_EH_PE_absptr: | |
6180ac2f | 227 | result = (_Unwind_Internal_Ptr) u->ptr; |
74bd2300 UD |
228 | p += sizeof (void *); |
229 | break; | |
230 | ||
231 | case DW_EH_PE_uleb128: | |
232 | { | |
6180ac2f UD |
233 | _Unwind_Word tmp; |
234 | p = read_uleb128 (p, &tmp); | |
235 | result = (_Unwind_Internal_Ptr) tmp; | |
74bd2300 UD |
236 | } |
237 | break; | |
238 | ||
239 | case DW_EH_PE_sleb128: | |
240 | { | |
6180ac2f UD |
241 | _Unwind_Sword tmp; |
242 | p = read_sleb128 (p, &tmp); | |
243 | result = (_Unwind_Internal_Ptr) tmp; | |
74bd2300 UD |
244 | } |
245 | break; | |
246 | ||
247 | case DW_EH_PE_udata2: | |
248 | result = u->u2; | |
249 | p += 2; | |
250 | break; | |
251 | case DW_EH_PE_udata4: | |
252 | result = u->u4; | |
253 | p += 4; | |
254 | break; | |
255 | case DW_EH_PE_udata8: | |
256 | result = u->u8; | |
257 | p += 8; | |
258 | break; | |
259 | ||
260 | case DW_EH_PE_sdata2: | |
261 | result = u->s2; | |
262 | p += 2; | |
263 | break; | |
264 | case DW_EH_PE_sdata4: | |
265 | result = u->s4; | |
266 | p += 4; | |
267 | break; | |
268 | case DW_EH_PE_sdata8: | |
269 | result = u->s8; | |
270 | p += 8; | |
271 | break; | |
272 | ||
273 | default: | |
274 | __gxx_abort (); | |
275 | } | |
276 | ||
277 | if (result != 0) | |
278 | { | |
279 | result += ((encoding & 0x70) == DW_EH_PE_pcrel | |
6180ac2f | 280 | ? (_Unwind_Internal_Ptr) u : base); |
74bd2300 | 281 | if (encoding & DW_EH_PE_indirect) |
6180ac2f | 282 | result = *(_Unwind_Internal_Ptr *) result; |
74bd2300 UD |
283 | } |
284 | } | |
285 | ||
286 | *val = result; | |
287 | return p; | |
288 | } | |
74bd2300 UD |
289 | |
290 | #ifndef NO_BASE_OF_ENCODED_VALUE | |
291 | ||
292 | /* Like read_encoded_value_with_base, but get the base from the context | |
293 | rather than providing it directly. */ | |
294 | ||
78678039 | 295 | STATIC const unsigned char * |
74bd2300 UD |
296 | read_encoded_value (struct _Unwind_Context *context, unsigned char encoding, |
297 | const unsigned char *p, _Unwind_Ptr *val) | |
298 | { | |
299 | return read_encoded_value_with_base (encoding, | |
300 | base_of_encoded_value (encoding, context), | |
301 | p, val); | |
302 | } | |
303 | ||
304 | #endif | |
78678039 | 305 | #endif /* _LIBC */ |