Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/system/lib/libcxxabi/src/cxa_personality.cpp
6173 views
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(__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__ || __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__ || __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
uintptr_t readPointerHelper(const uint8_t*& p) {
164
AsType value;
165
memcpy(&value, p, sizeof(AsType));
166
p += sizeof(AsType);
167
return static_cast<uintptr_t>(value);
168
}
169
170
} // 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
{
209
uintptr_t result = 0;
210
uintptr_t shift = 0;
211
unsigned char byte;
212
const uint8_t *p = *data;
213
do
214
{
215
byte = *p++;
216
result |= static_cast<uintptr_t>(byte & 0x7F) << shift;
217
shift += 7;
218
} while (byte & 0x80);
219
*data = p;
220
return result;
221
}
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
{
232
uintptr_t result = 0;
233
uintptr_t shift = 0;
234
unsigned char byte;
235
const uint8_t *p = *data;
236
do
237
{
238
byte = *p++;
239
result |= static_cast<uintptr_t>(byte & 0x7F) << shift;
240
shift += 7;
241
} while (byte & 0x80);
242
*data = p;
243
if ((byte & 0x40) && (shift < (sizeof(result) << 3)))
244
result |= static_cast<uintptr_t>(~0) << shift;
245
return static_cast<intptr_t>(result);
246
}
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
{
259
uintptr_t result = 0;
260
if (encoding == DW_EH_PE_omit)
261
return result;
262
const uint8_t* p = *data;
263
// first get value
264
switch (encoding & 0x0F)
265
{
266
case DW_EH_PE_absptr:
267
result = readPointerHelper<uintptr_t>(p);
268
break;
269
case DW_EH_PE_uleb128:
270
result = readULEB128(&p);
271
break;
272
case DW_EH_PE_sleb128:
273
result = static_cast<uintptr_t>(readSLEB128(&p));
274
break;
275
case DW_EH_PE_udata2:
276
result = readPointerHelper<uint16_t>(p);
277
break;
278
case DW_EH_PE_udata4:
279
result = readPointerHelper<uint32_t>(p);
280
break;
281
case DW_EH_PE_udata8:
282
result = readPointerHelper<uint64_t>(p);
283
break;
284
case DW_EH_PE_sdata2:
285
result = readPointerHelper<int16_t>(p);
286
break;
287
case DW_EH_PE_sdata4:
288
result = readPointerHelper<int32_t>(p);
289
break;
290
case DW_EH_PE_sdata8:
291
result = readPointerHelper<int64_t>(p);
292
break;
293
default:
294
// not supported
295
abort();
296
break;
297
}
298
// then add relative offset
299
switch (encoding & 0x70)
300
{
301
case DW_EH_PE_absptr:
302
// do nothing
303
break;
304
case DW_EH_PE_pcrel:
305
if (result)
306
result += (uintptr_t)(*data);
307
break;
308
case DW_EH_PE_datarel:
309
assert((base != 0) && "DW_EH_PE_datarel is invalid with a base of 0");
310
if (result)
311
result += base;
312
break;
313
case DW_EH_PE_textrel:
314
case DW_EH_PE_funcrel:
315
case DW_EH_PE_aligned:
316
default:
317
// not supported
318
abort();
319
break;
320
}
321
// then apply indirection
322
if (result && (encoding & DW_EH_PE_indirect))
323
result = *((uintptr_t*)result);
324
*data = p;
325
return result;
326
}
327
328
static
329
void
330
call_terminate(bool native_exception, _Unwind_Exception* unwind_exception)
331
{
332
__cxa_begin_catch(unwind_exception);
333
if (native_exception)
334
{
335
// Use the stored terminate_handler if possible
336
__cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
337
std::__terminate(exception_header->terminateHandler);
338
}
339
std::terminate();
340
}
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
{
390
if (classInfo == 0)
391
{
392
// this should not happen. Indicates corrupted eh_table.
393
call_terminate(native_exception, unwind_exception);
394
}
395
switch (ttypeEncoding & 0x0F)
396
{
397
case DW_EH_PE_absptr:
398
ttypeIndex *= sizeof(void*);
399
break;
400
case DW_EH_PE_udata2:
401
case DW_EH_PE_sdata2:
402
ttypeIndex *= 2;
403
break;
404
case DW_EH_PE_udata4:
405
case DW_EH_PE_sdata4:
406
ttypeIndex *= 4;
407
break;
408
case DW_EH_PE_udata8:
409
case DW_EH_PE_sdata8:
410
ttypeIndex *= 8;
411
break;
412
default:
413
// this should not happen. Indicates corrupted eh_table.
414
call_terminate(native_exception, unwind_exception);
415
}
416
classInfo -= ttypeIndex;
417
return (const __shim_type_info*)readEncodedPointer(&classInfo,
418
ttypeEncoding, base);
419
}
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
{
485
if (classInfo == 0)
486
{
487
// this should not happen. Indicates corrupted eh_table.
488
call_terminate(false, unwind_exception);
489
}
490
// specIndex is negative of 1-based byte offset into classInfo;
491
specIndex = -specIndex;
492
--specIndex;
493
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
while (true)
497
{
498
uint64_t ttypeIndex = readULEB128(&temp);
499
if (ttypeIndex == 0)
500
break;
501
const __shim_type_info* catchType = get_shim_type_info(ttypeIndex,
502
classInfo,
503
ttypeEncoding,
504
true,
505
unwind_exception,
506
base);
507
void* tempPtr = adjustedPtr;
508
if (catchType->can_catch(excpType, tempPtr))
509
return false;
510
}
511
return true;
512
}
513
#endif
514
515
static
516
void*
517
get_thrown_object_ptr(_Unwind_Exception* unwind_exception)
518
{
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
void* adjustedPtr = unwind_exception + 1;
522
if (__getExceptionClass(unwind_exception) == kOurDependentExceptionClass)
523
adjustedPtr = ((__cxa_dependent_exception*)adjustedPtr - 1)->primaryException;
524
return adjustedPtr;
525
}
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
{
550
#if defined(__USING_SJLJ_EXCEPTIONS__) || defined(__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
_Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
557
reinterpret_cast<uintptr_t>(unwind_exception));
558
_Unwind_SetGR(context, __builtin_eh_return_data_regno(1),
559
static_cast<uintptr_t>(results.ttypeIndex));
560
_Unwind_SetIP(context, results.landingPad);
561
}
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
_Unwind_Context *context) {
588
// Initialize results to found nothing but an error
589
results.ttypeIndex = 0;
590
results.actionRecord = 0;
591
results.languageSpecificData = 0;
592
results.landingPad = 0;
593
results.adjustedPtr = 0;
594
results.reason = _URC_FATAL_PHASE1_ERROR;
595
// Check for consistent actions
596
if (actions & _UA_SEARCH_PHASE)
597
{
598
// Do Phase 1
599
if (actions & (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME | _UA_FORCE_UNWIND))
600
{
601
// None of these flags should be set during Phase 1
602
// Client error
603
results.reason = _URC_FATAL_PHASE1_ERROR;
604
return;
605
}
606
}
607
else if (actions & _UA_CLEANUP_PHASE)
608
{
609
if ((actions & _UA_HANDLER_FRAME) && (actions & _UA_FORCE_UNWIND))
610
{
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
results.reason = _URC_FATAL_PHASE2_ERROR;
615
return;
616
}
617
}
618
else // Neither _UA_SEARCH_PHASE nor _UA_CLEANUP_PHASE is set
619
{
620
// One of these should be set.
621
// Client error
622
results.reason = _URC_FATAL_PHASE1_ERROR;
623
return;
624
}
625
// Start scan by getting exception table address.
626
const uint8_t *lsda = (const uint8_t *)_Unwind_GetLanguageSpecificData(context);
627
if (lsda == 0)
628
{
629
// There is no exception table
630
results.reason = _URC_CONTINUE_UNWIND;
631
return;
632
}
633
results.languageSpecificData = lsda;
634
#if defined(_AIX)
635
uintptr_t base = _Unwind_GetDataRelBase(context);
636
#else
637
uintptr_t base = 0;
638
#endif
639
// Get the current instruction pointer and offset it before next
640
// instruction in the current frame which threw the exception.
641
uintptr_t ip = _Unwind_GetIP(context) - 1;
642
// Get beginning current frame's code (as defined by the
643
// emitted dwarf code)
644
uintptr_t funcStart = _Unwind_GetRegionStart(context);
645
#if defined(__USING_SJLJ_EXCEPTIONS__) || defined(__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__ && !__WASM_EXCEPTIONS__
656
uintptr_t ipOffset = ip - funcStart;
657
#endif // !__USING_SJLJ_EXCEPTIONS__ && !__WASM_EXCEPTIONS__
658
const uint8_t* classInfo = NULL;
659
// Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding
660
// dwarf emission
661
// Parse LSDA header.
662
uint8_t lpStartEncoding = *lsda++;
663
const uint8_t* lpStart = lpStartEncoding == DW_EH_PE_omit
664
? (const uint8_t*)funcStart
665
: (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding, base);
666
(void)(lpStart); // Unused when using SjLj/Wasm exceptions
667
uint8_t ttypeEncoding = *lsda++;
668
if (ttypeEncoding != DW_EH_PE_omit)
669
{
670
// Calculate type info locations in emitted dwarf code which
671
// were flagged by type info arguments to llvm.eh.selector
672
// intrinsic
673
uintptr_t classInfoOffset = readULEB128(&lsda);
674
classInfo = lsda + classInfoOffset;
675
}
676
// Walk call-site table looking for range that
677
// includes current PC.
678
uint8_t callSiteEncoding = *lsda++;
679
#if defined(__USING_SJLJ_EXCEPTIONS__) || defined(__WASM_EXCEPTIONS__)
680
(void)callSiteEncoding; // Unused when using SjLj/Wasm exceptions
681
#endif
682
uint32_t callSiteTableLength = static_cast<uint32_t>(readULEB128(&lsda));
683
const uint8_t* callSiteTableStart = lsda;
684
const uint8_t* callSiteTableEnd = callSiteTableStart + callSiteTableLength;
685
const uint8_t* actionTableStart = callSiteTableEnd;
686
const uint8_t* callSitePtr = callSiteTableStart;
687
while (callSitePtr < callSiteTableEnd)
688
{
689
// There is one entry per call site.
690
#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__WASM_EXCEPTIONS__)
691
// The call sites are non-overlapping in [start, start+length)
692
// The call sites are ordered in increasing value of start
693
uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding);
694
uintptr_t length = readEncodedPointer(&callSitePtr, callSiteEncoding);
695
uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding);
696
uintptr_t actionEntry = readULEB128(&callSitePtr);
697
if ((start <= ipOffset) && (ipOffset < (start + length)))
698
#else // __USING_SJLJ_EXCEPTIONS__ || __WASM_EXCEPTIONS__
699
// ip is 1-based index into this table
700
uintptr_t landingPad = readULEB128(&callSitePtr);
701
uintptr_t actionEntry = readULEB128(&callSitePtr);
702
if (--ip == 0)
703
#endif // __USING_SJLJ_EXCEPTIONS__ || __WASM_EXCEPTIONS__
704
{
705
// Found the call site containing ip.
706
#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__WASM_EXCEPTIONS__)
707
if (landingPad == 0)
708
{
709
// No handler here
710
results.reason = _URC_CONTINUE_UNWIND;
711
return;
712
}
713
landingPad = (uintptr_t)lpStart + landingPad;
714
#else // __USING_SJLJ_EXCEPTIONS__ || __WASM_EXCEPTIONS__
715
++landingPad;
716
#endif // __USING_SJLJ_EXCEPTIONS__ || __WASM_EXCEPTIONS__
717
results.landingPad = landingPad;
718
if (actionEntry == 0)
719
{
720
// Found a cleanup
721
results.reason = (actions & _UA_SEARCH_PHASE) ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND;
722
return;
723
}
724
// Convert 1-based byte offset into
725
const uint8_t* action = actionTableStart + (actionEntry - 1);
726
bool hasCleanup = false;
727
// Scan action entries until you find a matching handler, cleanup, or the end of action list
728
while (true)
729
{
730
const uint8_t* actionRecord = action;
731
int64_t ttypeIndex = readSLEB128(&action);
732
if (ttypeIndex > 0)
733
{
734
// Found a catch, does it actually catch?
735
// First check for catch (...)
736
const __shim_type_info* catchType =
737
get_shim_type_info(static_cast<uint64_t>(ttypeIndex),
738
classInfo, ttypeEncoding,
739
native_exception, unwind_exception,
740
base);
741
if (catchType == 0)
742
{
743
// Found catch (...) catches everything, including
744
// foreign exceptions. This is search phase, cleanup
745
// phase with foreign exception, or forced unwinding.
746
assert(actions & (_UA_SEARCH_PHASE | _UA_HANDLER_FRAME |
747
_UA_FORCE_UNWIND));
748
results.ttypeIndex = ttypeIndex;
749
results.actionRecord = actionRecord;
750
results.adjustedPtr =
751
get_thrown_object_ptr(unwind_exception);
752
results.reason = _URC_HANDLER_FOUND;
753
return;
754
}
755
// Else this is a catch (T) clause and will never
756
// catch a foreign exception
757
else if (native_exception)
758
{
759
__cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
760
void* adjustedPtr = get_thrown_object_ptr(unwind_exception);
761
const __shim_type_info* excpType =
762
static_cast<const __shim_type_info*>(exception_header->exceptionType);
763
if (adjustedPtr == 0 || excpType == 0)
764
{
765
// Something very bad happened
766
call_terminate(native_exception, unwind_exception);
767
}
768
if (catchType->can_catch(excpType, adjustedPtr))
769
{
770
// Found a matching handler. This is either search
771
// phase or forced unwinding.
772
assert(actions &
773
(_UA_SEARCH_PHASE | _UA_FORCE_UNWIND));
774
results.ttypeIndex = ttypeIndex;
775
results.actionRecord = actionRecord;
776
results.adjustedPtr = adjustedPtr;
777
results.reason = _URC_HANDLER_FOUND;
778
return;
779
}
780
}
781
// Scan next action ...
782
}
783
else if (ttypeIndex < 0)
784
{
785
// Found an exception specification.
786
if (actions & _UA_FORCE_UNWIND) {
787
// Skip if forced unwinding.
788
} else if (native_exception) {
789
// Does the exception spec catch this native exception?
790
__cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
791
void* adjustedPtr = get_thrown_object_ptr(unwind_exception);
792
const __shim_type_info* excpType =
793
static_cast<const __shim_type_info*>(exception_header->exceptionType);
794
if (adjustedPtr == 0 || excpType == 0)
795
{
796
// Something very bad happened
797
call_terminate(native_exception, unwind_exception);
798
}
799
if (exception_spec_can_catch(ttypeIndex, classInfo,
800
ttypeEncoding, excpType,
801
adjustedPtr,
802
unwind_exception, base))
803
{
804
// Native exception caught by exception
805
// specification.
806
assert(actions & _UA_SEARCH_PHASE);
807
results.ttypeIndex = ttypeIndex;
808
results.actionRecord = actionRecord;
809
results.adjustedPtr = adjustedPtr;
810
results.reason = _URC_HANDLER_FOUND;
811
return;
812
}
813
} else {
814
// foreign exception caught by exception spec
815
results.ttypeIndex = ttypeIndex;
816
results.actionRecord = actionRecord;
817
results.adjustedPtr =
818
get_thrown_object_ptr(unwind_exception);
819
results.reason = _URC_HANDLER_FOUND;
820
return;
821
}
822
// Scan next action ...
823
} else {
824
hasCleanup = true;
825
}
826
const uint8_t* temp = action;
827
int64_t actionOffset = readSLEB128(&temp);
828
if (actionOffset == 0)
829
{
830
// End of action list. If this is phase 2 and we have found
831
// a cleanup (ttypeIndex=0), return _URC_HANDLER_FOUND;
832
// otherwise return _URC_CONTINUE_UNWIND.
833
results.reason = hasCleanup && actions & _UA_CLEANUP_PHASE
834
? _URC_HANDLER_FOUND
835
: _URC_CONTINUE_UNWIND;
836
return;
837
}
838
// Go to next action
839
action += actionOffset;
840
} // there is no break out of this loop, only return
841
}
842
#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__WASM_EXCEPTIONS__)
843
else if (ipOffset < start)
844
{
845
// There is no call site for this ip
846
// Something bad has happened. We should never get here.
847
// Possible stack corruption.
848
call_terminate(native_exception, unwind_exception);
849
}
850
#endif // !__USING_SJLJ_EXCEPTIONS__ && !__WASM_EXCEPTIONS__
851
} // there might be some tricky cases which break out of this loop
852
853
// It is possible that no eh table entry specify how to handle
854
// this exception. By spec, terminate it immediately.
855
call_terminate(native_exception, unwind_exception);
856
}
857
858
// public API
859
860
/*
861
The personality function branches on actions like so:
862
863
_UA_SEARCH_PHASE
864
865
If _UA_CLEANUP_PHASE or _UA_HANDLER_FRAME or _UA_FORCE_UNWIND there's
866
an error from above, return _URC_FATAL_PHASE1_ERROR.
867
868
Scan for anything that could stop unwinding:
869
870
1. A catch clause that will catch this exception
871
(will never catch foreign).
872
2. A catch (...) (will always catch foreign).
873
3. An exception spec that will catch this exception
874
(will always catch foreign).
875
If a handler is found
876
If not foreign
877
Save state in header
878
return _URC_HANDLER_FOUND
879
Else a handler not found
880
return _URC_CONTINUE_UNWIND
881
882
_UA_CLEANUP_PHASE
883
884
If _UA_HANDLER_FRAME
885
If _UA_FORCE_UNWIND
886
How did this happen? return _URC_FATAL_PHASE2_ERROR
887
If foreign
888
Do _UA_SEARCH_PHASE to recover state
889
else
890
Recover state from header
891
Transfer control to landing pad. return _URC_INSTALL_CONTEXT
892
893
Else
894
895
This branch handles both normal C++ non-catching handlers (cleanups)
896
and forced unwinding.
897
Scan for anything that can not stop unwinding:
898
899
1. A cleanup.
900
901
If a cleanup is found
902
transfer control to it. return _URC_INSTALL_CONTEXT
903
Else a cleanup is not found: return _URC_CONTINUE_UNWIND
904
*/
905
906
#if !defined(_LIBCXXABI_ARM_EHABI)
907
#ifdef __WASM_EXCEPTIONS__
908
_Unwind_Reason_Code __gxx_personality_wasm0
909
#elif defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
910
static _Unwind_Reason_Code __gxx_personality_imp
911
#else
912
_LIBCXXABI_FUNC_VIS _Unwind_Reason_Code
913
#ifdef __USING_SJLJ_EXCEPTIONS__
914
__gxx_personality_sj0
915
#elif defined(__MVS__)
916
__zos_cxx_personality_v2
917
#else
918
__gxx_personality_v0
919
#endif
920
#endif
921
(int version, _Unwind_Action actions, uint64_t exceptionClass,
922
_Unwind_Exception* unwind_exception, _Unwind_Context* context)
923
{
924
if (version != 1 || unwind_exception == 0 || context == 0)
925
return _URC_FATAL_PHASE1_ERROR;
926
927
bool native_exception = (exceptionClass & get_vendor_and_language) ==
928
(kOurExceptionClass & get_vendor_and_language);
929
scan_results results;
930
// Process a catch handler for a native exception first.
931
if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME) &&
932
native_exception) {
933
// Reload the results from the phase 1 cache.
934
__cxa_exception* exception_header =
935
(__cxa_exception*)(unwind_exception + 1) - 1;
936
results.ttypeIndex = exception_header->handlerSwitchValue;
937
results.actionRecord = exception_header->actionRecord;
938
results.languageSpecificData = exception_header->languageSpecificData;
939
results.landingPad =
940
reinterpret_cast<uintptr_t>(exception_header->catchTemp);
941
results.adjustedPtr = exception_header->adjustedPtr;
942
943
// Jump to the handler.
944
set_registers(unwind_exception, context, results);
945
// Cache base for calculating the address of ttype in
946
// __cxa_call_unexpected.
947
if (results.ttypeIndex < 0) {
948
#if defined(_AIX)
949
exception_header->catchTemp = (void *)_Unwind_GetDataRelBase(context);
950
#else
951
exception_header->catchTemp = 0;
952
#endif
953
}
954
return _URC_INSTALL_CONTEXT;
955
}
956
957
// In other cases we need to scan LSDA.
958
scan_eh_tab(results, actions, native_exception, unwind_exception, context);
959
if (results.reason == _URC_CONTINUE_UNWIND ||
960
results.reason == _URC_FATAL_PHASE1_ERROR)
961
return results.reason;
962
963
if (actions & _UA_SEARCH_PHASE)
964
{
965
// Phase 1 search: All we're looking for in phase 1 is a handler that
966
// halts unwinding
967
assert(results.reason == _URC_HANDLER_FOUND);
968
if (native_exception) {
969
// For a native exception, cache the LSDA result.
970
__cxa_exception* exc = (__cxa_exception*)(unwind_exception + 1) - 1;
971
exc->handlerSwitchValue = static_cast<int>(results.ttypeIndex);
972
exc->actionRecord = results.actionRecord;
973
exc->languageSpecificData = results.languageSpecificData;
974
exc->catchTemp = reinterpret_cast<void*>(results.landingPad);
975
exc->adjustedPtr = results.adjustedPtr;
976
#ifdef __WASM_EXCEPTIONS__
977
// Wasm only uses a single phase (_UA_SEARCH_PHASE), so save the
978
// results here.
979
set_registers(unwind_exception, context, results);
980
#endif
981
}
982
return _URC_HANDLER_FOUND;
983
}
984
985
assert(actions & _UA_CLEANUP_PHASE);
986
assert(results.reason == _URC_HANDLER_FOUND);
987
set_registers(unwind_exception, context, results);
988
// Cache base for calculating the address of ttype in __cxa_call_unexpected.
989
if (results.ttypeIndex < 0) {
990
__cxa_exception* exception_header =
991
(__cxa_exception*)(unwind_exception + 1) - 1;
992
#if defined(_AIX)
993
exception_header->catchTemp = (void *)_Unwind_GetDataRelBase(context);
994
#else
995
exception_header->catchTemp = 0;
996
#endif
997
}
998
return _URC_INSTALL_CONTEXT;
999
}
1000
1001
#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
1002
extern "C" _LIBCXXABI_FUNC_VIS EXCEPTION_DISPOSITION
1003
__gxx_personality_seh0(PEXCEPTION_RECORD ms_exc, void *this_frame,
1004
PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp)
1005
{
1006
return _GCC_specific_handler(ms_exc, this_frame, ms_orig_context, ms_disp,
1007
__gxx_personality_imp);
1008
}
1009
#endif
1010
1011
#else
1012
1013
extern "C" _Unwind_Reason_Code __gnu_unwind_frame(_Unwind_Exception*,
1014
_Unwind_Context*);
1015
1016
// Helper function to unwind one frame.
1017
// ARM EHABI 7.3 and 7.4: If the personality function returns _URC_CONTINUE_UNWIND, the
1018
// personality routine should update the virtual register set (VRS) according to the
1019
// corresponding frame unwinding instructions (ARM EHABI 9.3.)
1020
static _Unwind_Reason_Code continue_unwind(_Unwind_Exception* unwind_exception,
1021
_Unwind_Context* context)
1022
{
1023
switch (__gnu_unwind_frame(unwind_exception, context)) {
1024
case _URC_OK:
1025
return _URC_CONTINUE_UNWIND;
1026
case _URC_END_OF_STACK:
1027
return _URC_END_OF_STACK;
1028
default:
1029
return _URC_FAILURE;
1030
}
1031
}
1032
1033
// ARM register names
1034
#if !defined(_LIBUNWIND_VERSION)
1035
static const uint32_t REG_UCB = 12; // Register to save _Unwind_Control_Block
1036
#endif
1037
static const uint32_t REG_SP = 13;
1038
1039
static void save_results_to_barrier_cache(_Unwind_Exception* unwind_exception,
1040
const scan_results& results)
1041
{
1042
unwind_exception->barrier_cache.bitpattern[0] = (uint32_t)results.adjustedPtr;
1043
unwind_exception->barrier_cache.bitpattern[1] = (uint32_t)results.actionRecord;
1044
unwind_exception->barrier_cache.bitpattern[2] = (uint32_t)results.languageSpecificData;
1045
unwind_exception->barrier_cache.bitpattern[3] = (uint32_t)results.landingPad;
1046
unwind_exception->barrier_cache.bitpattern[4] = (uint32_t)results.ttypeIndex;
1047
}
1048
1049
static void load_results_from_barrier_cache(scan_results& results,
1050
const _Unwind_Exception* unwind_exception)
1051
{
1052
results.adjustedPtr = (void*)unwind_exception->barrier_cache.bitpattern[0];
1053
results.actionRecord = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[1];
1054
results.languageSpecificData = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[2];
1055
results.landingPad = (uintptr_t)unwind_exception->barrier_cache.bitpattern[3];
1056
results.ttypeIndex = (int64_t)(int32_t)unwind_exception->barrier_cache.bitpattern[4];
1057
}
1058
1059
extern "C" _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code
1060
__gxx_personality_v0(_Unwind_State state,
1061
_Unwind_Exception* unwind_exception,
1062
_Unwind_Context* context)
1063
{
1064
if (unwind_exception == 0 || context == 0)
1065
return _URC_FATAL_PHASE1_ERROR;
1066
1067
bool native_exception = __isOurExceptionClass(unwind_exception);
1068
1069
#if !defined(_LIBUNWIND_VERSION)
1070
// Copy the address of _Unwind_Control_Block to r12 so that
1071
// _Unwind_GetLanguageSpecificData() and _Unwind_GetRegionStart() can
1072
// return correct address.
1073
_Unwind_SetGR(context, REG_UCB, reinterpret_cast<uint32_t>(unwind_exception));
1074
#endif
1075
1076
// Check the undocumented force unwinding behavior
1077
bool is_force_unwinding = state & _US_FORCE_UNWIND;
1078
state &= ~_US_FORCE_UNWIND;
1079
1080
scan_results results;
1081
switch (state) {
1082
case _US_VIRTUAL_UNWIND_FRAME:
1083
if (is_force_unwinding)
1084
return continue_unwind(unwind_exception, context);
1085
1086
// Phase 1 search: All we're looking for in phase 1 is a handler that halts unwinding
1087
scan_eh_tab(results, _UA_SEARCH_PHASE, native_exception, unwind_exception, context);
1088
if (results.reason == _URC_HANDLER_FOUND)
1089
{
1090
unwind_exception->barrier_cache.sp = _Unwind_GetGR(context, REG_SP);
1091
if (native_exception)
1092
save_results_to_barrier_cache(unwind_exception, results);
1093
return _URC_HANDLER_FOUND;
1094
}
1095
// Did not find the catch handler
1096
if (results.reason == _URC_CONTINUE_UNWIND)
1097
return continue_unwind(unwind_exception, context);
1098
return results.reason;
1099
1100
case _US_UNWIND_FRAME_STARTING:
1101
// TODO: Support force unwinding in the phase 2 search.
1102
// NOTE: In order to call the cleanup functions, _Unwind_ForcedUnwind()
1103
// will call this personality function with (_US_FORCE_UNWIND |
1104
// _US_UNWIND_FRAME_STARTING).
1105
1106
// Phase 2 search
1107
if (unwind_exception->barrier_cache.sp == _Unwind_GetGR(context, REG_SP))
1108
{
1109
// Found a catching handler in phase 1
1110
if (native_exception)
1111
{
1112
// Load the result from the native exception barrier cache.
1113
load_results_from_barrier_cache(results, unwind_exception);
1114
results.reason = _URC_HANDLER_FOUND;
1115
}
1116
else
1117
{
1118
// Search for the catching handler again for the foreign exception.
1119
scan_eh_tab(results, static_cast<_Unwind_Action>(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME),
1120
native_exception, unwind_exception, context);
1121
if (results.reason != _URC_HANDLER_FOUND) // phase1 search should guarantee to find one
1122
call_terminate(native_exception, unwind_exception);
1123
}
1124
1125
// Install the context for the catching handler
1126
set_registers(unwind_exception, context, results);
1127
return _URC_INSTALL_CONTEXT;
1128
}
1129
1130
// Either we didn't do a phase 1 search (due to forced unwinding), or
1131
// phase 1 reported no catching-handlers.
1132
// Search for a (non-catching) cleanup
1133
if (is_force_unwinding)
1134
scan_eh_tab(
1135
results,
1136
static_cast<_Unwind_Action>(_UA_CLEANUP_PHASE | _UA_FORCE_UNWIND),
1137
native_exception, unwind_exception, context);
1138
else
1139
scan_eh_tab(results, _UA_CLEANUP_PHASE, native_exception,
1140
unwind_exception, context);
1141
if (results.reason == _URC_HANDLER_FOUND)
1142
{
1143
// Found a non-catching handler
1144
1145
// ARM EHABI 8.4.2: Before we can jump to the cleanup handler, we have to setup some
1146
// internal data structures, so that __cxa_end_cleanup() can get unwind_exception from
1147
// __cxa_get_globals().
1148
__cxa_begin_cleanup(unwind_exception);
1149
1150
// Install the context for the cleanup handler
1151
set_registers(unwind_exception, context, results);
1152
return _URC_INSTALL_CONTEXT;
1153
}
1154
1155
// Did not find any handler
1156
if (results.reason == _URC_CONTINUE_UNWIND)
1157
return continue_unwind(unwind_exception, context);
1158
return results.reason;
1159
1160
case _US_UNWIND_FRAME_RESUME:
1161
return continue_unwind(unwind_exception, context);
1162
}
1163
1164
// We were called improperly: neither a phase 1 or phase 2 search
1165
return _URC_FATAL_PHASE1_ERROR;
1166
}
1167
#endif
1168
1169
1170
__attribute__((noreturn))
1171
_LIBCXXABI_FUNC_VIS void
1172
__cxa_call_unexpected(void* arg)
1173
{
1174
_Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(arg);
1175
if (unwind_exception == 0)
1176
call_terminate(false, unwind_exception);
1177
__cxa_begin_catch(unwind_exception);
1178
bool native_old_exception = __isOurExceptionClass(unwind_exception);
1179
std::unexpected_handler u_handler;
1180
std::terminate_handler t_handler;
1181
__cxa_exception* old_exception_header = 0;
1182
int64_t ttypeIndex;
1183
const uint8_t* lsda;
1184
uintptr_t base = 0;
1185
1186
if (native_old_exception)
1187
{
1188
old_exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
1189
t_handler = old_exception_header->terminateHandler;
1190
u_handler = old_exception_header->unexpectedHandler;
1191
// If std::__unexpected(u_handler) rethrows the same exception,
1192
// these values get overwritten by the rethrow. So save them now:
1193
#if defined(_LIBCXXABI_ARM_EHABI)
1194
ttypeIndex = (int64_t)(int32_t)unwind_exception->barrier_cache.bitpattern[4];
1195
lsda = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[2];
1196
#else
1197
ttypeIndex = old_exception_header->handlerSwitchValue;
1198
lsda = old_exception_header->languageSpecificData;
1199
base = (uintptr_t)old_exception_header->catchTemp;
1200
#endif
1201
}
1202
else
1203
{
1204
t_handler = std::get_terminate();
1205
u_handler = std::get_unexpected();
1206
}
1207
try
1208
{
1209
std::__unexpected(u_handler);
1210
}
1211
catch (...)
1212
{
1213
// If the old exception is foreign, then all we can do is terminate.
1214
// We have no way to recover the needed old exception spec. There's
1215
// no way to pass that information here. And the personality routine
1216
// can't call us directly and do anything but terminate() if we throw
1217
// from here.
1218
if (native_old_exception)
1219
{
1220
// Have:
1221
// old_exception_header->languageSpecificData
1222
// old_exception_header->actionRecord
1223
// old_exception_header->catchTemp, base for calculating ttype
1224
// Need
1225
// const uint8_t* classInfo
1226
// uint8_t ttypeEncoding
1227
uint8_t lpStartEncoding = *lsda++;
1228
const uint8_t* lpStart =
1229
(const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding, base);
1230
(void)lpStart; // purposefully unused. Just needed to increment lsda.
1231
uint8_t ttypeEncoding = *lsda++;
1232
if (ttypeEncoding == DW_EH_PE_omit)
1233
std::__terminate(t_handler);
1234
uintptr_t classInfoOffset = readULEB128(&lsda);
1235
const uint8_t* classInfo = lsda + classInfoOffset;
1236
// Is this new exception catchable by the exception spec at ttypeIndex?
1237
// The answer is obviously yes if the new and old exceptions are the same exception
1238
// If no
1239
// throw;
1240
__cxa_eh_globals* globals = __cxa_get_globals_fast();
1241
__cxa_exception* new_exception_header = globals->caughtExceptions;
1242
if (new_exception_header == 0)
1243
// This shouldn't be able to happen!
1244
std::__terminate(t_handler);
1245
bool native_new_exception = __isOurExceptionClass(&new_exception_header->unwindHeader);
1246
void* adjustedPtr;
1247
if (native_new_exception && (new_exception_header != old_exception_header))
1248
{
1249
const __shim_type_info* excpType =
1250
static_cast<const __shim_type_info*>(new_exception_header->exceptionType);
1251
adjustedPtr =
1252
__getExceptionClass(&new_exception_header->unwindHeader) == kOurDependentExceptionClass ?
1253
((__cxa_dependent_exception*)new_exception_header)->primaryException :
1254
new_exception_header + 1;
1255
if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding,
1256
excpType, adjustedPtr,
1257
unwind_exception, base))
1258
{
1259
// We need to __cxa_end_catch, but for the old exception,
1260
// not the new one. This is a little tricky ...
1261
// Disguise new_exception_header as a rethrown exception, but
1262
// don't actually rethrow it. This means you can temporarily
1263
// end the catch clause enclosing new_exception_header without
1264
// __cxa_end_catch destroying new_exception_header.
1265
new_exception_header->handlerCount = -new_exception_header->handlerCount;
1266
globals->uncaughtExceptions += 1;
1267
// Call __cxa_end_catch for new_exception_header
1268
__cxa_end_catch();
1269
// Call __cxa_end_catch for old_exception_header
1270
__cxa_end_catch();
1271
// Renter this catch clause with new_exception_header
1272
__cxa_begin_catch(&new_exception_header->unwindHeader);
1273
// Rethrow new_exception_header
1274
throw;
1275
}
1276
}
1277
// Will a std::bad_exception be catchable by the exception spec at
1278
// ttypeIndex?
1279
// If no
1280
// throw std::bad_exception();
1281
const __shim_type_info* excpType =
1282
static_cast<const __shim_type_info*>(&typeid(std::bad_exception));
1283
std::bad_exception be;
1284
adjustedPtr = &be;
1285
if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding,
1286
excpType, adjustedPtr,
1287
unwind_exception, base))
1288
{
1289
// We need to __cxa_end_catch for both the old exception and the
1290
// new exception. Technically we should do it in that order.
1291
// But it is expedient to do it in the opposite order:
1292
// Call __cxa_end_catch for new_exception_header
1293
__cxa_end_catch();
1294
// Throw std::bad_exception will __cxa_end_catch for
1295
// old_exception_header
1296
throw be;
1297
}
1298
}
1299
}
1300
std::__terminate(t_handler);
1301
}
1302
1303
#if defined(_AIX)
1304
// Personality routine for EH using the range table. Make it an alias of
1305
// __gxx_personality_v0().
1306
_LIBCXXABI_FUNC_VIS _Unwind_Reason_Code __xlcxx_personality_v1(
1307
int version, _Unwind_Action actions, uint64_t exceptionClass,
1308
_Unwind_Exception* unwind_exception, _Unwind_Context* context)
1309
__attribute__((__alias__("__gxx_personality_v0")));
1310
#endif
1311
1312
} // extern "C"
1313
1314
} // __cxxabiv1
1315
1316
#if defined(_AIX)
1317
// Include implementation of the personality and helper functions for the
1318
// state table based EH used by IBM legacy compilers xlC and xlclang++ on AIX.
1319
# include "aix_state_tab_eh.inc"
1320
#endif
1321
1322