Coverage Report

Created: 2025-12-31 07:17

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