Home | History | Annotate | Line # | Download | only in gcc
      1      1.1  mrg // GNU D Compiler exception personality routines.
      2  1.1.1.3  mrg // Copyright (C) 2011-2022 Free Software Foundation, Inc.
      3      1.1  mrg 
      4      1.1  mrg // GCC is free software; you can redistribute it and/or modify it under
      5      1.1  mrg // the terms of the GNU General Public License as published by the Free
      6      1.1  mrg // Software Foundation; either version 3, or (at your option) any later
      7      1.1  mrg // version.
      8      1.1  mrg 
      9      1.1  mrg // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
     10      1.1  mrg // WARRANTY; without even the implied warranty of MERCHANTABILITY or
     11      1.1  mrg // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     12      1.1  mrg // for more details.
     13      1.1  mrg 
     14      1.1  mrg // Under Section 7 of GPL version 3, you are granted additional
     15      1.1  mrg // permissions described in the GCC Runtime Library Exception, version
     16      1.1  mrg // 3.1, as published by the Free Software Foundation.
     17      1.1  mrg 
     18      1.1  mrg // You should have received a copy of the GNU General Public License and
     19      1.1  mrg // a copy of the GCC Runtime Library Exception along with this program;
     20      1.1  mrg // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     21      1.1  mrg // <http://www.gnu.org/licenses/>.
     22      1.1  mrg 
     23      1.1  mrg // This code is based on the libstdc++ exception handling routines.
     24      1.1  mrg 
     25      1.1  mrg module gcc.deh;
     26      1.1  mrg 
     27      1.1  mrg import gcc.unwind;
     28      1.1  mrg import gcc.unwind.pe;
     29      1.1  mrg import gcc.builtins;
     30      1.1  mrg import gcc.config;
     31  1.1.1.3  mrg import gcc.attributes;
     32      1.1  mrg 
     33      1.1  mrg extern(C)
     34      1.1  mrg {
     35  1.1.1.3  mrg     int _d_isbaseof(ClassInfo, ClassInfo) @nogc nothrow pure @safe;
     36  1.1.1.3  mrg     void _d_createTrace(Throwable, void*);
     37  1.1.1.3  mrg     void _d_print_throwable(Throwable t);
     38      1.1  mrg }
     39      1.1  mrg 
     40      1.1  mrg /**
     41      1.1  mrg  * Declare all known and handled exception classes.
     42      1.1  mrg  * D exceptions -- "GNUCD\0\0\0".
     43      1.1  mrg  * C++ exceptions -- "GNUCC++\0"
     44      1.1  mrg  * C++ dependent exceptions -- "GNUCC++\x01"
     45      1.1  mrg  */
     46      1.1  mrg static if (GNU_ARM_EABI_Unwinder)
     47      1.1  mrg {
     48      1.1  mrg     enum _Unwind_Exception_Class gdcExceptionClass = "GNUCD\0\0\0";
     49      1.1  mrg     enum _Unwind_Exception_Class gxxExceptionClass = "GNUCC++\0";
     50      1.1  mrg     enum _Unwind_Exception_Class gxxDependentExceptionClass = "GNUCC++\x01";
     51      1.1  mrg }
     52      1.1  mrg else
     53      1.1  mrg {
     54      1.1  mrg     enum _Unwind_Exception_Class gdcExceptionClass =
     55      1.1  mrg         (cast(_Unwind_Exception_Class)'G' << 56) |
     56      1.1  mrg         (cast(_Unwind_Exception_Class)'N' << 48) |
     57      1.1  mrg         (cast(_Unwind_Exception_Class)'U' << 40) |
     58      1.1  mrg         (cast(_Unwind_Exception_Class)'C' << 32) |
     59      1.1  mrg         (cast(_Unwind_Exception_Class)'D' << 24);
     60      1.1  mrg 
     61      1.1  mrg     enum _Unwind_Exception_Class gxxExceptionClass =
     62      1.1  mrg         (cast(_Unwind_Exception_Class)'G' << 56) |
     63      1.1  mrg         (cast(_Unwind_Exception_Class)'N' << 48) |
     64      1.1  mrg         (cast(_Unwind_Exception_Class)'U' << 40) |
     65      1.1  mrg         (cast(_Unwind_Exception_Class)'C' << 32) |
     66      1.1  mrg         (cast(_Unwind_Exception_Class)'C' << 24) |
     67      1.1  mrg         (cast(_Unwind_Exception_Class)'+' << 16) |
     68      1.1  mrg         (cast(_Unwind_Exception_Class)'+' <<  8) |
     69      1.1  mrg         (cast(_Unwind_Exception_Class)0 <<  0);
     70      1.1  mrg 
     71      1.1  mrg     enum _Unwind_Exception_Class gxxDependentExceptionClass =
     72      1.1  mrg         gxxExceptionClass + 1;
     73      1.1  mrg }
     74      1.1  mrg 
     75      1.1  mrg /**
     76      1.1  mrg  * Checks for GDC exception class.
     77      1.1  mrg  */
     78      1.1  mrg bool isGdcExceptionClass(_Unwind_Exception_Class c) @nogc
     79      1.1  mrg {
     80      1.1  mrg     static if (GNU_ARM_EABI_Unwinder)
     81      1.1  mrg     {
     82      1.1  mrg         return c[0] == gdcExceptionClass[0]
     83      1.1  mrg             && c[1] == gdcExceptionClass[1]
     84      1.1  mrg             && c[2] == gdcExceptionClass[2]
     85      1.1  mrg             && c[3] == gdcExceptionClass[3]
     86      1.1  mrg             && c[4] == gdcExceptionClass[4]
     87      1.1  mrg             && c[5] == gdcExceptionClass[5]
     88      1.1  mrg             && c[6] == gdcExceptionClass[6]
     89      1.1  mrg             && c[7] == gdcExceptionClass[7];
     90      1.1  mrg     }
     91      1.1  mrg     else
     92      1.1  mrg     {
     93      1.1  mrg         return c == gdcExceptionClass;
     94      1.1  mrg     }
     95      1.1  mrg }
     96      1.1  mrg 
     97      1.1  mrg /**
     98      1.1  mrg  * Checks for any C++ exception class.
     99      1.1  mrg  */
    100      1.1  mrg bool isGxxExceptionClass(_Unwind_Exception_Class c) @nogc
    101      1.1  mrg {
    102      1.1  mrg     static if (GNU_ARM_EABI_Unwinder)
    103      1.1  mrg     {
    104      1.1  mrg         return c[0] == gxxExceptionClass[0]
    105      1.1  mrg             && c[1] == gxxExceptionClass[1]
    106      1.1  mrg             && c[2] == gxxExceptionClass[2]
    107      1.1  mrg             && c[3] == gxxExceptionClass[3]
    108      1.1  mrg             && c[4] == gxxExceptionClass[4]
    109      1.1  mrg             && c[5] == gxxExceptionClass[5]
    110      1.1  mrg             && c[6] == gxxExceptionClass[6]
    111      1.1  mrg             && (c[7] == gxxExceptionClass[7]
    112      1.1  mrg                 || c[7] == gxxDependentExceptionClass[7]);
    113      1.1  mrg     }
    114      1.1  mrg     else
    115      1.1  mrg     {
    116      1.1  mrg         return c == gxxExceptionClass
    117      1.1  mrg             || c == gxxDependentExceptionClass;
    118      1.1  mrg     }
    119      1.1  mrg }
    120      1.1  mrg 
    121      1.1  mrg /**
    122      1.1  mrg  * Checks for primary or dependent, but not that it is a C++ exception.
    123      1.1  mrg  */
    124      1.1  mrg bool isDependentException(_Unwind_Exception_Class c) @nogc
    125      1.1  mrg {
    126      1.1  mrg     static if (GNU_ARM_EABI_Unwinder)
    127      1.1  mrg         return (c[7] == '\x01');
    128      1.1  mrg     else
    129      1.1  mrg         return (c & 1);
    130      1.1  mrg }
    131      1.1  mrg 
    132      1.1  mrg /**
    133      1.1  mrg  * A D exception object consists of a header, which is a wrapper
    134      1.1  mrg  * around an unwind object header with additional D specific
    135      1.1  mrg  * information, prefixed by the exception object itself.
    136      1.1  mrg  */
    137      1.1  mrg struct ExceptionHeader
    138      1.1  mrg {
    139      1.1  mrg     // Because of a lack of __aligned__ style attribute, our object
    140      1.1  mrg     // and the unwind object are the first two fields.
    141      1.1  mrg     static if (Throwable.alignof < _Unwind_Exception.alignof)
    142      1.1  mrg         ubyte[_Unwind_Exception.alignof - Throwable.alignof] pad;
    143      1.1  mrg 
    144      1.1  mrg     // The object being thrown.  The compiled code expects this to
    145      1.1  mrg     // be immediately before the generic exception header.
    146      1.1  mrg     Throwable object;
    147      1.1  mrg 
    148      1.1  mrg     // The generic exception header.
    149      1.1  mrg     _Unwind_Exception unwindHeader;
    150      1.1  mrg 
    151      1.1  mrg     static assert(unwindHeader.offsetof - object.offsetof == object.sizeof);
    152      1.1  mrg 
    153      1.1  mrg     // Cache handler details between Phase 1 and Phase 2.
    154      1.1  mrg     static if (GNU_ARM_EABI_Unwinder)
    155      1.1  mrg     {
    156      1.1  mrg         // Nothing here yet.
    157      1.1  mrg     }
    158      1.1  mrg     else
    159      1.1  mrg     {
    160      1.1  mrg         // Which catch was found.
    161      1.1  mrg         int handler;
    162      1.1  mrg 
    163      1.1  mrg         // Language Specific Data Area for function enclosing the handler.
    164      1.1  mrg         const(ubyte)* languageSpecificData;
    165      1.1  mrg 
    166      1.1  mrg         // Pointer to catch code.
    167      1.1  mrg         _Unwind_Ptr landingPad;
    168      1.1  mrg 
    169      1.1  mrg         // Canonical Frame Address (CFA) for the enclosing handler.
    170      1.1  mrg         _Unwind_Word canonicalFrameAddress;
    171      1.1  mrg     }
    172      1.1  mrg 
    173      1.1  mrg     // Stack other thrown exceptions in current thread through here.
    174      1.1  mrg     ExceptionHeader* next;
    175      1.1  mrg 
    176      1.1  mrg     // Thread local stack of chained exceptions.
    177      1.1  mrg     static ExceptionHeader* stack;
    178      1.1  mrg 
    179      1.1  mrg     // Pre-allocate storage for 1 instance per thread.
    180      1.1  mrg     // Use calloc/free for multiple exceptions in flight.
    181      1.1  mrg     static ExceptionHeader ehstorage;
    182      1.1  mrg 
    183      1.1  mrg     /**
    184      1.1  mrg      * Allocate and initialize an ExceptionHeader.
    185      1.1  mrg      */
    186      1.1  mrg     static ExceptionHeader* create(Throwable o) @nogc
    187      1.1  mrg     {
    188      1.1  mrg         auto eh = &ehstorage;
    189      1.1  mrg 
    190      1.1  mrg         // Check exception object in use.
    191      1.1  mrg         if (eh.object)
    192      1.1  mrg         {
    193      1.1  mrg             eh = cast(ExceptionHeader*) __builtin_calloc(ExceptionHeader.sizeof, 1);
    194      1.1  mrg             // Out of memory while throwing - not much else can be done.
    195      1.1  mrg             if (!eh)
    196      1.1  mrg                 terminate("out of memory", __LINE__);
    197      1.1  mrg         }
    198      1.1  mrg         eh.object = o;
    199      1.1  mrg 
    200      1.1  mrg         eh.unwindHeader.exception_class = gdcExceptionClass;
    201      1.1  mrg 
    202      1.1  mrg         return eh;
    203      1.1  mrg     }
    204      1.1  mrg 
    205      1.1  mrg     /**
    206      1.1  mrg      * Free ExceptionHeader that was created by create().
    207      1.1  mrg      */
    208      1.1  mrg     static void free(ExceptionHeader* eh) @nogc
    209      1.1  mrg     {
    210  1.1.1.3  mrg         __builtin_memset(eh, 0, ExceptionHeader.sizeof);
    211      1.1  mrg         if (eh != &ehstorage)
    212      1.1  mrg             __builtin_free(eh);
    213      1.1  mrg     }
    214      1.1  mrg 
    215      1.1  mrg     /**
    216      1.1  mrg      * Push this onto stack of chained exceptions.
    217      1.1  mrg      */
    218      1.1  mrg     void push() @nogc
    219      1.1  mrg     {
    220      1.1  mrg         next = stack;
    221      1.1  mrg         stack = &this;
    222      1.1  mrg     }
    223      1.1  mrg 
    224      1.1  mrg     /**
    225      1.1  mrg      * Pop and return top of chained exception stack.
    226      1.1  mrg      */
    227      1.1  mrg     static ExceptionHeader* pop() @nogc
    228      1.1  mrg     {
    229      1.1  mrg         auto eh = stack;
    230      1.1  mrg         stack = eh.next;
    231      1.1  mrg         return eh;
    232      1.1  mrg     }
    233      1.1  mrg 
    234      1.1  mrg     /**
    235      1.1  mrg      * Save stage1 handler information in the exception object.
    236      1.1  mrg      */
    237      1.1  mrg     static void save(_Unwind_Exception* unwindHeader,
    238      1.1  mrg                      _Unwind_Word cfa, int handler,
    239      1.1  mrg                      const(ubyte)* lsda, _Unwind_Ptr landingPad) @nogc
    240      1.1  mrg     {
    241      1.1  mrg         static if (GNU_ARM_EABI_Unwinder)
    242      1.1  mrg         {
    243      1.1  mrg             unwindHeader.barrier_cache.sp = cfa;
    244      1.1  mrg             unwindHeader.barrier_cache.bitpattern[1] = cast(_uw)handler;
    245      1.1  mrg             unwindHeader.barrier_cache.bitpattern[2] = cast(_uw)lsda;
    246      1.1  mrg             unwindHeader.barrier_cache.bitpattern[3] = cast(_uw)landingPad;
    247      1.1  mrg         }
    248      1.1  mrg         else
    249      1.1  mrg         {
    250      1.1  mrg             ExceptionHeader* eh = toExceptionHeader(unwindHeader);
    251      1.1  mrg             eh.canonicalFrameAddress = cfa;
    252      1.1  mrg             eh.handler = handler;
    253      1.1  mrg             eh.languageSpecificData = lsda;
    254      1.1  mrg             eh.landingPad = landingPad;
    255      1.1  mrg         }
    256      1.1  mrg     }
    257      1.1  mrg 
    258      1.1  mrg     /**
    259      1.1  mrg      * Restore the catch handler data saved during phase1.
    260      1.1  mrg      */
    261      1.1  mrg     static void restore(_Unwind_Exception* unwindHeader, out int handler,
    262      1.1  mrg                         out const(ubyte)* lsda, out _Unwind_Ptr landingPad,
    263      1.1  mrg                         out _Unwind_Word cfa) @nogc
    264      1.1  mrg     {
    265      1.1  mrg         static if (GNU_ARM_EABI_Unwinder)
    266      1.1  mrg         {
    267      1.1  mrg             cfa = unwindHeader.barrier_cache.sp;
    268      1.1  mrg             handler = cast(int)unwindHeader.barrier_cache.bitpattern[1];
    269      1.1  mrg             lsda = cast(ubyte*)unwindHeader.barrier_cache.bitpattern[2];
    270      1.1  mrg             landingPad = cast(_Unwind_Ptr)unwindHeader.barrier_cache.bitpattern[3];
    271      1.1  mrg         }
    272      1.1  mrg         else
    273      1.1  mrg         {
    274      1.1  mrg             ExceptionHeader* eh = toExceptionHeader(unwindHeader);
    275      1.1  mrg             cfa = eh.canonicalFrameAddress;
    276      1.1  mrg             handler = eh.handler;
    277      1.1  mrg             lsda = eh.languageSpecificData;
    278      1.1  mrg             landingPad = cast(_Unwind_Ptr)eh.landingPad;
    279      1.1  mrg         }
    280      1.1  mrg     }
    281      1.1  mrg 
    282      1.1  mrg     /**
    283      1.1  mrg      * Convert from pointer to unwindHeader to pointer to ExceptionHeader
    284      1.1  mrg      * that it is embedded inside of.
    285      1.1  mrg      */
    286      1.1  mrg     static ExceptionHeader* toExceptionHeader(_Unwind_Exception* exc) @nogc
    287      1.1  mrg     {
    288      1.1  mrg         return cast(ExceptionHeader*)(cast(void*)exc - ExceptionHeader.unwindHeader.offsetof);
    289      1.1  mrg     }
    290      1.1  mrg }
    291      1.1  mrg 
    292      1.1  mrg /**
    293      1.1  mrg  * Map to C++ std::type_info's virtual functions from D,
    294      1.1  mrg  * being careful to not require linking with libstdc++.
    295      1.1  mrg  * So it is given a different name.
    296      1.1  mrg  */
    297      1.1  mrg extern(C++) interface CxxTypeInfo
    298      1.1  mrg {
    299      1.1  mrg     void dtor1();
    300      1.1  mrg     void dtor2();
    301      1.1  mrg     bool __is_pointer_p() const;
    302      1.1  mrg     bool __is_function_p() const;
    303      1.1  mrg     bool __do_catch(const CxxTypeInfo, void**, uint) const;
    304      1.1  mrg     bool __do_upcast(const void*, void**) const;
    305      1.1  mrg }
    306      1.1  mrg 
    307      1.1  mrg /**
    308      1.1  mrg  * Structure of a C++ exception, represented as a C structure.
    309      1.1  mrg  * See unwind-cxx.h for the full definition.
    310      1.1  mrg  */
    311      1.1  mrg struct CxaExceptionHeader
    312      1.1  mrg {
    313      1.1  mrg     union
    314      1.1  mrg     {
    315      1.1  mrg         CxxTypeInfo exceptionType;
    316      1.1  mrg         void* primaryException;
    317      1.1  mrg     }
    318      1.1  mrg     void function(void*) exceptionDestructor;
    319      1.1  mrg     void function() unexpectedHandler;
    320      1.1  mrg     void function() terminateHandler;
    321      1.1  mrg     CxaExceptionHeader* nextException;
    322      1.1  mrg     int handlerCount;
    323      1.1  mrg 
    324      1.1  mrg     static if (GNU_ARM_EABI_Unwinder)
    325      1.1  mrg     {
    326      1.1  mrg         CxaExceptionHeader* nextPropagatingException;
    327      1.1  mrg         int propagationCount;
    328      1.1  mrg     }
    329      1.1  mrg     else
    330      1.1  mrg     {
    331      1.1  mrg         int handlerSwitchValue;
    332      1.1  mrg         const(ubyte)* actionRecord;
    333      1.1  mrg         const(ubyte)* languageSpecificData;
    334      1.1  mrg         _Unwind_Ptr catchTemp;
    335      1.1  mrg         void* adjustedPtr;
    336      1.1  mrg     }
    337      1.1  mrg 
    338      1.1  mrg     _Unwind_Exception unwindHeader;
    339      1.1  mrg 
    340      1.1  mrg     /**
    341      1.1  mrg      * There's no saving between phases, so only cache pointer.
    342      1.1  mrg      * __cxa_begin_catch expects this to be set.
    343      1.1  mrg      */
    344      1.1  mrg     static void save(_Unwind_Exception* unwindHeader, void* thrownPtr) @nogc
    345      1.1  mrg     {
    346      1.1  mrg         static if (GNU_ARM_EABI_Unwinder)
    347      1.1  mrg             unwindHeader.barrier_cache.bitpattern[0] = cast(_uw) thrownPtr;
    348      1.1  mrg         else
    349      1.1  mrg         {
    350      1.1  mrg             auto eh = toExceptionHeader(unwindHeader);
    351      1.1  mrg             eh.adjustedPtr = thrownPtr;
    352      1.1  mrg         }
    353      1.1  mrg     }
    354      1.1  mrg 
    355      1.1  mrg     /**
    356      1.1  mrg      * Get pointer to the thrown object if the thrown object type behind the
    357      1.1  mrg      * exception is implicitly convertible to the catch type.
    358      1.1  mrg      */
    359      1.1  mrg     static void* getAdjustedPtr(_Unwind_Exception* exc, CxxTypeInfo catchType)
    360      1.1  mrg     {
    361      1.1  mrg         void* thrownPtr;
    362      1.1  mrg 
    363      1.1  mrg         // A dependent C++ exceptions is just a wrapper around the unwind header.
    364      1.1  mrg         // A primary C++ exception has the thrown object located immediately after it.
    365      1.1  mrg         if (isDependentException(exc.exception_class))
    366      1.1  mrg             thrownPtr = toExceptionHeader(exc).primaryException;
    367      1.1  mrg         else
    368      1.1  mrg             thrownPtr = cast(void*)(exc + 1);
    369      1.1  mrg 
    370      1.1  mrg         // Pointer types need to adjust the actual pointer, not the pointer that is
    371      1.1  mrg         // the exception object.  This also has the effect of passing pointer types
    372      1.1  mrg         // "by value" through the __cxa_begin_catch return value.
    373      1.1  mrg         const throw_type = (cast(CxaExceptionHeader*)thrownPtr - 1).exceptionType;
    374      1.1  mrg 
    375      1.1  mrg         if (throw_type.__is_pointer_p())
    376      1.1  mrg             thrownPtr = *cast(void**)thrownPtr;
    377      1.1  mrg 
    378      1.1  mrg         // Pointer adjustment may be necessary due to multiple inheritance
    379      1.1  mrg         if (catchType is throw_type
    380      1.1  mrg             || catchType.__do_catch(throw_type, &thrownPtr, 1))
    381      1.1  mrg             return thrownPtr;
    382      1.1  mrg 
    383      1.1  mrg         return null;
    384      1.1  mrg     }
    385      1.1  mrg 
    386      1.1  mrg     /**
    387      1.1  mrg      * Convert from pointer to unwindHeader to pointer to CxaExceptionHeader
    388      1.1  mrg      * that it is embedded inside of.
    389      1.1  mrg      */
    390      1.1  mrg     static CxaExceptionHeader* toExceptionHeader(_Unwind_Exception* exc) @nogc
    391      1.1  mrg     {
    392      1.1  mrg         return cast(CxaExceptionHeader*)(exc + 1) - 1;
    393      1.1  mrg     }
    394      1.1  mrg }
    395      1.1  mrg 
    396      1.1  mrg /**
    397      1.1  mrg  * Called if exception handling must be abandoned for any reason.
    398      1.1  mrg  */
    399      1.1  mrg private void terminate(string msg, uint line) @nogc
    400      1.1  mrg {
    401      1.1  mrg     import core.stdc.stdio;
    402      1.1  mrg     import core.stdc.stdlib;
    403      1.1  mrg 
    404      1.1  mrg     static bool terminating;
    405      1.1  mrg     if (terminating)
    406      1.1  mrg     {
    407      1.1  mrg         fputs("terminate called recursively\n", stderr);
    408      1.1  mrg         abort();
    409      1.1  mrg     }
    410      1.1  mrg     terminating = true;
    411      1.1  mrg 
    412      1.1  mrg     fprintf(stderr, "gcc.deh(%u): %.*s\n", line, cast(int)msg.length, msg.ptr);
    413      1.1  mrg 
    414      1.1  mrg     abort();
    415      1.1  mrg }
    416      1.1  mrg 
    417      1.1  mrg /**
    418      1.1  mrg  * Called when fibers switch contexts.
    419      1.1  mrg  */
    420      1.1  mrg extern(C) void* _d_eh_swapContext(void* newContext) nothrow @nogc
    421      1.1  mrg {
    422      1.1  mrg     auto old = ExceptionHeader.stack;
    423      1.1  mrg     ExceptionHeader.stack = cast(ExceptionHeader*)newContext;
    424      1.1  mrg     return old;
    425      1.1  mrg }
    426      1.1  mrg 
    427      1.1  mrg /**
    428      1.1  mrg  * Called before starting a catch.  Returns the exception object.
    429      1.1  mrg  */
    430      1.1  mrg extern(C) void* __gdc_begin_catch(_Unwind_Exception* unwindHeader)
    431      1.1  mrg {
    432      1.1  mrg     ExceptionHeader* header = ExceptionHeader.toExceptionHeader(unwindHeader);
    433      1.1  mrg 
    434      1.1  mrg     void* objectp = cast(void*)header.object;
    435  1.1.1.3  mrg     // Remove our reference to the exception. We should not decrease its refcount,
    436  1.1.1.3  mrg     // because we pass the object on to the caller.
    437  1.1.1.3  mrg     header.object = null;
    438      1.1  mrg 
    439      1.1  mrg     // Something went wrong when stacking up chained headers...
    440      1.1  mrg     if (header != ExceptionHeader.pop())
    441      1.1  mrg         terminate("catch error", __LINE__);
    442      1.1  mrg 
    443      1.1  mrg     // Handling for this exception is complete.
    444      1.1  mrg     _Unwind_DeleteException(&header.unwindHeader);
    445      1.1  mrg 
    446      1.1  mrg     return objectp;
    447      1.1  mrg }
    448      1.1  mrg 
    449      1.1  mrg /**
    450      1.1  mrg  * Perform a throw, D style. Throw will unwind through this call,
    451      1.1  mrg  * so there better not be any handlers or exception thrown here.
    452      1.1  mrg  */
    453      1.1  mrg extern(C) void _d_throw(Throwable object)
    454      1.1  mrg {
    455      1.1  mrg     // If possible, avoid always allocating new memory for exception headers.
    456      1.1  mrg     ExceptionHeader *eh = ExceptionHeader.create(object);
    457      1.1  mrg 
    458      1.1  mrg     // Add to thrown exception stack.
    459      1.1  mrg     eh.push();
    460      1.1  mrg 
    461  1.1.1.3  mrg     // Increment reference count if object is a refcounted Throwable.
    462  1.1.1.3  mrg     auto refcount = object.refcount();
    463  1.1.1.3  mrg     if (refcount)
    464  1.1.1.3  mrg         object.refcount() = refcount + 1;
    465  1.1.1.3  mrg 
    466      1.1  mrg     // Called by unwinder when exception object needs destruction by other than our code.
    467      1.1  mrg     extern(C) void exception_cleanup(_Unwind_Reason_Code code, _Unwind_Exception* exc)
    468      1.1  mrg     {
    469      1.1  mrg         // If we haven't been caught by a foreign handler, then this is
    470      1.1  mrg         // some sort of unwind error.  In that case just die immediately.
    471      1.1  mrg         // _Unwind_DeleteException in the HP-UX IA64 libunwind library
    472      1.1  mrg         //  returns _URC_NO_REASON and not _URC_FOREIGN_EXCEPTION_CAUGHT
    473      1.1  mrg         // like the GCC _Unwind_DeleteException function does.
    474      1.1  mrg         if (code != _URC_FOREIGN_EXCEPTION_CAUGHT && code != _URC_NO_REASON)
    475      1.1  mrg             terminate("uncaught exception", __LINE__);
    476      1.1  mrg 
    477      1.1  mrg         auto eh = ExceptionHeader.toExceptionHeader(exc);
    478      1.1  mrg         ExceptionHeader.free(eh);
    479      1.1  mrg     }
    480      1.1  mrg 
    481      1.1  mrg     eh.unwindHeader.exception_cleanup = &exception_cleanup;
    482      1.1  mrg 
    483      1.1  mrg     // Runtime now expects us to do this first before unwinding.
    484      1.1  mrg     _d_createTrace(eh.object, null);
    485      1.1  mrg 
    486      1.1  mrg     // We're happy with setjmp/longjmp exceptions or region-based
    487      1.1  mrg     // exception handlers: entry points are provided here for both.
    488      1.1  mrg     _Unwind_Reason_Code r = void;
    489      1.1  mrg 
    490      1.1  mrg     version (GNU_SjLj_Exceptions)
    491      1.1  mrg         r = _Unwind_SjLj_RaiseException(&eh.unwindHeader);
    492      1.1  mrg     else
    493      1.1  mrg         r = _Unwind_RaiseException(&eh.unwindHeader);
    494      1.1  mrg 
    495      1.1  mrg     // If code == _URC_END_OF_STACK, then we reached top of stack without finding
    496      1.1  mrg     // a handler for the exception.  Since each thread is run in a try/catch,
    497      1.1  mrg     // this oughtn't happen.  If code is something else, we encountered some sort
    498      1.1  mrg     // of heinous lossage from which we could not recover.  As is the way of such
    499      1.1  mrg     // things, almost certainly we will have crashed before now, rather than
    500      1.1  mrg     // actually being able to diagnose the problem.
    501      1.1  mrg     if (r == _URC_END_OF_STACK)
    502  1.1.1.3  mrg     {
    503  1.1.1.3  mrg         __gdc_begin_catch(&eh.unwindHeader);
    504  1.1.1.3  mrg         _d_print_throwable(object);
    505      1.1  mrg         terminate("uncaught exception", __LINE__);
    506  1.1.1.3  mrg     }
    507      1.1  mrg 
    508      1.1  mrg     terminate("unwind error", __LINE__);
    509      1.1  mrg }
    510      1.1  mrg 
    511      1.1  mrg static if (GNU_ARM_EABI_Unwinder)
    512      1.1  mrg {
    513      1.1  mrg     enum personality_fn_attributes = attribute("target", ("general-regs-only"));
    514      1.1  mrg }
    515      1.1  mrg else
    516      1.1  mrg {
    517      1.1  mrg     enum personality_fn_attributes = "";
    518      1.1  mrg }
    519      1.1  mrg 
    520      1.1  mrg /**
    521      1.1  mrg  * Read and extract information from the LSDA (.gcc_except_table section).
    522      1.1  mrg  */
    523      1.1  mrg @personality_fn_attributes
    524      1.1  mrg _Unwind_Reason_Code scanLSDA(const(ubyte)* lsda, _Unwind_Exception_Class exceptionClass,
    525      1.1  mrg                              _Unwind_Action actions, _Unwind_Exception* unwindHeader,
    526      1.1  mrg                              _Unwind_Context* context, _Unwind_Word cfa,
    527      1.1  mrg                              out _Unwind_Ptr landingPad, out int handler)
    528      1.1  mrg {
    529      1.1  mrg     // If no LSDA, then there are no handlers or cleanups.
    530      1.1  mrg     if (lsda is null)
    531      1.1  mrg         return CONTINUE_UNWINDING(unwindHeader, context);
    532      1.1  mrg 
    533      1.1  mrg     // Parse the LSDA header
    534      1.1  mrg     auto p = lsda;
    535      1.1  mrg 
    536      1.1  mrg     auto Start = (context ? _Unwind_GetRegionStart(context) : 0);
    537      1.1  mrg 
    538      1.1  mrg     // Find @LPStart, the base to which landing pad offsets are relative.
    539      1.1  mrg     ubyte LPStartEncoding = *p++;
    540      1.1  mrg     _Unwind_Ptr LPStart = 0;
    541      1.1  mrg 
    542      1.1  mrg     if (LPStartEncoding != DW_EH_PE_omit)
    543  1.1.1.3  mrg         LPStart = read_encoded_value(context, LPStartEncoding, p);
    544      1.1  mrg     else
    545      1.1  mrg         LPStart = Start;
    546      1.1  mrg 
    547      1.1  mrg     // Find @TType, the base of the handler and exception spec type data.
    548      1.1  mrg     ubyte TTypeEncoding = *p++;
    549      1.1  mrg     const(ubyte)* TType = null;
    550      1.1  mrg 
    551      1.1  mrg     if (TTypeEncoding != DW_EH_PE_omit)
    552      1.1  mrg     {
    553      1.1  mrg         static if (__traits(compiles, _TTYPE_ENCODING))
    554      1.1  mrg         {
    555      1.1  mrg             // Older ARM EABI toolchains set this value incorrectly, so use a
    556      1.1  mrg             // hardcoded OS-specific format.
    557      1.1  mrg             TTypeEncoding = _TTYPE_ENCODING;
    558      1.1  mrg         }
    559  1.1.1.3  mrg         auto TTbase = read_uleb128(p);
    560      1.1  mrg         TType = p + TTbase;
    561      1.1  mrg     }
    562      1.1  mrg 
    563      1.1  mrg     // The encoding and length of the call-site table; the action table
    564      1.1  mrg     // immediately follows.
    565      1.1  mrg     ubyte CSEncoding = *p++;
    566  1.1.1.3  mrg     auto CSTableSize = read_uleb128(p);
    567      1.1  mrg     const(ubyte)* actionTable = p + CSTableSize;
    568      1.1  mrg 
    569      1.1  mrg     auto TTypeBase = base_of_encoded_value(TTypeEncoding, context);
    570      1.1  mrg 
    571      1.1  mrg     // Get instruction pointer (ip) at start of instruction that threw.
    572      1.1  mrg     version (CRuntime_Glibc)
    573      1.1  mrg     {
    574      1.1  mrg         int ip_before_insn;
    575      1.1  mrg         auto ip = _Unwind_GetIPInfo(context, &ip_before_insn);
    576      1.1  mrg         if (!ip_before_insn)
    577      1.1  mrg             --ip;
    578      1.1  mrg     }
    579      1.1  mrg     else
    580      1.1  mrg     {
    581      1.1  mrg         auto ip = _Unwind_GetIP(context);
    582      1.1  mrg         --ip;
    583      1.1  mrg     }
    584      1.1  mrg 
    585      1.1  mrg     bool saw_cleanup = false;
    586      1.1  mrg     bool saw_handler = false;
    587      1.1  mrg     const(ubyte)* actionRecord = null;
    588      1.1  mrg 
    589      1.1  mrg     version (GNU_SjLj_Exceptions)
    590      1.1  mrg     {
    591      1.1  mrg         // The given "IP" is an index into the call-site table, with two
    592      1.1  mrg         // exceptions -- -1 means no-action, and 0 means terminate.
    593      1.1  mrg         // But since we're using uleb128 values, we've not got random
    594      1.1  mrg         // access to the array.
    595      1.1  mrg         if (cast(int) ip <= 0)
    596      1.1  mrg         {
    597      1.1  mrg             return _URC_CONTINUE_UNWIND;
    598      1.1  mrg         }
    599      1.1  mrg         else
    600      1.1  mrg         {
    601      1.1  mrg             _uleb128_t CSLandingPad, CSAction;
    602      1.1  mrg             do
    603      1.1  mrg             {
    604  1.1.1.3  mrg                 CSLandingPad = read_uleb128(p);
    605  1.1.1.3  mrg                 CSAction = read_uleb128(p);
    606      1.1  mrg             }
    607      1.1  mrg             while (--ip);
    608      1.1  mrg 
    609      1.1  mrg             // Can never have null landing pad for sjlj -- that would have
    610      1.1  mrg             // been indicated by a -1 call site index.
    611      1.1  mrg             landingPad = CSLandingPad + 1;
    612      1.1  mrg             if (CSAction)
    613      1.1  mrg                 actionRecord = actionTable + CSAction - 1;
    614      1.1  mrg         }
    615      1.1  mrg     }
    616      1.1  mrg     else
    617      1.1  mrg     {
    618      1.1  mrg         // Search the call-site table for the action associated with this IP.
    619      1.1  mrg         while (p < actionTable)
    620      1.1  mrg         {
    621      1.1  mrg             // Note that all call-site encodings are "absolute" displacements.
    622  1.1.1.3  mrg             auto CSStart = read_encoded_value(null, CSEncoding, p);
    623  1.1.1.3  mrg             auto CSLen = read_encoded_value(null, CSEncoding, p);
    624  1.1.1.3  mrg             auto CSLandingPad = read_encoded_value(null, CSEncoding, p);
    625  1.1.1.3  mrg             auto CSAction = read_uleb128(p);
    626      1.1  mrg 
    627      1.1  mrg             // The table is sorted, so if we've passed the ip, stop.
    628      1.1  mrg             if (ip < Start + CSStart)
    629      1.1  mrg                 p = actionTable;
    630      1.1  mrg             else if (ip < Start + CSStart + CSLen)
    631      1.1  mrg             {
    632      1.1  mrg                 if (CSLandingPad)
    633      1.1  mrg                     landingPad = LPStart + CSLandingPad;
    634      1.1  mrg                 if (CSAction)
    635      1.1  mrg                     actionRecord = actionTable + CSAction - 1;
    636      1.1  mrg                 break;
    637      1.1  mrg             }
    638      1.1  mrg         }
    639      1.1  mrg     }
    640      1.1  mrg 
    641      1.1  mrg     if (landingPad == 0)
    642      1.1  mrg     {
    643      1.1  mrg         // IP is present, but has a null landing pad.
    644      1.1  mrg         // No cleanups or handlers to be run.
    645      1.1  mrg     }
    646      1.1  mrg     else if (actionRecord is null)
    647      1.1  mrg     {
    648      1.1  mrg         // If ip is present, has a non-null landing pad, and a null
    649      1.1  mrg         // action table offset, then there are only cleanups present.
    650      1.1  mrg         // Cleanups use a zero switch value, as set above.
    651      1.1  mrg         saw_cleanup = true;
    652      1.1  mrg     }
    653      1.1  mrg     else
    654      1.1  mrg     {
    655      1.1  mrg         // Otherwise we have a catch handler or exception specification.
    656      1.1  mrg         handler = actionTableLookup(actions, unwindHeader, actionRecord,
    657  1.1.1.3  mrg                                     lsda, exceptionClass, TTypeBase,
    658      1.1  mrg                                     TType, TTypeEncoding,
    659      1.1  mrg                                     saw_handler, saw_cleanup);
    660      1.1  mrg     }
    661      1.1  mrg 
    662      1.1  mrg     // IP is not in table.  No associated cleanups.
    663      1.1  mrg     if (!saw_handler && !saw_cleanup)
    664      1.1  mrg         return CONTINUE_UNWINDING(unwindHeader, context);
    665      1.1  mrg 
    666      1.1  mrg     if (actions & _UA_SEARCH_PHASE)
    667      1.1  mrg     {
    668      1.1  mrg         if (!saw_handler)
    669      1.1  mrg             return CONTINUE_UNWINDING(unwindHeader, context);
    670      1.1  mrg 
    671      1.1  mrg         // For domestic exceptions, we cache data from phase 1 for phase 2.
    672      1.1  mrg         if (isGdcExceptionClass(exceptionClass))
    673      1.1  mrg             ExceptionHeader.save(unwindHeader, cfa, handler, lsda, landingPad);
    674      1.1  mrg 
    675      1.1  mrg         return _URC_HANDLER_FOUND;
    676      1.1  mrg     }
    677      1.1  mrg 
    678      1.1  mrg     return 0;
    679      1.1  mrg }
    680      1.1  mrg 
    681      1.1  mrg /**
    682      1.1  mrg  * Look up and return the handler index of the classType in Action Table.
    683      1.1  mrg  */
    684      1.1  mrg int actionTableLookup(_Unwind_Action actions, _Unwind_Exception* unwindHeader,
    685  1.1.1.3  mrg                       const(ubyte)* actionRecord, const(ubyte)* lsda,
    686  1.1.1.3  mrg                       _Unwind_Exception_Class exceptionClass,
    687      1.1  mrg                       _Unwind_Ptr TTypeBase, const(ubyte)* TType,
    688      1.1  mrg                       ubyte TTypeEncoding,
    689      1.1  mrg                       out bool saw_handler, out bool saw_cleanup)
    690      1.1  mrg {
    691      1.1  mrg     ClassInfo thrownType;
    692      1.1  mrg     if (isGdcExceptionClass(exceptionClass))
    693      1.1  mrg     {
    694  1.1.1.3  mrg         thrownType = getClassInfo(unwindHeader, lsda);
    695      1.1  mrg     }
    696      1.1  mrg 
    697      1.1  mrg     while (1)
    698      1.1  mrg     {
    699      1.1  mrg         auto ap = actionRecord;
    700  1.1.1.3  mrg         auto ARFilter = read_sleb128(ap);
    701      1.1  mrg         auto apn = ap;
    702  1.1.1.3  mrg         auto ARDisp = read_sleb128(ap);
    703      1.1  mrg 
    704      1.1  mrg         if (ARFilter == 0)
    705      1.1  mrg         {
    706      1.1  mrg             // Zero filter values are cleanups.
    707      1.1  mrg             saw_cleanup = true;
    708      1.1  mrg         }
    709      1.1  mrg         else if (actions & _UA_FORCE_UNWIND)
    710      1.1  mrg         {
    711      1.1  mrg             // During forced unwinding, we only run cleanups.
    712      1.1  mrg         }
    713      1.1  mrg         else if (ARFilter > 0)
    714      1.1  mrg         {
    715      1.1  mrg             // Positive filter values are handlers.
    716      1.1  mrg             auto encodedSize = size_of_encoded_value(TTypeEncoding);
    717      1.1  mrg 
    718      1.1  mrg             // ARFilter is the negative index from TType, which is where
    719      1.1  mrg             // the ClassInfo is stored.
    720      1.1  mrg             const(ubyte)* tp = TType - ARFilter * encodedSize;
    721      1.1  mrg 
    722  1.1.1.3  mrg             auto entry = read_encoded_value_with_base(TTypeEncoding, TTypeBase, tp);
    723      1.1  mrg             ClassInfo ci = cast(ClassInfo)cast(void*)(entry);
    724      1.1  mrg 
    725      1.1  mrg             // D does not have catch-all handlers, and so the following
    726      1.1  mrg             // assumes that we will never handle a null value.
    727      1.1  mrg             assert(ci !is null);
    728      1.1  mrg 
    729      1.1  mrg             if (ci.classinfo is __cpp_type_info_ptr.classinfo
    730      1.1  mrg                 && isGxxExceptionClass(exceptionClass))
    731      1.1  mrg             {
    732      1.1  mrg                 // catchType is the catch clause type_info.
    733      1.1  mrg                 auto catchType = cast(CxxTypeInfo)((cast(__cpp_type_info_ptr)cast(void*)ci).ptr);
    734      1.1  mrg                 auto thrownPtr = CxaExceptionHeader.getAdjustedPtr(unwindHeader, catchType);
    735      1.1  mrg 
    736      1.1  mrg                 if (thrownPtr !is null)
    737      1.1  mrg                 {
    738      1.1  mrg                     if (actions & _UA_SEARCH_PHASE)
    739      1.1  mrg                         CxaExceptionHeader.save(unwindHeader, thrownPtr);
    740      1.1  mrg                     saw_handler = true;
    741      1.1  mrg                     return cast(int)ARFilter;
    742      1.1  mrg                 }
    743      1.1  mrg             }
    744      1.1  mrg             else if (isGdcExceptionClass(exceptionClass)
    745      1.1  mrg                      && _d_isbaseof(thrownType, ci))
    746      1.1  mrg             {
    747      1.1  mrg                 saw_handler = true;
    748      1.1  mrg                 return cast(int)ARFilter;
    749      1.1  mrg             }
    750      1.1  mrg             else
    751      1.1  mrg             {
    752      1.1  mrg                 // ??? What to do about other GNU language exceptions.
    753      1.1  mrg             }
    754      1.1  mrg         }
    755      1.1  mrg         else
    756      1.1  mrg         {
    757      1.1  mrg             // Negative filter values are exception specifications,
    758      1.1  mrg             // which D does not use.
    759      1.1  mrg             break;
    760      1.1  mrg         }
    761      1.1  mrg 
    762      1.1  mrg         if (ARDisp == 0)
    763      1.1  mrg             break;
    764      1.1  mrg         actionRecord = apn + ARDisp;
    765      1.1  mrg     }
    766      1.1  mrg 
    767      1.1  mrg     return 0;
    768      1.1  mrg }
    769      1.1  mrg 
    770      1.1  mrg /**
    771  1.1.1.3  mrg  * Look at the chain of inflight exceptions and pick the class type that'll
    772  1.1.1.3  mrg  * be looked for in catch clauses.
    773  1.1.1.3  mrg  */
    774  1.1.1.3  mrg ClassInfo getClassInfo(_Unwind_Exception* unwindHeader,
    775  1.1.1.3  mrg                        const(ubyte)* currentLsd) @nogc
    776  1.1.1.3  mrg {
    777  1.1.1.3  mrg     ExceptionHeader* eh = ExceptionHeader.toExceptionHeader(unwindHeader);
    778  1.1.1.3  mrg     // The first thrown Exception at the top of the stack takes precedence
    779  1.1.1.3  mrg     // over others that are inflight, unless an Error was thrown, in which
    780  1.1.1.3  mrg     // case, we search for error handlers instead.
    781  1.1.1.3  mrg     Throwable ehobject = eh.object;
    782  1.1.1.3  mrg     for (ExceptionHeader* ehn = eh.next; ehn; ehn = ehn.next)
    783  1.1.1.3  mrg     {
    784  1.1.1.3  mrg         const(ubyte)* nextLsd = void;
    785  1.1.1.3  mrg         _Unwind_Ptr nextLandingPad = void;
    786  1.1.1.3  mrg         _Unwind_Word nextCfa = void;
    787  1.1.1.3  mrg         int nextHandler = void;
    788  1.1.1.3  mrg 
    789  1.1.1.3  mrg         ExceptionHeader.restore(&ehn.unwindHeader, nextHandler, nextLsd, nextLandingPad, nextCfa);
    790  1.1.1.3  mrg 
    791  1.1.1.3  mrg         // Don't combine when the exceptions are from different functions.
    792  1.1.1.3  mrg         if (currentLsd != nextLsd)
    793  1.1.1.3  mrg             break;
    794  1.1.1.3  mrg 
    795  1.1.1.3  mrg         Error e = cast(Error)ehobject;
    796  1.1.1.3  mrg         if (e is null || (cast(Error)ehn.object) !is null)
    797  1.1.1.3  mrg         {
    798  1.1.1.3  mrg             currentLsd = nextLsd;
    799  1.1.1.3  mrg             ehobject = ehn.object;
    800  1.1.1.3  mrg         }
    801  1.1.1.3  mrg     }
    802  1.1.1.3  mrg     return ehobject.classinfo;
    803  1.1.1.3  mrg }
    804  1.1.1.3  mrg 
    805  1.1.1.3  mrg /**
    806      1.1  mrg  * Called when the personality function has found neither a cleanup or handler.
    807      1.1  mrg  * To support ARM EABI personality routines, that must also unwind the stack.
    808      1.1  mrg  */
    809      1.1  mrg @personality_fn_attributes
    810      1.1  mrg _Unwind_Reason_Code CONTINUE_UNWINDING(_Unwind_Exception* unwindHeader, _Unwind_Context* context)
    811      1.1  mrg {
    812      1.1  mrg     static if (GNU_ARM_EABI_Unwinder)
    813      1.1  mrg     {
    814      1.1  mrg         if (__gnu_unwind_frame(unwindHeader, context) != _URC_OK)
    815      1.1  mrg             return _URC_FAILURE;
    816      1.1  mrg     }
    817      1.1  mrg     return _URC_CONTINUE_UNWIND;
    818      1.1  mrg }
    819      1.1  mrg 
    820      1.1  mrg /**
    821      1.1  mrg  * Using a different personality function name causes link failures
    822      1.1  mrg  * when trying to mix code using different exception handling models.
    823      1.1  mrg  */
    824      1.1  mrg version (GNU_SEH_Exceptions)
    825      1.1  mrg {
    826      1.1  mrg     enum PERSONALITY_FUNCTION = "__gdc_personality_imp";
    827      1.1  mrg 
    828      1.1  mrg     extern(C) EXCEPTION_DISPOSITION __gdc_personality_seh0(void* ms_exc, void* this_frame,
    829      1.1  mrg                                                            void* ms_orig_context, void* ms_disp)
    830      1.1  mrg     {
    831      1.1  mrg         return _GCC_specific_handler(ms_exc, this_frame, ms_orig_context,
    832  1.1.1.3  mrg                                      ms_disp, &gdc_personality);
    833      1.1  mrg     }
    834      1.1  mrg }
    835      1.1  mrg else version (GNU_SjLj_Exceptions)
    836      1.1  mrg {
    837      1.1  mrg     enum PERSONALITY_FUNCTION = "__gdc_personality_sj0";
    838      1.1  mrg 
    839      1.1  mrg     private int __builtin_eh_return_data_regno(int x) { return x; }
    840      1.1  mrg }
    841      1.1  mrg else
    842      1.1  mrg {
    843      1.1  mrg     enum PERSONALITY_FUNCTION = "__gdc_personality_v0";
    844      1.1  mrg }
    845      1.1  mrg 
    846      1.1  mrg /**
    847      1.1  mrg  * The "personality" function, specific to each language.
    848      1.1  mrg  */
    849      1.1  mrg static if (GNU_ARM_EABI_Unwinder)
    850      1.1  mrg {
    851      1.1  mrg     pragma(mangle, PERSONALITY_FUNCTION)
    852      1.1  mrg     @personality_fn_attributes
    853      1.1  mrg     extern(C) _Unwind_Reason_Code gdc_personality(_Unwind_State state,
    854      1.1  mrg                                                   _Unwind_Exception* unwindHeader,
    855      1.1  mrg                                                   _Unwind_Context* context)
    856      1.1  mrg     {
    857      1.1  mrg         _Unwind_Action actions;
    858      1.1  mrg 
    859      1.1  mrg         switch (state & _US_ACTION_MASK)
    860      1.1  mrg         {
    861      1.1  mrg             case _US_VIRTUAL_UNWIND_FRAME:
    862      1.1  mrg                 // If the unwind state pattern is (_US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND)
    863      1.1  mrg                 // then we don't need to search for any handler as it is not a real exception.
    864      1.1  mrg                 // Just unwind the stack.
    865      1.1  mrg                 if (state & _US_FORCE_UNWIND)
    866      1.1  mrg                     return CONTINUE_UNWINDING(unwindHeader, context);
    867      1.1  mrg                 actions = _UA_SEARCH_PHASE;
    868      1.1  mrg                 break;
    869      1.1  mrg 
    870      1.1  mrg             case _US_UNWIND_FRAME_STARTING:
    871      1.1  mrg                 actions = _UA_CLEANUP_PHASE;
    872      1.1  mrg                 if (!(state & _US_FORCE_UNWIND)
    873      1.1  mrg                     && unwindHeader.barrier_cache.sp == _Unwind_GetGR(context, UNWIND_STACK_REG))
    874      1.1  mrg                     actions |= _UA_HANDLER_FRAME;
    875      1.1  mrg                 break;
    876      1.1  mrg 
    877      1.1  mrg             case _US_UNWIND_FRAME_RESUME:
    878      1.1  mrg                 return CONTINUE_UNWINDING(unwindHeader, context);
    879      1.1  mrg 
    880      1.1  mrg             default:
    881      1.1  mrg                 terminate("unwind error", __LINE__);
    882      1.1  mrg         }
    883      1.1  mrg         actions |= state & _US_FORCE_UNWIND;
    884      1.1  mrg 
    885      1.1  mrg         // The dwarf unwinder assumes the context structure holds things like
    886      1.1  mrg         // the function and LSDA pointers.  The ARM implementation caches these
    887      1.1  mrg         // in the exception header (UCB).  To avoid rewriting everything we make
    888      1.1  mrg         // the virtual IP register point at the UCB.
    889      1.1  mrg         _Unwind_SetGR(context, UNWIND_POINTER_REG, cast(_Unwind_Ptr)unwindHeader);
    890      1.1  mrg 
    891      1.1  mrg         return __gdc_personality(actions, unwindHeader.exception_class,
    892      1.1  mrg                                  unwindHeader, context);
    893      1.1  mrg     }
    894      1.1  mrg }
    895      1.1  mrg else
    896      1.1  mrg {
    897      1.1  mrg     pragma(mangle, PERSONALITY_FUNCTION)
    898      1.1  mrg     extern(C) _Unwind_Reason_Code gdc_personality(int iversion,
    899      1.1  mrg                                                   _Unwind_Action actions,
    900      1.1  mrg                                                   _Unwind_Exception_Class exceptionClass,
    901      1.1  mrg                                                   _Unwind_Exception* unwindHeader,
    902      1.1  mrg                                                   _Unwind_Context* context)
    903      1.1  mrg     {
    904      1.1  mrg         // Interface version check.
    905      1.1  mrg         if (iversion != 1)
    906      1.1  mrg             return _URC_FATAL_PHASE1_ERROR;
    907      1.1  mrg 
    908      1.1  mrg         return __gdc_personality(actions, exceptionClass, unwindHeader, context);
    909      1.1  mrg     }
    910      1.1  mrg }
    911      1.1  mrg 
    912      1.1  mrg @personality_fn_attributes
    913      1.1  mrg private _Unwind_Reason_Code __gdc_personality(_Unwind_Action actions,
    914      1.1  mrg                                               _Unwind_Exception_Class exceptionClass,
    915      1.1  mrg                                               _Unwind_Exception* unwindHeader,
    916      1.1  mrg                                               _Unwind_Context* context)
    917      1.1  mrg {
    918      1.1  mrg     const(ubyte)* lsda;
    919      1.1  mrg     _Unwind_Ptr landingPad;
    920      1.1  mrg     _Unwind_Word cfa;
    921      1.1  mrg     int handler;
    922      1.1  mrg 
    923      1.1  mrg     // Shortcut for phase 2 found handler for domestic exception.
    924      1.1  mrg     if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME)
    925      1.1  mrg         && isGdcExceptionClass(exceptionClass))
    926      1.1  mrg     {
    927      1.1  mrg         ExceptionHeader.restore(unwindHeader, handler, lsda, landingPad, cfa);
    928      1.1  mrg         // Shouldn't have cached a null landing pad in phase 1.
    929      1.1  mrg         if (landingPad == 0)
    930      1.1  mrg             terminate("unwind error", __LINE__);
    931      1.1  mrg     }
    932      1.1  mrg     else
    933      1.1  mrg     {
    934      1.1  mrg         lsda = cast(ubyte*)_Unwind_GetLanguageSpecificData(context);
    935      1.1  mrg 
    936      1.1  mrg         static if (GNU_ARM_EABI_Unwinder)
    937      1.1  mrg             cfa = _Unwind_GetGR(context, UNWIND_STACK_REG);
    938      1.1  mrg         else
    939      1.1  mrg             cfa = _Unwind_GetCFA(context);
    940      1.1  mrg 
    941      1.1  mrg         auto result = scanLSDA(lsda, exceptionClass, actions, unwindHeader,
    942      1.1  mrg                                context, cfa, landingPad, handler);
    943      1.1  mrg 
    944      1.1  mrg         // Positive on handler found in phase 1, continue unwinding, or failure.
    945      1.1  mrg         if (result)
    946      1.1  mrg             return result;
    947      1.1  mrg     }
    948      1.1  mrg 
    949      1.1  mrg     // Unexpected negative handler, call terminate directly.
    950      1.1  mrg     if (handler < 0)
    951      1.1  mrg         terminate("unwind error", __LINE__);
    952      1.1  mrg 
    953      1.1  mrg     // We can't use any of the deh routines with foreign exceptions,
    954      1.1  mrg     // because they all expect unwindHeader to be an ExceptionHeader.
    955      1.1  mrg     if (isGdcExceptionClass(exceptionClass))
    956      1.1  mrg     {
    957      1.1  mrg         // If there are any in-flight exceptions being thrown, chain our
    958      1.1  mrg         // current object onto the end of the prevous object.
    959      1.1  mrg         ExceptionHeader* eh = ExceptionHeader.toExceptionHeader(unwindHeader);
    960      1.1  mrg         auto currentLsd = lsda;
    961      1.1  mrg         bool bypassed = false;
    962      1.1  mrg 
    963      1.1  mrg         while (eh.next)
    964      1.1  mrg         {
    965      1.1  mrg             ExceptionHeader* ehn = eh.next;
    966  1.1.1.3  mrg             const(ubyte)* nextLsd = void;
    967  1.1.1.3  mrg             _Unwind_Ptr nextLandingPad = void;
    968  1.1.1.3  mrg             _Unwind_Word nextCfa = void;
    969  1.1.1.3  mrg             int nextHandler = void;
    970      1.1  mrg 
    971      1.1  mrg             ExceptionHeader.restore(&ehn.unwindHeader, nextHandler, nextLsd, nextLandingPad, nextCfa);
    972      1.1  mrg 
    973      1.1  mrg             Error e = cast(Error)eh.object;
    974      1.1  mrg             if (e !is null && !cast(Error)ehn.object)
    975      1.1  mrg             {
    976      1.1  mrg                 // We found an Error, bypass the exception chain.
    977      1.1  mrg                 currentLsd = nextLsd;
    978      1.1  mrg                 eh = ehn;
    979      1.1  mrg                 bypassed = true;
    980      1.1  mrg                 continue;
    981      1.1  mrg             }
    982      1.1  mrg 
    983      1.1  mrg             // Don't combine when the exceptions are from different functions.
    984  1.1.1.3  mrg             if (currentLsd != nextLsd)
    985      1.1  mrg                 break;
    986      1.1  mrg 
    987  1.1.1.3  mrg             // Add our object onto the end of the existing chain and replace
    988  1.1.1.3  mrg             // our exception object with in-flight one.
    989  1.1.1.3  mrg             eh.object = Throwable.chainTogether(ehn.object, eh.object);
    990      1.1  mrg 
    991      1.1  mrg             if (nextHandler != handler && !bypassed)
    992      1.1  mrg             {
    993      1.1  mrg                 handler = nextHandler;
    994      1.1  mrg                 ExceptionHeader.save(unwindHeader, cfa, handler, lsda, landingPad);
    995      1.1  mrg             }
    996      1.1  mrg 
    997      1.1  mrg             // Exceptions chained, can now throw away the previous header.
    998      1.1  mrg             eh.next = ehn.next;
    999      1.1  mrg             _Unwind_DeleteException(&ehn.unwindHeader);
   1000      1.1  mrg         }
   1001      1.1  mrg 
   1002      1.1  mrg         if (bypassed)
   1003      1.1  mrg         {
   1004      1.1  mrg             eh = ExceptionHeader.toExceptionHeader(unwindHeader);
   1005      1.1  mrg             Error e = cast(Error)eh.object;
   1006      1.1  mrg             auto ehn = eh.next;
   1007      1.1  mrg             e.bypassedException = ehn.object;
   1008      1.1  mrg             eh.next = ehn.next;
   1009      1.1  mrg             _Unwind_DeleteException(&ehn.unwindHeader);
   1010      1.1  mrg         }
   1011      1.1  mrg     }
   1012      1.1  mrg 
   1013      1.1  mrg     // Set up registers and jump to cleanup or handler.
   1014      1.1  mrg     // For targets with pointers smaller than the word size, we must extend the
   1015      1.1  mrg     // pointer, and this extension is target dependent.
   1016      1.1  mrg     _Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
   1017      1.1  mrg                   cast(_Unwind_Ptr)unwindHeader);
   1018      1.1  mrg     _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), handler);
   1019      1.1  mrg     _Unwind_SetIP(context, landingPad);
   1020      1.1  mrg 
   1021      1.1  mrg     return _URC_INSTALL_CONTEXT;
   1022      1.1  mrg }
   1023