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