/src/llvm-project-18.1.8.src/libcxxabi/src/cxa_personality.cpp
Line | Count | Source |
1 | | //===----------------------------------------------------------------------===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | // |
8 | | // This file implements the "Exception Handling APIs" |
9 | | // https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html |
10 | | // http://www.intel.com/design/itanium/downloads/245358.htm |
11 | | // |
12 | | //===----------------------------------------------------------------------===// |
13 | | |
14 | | #include <assert.h> |
15 | | #include <stdlib.h> |
16 | | #include <string.h> |
17 | | #include <typeinfo> |
18 | | |
19 | | #include "__cxxabi_config.h" |
20 | | #include "cxa_exception.h" |
21 | | #include "cxa_handlers.h" |
22 | | #include "private_typeinfo.h" |
23 | | #include "unwind.h" |
24 | | |
25 | | // TODO: This is a temporary workaround for libc++abi to recognize that it's being |
26 | | // built against LLVM's libunwind. LLVM's libunwind started reporting _LIBUNWIND_VERSION |
27 | | // in LLVM 15 -- we can remove this workaround after shipping LLVM 17. Once we remove |
28 | | // this workaround, it won't be possible to build libc++abi against libunwind headers |
29 | | // from LLVM 14 and before anymore. |
30 | | #if defined(____LIBUNWIND_CONFIG_H__) && !defined(_LIBUNWIND_VERSION) |
31 | | # define _LIBUNWIND_VERSION |
32 | | #endif |
33 | | |
34 | | #if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) |
35 | | #include <windows.h> |
36 | | #include <winnt.h> |
37 | | |
38 | | extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, |
39 | | void *, PCONTEXT, |
40 | | PDISPATCHER_CONTEXT, |
41 | | _Unwind_Personality_Fn); |
42 | | #endif |
43 | | |
44 | | /* |
45 | | Exception Header Layout: |
46 | | |
47 | | +---------------------------+-----------------------------+---------------+ |
48 | | | __cxa_exception | _Unwind_Exception CLNGC++\0 | thrown object | |
49 | | +---------------------------+-----------------------------+---------------+ |
50 | | ^ |
51 | | | |
52 | | +-------------------------------------------------------+ |
53 | | | |
54 | | +---------------------------+-----------------------------+ |
55 | | | __cxa_dependent_exception | _Unwind_Exception CLNGC++\1 | |
56 | | +---------------------------+-----------------------------+ |
57 | | |
58 | | Exception Handling Table Layout: |
59 | | |
60 | | +-----------------+--------+ |
61 | | | lpStartEncoding | (char) | |
62 | | +---------+-------+--------+---------------+-----------------------+ |
63 | | | lpStart | (encoded with lpStartEncoding) | defaults to funcStart | |
64 | | +---------+-----+--------+-----------------+---------------+-------+ |
65 | | | ttypeEncoding | (char) | Encoding of the type_info table | |
66 | | +---------------+-+------+----+----------------------------+----------------+ |
67 | | | classInfoOffset | (ULEB128) | Offset to type_info table, defaults to null | |
68 | | +-----------------++--------+-+----------------------------+----------------+ |
69 | | | callSiteEncoding | (char) | Encoding for Call Site Table | |
70 | | +------------------+--+-----+-----+------------------------+--------------------------+ |
71 | | | callSiteTableLength | (ULEB128) | Call Site Table length, used to find Action table | |
72 | | +---------------------+-----------+---------------------------------------------------+ |
73 | | #if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__USING_WASM_EXCEPTIONS__) |
74 | | +---------------------+-----------+------------------------------------------------+ |
75 | | | Beginning of Call Site Table The current ip lies within the | |
76 | | | ... (start, length) range of one of these | |
77 | | | call sites. There may be action needed. | |
78 | | | +-------------+---------------------------------+------------------------------+ | |
79 | | | | start | (encoded with callSiteEncoding) | offset relative to funcStart | | |
80 | | | | length | (encoded with callSiteEncoding) | length of code fragment | | |
81 | | | | landingPad | (encoded with callSiteEncoding) | offset relative to lpStart | | |
82 | | | | actionEntry | (ULEB128) | Action Table Index 1-based | | |
83 | | | | | | actionEntry == 0 -> cleanup | | |
84 | | | +-------------+---------------------------------+------------------------------+ | |
85 | | | ... | |
86 | | +----------------------------------------------------------------------------------+ |
87 | | #else // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__ |
88 | | +---------------------+-----------+------------------------------------------------+ |
89 | | | Beginning of Call Site Table The current ip is a 1-based index into | |
90 | | | ... this table. Or it is -1 meaning no | |
91 | | | action is needed. Or it is 0 meaning | |
92 | | | terminate. | |
93 | | | +-------------+---------------------------------+------------------------------+ | |
94 | | | | landingPad | (ULEB128) | offset relative to lpStart | | |
95 | | | | actionEntry | (ULEB128) | Action Table Index 1-based | | |
96 | | | | | | actionEntry == 0 -> cleanup | | |
97 | | | +-------------+---------------------------------+------------------------------+ | |
98 | | | ... | |
99 | | +----------------------------------------------------------------------------------+ |
100 | | #endif // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__ |
101 | | +---------------------------------------------------------------------+ |
102 | | | Beginning of Action Table ttypeIndex == 0 : cleanup | |
103 | | | ... ttypeIndex > 0 : catch | |
104 | | | ttypeIndex < 0 : exception spec | |
105 | | | +--------------+-----------+--------------------------------------+ | |
106 | | | | ttypeIndex | (SLEB128) | Index into type_info Table (1-based) | | |
107 | | | | actionOffset | (SLEB128) | Offset into next Action Table entry | | |
108 | | | +--------------+-----------+--------------------------------------+ | |
109 | | | ... | |
110 | | +---------------------------------------------------------------------+-----------------+ |
111 | | | type_info Table, but classInfoOffset does *not* point here! | |
112 | | | +----------------+------------------------------------------------+-----------------+ | |
113 | | | | Nth type_info* | Encoded with ttypeEncoding, 0 means catch(...) | ttypeIndex == N | | |
114 | | | +----------------+------------------------------------------------+-----------------+ | |
115 | | | ... | |
116 | | | +----------------+------------------------------------------------+-----------------+ | |
117 | | | | 1st type_info* | Encoded with ttypeEncoding, 0 means catch(...) | ttypeIndex == 1 | | |
118 | | | +----------------+------------------------------------------------+-----------------+ | |
119 | | | +---------------------------------------+-----------+------------------------------+ | |
120 | | | | 1st ttypeIndex for 1st exception spec | (ULEB128) | classInfoOffset points here! | | |
121 | | | | ... | (ULEB128) | | | |
122 | | | | Mth ttypeIndex for 1st exception spec | (ULEB128) | | | |
123 | | | | 0 | (ULEB128) | | | |
124 | | | +---------------------------------------+------------------------------------------+ | |
125 | | | ... | |
126 | | | +---------------------------------------+------------------------------------------+ | |
127 | | | | 0 | (ULEB128) | throw() | | |
128 | | | +---------------------------------------+------------------------------------------+ | |
129 | | | ... | |
130 | | | +---------------------------------------+------------------------------------------+ | |
131 | | | | 1st ttypeIndex for Nth exception spec | (ULEB128) | | | |
132 | | | | ... | (ULEB128) | | | |
133 | | | | Mth ttypeIndex for Nth exception spec | (ULEB128) | | | |
134 | | | | 0 | (ULEB128) | | | |
135 | | | +---------------------------------------+------------------------------------------+ | |
136 | | +---------------------------------------------------------------------------------------+ |
137 | | |
138 | | Notes: |
139 | | |
140 | | * ttypeIndex in the Action Table, and in the exception spec table, is an index, |
141 | | not a byte count, if positive. It is a negative index offset of |
142 | | classInfoOffset and the sizeof entry depends on ttypeEncoding. |
143 | | But if ttypeIndex is negative, it is a positive 1-based byte offset into the |
144 | | type_info Table. |
145 | | And if ttypeIndex is zero, it refers to a catch (...). |
146 | | |
147 | | * landingPad can be 0, this implies there is nothing to be done. |
148 | | |
149 | | * landingPad != 0 and actionEntry == 0 implies a cleanup needs to be done |
150 | | @landingPad. |
151 | | |
152 | | * A cleanup can also be found under landingPad != 0 and actionEntry != 0 in |
153 | | the Action Table with ttypeIndex == 0. |
154 | | */ |
155 | | |
156 | | namespace __cxxabiv1 |
157 | | { |
158 | | |
159 | | namespace |
160 | | { |
161 | | |
162 | | template <class AsType> |
163 | 2.79M | uintptr_t readPointerHelper(const uint8_t*& p) { |
164 | 2.79M | AsType value; |
165 | 2.79M | memcpy(&value, p, sizeof(AsType)); |
166 | 2.79M | p += sizeof(AsType); |
167 | 2.79M | return static_cast<uintptr_t>(value); |
168 | 2.79M | } Unexecuted instantiation: cxa_personality.cpp:unsigned long __cxxabiv1::(anonymous namespace)::readPointerHelper<unsigned long>(unsigned char const*&) Unexecuted instantiation: cxa_personality.cpp:unsigned long __cxxabiv1::(anonymous namespace)::readPointerHelper<unsigned short>(unsigned char const*&) Unexecuted instantiation: cxa_personality.cpp:unsigned long __cxxabiv1::(anonymous namespace)::readPointerHelper<unsigned int>(unsigned char const*&) Unexecuted instantiation: cxa_personality.cpp:unsigned long __cxxabiv1::(anonymous namespace)::readPointerHelper<short>(unsigned char const*&) cxa_personality.cpp:unsigned long __cxxabiv1::(anonymous namespace)::readPointerHelper<int>(unsigned char const*&) Line | Count | Source | 163 | 2.79M | uintptr_t readPointerHelper(const uint8_t*& p) { | 164 | 2.79M | AsType value; | 165 | 2.79M | memcpy(&value, p, sizeof(AsType)); | 166 | 2.79M | p += sizeof(AsType); | 167 | 2.79M | return static_cast<uintptr_t>(value); | 168 | 2.79M | } |
Unexecuted instantiation: cxa_personality.cpp:unsigned long __cxxabiv1::(anonymous namespace)::readPointerHelper<long>(unsigned char const*&) |
169 | | |
170 | | } // end namespace |
171 | | |
172 | | extern "C" |
173 | | { |
174 | | |
175 | | // private API |
176 | | |
177 | | // Heavily borrowed from llvm/examples/ExceptionDemo/ExceptionDemo.cpp |
178 | | |
179 | | // DWARF Constants |
180 | | enum |
181 | | { |
182 | | DW_EH_PE_absptr = 0x00, |
183 | | DW_EH_PE_uleb128 = 0x01, |
184 | | DW_EH_PE_udata2 = 0x02, |
185 | | DW_EH_PE_udata4 = 0x03, |
186 | | DW_EH_PE_udata8 = 0x04, |
187 | | DW_EH_PE_sleb128 = 0x09, |
188 | | DW_EH_PE_sdata2 = 0x0A, |
189 | | DW_EH_PE_sdata4 = 0x0B, |
190 | | DW_EH_PE_sdata8 = 0x0C, |
191 | | DW_EH_PE_pcrel = 0x10, |
192 | | DW_EH_PE_textrel = 0x20, |
193 | | DW_EH_PE_datarel = 0x30, |
194 | | DW_EH_PE_funcrel = 0x40, |
195 | | DW_EH_PE_aligned = 0x50, |
196 | | DW_EH_PE_indirect = 0x80, |
197 | | DW_EH_PE_omit = 0xFF |
198 | | }; |
199 | | |
200 | | /// Read a uleb128 encoded value and advance pointer |
201 | | /// See Variable Length Data Appendix C in: |
202 | | /// @link http://dwarfstd.org/Dwarf4.pdf @unlink |
203 | | /// @param data reference variable holding memory pointer to decode from |
204 | | /// @returns decoded value |
205 | | static |
206 | | uintptr_t |
207 | | readULEB128(const uint8_t** data) |
208 | 235M | { |
209 | 235M | uintptr_t result = 0; |
210 | 235M | uintptr_t shift = 0; |
211 | 235M | unsigned char byte; |
212 | 235M | const uint8_t *p = *data; |
213 | 235M | do |
214 | 329M | { |
215 | 329M | byte = *p++; |
216 | 329M | result |= static_cast<uintptr_t>(byte & 0x7F) << shift; |
217 | 329M | shift += 7; |
218 | 329M | } while (byte & 0x80); |
219 | 235M | *data = p; |
220 | 235M | return result; |
221 | 235M | } |
222 | | |
223 | | /// Read a sleb128 encoded value and advance pointer |
224 | | /// See Variable Length Data Appendix C in: |
225 | | /// @link http://dwarfstd.org/Dwarf4.pdf @unlink |
226 | | /// @param data reference variable holding memory pointer to decode from |
227 | | /// @returns decoded value |
228 | | static |
229 | | intptr_t |
230 | | readSLEB128(const uint8_t** data) |
231 | 3.53M | { |
232 | 3.53M | uintptr_t result = 0; |
233 | 3.53M | uintptr_t shift = 0; |
234 | 3.53M | unsigned char byte; |
235 | 3.53M | const uint8_t *p = *data; |
236 | 3.53M | do |
237 | 3.53M | { |
238 | 3.53M | byte = *p++; |
239 | 3.53M | result |= static_cast<uintptr_t>(byte & 0x7F) << shift; |
240 | 3.53M | shift += 7; |
241 | 3.53M | } while (byte & 0x80); |
242 | 3.53M | *data = p; |
243 | 3.53M | if ((byte & 0x40) && (shift < (sizeof(result) << 3))) |
244 | 396k | result |= static_cast<uintptr_t>(~0) << shift; |
245 | 3.53M | return static_cast<intptr_t>(result); |
246 | 3.53M | } |
247 | | |
248 | | /// Read a pointer encoded value and advance pointer |
249 | | /// See Variable Length Data in: |
250 | | /// @link http://dwarfstd.org/Dwarf3.pdf @unlink |
251 | | /// @param data reference variable holding memory pointer to decode from |
252 | | /// @param encoding dwarf encoding type |
253 | | /// @param base for adding relative offset, default to 0 |
254 | | /// @returns decoded value |
255 | | static |
256 | | uintptr_t |
257 | | readEncodedPointer(const uint8_t** data, uint8_t encoding, uintptr_t base = 0) |
258 | 168M | { |
259 | 168M | uintptr_t result = 0; |
260 | 168M | if (encoding == DW_EH_PE_omit) |
261 | 0 | return result; |
262 | 168M | const uint8_t* p = *data; |
263 | | // first get value |
264 | 168M | switch (encoding & 0x0F) |
265 | 168M | { |
266 | 0 | case DW_EH_PE_absptr: |
267 | 0 | result = readPointerHelper<uintptr_t>(p); |
268 | 0 | break; |
269 | 165M | case DW_EH_PE_uleb128: |
270 | 165M | result = readULEB128(&p); |
271 | 165M | break; |
272 | 0 | case DW_EH_PE_sleb128: |
273 | 0 | result = static_cast<uintptr_t>(readSLEB128(&p)); |
274 | 0 | break; |
275 | 0 | case DW_EH_PE_udata2: |
276 | 0 | result = readPointerHelper<uint16_t>(p); |
277 | 0 | break; |
278 | 0 | case DW_EH_PE_udata4: |
279 | 0 | result = readPointerHelper<uint32_t>(p); |
280 | 0 | break; |
281 | 0 | case DW_EH_PE_udata8: |
282 | 0 | result = readPointerHelper<uint64_t>(p); |
283 | 0 | break; |
284 | 0 | case DW_EH_PE_sdata2: |
285 | 0 | result = readPointerHelper<int16_t>(p); |
286 | 0 | break; |
287 | 2.79M | case DW_EH_PE_sdata4: |
288 | 2.79M | result = readPointerHelper<int32_t>(p); |
289 | 2.79M | break; |
290 | 0 | case DW_EH_PE_sdata8: |
291 | 0 | result = readPointerHelper<int64_t>(p); |
292 | 0 | break; |
293 | 0 | default: |
294 | | // not supported |
295 | 0 | abort(); |
296 | 0 | break; |
297 | 168M | } |
298 | | // then add relative offset |
299 | 168M | switch (encoding & 0x70) |
300 | 168M | { |
301 | 165M | case DW_EH_PE_absptr: |
302 | | // do nothing |
303 | 165M | break; |
304 | 2.79M | case DW_EH_PE_pcrel: |
305 | 2.79M | if (result) |
306 | 2.79M | result += (uintptr_t)(*data); |
307 | 2.79M | break; |
308 | 0 | case DW_EH_PE_datarel: |
309 | 0 | assert((base != 0) && "DW_EH_PE_datarel is invalid with a base of 0"); |
310 | 0 | if (result) |
311 | 0 | result += base; |
312 | 0 | break; |
313 | 0 | case DW_EH_PE_textrel: |
314 | 0 | case DW_EH_PE_funcrel: |
315 | 0 | case DW_EH_PE_aligned: |
316 | 0 | default: |
317 | | // not supported |
318 | 0 | abort(); |
319 | 0 | break; |
320 | 168M | } |
321 | | // then apply indirection |
322 | 168M | if (result && (encoding & DW_EH_PE_indirect)) |
323 | 2.79M | result = *((uintptr_t*)result); |
324 | 168M | *data = p; |
325 | 168M | return result; |
326 | 168M | } |
327 | | |
328 | | static |
329 | | void |
330 | | call_terminate(bool native_exception, _Unwind_Exception* unwind_exception) |
331 | 0 | { |
332 | 0 | __cxa_begin_catch(unwind_exception); |
333 | 0 | if (native_exception) |
334 | 0 | { |
335 | | // Use the stored terminate_handler if possible |
336 | 0 | __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; |
337 | 0 | std::__terminate(exception_header->terminateHandler); |
338 | 0 | } |
339 | 0 | std::terminate(); |
340 | 0 | } |
341 | | |
342 | | #if defined(_LIBCXXABI_ARM_EHABI) |
343 | | static const void* read_target2_value(const void* ptr) |
344 | | { |
345 | | uintptr_t offset = *reinterpret_cast<const uintptr_t*>(ptr); |
346 | | if (!offset) |
347 | | return 0; |
348 | | // "ARM EABI provides a TARGET2 relocation to describe these typeinfo |
349 | | // pointers. The reason being it allows their precise semantics to be |
350 | | // deferred to the linker. For bare-metal they turn into absolute |
351 | | // relocations. For linux they turn into GOT-REL relocations." |
352 | | // https://gcc.gnu.org/ml/gcc-patches/2009-08/msg00264.html |
353 | | #if defined(LIBCXXABI_BAREMETAL) |
354 | | return reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(ptr) + |
355 | | offset); |
356 | | #else |
357 | | return *reinterpret_cast<const void **>(reinterpret_cast<uintptr_t>(ptr) + |
358 | | offset); |
359 | | #endif |
360 | | } |
361 | | |
362 | | static const __shim_type_info* |
363 | | get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo, |
364 | | uint8_t ttypeEncoding, bool native_exception, |
365 | | _Unwind_Exception* unwind_exception, uintptr_t /*base*/ = 0) |
366 | | { |
367 | | if (classInfo == 0) |
368 | | { |
369 | | // this should not happen. Indicates corrupted eh_table. |
370 | | call_terminate(native_exception, unwind_exception); |
371 | | } |
372 | | |
373 | | assert(((ttypeEncoding == DW_EH_PE_absptr) || // LLVM or GCC 4.6 |
374 | | (ttypeEncoding == DW_EH_PE_pcrel) || // GCC 4.7 baremetal |
375 | | (ttypeEncoding == (DW_EH_PE_pcrel | DW_EH_PE_indirect))) && // GCC 4.7 linux |
376 | | "Unexpected TTypeEncoding"); |
377 | | (void)ttypeEncoding; |
378 | | |
379 | | const uint8_t* ttypePtr = classInfo - ttypeIndex * sizeof(uintptr_t); |
380 | | return reinterpret_cast<const __shim_type_info *>( |
381 | | read_target2_value(ttypePtr)); |
382 | | } |
383 | | #else // !defined(_LIBCXXABI_ARM_EHABI) |
384 | | static |
385 | | const __shim_type_info* |
386 | | get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo, |
387 | | uint8_t ttypeEncoding, bool native_exception, |
388 | | _Unwind_Exception* unwind_exception, uintptr_t base = 0) |
389 | 2.79M | { |
390 | 2.79M | if (classInfo == 0) |
391 | 0 | { |
392 | | // this should not happen. Indicates corrupted eh_table. |
393 | 0 | call_terminate(native_exception, unwind_exception); |
394 | 0 | } |
395 | 2.79M | switch (ttypeEncoding & 0x0F) |
396 | 2.79M | { |
397 | 0 | case DW_EH_PE_absptr: |
398 | 0 | ttypeIndex *= sizeof(void*); |
399 | 0 | break; |
400 | 0 | case DW_EH_PE_udata2: |
401 | 0 | case DW_EH_PE_sdata2: |
402 | 0 | ttypeIndex *= 2; |
403 | 0 | break; |
404 | 0 | case DW_EH_PE_udata4: |
405 | 2.79M | case DW_EH_PE_sdata4: |
406 | 2.79M | ttypeIndex *= 4; |
407 | 2.79M | break; |
408 | 0 | case DW_EH_PE_udata8: |
409 | 0 | case DW_EH_PE_sdata8: |
410 | 0 | ttypeIndex *= 8; |
411 | 0 | break; |
412 | 0 | default: |
413 | | // this should not happen. Indicates corrupted eh_table. |
414 | 0 | call_terminate(native_exception, unwind_exception); |
415 | 2.79M | } |
416 | 2.79M | classInfo -= ttypeIndex; |
417 | 2.79M | return (const __shim_type_info*)readEncodedPointer(&classInfo, |
418 | 2.79M | ttypeEncoding, base); |
419 | 2.79M | } |
420 | | #endif // !defined(_LIBCXXABI_ARM_EHABI) |
421 | | |
422 | | /* |
423 | | This is checking a thrown exception type, excpType, against a possibly empty |
424 | | list of catchType's which make up an exception spec. |
425 | | |
426 | | An exception spec acts like a catch handler, but in reverse. This "catch |
427 | | handler" will catch an excpType if and only if none of the catchType's in |
428 | | the list will catch a excpType. If any catchType in the list can catch an |
429 | | excpType, then this exception spec does not catch the excpType. |
430 | | */ |
431 | | #if defined(_LIBCXXABI_ARM_EHABI) |
432 | | static |
433 | | bool |
434 | | exception_spec_can_catch(int64_t specIndex, const uint8_t* classInfo, |
435 | | uint8_t ttypeEncoding, const __shim_type_info* excpType, |
436 | | void* adjustedPtr, _Unwind_Exception* unwind_exception, |
437 | | uintptr_t /*base*/ = 0) |
438 | | { |
439 | | if (classInfo == 0) |
440 | | { |
441 | | // this should not happen. Indicates corrupted eh_table. |
442 | | call_terminate(false, unwind_exception); |
443 | | } |
444 | | |
445 | | assert(((ttypeEncoding == DW_EH_PE_absptr) || // LLVM or GCC 4.6 |
446 | | (ttypeEncoding == DW_EH_PE_pcrel) || // GCC 4.7 baremetal |
447 | | (ttypeEncoding == (DW_EH_PE_pcrel | DW_EH_PE_indirect))) && // GCC 4.7 linux |
448 | | "Unexpected TTypeEncoding"); |
449 | | (void)ttypeEncoding; |
450 | | |
451 | | // specIndex is negative of 1-based byte offset into classInfo; |
452 | | specIndex = -specIndex; |
453 | | --specIndex; |
454 | | const void** temp = reinterpret_cast<const void**>( |
455 | | reinterpret_cast<uintptr_t>(classInfo) + |
456 | | static_cast<uintptr_t>(specIndex) * sizeof(uintptr_t)); |
457 | | // If any type in the spec list can catch excpType, return false, else return true |
458 | | // adjustments to adjustedPtr are ignored. |
459 | | while (true) |
460 | | { |
461 | | // ARM EHABI exception specification table (filter table) consists of |
462 | | // several pointers which will directly point to the type info object |
463 | | // (instead of ttypeIndex). The table will be terminated with 0. |
464 | | const void** ttypePtr = temp++; |
465 | | if (*ttypePtr == 0) |
466 | | break; |
467 | | // We can get the __shim_type_info simply by performing a |
468 | | // R_ARM_TARGET2 relocation, and cast the result to __shim_type_info. |
469 | | const __shim_type_info* catchType = |
470 | | static_cast<const __shim_type_info*>(read_target2_value(ttypePtr)); |
471 | | void* tempPtr = adjustedPtr; |
472 | | if (catchType->can_catch(excpType, tempPtr)) |
473 | | return false; |
474 | | } |
475 | | return true; |
476 | | } |
477 | | #else |
478 | | static |
479 | | bool |
480 | | exception_spec_can_catch(int64_t specIndex, const uint8_t* classInfo, |
481 | | uint8_t ttypeEncoding, const __shim_type_info* excpType, |
482 | | void* adjustedPtr, _Unwind_Exception* unwind_exception, |
483 | | uintptr_t base = 0) |
484 | 0 | { |
485 | 0 | if (classInfo == 0) |
486 | 0 | { |
487 | | // this should not happen. Indicates corrupted eh_table. |
488 | 0 | call_terminate(false, unwind_exception); |
489 | 0 | } |
490 | | // specIndex is negative of 1-based byte offset into classInfo; |
491 | 0 | specIndex = -specIndex; |
492 | 0 | --specIndex; |
493 | 0 | const uint8_t* temp = classInfo + specIndex; |
494 | | // If any type in the spec list can catch excpType, return false, else return true |
495 | | // adjustments to adjustedPtr are ignored. |
496 | 0 | while (true) |
497 | 0 | { |
498 | 0 | uint64_t ttypeIndex = readULEB128(&temp); |
499 | 0 | if (ttypeIndex == 0) |
500 | 0 | break; |
501 | 0 | const __shim_type_info* catchType = get_shim_type_info(ttypeIndex, |
502 | 0 | classInfo, |
503 | 0 | ttypeEncoding, |
504 | 0 | true, |
505 | 0 | unwind_exception, |
506 | 0 | base); |
507 | 0 | void* tempPtr = adjustedPtr; |
508 | 0 | if (catchType->can_catch(excpType, tempPtr)) |
509 | 0 | return false; |
510 | 0 | } |
511 | 0 | return true; |
512 | 0 | } |
513 | | #endif |
514 | | |
515 | | static |
516 | | void* |
517 | | get_thrown_object_ptr(_Unwind_Exception* unwind_exception) |
518 | 2.79M | { |
519 | | // Even for foreign exceptions, the exception object is *probably* at unwind_exception + 1 |
520 | | // Regardless, this library is prohibited from touching a foreign exception |
521 | 2.79M | void* adjustedPtr = unwind_exception + 1; |
522 | 2.79M | if (__getExceptionClass(unwind_exception) == kOurDependentExceptionClass) |
523 | 0 | adjustedPtr = ((__cxa_dependent_exception*)adjustedPtr - 1)->primaryException; |
524 | 2.79M | return adjustedPtr; |
525 | 2.79M | } |
526 | | |
527 | | namespace |
528 | | { |
529 | | |
530 | | struct scan_results |
531 | | { |
532 | | int64_t ttypeIndex; // > 0 catch handler, < 0 exception spec handler, == 0 a cleanup |
533 | | const uint8_t* actionRecord; // Currently unused. Retained to ease future maintenance. |
534 | | const uint8_t* languageSpecificData; // Needed only for __cxa_call_unexpected |
535 | | uintptr_t landingPad; // null -> nothing found, else something found |
536 | | void* adjustedPtr; // Used in cxa_exception.cpp |
537 | | _Unwind_Reason_Code reason; // One of _URC_FATAL_PHASE1_ERROR, |
538 | | // _URC_FATAL_PHASE2_ERROR, |
539 | | // _URC_CONTINUE_UNWIND, |
540 | | // _URC_HANDLER_FOUND |
541 | | }; |
542 | | |
543 | | } // unnamed namespace |
544 | | |
545 | | static |
546 | | void |
547 | | set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context, |
548 | | const scan_results& results) |
549 | 3.66M | { |
550 | | #if defined(__USING_SJLJ_EXCEPTIONS__) || defined(__USING_WASM_EXCEPTIONS__) |
551 | | #define __builtin_eh_return_data_regno(regno) regno |
552 | | #elif defined(__ibmxl__) |
553 | | // IBM xlclang++ compiler does not support __builtin_eh_return_data_regno. |
554 | | #define __builtin_eh_return_data_regno(regno) regno + 3 |
555 | | #endif |
556 | 3.66M | _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), |
557 | 3.66M | reinterpret_cast<uintptr_t>(unwind_exception)); |
558 | 3.66M | _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), |
559 | 3.66M | static_cast<uintptr_t>(results.ttypeIndex)); |
560 | 3.66M | _Unwind_SetIP(context, results.landingPad); |
561 | 3.66M | } |
562 | | |
563 | | /* |
564 | | There are 3 types of scans needed: |
565 | | |
566 | | 1. Scan for handler with native or foreign exception. If handler found, |
567 | | save state and return _URC_HANDLER_FOUND, else return _URC_CONTINUE_UNWIND. |
568 | | May also report an error on invalid input. |
569 | | May terminate for invalid exception table. |
570 | | _UA_SEARCH_PHASE |
571 | | |
572 | | 2. Scan for handler with foreign exception. Must return _URC_HANDLER_FOUND, |
573 | | or call terminate. |
574 | | _UA_CLEANUP_PHASE && _UA_HANDLER_FRAME && !native_exception |
575 | | |
576 | | 3. Scan for cleanups. If a handler is found and this isn't forced unwind, |
577 | | then terminate, otherwise ignore the handler and keep looking for cleanup. |
578 | | If a cleanup is found, return _URC_HANDLER_FOUND, else return _URC_CONTINUE_UNWIND. |
579 | | May also report an error on invalid input. |
580 | | May terminate for invalid exception table. |
581 | | _UA_CLEANUP_PHASE && !_UA_HANDLER_FRAME |
582 | | */ |
583 | | |
584 | | static void scan_eh_tab(scan_results &results, _Unwind_Action actions, |
585 | | bool native_exception, |
586 | | _Unwind_Exception *unwind_exception, |
587 | 11.2M | _Unwind_Context *context) { |
588 | | // Initialize results to found nothing but an error |
589 | 11.2M | results.ttypeIndex = 0; |
590 | 11.2M | results.actionRecord = 0; |
591 | 11.2M | results.languageSpecificData = 0; |
592 | 11.2M | results.landingPad = 0; |
593 | 11.2M | results.adjustedPtr = 0; |
594 | 11.2M | results.reason = _URC_FATAL_PHASE1_ERROR; |
595 | | // Check for consistent actions |
596 | 11.2M | if (actions & _UA_SEARCH_PHASE) |
597 | 6.10M | { |
598 | | // Do Phase 1 |
599 | 6.10M | if (actions & (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME | _UA_FORCE_UNWIND)) |
600 | 0 | { |
601 | | // None of these flags should be set during Phase 1 |
602 | | // Client error |
603 | 0 | results.reason = _URC_FATAL_PHASE1_ERROR; |
604 | 0 | return; |
605 | 0 | } |
606 | 6.10M | } |
607 | 5.13M | else if (actions & _UA_CLEANUP_PHASE) |
608 | 5.14M | { |
609 | 5.14M | if ((actions & _UA_HANDLER_FRAME) && (actions & _UA_FORCE_UNWIND)) |
610 | 0 | { |
611 | | // _UA_HANDLER_FRAME should only be set if phase 1 found a handler. |
612 | | // If _UA_FORCE_UNWIND is set, phase 1 shouldn't have happened. |
613 | | // Client error |
614 | 0 | results.reason = _URC_FATAL_PHASE2_ERROR; |
615 | 0 | return; |
616 | 0 | } |
617 | 5.14M | } |
618 | 18.4E | else // Neither _UA_SEARCH_PHASE nor _UA_CLEANUP_PHASE is set |
619 | 18.4E | { |
620 | | // One of these should be set. |
621 | | // Client error |
622 | 18.4E | results.reason = _URC_FATAL_PHASE1_ERROR; |
623 | 18.4E | return; |
624 | 18.4E | } |
625 | | // Start scan by getting exception table address. |
626 | 11.2M | const uint8_t *lsda = (const uint8_t *)_Unwind_GetLanguageSpecificData(context); |
627 | 11.2M | if (lsda == 0) |
628 | 0 | { |
629 | | // There is no exception table |
630 | 0 | results.reason = _URC_CONTINUE_UNWIND; |
631 | 0 | return; |
632 | 0 | } |
633 | 11.2M | results.languageSpecificData = lsda; |
634 | | #if defined(_AIX) |
635 | | uintptr_t base = _Unwind_GetDataRelBase(context); |
636 | | #else |
637 | 11.2M | uintptr_t base = 0; |
638 | 11.2M | #endif |
639 | | // Get the current instruction pointer and offset it before next |
640 | | // instruction in the current frame which threw the exception. |
641 | 11.2M | uintptr_t ip = _Unwind_GetIP(context) - 1; |
642 | | // Get beginning current frame's code (as defined by the |
643 | | // emitted dwarf code) |
644 | 11.2M | uintptr_t funcStart = _Unwind_GetRegionStart(context); |
645 | | #if defined(__USING_SJLJ_EXCEPTIONS__) || defined(__USING_WASM_EXCEPTIONS__) |
646 | | if (ip == uintptr_t(-1)) |
647 | | { |
648 | | // no action |
649 | | results.reason = _URC_CONTINUE_UNWIND; |
650 | | return; |
651 | | } |
652 | | else if (ip == 0) |
653 | | call_terminate(native_exception, unwind_exception); |
654 | | // ip is 1-based index into call site table |
655 | | #else // !__USING_SJLJ_EXCEPTIONS__ && !__USING_WASM_EXCEPTIONS__ |
656 | 11.2M | uintptr_t ipOffset = ip - funcStart; |
657 | 11.2M | #endif // !__USING_SJLJ_EXCEPTIONS__ && !__USING_WASM_EXCEPTIONS__ |
658 | 11.2M | const uint8_t* classInfo = NULL; |
659 | | // Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding |
660 | | // dwarf emission |
661 | | // Parse LSDA header. |
662 | 11.2M | uint8_t lpStartEncoding = *lsda++; |
663 | 11.2M | const uint8_t* lpStart = lpStartEncoding == DW_EH_PE_omit |
664 | 11.2M | ? (const uint8_t*)funcStart |
665 | 11.2M | : (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding, base); |
666 | 11.2M | uint8_t ttypeEncoding = *lsda++; |
667 | 11.2M | if (ttypeEncoding != DW_EH_PE_omit) |
668 | 2.86M | { |
669 | | // Calculate type info locations in emitted dwarf code which |
670 | | // were flagged by type info arguments to llvm.eh.selector |
671 | | // intrinsic |
672 | 2.86M | uintptr_t classInfoOffset = readULEB128(&lsda); |
673 | 2.86M | classInfo = lsda + classInfoOffset; |
674 | 2.86M | } |
675 | | // Walk call-site table looking for range that |
676 | | // includes current PC. |
677 | 11.2M | uint8_t callSiteEncoding = *lsda++; |
678 | | #if defined(__USING_SJLJ_EXCEPTIONS__) || defined(__USING_WASM_EXCEPTIONS__) |
679 | | (void)callSiteEncoding; // When using SjLj/Wasm exceptions, callSiteEncoding is never used |
680 | | #endif |
681 | 11.2M | uint32_t callSiteTableLength = static_cast<uint32_t>(readULEB128(&lsda)); |
682 | 11.2M | const uint8_t* callSiteTableStart = lsda; |
683 | 11.2M | const uint8_t* callSiteTableEnd = callSiteTableStart + callSiteTableLength; |
684 | 11.2M | const uint8_t* actionTableStart = callSiteTableEnd; |
685 | 11.2M | const uint8_t* callSitePtr = callSiteTableStart; |
686 | 55.3M | while (callSitePtr < callSiteTableEnd) |
687 | 55.3M | { |
688 | | // There is one entry per call site. |
689 | 55.3M | #if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__USING_WASM_EXCEPTIONS__) |
690 | | // The call sites are non-overlapping in [start, start+length) |
691 | | // The call sites are ordered in increasing value of start |
692 | 55.3M | uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding); |
693 | 55.3M | uintptr_t length = readEncodedPointer(&callSitePtr, callSiteEncoding); |
694 | 55.3M | uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding); |
695 | 55.3M | uintptr_t actionEntry = readULEB128(&callSitePtr); |
696 | 55.3M | if ((start <= ipOffset) && (ipOffset < (start + length))) |
697 | | #else // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__ |
698 | | // ip is 1-based index into this table |
699 | | uintptr_t landingPad = readULEB128(&callSitePtr); |
700 | | uintptr_t actionEntry = readULEB128(&callSitePtr); |
701 | | if (--ip == 0) |
702 | | #endif // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__ |
703 | 11.2M | { |
704 | | // Found the call site containing ip. |
705 | 11.2M | #if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__USING_WASM_EXCEPTIONS__) |
706 | 11.2M | if (landingPad == 0) |
707 | 6.13M | { |
708 | | // No handler here |
709 | 6.13M | results.reason = _URC_CONTINUE_UNWIND; |
710 | 6.13M | return; |
711 | 6.13M | } |
712 | 5.09M | landingPad = (uintptr_t)lpStart + landingPad; |
713 | | #else // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__ |
714 | | ++landingPad; |
715 | | #endif // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__ |
716 | 5.09M | results.landingPad = landingPad; |
717 | 5.09M | if (actionEntry == 0) |
718 | 2.57M | { |
719 | | // Found a cleanup |
720 | 2.57M | results.reason = actions & _UA_SEARCH_PHASE |
721 | 2.57M | ? _URC_CONTINUE_UNWIND |
722 | 2.57M | : _URC_HANDLER_FOUND; |
723 | 2.57M | return; |
724 | 2.57M | } |
725 | | // Convert 1-based byte offset into |
726 | 2.52M | const uint8_t* action = actionTableStart + (actionEntry - 1); |
727 | 2.52M | bool hasCleanup = false; |
728 | | // Scan action entries until you find a matching handler, cleanup, or the end of action list |
729 | 2.91M | while (true) |
730 | 2.92M | { |
731 | 2.92M | const uint8_t* actionRecord = action; |
732 | 2.92M | int64_t ttypeIndex = readSLEB128(&action); |
733 | 2.92M | if (ttypeIndex > 0) |
734 | 2.79M | { |
735 | | // Found a catch, does it actually catch? |
736 | | // First check for catch (...) |
737 | 2.79M | const __shim_type_info* catchType = |
738 | 2.79M | get_shim_type_info(static_cast<uint64_t>(ttypeIndex), |
739 | 2.79M | classInfo, ttypeEncoding, |
740 | 2.79M | native_exception, unwind_exception, |
741 | 2.79M | base); |
742 | 2.79M | if (catchType == 0) |
743 | 2.05k | { |
744 | | // Found catch (...) catches everything, including |
745 | | // foreign exceptions. This is search phase, cleanup |
746 | | // phase with foreign exception, or forced unwinding. |
747 | 2.05k | assert(actions & (_UA_SEARCH_PHASE | _UA_HANDLER_FRAME | |
748 | 2.05k | _UA_FORCE_UNWIND)); |
749 | 2.05k | results.ttypeIndex = ttypeIndex; |
750 | 2.05k | results.actionRecord = actionRecord; |
751 | 2.05k | results.adjustedPtr = |
752 | 2.05k | get_thrown_object_ptr(unwind_exception); |
753 | 2.05k | results.reason = _URC_HANDLER_FOUND; |
754 | 2.05k | return; |
755 | 2.05k | } |
756 | | // Else this is a catch (T) clause and will never |
757 | | // catch a foreign exception |
758 | 2.79M | else if (native_exception) |
759 | 2.79M | { |
760 | 2.79M | __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; |
761 | 2.79M | void* adjustedPtr = get_thrown_object_ptr(unwind_exception); |
762 | 2.79M | const __shim_type_info* excpType = |
763 | 2.79M | static_cast<const __shim_type_info*>(exception_header->exceptionType); |
764 | 2.79M | if (adjustedPtr == 0 || excpType == 0) |
765 | 0 | { |
766 | | // Something very bad happened |
767 | 0 | call_terminate(native_exception, unwind_exception); |
768 | 0 | } |
769 | 2.79M | if (catchType->can_catch(excpType, adjustedPtr)) |
770 | 2.31M | { |
771 | | // Found a matching handler. This is either search |
772 | | // phase or forced unwinding. |
773 | 2.31M | assert(actions & |
774 | 2.31M | (_UA_SEARCH_PHASE | _UA_FORCE_UNWIND)); |
775 | 2.31M | results.ttypeIndex = ttypeIndex; |
776 | 2.31M | results.actionRecord = actionRecord; |
777 | 2.31M | results.adjustedPtr = adjustedPtr; |
778 | 2.31M | results.reason = _URC_HANDLER_FOUND; |
779 | 2.31M | return; |
780 | 2.31M | } |
781 | 2.79M | } |
782 | | // Scan next action ... |
783 | 2.79M | } |
784 | 130k | else if (ttypeIndex < 0) |
785 | 0 | { |
786 | | // Found an exception specification. |
787 | 0 | if (actions & _UA_FORCE_UNWIND) { |
788 | | // Skip if forced unwinding. |
789 | 0 | } else if (native_exception) { |
790 | | // Does the exception spec catch this native exception? |
791 | 0 | __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; |
792 | 0 | void* adjustedPtr = get_thrown_object_ptr(unwind_exception); |
793 | 0 | const __shim_type_info* excpType = |
794 | 0 | static_cast<const __shim_type_info*>(exception_header->exceptionType); |
795 | 0 | if (adjustedPtr == 0 || excpType == 0) |
796 | 0 | { |
797 | | // Something very bad happened |
798 | 0 | call_terminate(native_exception, unwind_exception); |
799 | 0 | } |
800 | 0 | if (exception_spec_can_catch(ttypeIndex, classInfo, |
801 | 0 | ttypeEncoding, excpType, |
802 | 0 | adjustedPtr, |
803 | 0 | unwind_exception, base)) |
804 | 0 | { |
805 | | // Native exception caught by exception |
806 | | // specification. |
807 | 0 | assert(actions & _UA_SEARCH_PHASE); |
808 | 0 | results.ttypeIndex = ttypeIndex; |
809 | 0 | results.actionRecord = actionRecord; |
810 | 0 | results.adjustedPtr = adjustedPtr; |
811 | 0 | results.reason = _URC_HANDLER_FOUND; |
812 | 0 | return; |
813 | 0 | } |
814 | 0 | } else { |
815 | | // foreign exception caught by exception spec |
816 | 0 | results.ttypeIndex = ttypeIndex; |
817 | 0 | results.actionRecord = actionRecord; |
818 | 0 | results.adjustedPtr = |
819 | 0 | get_thrown_object_ptr(unwind_exception); |
820 | 0 | results.reason = _URC_HANDLER_FOUND; |
821 | 0 | return; |
822 | 0 | } |
823 | | // Scan next action ... |
824 | 130k | } else { |
825 | 130k | hasCleanup = true; |
826 | 130k | } |
827 | 612k | const uint8_t* temp = action; |
828 | 612k | int64_t actionOffset = readSLEB128(&temp); |
829 | 612k | if (actionOffset == 0) |
830 | 215k | { |
831 | | // End of action list. If this is phase 2 and we have found |
832 | | // a cleanup (ttypeIndex=0), return _URC_HANDLER_FOUND; |
833 | | // otherwise return _URC_CONTINUE_UNWIND. |
834 | 215k | results.reason = hasCleanup && actions & _UA_CLEANUP_PHASE |
835 | 215k | ? _URC_HANDLER_FOUND |
836 | 215k | : _URC_CONTINUE_UNWIND; |
837 | 215k | return; |
838 | 215k | } |
839 | | // Go to next action |
840 | 396k | action += actionOffset; |
841 | 396k | } // there is no break out of this loop, only return |
842 | 2.52M | } |
843 | 44.1M | #if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__USING_WASM_EXCEPTIONS__) |
844 | 44.1M | else if (ipOffset < start) |
845 | 0 | { |
846 | | // There is no call site for this ip |
847 | | // Something bad has happened. We should never get here. |
848 | | // Possible stack corruption. |
849 | 0 | call_terminate(native_exception, unwind_exception); |
850 | 0 | } |
851 | 55.3M | #endif // !__USING_SJLJ_EXCEPTIONS__ && !__USING_WASM_EXCEPTIONS__ |
852 | 55.3M | } // there might be some tricky cases which break out of this loop |
853 | | |
854 | | // It is possible that no eh table entry specify how to handle |
855 | | // this exception. By spec, terminate it immediately. |
856 | 10.3k | call_terminate(native_exception, unwind_exception); |
857 | 10.3k | } |
858 | | |
859 | | // public API |
860 | | |
861 | | /* |
862 | | The personality function branches on actions like so: |
863 | | |
864 | | _UA_SEARCH_PHASE |
865 | | |
866 | | If _UA_CLEANUP_PHASE or _UA_HANDLER_FRAME or _UA_FORCE_UNWIND there's |
867 | | an error from above, return _URC_FATAL_PHASE1_ERROR. |
868 | | |
869 | | Scan for anything that could stop unwinding: |
870 | | |
871 | | 1. A catch clause that will catch this exception |
872 | | (will never catch foreign). |
873 | | 2. A catch (...) (will always catch foreign). |
874 | | 3. An exception spec that will catch this exception |
875 | | (will always catch foreign). |
876 | | If a handler is found |
877 | | If not foreign |
878 | | Save state in header |
879 | | return _URC_HANDLER_FOUND |
880 | | Else a handler not found |
881 | | return _URC_CONTINUE_UNWIND |
882 | | |
883 | | _UA_CLEANUP_PHASE |
884 | | |
885 | | If _UA_HANDLER_FRAME |
886 | | If _UA_FORCE_UNWIND |
887 | | How did this happen? return _URC_FATAL_PHASE2_ERROR |
888 | | If foreign |
889 | | Do _UA_SEARCH_PHASE to recover state |
890 | | else |
891 | | Recover state from header |
892 | | Transfer control to landing pad. return _URC_INSTALL_CONTEXT |
893 | | |
894 | | Else |
895 | | |
896 | | This branch handles both normal C++ non-catching handlers (cleanups) |
897 | | and forced unwinding. |
898 | | Scan for anything that can not stop unwinding: |
899 | | |
900 | | 1. A cleanup. |
901 | | |
902 | | If a cleanup is found |
903 | | transfer control to it. return _URC_INSTALL_CONTEXT |
904 | | Else a cleanup is not found: return _URC_CONTINUE_UNWIND |
905 | | */ |
906 | | |
907 | | #if !defined(_LIBCXXABI_ARM_EHABI) |
908 | | #ifdef __USING_WASM_EXCEPTIONS__ |
909 | | _Unwind_Reason_Code __gxx_personality_wasm0 |
910 | | #elif defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) |
911 | | static _Unwind_Reason_Code __gxx_personality_imp |
912 | | #else |
913 | | _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code |
914 | | #ifdef __USING_SJLJ_EXCEPTIONS__ |
915 | | __gxx_personality_sj0 |
916 | | #elif defined(__MVS__) |
917 | | __zos_cxx_personality_v2 |
918 | | #else |
919 | | __gxx_personality_v0 |
920 | | #endif |
921 | | #endif |
922 | | (int version, _Unwind_Action actions, uint64_t exceptionClass, |
923 | | _Unwind_Exception* unwind_exception, _Unwind_Context* context) |
924 | 13.5M | { |
925 | 13.5M | if (version != 1 || unwind_exception == 0 || context == 0) |
926 | 0 | return _URC_FATAL_PHASE1_ERROR; |
927 | | |
928 | 13.5M | bool native_exception = (exceptionClass & get_vendor_and_language) == |
929 | 13.5M | (kOurExceptionClass & get_vendor_and_language); |
930 | 13.5M | scan_results results; |
931 | | // Process a catch handler for a native exception first. |
932 | 13.5M | if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME) && |
933 | 2.31M | native_exception) { |
934 | | // Reload the results from the phase 1 cache. |
935 | 2.31M | __cxa_exception* exception_header = |
936 | 2.31M | (__cxa_exception*)(unwind_exception + 1) - 1; |
937 | 2.31M | results.ttypeIndex = exception_header->handlerSwitchValue; |
938 | 2.31M | results.actionRecord = exception_header->actionRecord; |
939 | 2.31M | results.languageSpecificData = exception_header->languageSpecificData; |
940 | 2.31M | results.landingPad = |
941 | 2.31M | reinterpret_cast<uintptr_t>(exception_header->catchTemp); |
942 | 2.31M | results.adjustedPtr = exception_header->adjustedPtr; |
943 | | |
944 | | // Jump to the handler. |
945 | 2.31M | set_registers(unwind_exception, context, results); |
946 | | // Cache base for calculating the address of ttype in |
947 | | // __cxa_call_unexpected. |
948 | 2.31M | if (results.ttypeIndex < 0) { |
949 | | #if defined(_AIX) |
950 | | exception_header->catchTemp = (void *)_Unwind_GetDataRelBase(context); |
951 | | #else |
952 | 0 | exception_header->catchTemp = 0; |
953 | 0 | #endif |
954 | 0 | } |
955 | 2.31M | return _URC_INSTALL_CONTEXT; |
956 | 2.31M | } |
957 | | |
958 | | // In other cases we need to scan LSDA. |
959 | 11.2M | scan_eh_tab(results, actions, native_exception, unwind_exception, context); |
960 | 11.2M | if (results.reason == _URC_CONTINUE_UNWIND || |
961 | 3.66M | results.reason == _URC_FATAL_PHASE1_ERROR) |
962 | 7.56M | return results.reason; |
963 | | |
964 | 3.67M | if (actions & _UA_SEARCH_PHASE) |
965 | 2.31M | { |
966 | | // Phase 1 search: All we're looking for in phase 1 is a handler that |
967 | | // halts unwinding |
968 | 2.31M | assert(results.reason == _URC_HANDLER_FOUND); |
969 | 2.31M | if (native_exception) { |
970 | | // For a native exception, cache the LSDA result. |
971 | 2.31M | __cxa_exception* exc = (__cxa_exception*)(unwind_exception + 1) - 1; |
972 | 2.31M | exc->handlerSwitchValue = static_cast<int>(results.ttypeIndex); |
973 | 2.31M | exc->actionRecord = results.actionRecord; |
974 | 2.31M | exc->languageSpecificData = results.languageSpecificData; |
975 | 2.31M | exc->catchTemp = reinterpret_cast<void*>(results.landingPad); |
976 | 2.31M | exc->adjustedPtr = results.adjustedPtr; |
977 | | #ifdef __USING_WASM_EXCEPTIONS__ |
978 | | // Wasm only uses a single phase (_UA_SEARCH_PHASE), so save the |
979 | | // results here. |
980 | | set_registers(unwind_exception, context, results); |
981 | | #endif |
982 | 2.31M | } |
983 | 2.31M | return _URC_HANDLER_FOUND; |
984 | 2.31M | } |
985 | | |
986 | 3.67M | assert(actions & _UA_CLEANUP_PHASE); |
987 | 1.35M | assert(results.reason == _URC_HANDLER_FOUND); |
988 | 1.35M | set_registers(unwind_exception, context, results); |
989 | | // Cache base for calculating the address of ttype in __cxa_call_unexpected. |
990 | 1.35M | if (results.ttypeIndex < 0) { |
991 | 0 | __cxa_exception* exception_header = |
992 | 0 | (__cxa_exception*)(unwind_exception + 1) - 1; |
993 | | #if defined(_AIX) |
994 | | exception_header->catchTemp = (void *)_Unwind_GetDataRelBase(context); |
995 | | #else |
996 | 0 | exception_header->catchTemp = 0; |
997 | 0 | #endif |
998 | 0 | } |
999 | 1.35M | return _URC_INSTALL_CONTEXT; |
1000 | 1.35M | } |
1001 | | |
1002 | | #if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) |
1003 | | extern "C" _LIBCXXABI_FUNC_VIS EXCEPTION_DISPOSITION |
1004 | | __gxx_personality_seh0(PEXCEPTION_RECORD ms_exc, void *this_frame, |
1005 | | PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp) |
1006 | | { |
1007 | | return _GCC_specific_handler(ms_exc, this_frame, ms_orig_context, ms_disp, |
1008 | | __gxx_personality_imp); |
1009 | | } |
1010 | | #endif |
1011 | | |
1012 | | #else |
1013 | | |
1014 | | extern "C" _Unwind_Reason_Code __gnu_unwind_frame(_Unwind_Exception*, |
1015 | | _Unwind_Context*); |
1016 | | |
1017 | | // Helper function to unwind one frame. |
1018 | | // ARM EHABI 7.3 and 7.4: If the personality function returns _URC_CONTINUE_UNWIND, the |
1019 | | // personality routine should update the virtual register set (VRS) according to the |
1020 | | // corresponding frame unwinding instructions (ARM EHABI 9.3.) |
1021 | | static _Unwind_Reason_Code continue_unwind(_Unwind_Exception* unwind_exception, |
1022 | | _Unwind_Context* context) |
1023 | | { |
1024 | | switch (__gnu_unwind_frame(unwind_exception, context)) { |
1025 | | case _URC_OK: |
1026 | | return _URC_CONTINUE_UNWIND; |
1027 | | case _URC_END_OF_STACK: |
1028 | | return _URC_END_OF_STACK; |
1029 | | default: |
1030 | | return _URC_FAILURE; |
1031 | | } |
1032 | | } |
1033 | | |
1034 | | // ARM register names |
1035 | | #if !defined(_LIBUNWIND_VERSION) |
1036 | | static const uint32_t REG_UCB = 12; // Register to save _Unwind_Control_Block |
1037 | | #endif |
1038 | | static const uint32_t REG_SP = 13; |
1039 | | |
1040 | | static void save_results_to_barrier_cache(_Unwind_Exception* unwind_exception, |
1041 | | const scan_results& results) |
1042 | | { |
1043 | | unwind_exception->barrier_cache.bitpattern[0] = (uint32_t)results.adjustedPtr; |
1044 | | unwind_exception->barrier_cache.bitpattern[1] = (uint32_t)results.actionRecord; |
1045 | | unwind_exception->barrier_cache.bitpattern[2] = (uint32_t)results.languageSpecificData; |
1046 | | unwind_exception->barrier_cache.bitpattern[3] = (uint32_t)results.landingPad; |
1047 | | unwind_exception->barrier_cache.bitpattern[4] = (uint32_t)results.ttypeIndex; |
1048 | | } |
1049 | | |
1050 | | static void load_results_from_barrier_cache(scan_results& results, |
1051 | | const _Unwind_Exception* unwind_exception) |
1052 | | { |
1053 | | results.adjustedPtr = (void*)unwind_exception->barrier_cache.bitpattern[0]; |
1054 | | results.actionRecord = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[1]; |
1055 | | results.languageSpecificData = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[2]; |
1056 | | results.landingPad = (uintptr_t)unwind_exception->barrier_cache.bitpattern[3]; |
1057 | | results.ttypeIndex = (int64_t)(int32_t)unwind_exception->barrier_cache.bitpattern[4]; |
1058 | | } |
1059 | | |
1060 | | extern "C" _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code |
1061 | | __gxx_personality_v0(_Unwind_State state, |
1062 | | _Unwind_Exception* unwind_exception, |
1063 | | _Unwind_Context* context) |
1064 | | { |
1065 | | if (unwind_exception == 0 || context == 0) |
1066 | | return _URC_FATAL_PHASE1_ERROR; |
1067 | | |
1068 | | bool native_exception = __isOurExceptionClass(unwind_exception); |
1069 | | |
1070 | | #if !defined(_LIBUNWIND_VERSION) |
1071 | | // Copy the address of _Unwind_Control_Block to r12 so that |
1072 | | // _Unwind_GetLanguageSpecificData() and _Unwind_GetRegionStart() can |
1073 | | // return correct address. |
1074 | | _Unwind_SetGR(context, REG_UCB, reinterpret_cast<uint32_t>(unwind_exception)); |
1075 | | #endif |
1076 | | |
1077 | | // Check the undocumented force unwinding behavior |
1078 | | bool is_force_unwinding = state & _US_FORCE_UNWIND; |
1079 | | state &= ~_US_FORCE_UNWIND; |
1080 | | |
1081 | | scan_results results; |
1082 | | switch (state) { |
1083 | | case _US_VIRTUAL_UNWIND_FRAME: |
1084 | | if (is_force_unwinding) |
1085 | | return continue_unwind(unwind_exception, context); |
1086 | | |
1087 | | // Phase 1 search: All we're looking for in phase 1 is a handler that halts unwinding |
1088 | | scan_eh_tab(results, _UA_SEARCH_PHASE, native_exception, unwind_exception, context); |
1089 | | if (results.reason == _URC_HANDLER_FOUND) |
1090 | | { |
1091 | | unwind_exception->barrier_cache.sp = _Unwind_GetGR(context, REG_SP); |
1092 | | if (native_exception) |
1093 | | save_results_to_barrier_cache(unwind_exception, results); |
1094 | | return _URC_HANDLER_FOUND; |
1095 | | } |
1096 | | // Did not find the catch handler |
1097 | | if (results.reason == _URC_CONTINUE_UNWIND) |
1098 | | return continue_unwind(unwind_exception, context); |
1099 | | return results.reason; |
1100 | | |
1101 | | case _US_UNWIND_FRAME_STARTING: |
1102 | | // TODO: Support force unwinding in the phase 2 search. |
1103 | | // NOTE: In order to call the cleanup functions, _Unwind_ForcedUnwind() |
1104 | | // will call this personality function with (_US_FORCE_UNWIND | |
1105 | | // _US_UNWIND_FRAME_STARTING). |
1106 | | |
1107 | | // Phase 2 search |
1108 | | if (unwind_exception->barrier_cache.sp == _Unwind_GetGR(context, REG_SP)) |
1109 | | { |
1110 | | // Found a catching handler in phase 1 |
1111 | | if (native_exception) |
1112 | | { |
1113 | | // Load the result from the native exception barrier cache. |
1114 | | load_results_from_barrier_cache(results, unwind_exception); |
1115 | | results.reason = _URC_HANDLER_FOUND; |
1116 | | } |
1117 | | else |
1118 | | { |
1119 | | // Search for the catching handler again for the foreign exception. |
1120 | | scan_eh_tab(results, static_cast<_Unwind_Action>(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME), |
1121 | | native_exception, unwind_exception, context); |
1122 | | if (results.reason != _URC_HANDLER_FOUND) // phase1 search should guarantee to find one |
1123 | | call_terminate(native_exception, unwind_exception); |
1124 | | } |
1125 | | |
1126 | | // Install the context for the catching handler |
1127 | | set_registers(unwind_exception, context, results); |
1128 | | return _URC_INSTALL_CONTEXT; |
1129 | | } |
1130 | | |
1131 | | // Either we didn't do a phase 1 search (due to forced unwinding), or |
1132 | | // phase 1 reported no catching-handlers. |
1133 | | // Search for a (non-catching) cleanup |
1134 | | if (is_force_unwinding) |
1135 | | scan_eh_tab( |
1136 | | results, |
1137 | | static_cast<_Unwind_Action>(_UA_CLEANUP_PHASE | _UA_FORCE_UNWIND), |
1138 | | native_exception, unwind_exception, context); |
1139 | | else |
1140 | | scan_eh_tab(results, _UA_CLEANUP_PHASE, native_exception, |
1141 | | unwind_exception, context); |
1142 | | if (results.reason == _URC_HANDLER_FOUND) |
1143 | | { |
1144 | | // Found a non-catching handler |
1145 | | |
1146 | | // ARM EHABI 8.4.2: Before we can jump to the cleanup handler, we have to setup some |
1147 | | // internal data structures, so that __cxa_end_cleanup() can get unwind_exception from |
1148 | | // __cxa_get_globals(). |
1149 | | __cxa_begin_cleanup(unwind_exception); |
1150 | | |
1151 | | // Install the context for the cleanup handler |
1152 | | set_registers(unwind_exception, context, results); |
1153 | | return _URC_INSTALL_CONTEXT; |
1154 | | } |
1155 | | |
1156 | | // Did not find any handler |
1157 | | if (results.reason == _URC_CONTINUE_UNWIND) |
1158 | | return continue_unwind(unwind_exception, context); |
1159 | | return results.reason; |
1160 | | |
1161 | | case _US_UNWIND_FRAME_RESUME: |
1162 | | return continue_unwind(unwind_exception, context); |
1163 | | } |
1164 | | |
1165 | | // We were called improperly: neither a phase 1 or phase 2 search |
1166 | | return _URC_FATAL_PHASE1_ERROR; |
1167 | | } |
1168 | | #endif |
1169 | | |
1170 | | |
1171 | | __attribute__((noreturn)) |
1172 | | _LIBCXXABI_FUNC_VIS void |
1173 | | __cxa_call_unexpected(void* arg) |
1174 | 0 | { |
1175 | 0 | _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(arg); |
1176 | 0 | if (unwind_exception == 0) |
1177 | 0 | call_terminate(false, unwind_exception); |
1178 | 0 | __cxa_begin_catch(unwind_exception); |
1179 | 0 | bool native_old_exception = __isOurExceptionClass(unwind_exception); |
1180 | 0 | std::unexpected_handler u_handler; |
1181 | 0 | std::terminate_handler t_handler; |
1182 | 0 | __cxa_exception* old_exception_header = 0; |
1183 | 0 | int64_t ttypeIndex; |
1184 | 0 | const uint8_t* lsda; |
1185 | 0 | uintptr_t base = 0; |
1186 | |
|
1187 | 0 | if (native_old_exception) |
1188 | 0 | { |
1189 | 0 | old_exception_header = (__cxa_exception*)(unwind_exception+1) - 1; |
1190 | 0 | t_handler = old_exception_header->terminateHandler; |
1191 | 0 | u_handler = old_exception_header->unexpectedHandler; |
1192 | | // If std::__unexpected(u_handler) rethrows the same exception, |
1193 | | // these values get overwritten by the rethrow. So save them now: |
1194 | | #if defined(_LIBCXXABI_ARM_EHABI) |
1195 | | ttypeIndex = (int64_t)(int32_t)unwind_exception->barrier_cache.bitpattern[4]; |
1196 | | lsda = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[2]; |
1197 | | #else |
1198 | 0 | ttypeIndex = old_exception_header->handlerSwitchValue; |
1199 | 0 | lsda = old_exception_header->languageSpecificData; |
1200 | 0 | base = (uintptr_t)old_exception_header->catchTemp; |
1201 | 0 | #endif |
1202 | 0 | } |
1203 | 0 | else |
1204 | 0 | { |
1205 | 0 | t_handler = std::get_terminate(); |
1206 | 0 | u_handler = std::get_unexpected(); |
1207 | 0 | } |
1208 | 0 | try |
1209 | 0 | { |
1210 | 0 | std::__unexpected(u_handler); |
1211 | 0 | } |
1212 | 0 | catch (...) |
1213 | 0 | { |
1214 | | // If the old exception is foreign, then all we can do is terminate. |
1215 | | // We have no way to recover the needed old exception spec. There's |
1216 | | // no way to pass that information here. And the personality routine |
1217 | | // can't call us directly and do anything but terminate() if we throw |
1218 | | // from here. |
1219 | 0 | if (native_old_exception) |
1220 | 0 | { |
1221 | | // Have: |
1222 | | // old_exception_header->languageSpecificData |
1223 | | // old_exception_header->actionRecord |
1224 | | // old_exception_header->catchTemp, base for calculating ttype |
1225 | | // Need |
1226 | | // const uint8_t* classInfo |
1227 | | // uint8_t ttypeEncoding |
1228 | 0 | uint8_t lpStartEncoding = *lsda++; |
1229 | 0 | const uint8_t* lpStart = |
1230 | 0 | (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding, base); |
1231 | 0 | (void)lpStart; // purposefully unused. Just needed to increment lsda. |
1232 | 0 | uint8_t ttypeEncoding = *lsda++; |
1233 | 0 | if (ttypeEncoding == DW_EH_PE_omit) |
1234 | 0 | std::__terminate(t_handler); |
1235 | 0 | uintptr_t classInfoOffset = readULEB128(&lsda); |
1236 | 0 | const uint8_t* classInfo = lsda + classInfoOffset; |
1237 | | // Is this new exception catchable by the exception spec at ttypeIndex? |
1238 | | // The answer is obviously yes if the new and old exceptions are the same exception |
1239 | | // If no |
1240 | | // throw; |
1241 | 0 | __cxa_eh_globals* globals = __cxa_get_globals_fast(); |
1242 | 0 | __cxa_exception* new_exception_header = globals->caughtExceptions; |
1243 | 0 | if (new_exception_header == 0) |
1244 | | // This shouldn't be able to happen! |
1245 | 0 | std::__terminate(t_handler); |
1246 | 0 | bool native_new_exception = __isOurExceptionClass(&new_exception_header->unwindHeader); |
1247 | 0 | void* adjustedPtr; |
1248 | 0 | if (native_new_exception && (new_exception_header != old_exception_header)) |
1249 | 0 | { |
1250 | 0 | const __shim_type_info* excpType = |
1251 | 0 | static_cast<const __shim_type_info*>(new_exception_header->exceptionType); |
1252 | 0 | adjustedPtr = |
1253 | 0 | __getExceptionClass(&new_exception_header->unwindHeader) == kOurDependentExceptionClass ? |
1254 | 0 | ((__cxa_dependent_exception*)new_exception_header)->primaryException : |
1255 | 0 | new_exception_header + 1; |
1256 | 0 | if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding, |
1257 | 0 | excpType, adjustedPtr, |
1258 | 0 | unwind_exception, base)) |
1259 | 0 | { |
1260 | | // We need to __cxa_end_catch, but for the old exception, |
1261 | | // not the new one. This is a little tricky ... |
1262 | | // Disguise new_exception_header as a rethrown exception, but |
1263 | | // don't actually rethrow it. This means you can temporarily |
1264 | | // end the catch clause enclosing new_exception_header without |
1265 | | // __cxa_end_catch destroying new_exception_header. |
1266 | 0 | new_exception_header->handlerCount = -new_exception_header->handlerCount; |
1267 | 0 | globals->uncaughtExceptions += 1; |
1268 | | // Call __cxa_end_catch for new_exception_header |
1269 | 0 | __cxa_end_catch(); |
1270 | | // Call __cxa_end_catch for old_exception_header |
1271 | 0 | __cxa_end_catch(); |
1272 | | // Renter this catch clause with new_exception_header |
1273 | 0 | __cxa_begin_catch(&new_exception_header->unwindHeader); |
1274 | | // Rethrow new_exception_header |
1275 | 0 | throw; |
1276 | 0 | } |
1277 | 0 | } |
1278 | | // Will a std::bad_exception be catchable by the exception spec at |
1279 | | // ttypeIndex? |
1280 | | // If no |
1281 | | // throw std::bad_exception(); |
1282 | 0 | const __shim_type_info* excpType = |
1283 | 0 | static_cast<const __shim_type_info*>(&typeid(std::bad_exception)); |
1284 | 0 | std::bad_exception be; |
1285 | 0 | adjustedPtr = &be; |
1286 | 0 | if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding, |
1287 | 0 | excpType, adjustedPtr, |
1288 | 0 | unwind_exception, base)) |
1289 | 0 | { |
1290 | | // We need to __cxa_end_catch for both the old exception and the |
1291 | | // new exception. Technically we should do it in that order. |
1292 | | // But it is expedient to do it in the opposite order: |
1293 | | // Call __cxa_end_catch for new_exception_header |
1294 | 0 | __cxa_end_catch(); |
1295 | | // Throw std::bad_exception will __cxa_end_catch for |
1296 | | // old_exception_header |
1297 | 0 | throw be; |
1298 | 0 | } |
1299 | 0 | } |
1300 | 0 | } |
1301 | 0 | std::__terminate(t_handler); |
1302 | 0 | } |
1303 | | |
1304 | | #if defined(_AIX) |
1305 | | // Personality routine for EH using the range table. Make it an alias of |
1306 | | // __gxx_personality_v0(). |
1307 | | _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code __xlcxx_personality_v1( |
1308 | | int version, _Unwind_Action actions, uint64_t exceptionClass, |
1309 | | _Unwind_Exception* unwind_exception, _Unwind_Context* context) |
1310 | | __attribute__((__alias__("__gxx_personality_v0"))); |
1311 | | #endif |
1312 | | |
1313 | | } // extern "C" |
1314 | | |
1315 | | } // __cxxabiv1 |
1316 | | |
1317 | | #if defined(_AIX) |
1318 | | // Include implementation of the personality and helper functions for the |
1319 | | // state table based EH used by IBM legacy compilers xlC and xlclang++ on AIX. |
1320 | | # include "aix_state_tab_eh.inc" |
1321 | | #endif |