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