Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/exception.c

    r3b9c674 r851fd92  
    99// Author           : Andrew Beach
    1010// Created On       : Mon Jun 26 15:13:00 2017
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb 22 18:17:34 2018
    13 // Update Count     : 11
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Apr 14 12:01:00 2020
     13// Update Count     : 18
    1414//
    1515
     16// Normally we would get this from the CFA prelude.
    1617#include <stddef.h> // for size_t
    1718
    1819#include "exception.h"
    1920
    20 // Implementation of the secret header.
     21// Implementation of the secret header is hardware dependent.
     22#if !( defined( __x86_64 ) || defined( __i386 ) )
     23#error Exception Handling: No known architecture detected.
     24#endif
    2125
    2226#include <stdlib.h>
     
    2428#include <unwind.h>
    2529#include <bits/debug.hfa>
     30#include "stdhdr/assert.h"
    2631
    2732// FIX ME: temporary hack to keep ARM build working
    2833#ifndef _URC_FATAL_PHASE1_ERROR
    29 #define _URC_FATAL_PHASE1_ERROR 2
     34#define _URC_FATAL_PHASE1_ERROR 3
    3035#endif // ! _URC_FATAL_PHASE1_ERROR
    3136#ifndef _URC_FATAL_PHASE2_ERROR
     
    3540#include "lsda.h"
    3641
     42/* The exception class for our exceptions. Because of the vendor component
     43 * its value would not be standard.
     44 * Vendor: UWPL
     45 * Language: CFA\0
     46 */
     47const _Unwind_Exception_Class __cfaehm_exception_class = 0x4c50575500414643;
    3748
    3849// Base exception vtable is abstract, you should not have base exceptions.
    39 struct __cfaabi_ehm__base_exception_t_vtable
    40                 ___cfaabi_ehm__base_exception_t_vtable_instance = {
     50struct __cfaehm_base_exception_t_vtable
     51                ___cfaehm_base_exception_t_vtable_instance = {
    4152        .parent = NULL,
    4253        .size = 0,
     
    4960// Temperary global exception context. Does not work with concurency.
    5061struct exception_context_t {
    51     struct __cfaabi_ehm__try_resume_node * top_resume;
    52     struct __cfaabi_ehm__try_resume_node * current_resume;
    53 
    54     exception_t * current_exception;
    55     int current_handler_index;
    56 } shared_stack = {NULL, NULL, 0, 0};
     62        struct __cfaehm_try_resume_node * top_resume;
     63
     64        exception_t * current_exception;
     65        int current_handler_index;
     66} static shared_stack = {NULL, NULL, 0};
    5767
    5868// Get the current exception context.
     
    6272        return &shared_stack;
    6373}
    64 //#define SAVE_EXCEPTION_CONTEXT(to_name)
    65 //struct exception_context_t * to_name = this_exception_context();
    66 //exception * this_exception() {
    67 //    return this_exception_context()->current_exception;
    68 //}
    69 
    70 
    71 // This macro should be the only thing that needs to change across machines.
    72 // Used in the personality function, way down in termination.
    73 // struct _Unwind_Context * -> _Unwind_Reason_Code(*)(exception_t *)
    74 #define MATCHER_FROM_CONTEXT(ptr_to_context) \
    75         (*(_Unwind_Reason_Code(**)(exception_t *))(_Unwind_GetCFA(ptr_to_context) + 8))
    7674
    7775
    7876// RESUMPTION ================================================================
    7977
    80 void __cfaabi_ehm__throw_resume(exception_t * except) {
    81 
    82         __cfaabi_dbg_print_safe("Throwing resumption exception\n");
    83 
    84         struct __cfaabi_ehm__try_resume_node * original_head = shared_stack.current_resume;
    85         struct __cfaabi_ehm__try_resume_node * current =
    86                 (original_head) ? original_head->next : shared_stack.top_resume;
     78static void reset_top_resume(struct __cfaehm_try_resume_node ** store) {
     79        this_exception_context()->top_resume = *store;
     80}
     81
     82void __cfaehm_throw_resume(exception_t * except) {
     83        struct exception_context_t * context = this_exception_context();
     84
     85        __cfadbg_print_safe(exception, "Throwing resumption exception\n");
     86
     87        __attribute__((cleanup(reset_top_resume)))
     88        struct __cfaehm_try_resume_node * original_head = context->top_resume;
     89        struct __cfaehm_try_resume_node * current = context->top_resume;
    8790
    8891        for ( ; current ; current = current->next) {
    89                 shared_stack.current_resume = current;
     92                context->top_resume = current->next;
    9093                if (current->handler(except)) {
    91                         shared_stack.current_resume = original_head;
    9294                        return;
    9395                }
    9496        }
    9597
    96         __cfaabi_dbg_print_safe("Unhandled exception\n");
    97         shared_stack.current_resume = original_head;
     98        __cfadbg_print_safe(exception, "Unhandled exception\n");
    9899
    99100        // Fall back to termination:
    100         __cfaabi_ehm__throw_terminate(except);
     101        __cfaehm_throw_terminate(except);
    101102        // TODO: Default handler for resumption.
    102103}
     
    106107// be added after the node is built but before it is made the top node.
    107108
    108 void __cfaabi_ehm__try_resume_setup(struct __cfaabi_ehm__try_resume_node * node,
     109void __cfaehm_try_resume_setup(struct __cfaehm_try_resume_node * node,
    109110                        _Bool (*handler)(exception_t * except)) {
    110         node->next = shared_stack.top_resume;
     111        struct exception_context_t * context = this_exception_context();
     112        node->next = context->top_resume;
    111113        node->handler = handler;
    112         shared_stack.top_resume = node;
    113 }
    114 
    115 void __cfaabi_ehm__try_resume_cleanup(struct __cfaabi_ehm__try_resume_node * node) {
    116         shared_stack.top_resume = node->next;
     114        context->top_resume = node;
     115}
     116
     117void __cfaehm_try_resume_cleanup(struct __cfaehm_try_resume_node * node) {
     118        struct exception_context_t * context = this_exception_context();
     119        context->top_resume = node->next;
    117120}
    118121
     
    123126// May have to move to cfa for constructors and destructors (references).
    124127
    125 struct __cfaabi_ehm__node {
    126         struct __cfaabi_ehm__node * next;
     128// How to clean up an exception in various situations.
     129static void __cfaehm_exception_cleanup(
     130                _Unwind_Reason_Code reason,
     131                struct _Unwind_Exception * exception) {
     132        switch (reason) {
     133        case _URC_FOREIGN_EXCEPTION_CAUGHT:
     134                // This one we could clean-up to allow cross-language exceptions.
     135        case _URC_FATAL_PHASE1_ERROR:
     136        case _URC_FATAL_PHASE2_ERROR:
     137        default:
     138                abort();
     139        }
     140}
     141
     142// We need a piece of storage to raise the exception, for now its a single
     143// piece.
     144static struct _Unwind_Exception this_exception_storage;
     145
     146struct __cfaehm_node {
     147        struct __cfaehm_node * next;
    127148};
    128149
    129150#define NODE_TO_EXCEPT(node) ((exception_t *)(1 + (node)))
    130 #define EXCEPT_TO_NODE(except) ((struct __cfaabi_ehm__node *)(except) - 1)
     151#define EXCEPT_TO_NODE(except) ((struct __cfaehm_node *)(except) - 1)
    131152
    132153// Creates a copy of the indicated exception and sets current_exception to it.
    133 static void __cfaabi_ehm__allocate_exception( exception_t * except ) {
     154static void __cfaehm_allocate_exception( exception_t * except ) {
    134155        struct exception_context_t * context = this_exception_context();
    135156
    136157        // Allocate memory for the exception.
    137         struct __cfaabi_ehm__node * store = malloc(
    138                 sizeof( struct __cfaabi_ehm__node ) + except->virtual_table->size );
     158        struct __cfaehm_node * store = malloc(
     159                sizeof( struct __cfaehm_node ) + except->virtual_table->size );
    139160
    140161        if ( ! store ) {
     
    149170        // Copy the exception to storage.
    150171        except->virtual_table->copy( context->current_exception, except );
     172
     173        // Set up the exception storage.
     174        this_exception_storage.exception_class = __cfaehm_exception_class;
     175        this_exception_storage.exception_cleanup = __cfaehm_exception_cleanup;
    151176}
    152177
    153178// Delete the provided exception, unsetting current_exception if relivant.
    154 static void __cfaabi_ehm__delete_exception( exception_t * except ) {
     179static void __cfaehm_delete_exception( exception_t * except ) {
    155180        struct exception_context_t * context = this_exception_context();
    156181
    157         __cfaabi_dbg_print_safe("Deleting Exception\n");
     182        __cfadbg_print_safe(exception, "Deleting Exception\n");
    158183
    159184        // Remove the exception from the list.
    160         struct __cfaabi_ehm__node * to_free = EXCEPT_TO_NODE(except);
    161         struct __cfaabi_ehm__node * node;
     185        struct __cfaehm_node * to_free = EXCEPT_TO_NODE(except);
     186        struct __cfaehm_node * node;
    162187
    163188        if ( context->current_exception == except ) {
     
    167192                node = EXCEPT_TO_NODE(context->current_exception);
    168193                // It may always be in the first or second position.
    169                 while( to_free != node->next ) {
     194                while ( to_free != node->next ) {
    170195                        node = node->next;
    171196                }
     
    179204
    180205// If this isn't a rethrow (*except==0), delete the provided exception.
    181 void __cfaabi_ehm__cleanup_terminate( void * except ) {
    182         if ( *(void**)except ) __cfaabi_ehm__delete_exception( *(exception_t **)except );
    183 }
    184 
    185 
    186 // We need a piece of storage to raise the exception
    187 struct _Unwind_Exception this_exception_storage;
     206void __cfaehm_cleanup_terminate( void * except ) {
     207        if ( *(void**)except ) __cfaehm_delete_exception( *(exception_t **)except );
     208}
    188209
    189210// Function needed by force unwind
     
    192213                int version,
    193214                _Unwind_Action actions,
    194                 _Unwind_Exception_Class exceptionClass,
     215                _Unwind_Exception_Class exception_class,
    195216                struct _Unwind_Exception * unwind_exception,
    196                 struct _Unwind_Context * context,
    197                 void * some_param) {
    198         if( actions & _UA_END_OF_STACK  ) exit(1);
    199         if( actions & _UA_CLEANUP_PHASE ) return _URC_NO_REASON;
    200 
    201         return _URC_FATAL_PHASE2_ERROR;
     217                struct _Unwind_Context * unwind_context,
     218                void * stop_param) {
     219        // Verify actions follow the rules we expect.
     220        verify((actions & _UA_CLEANUP_PHASE) && (actions & _UA_FORCE_UNWIND));
     221        verify(!(actions & (_UA_SEARCH_PHASE | _UA_HANDER_FRAME)));
     222
     223        if ( actions & _UA_END_OF_STACK ) {
     224                exit(1);
     225        } else {
     226                return _URC_NO_REASON;
     227        }
    202228}
    203229
    204230// The exception that is being thrown must already be stored.
    205 __attribute__((noreturn)) void __cfaabi_ehm__begin_unwind(void) {
     231static __attribute__((noreturn)) void __cfaehm_begin_unwind(void) {
    206232        if ( ! this_exception_context()->current_exception ) {
    207233                printf("UNWIND ERROR missing exception in begin unwind\n");
    208234                abort();
    209235        }
    210 
    211236
    212237        // Call stdlibc to raise the exception
     
    220245        // the whole stack.
    221246
    222         if( ret == _URC_END_OF_STACK ) {
     247        if ( ret == _URC_END_OF_STACK ) {
    223248                // No proper handler was found. This can be handled in many ways, C++ calls std::terminate.
    224249                // Here we force unwind the stack, basically raising a cancellation.
     
    235260}
    236261
    237 void __cfaabi_ehm__throw_terminate( exception_t * val ) {
    238         __cfaabi_dbg_print_safe("Throwing termination exception\n");
    239 
    240         __cfaabi_ehm__allocate_exception( val );
    241         __cfaabi_ehm__begin_unwind();
    242 }
    243 
    244 void __cfaabi_ehm__rethrow_terminate(void) {
    245         __cfaabi_dbg_print_safe("Rethrowing termination exception\n");
    246 
    247         __cfaabi_ehm__begin_unwind();
    248 }
    249 
    250 #pragma GCC push_options
    251 #pragma GCC optimize("O0")
     262void __cfaehm_throw_terminate( exception_t * val ) {
     263        __cfadbg_print_safe(exception, "Throwing termination exception\n");
     264
     265        __cfaehm_allocate_exception( val );
     266        __cfaehm_begin_unwind();
     267}
     268
     269void __cfaehm_rethrow_terminate(void) {
     270        __cfadbg_print_safe(exception, "Rethrowing termination exception\n");
     271
     272        __cfaehm_begin_unwind();
     273}
    252274
    253275// This is our personality routine. For every stack frame annotated with
    254276// ".cfi_personality 0x3,__gcfa_personality_v0" this function will be called twice when unwinding.
    255277//  Once in the search phase and once in the cleanup phase.
    256 _Unwind_Reason_Code __gcfa_personality_v0 (
    257                 int version, _Unwind_Action actions, unsigned long long exceptionClass,
    258                 struct _Unwind_Exception* unwind_exception,
    259                 struct _Unwind_Context* context)
     278_Unwind_Reason_Code __gcfa_personality_v0(
     279                int version,
     280                _Unwind_Action actions,
     281                unsigned long long exception_class,
     282                struct _Unwind_Exception * unwind_exception,
     283                struct _Unwind_Context * unwind_context)
    260284{
    261285
    262         //__cfaabi_dbg_print_safe("CFA: 0x%lx\n", _Unwind_GetCFA(context));
    263         __cfaabi_dbg_print_safe("Personality function (%d, %x, %llu, %p, %p):",
    264                         version, actions, exceptionClass, unwind_exception, context);
    265 
    266         // If we've reached the end of the stack then there is nothing much we can do...
    267         if( actions & _UA_END_OF_STACK ) return _URC_END_OF_STACK;
    268 
     286        //__cfadbg_print_safe(exception, "CFA: 0x%lx\n", _Unwind_GetCFA(context));
     287        __cfadbg_print_safe(exception, "Personality function (%d, %x, %llu, %p, %p):",
     288                        version, actions, exception_class, unwind_exception, unwind_context);
     289
     290        // Verify that actions follow the rules we expect.
     291        // This function should never be called at the end of the stack.
     292        verify(!(actions & _UA_END_OF_STACK));
     293        // Either only the search phase flag is set or...
    269294        if (actions & _UA_SEARCH_PHASE) {
    270                 __cfaabi_dbg_print_safe(" lookup phase");
    271         }
    272         else if (actions & _UA_CLEANUP_PHASE) {
    273                 __cfaabi_dbg_print_safe(" cleanup phase");
    274         }
    275         // Just in case, probably can't actually happen
    276         else {
    277                 printf(" error\n");
    278                 return _URC_FATAL_PHASE1_ERROR;
     295                verify(actions == _UA_SEARCH_PHASE);
     296                __cfadbg_print_safe(exception, " lookup phase");
     297        // ... we are in clean-up phase.
     298        } else {
     299                verify(actions & _UA_CLEANUP_PHASE);
     300                __cfadbg_print_safe(exception, " cleanup phase");
     301                // We shouldn't be the handler frame during forced unwind.
     302                if (actions & _UA_HANDLER_FRAME) {
     303                        verify(!(actions & _UA_FORCE_UNWIND));
     304                        __cfadbg_print_safe(exception, " (handler frame)");
     305                } else if (actions & _UA_FORCE_UNWIND) {
     306                        __cfadbg_print_safe(exception, " (force unwind)");
     307                }
    279308        }
    280309
    281310        // Get a pointer to the language specific data from which we will read what we need
    282         const unsigned char * lsd = (const unsigned char*) _Unwind_GetLanguageSpecificData( context );
    283 
    284         if( !lsd ) {    //Nothing to do, keep unwinding
     311        const unsigned char * lsd = _Unwind_GetLanguageSpecificData( unwind_context );
     312
     313        if ( !lsd ) {   //Nothing to do, keep unwinding
    285314                printf(" no LSD");
    286315                goto UNWIND;
     
    289318        // Get the instuction pointer and a reading pointer into the exception table
    290319        lsda_header_info lsd_info;
    291         const unsigned char * cur_ptr = parse_lsda_header(context, lsd, &lsd_info);
    292         _Unwind_Ptr instruction_ptr = _Unwind_GetIP( context );
     320        const unsigned char * cur_ptr = parse_lsda_header(unwind_context, lsd, &lsd_info);
     321        _Unwind_Ptr instruction_ptr = _Unwind_GetIP(unwind_context);
     322
     323        struct exception_context_t * context = this_exception_context();
    293324
    294325        // Linearly search the table for stuff to do
    295         while( cur_ptr < lsd_info.action_table ) {
     326        while ( cur_ptr < lsd_info.action_table ) {
    296327                _Unwind_Ptr callsite_start;
    297328                _Unwind_Ptr callsite_len;
     
    306337
    307338                // Have we reach the correct frame info yet?
    308                 if( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) {
     339                if ( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) {
    309340#ifdef __CFA_DEBUG_PRINT__
    310341                        void * ls = (void*)lsd_info.Start;
     
    314345                        void * ep = (void*)lsd_info.Start + callsite_start + callsite_len;
    315346                        void * ip = (void*)instruction_ptr;
    316                         __cfaabi_dbg_print_safe("\nfound %p - %p (%p, %p, %p), looking for %p\n",
     347                        __cfadbg_print_safe(exception, "\nfound %p - %p (%p, %p, %p), looking for %p\n",
    317348                                        bp, ep, ls, cs, cl, ip);
    318349#endif // __CFA_DEBUG_PRINT__
     
    321352
    322353                // Have we gone too far?
    323                 if( lsd_info.Start + callsite_start > instruction_ptr ) {
     354                if ( lsd_info.Start + callsite_start > instruction_ptr ) {
    324355                        printf(" gone too far");
    325356                        break;
    326357                }
    327358
    328                 // Something to do?
    329                 if( callsite_landing_pad ) {
    330                         // Which phase are we in
    331                         if (actions & _UA_SEARCH_PHASE) {
    332                                 // In search phase, these means we found a potential handler we must check.
    333 
    334                                 // We have arbitrarily decided that 0 means nothing to do and 1 means there is
    335                                 // a potential handler. This doesn't seem to conflict the gcc default behavior.
    336                                 if (callsite_action != 0) {
    337                                         // Now we want to run some code to see if the handler matches
    338                                         // This is the tricky part where we want to the power to run arbitrary code
    339                                         // However, generating a new exception table entry and try routine every time
    340                                         // is way more expansive than we might like
    341                                         // The information we have is :
    342                                         //  - The GR (Series of registers)
    343                                         //    GR1=GP Global Pointer of frame ref by context
    344                                         //  - The instruction pointer
    345                                         //  - The instruction pointer info (???)
    346                                         //  - The CFA (Canonical Frame Address)
    347                                         //  - The BSP (Probably the base stack pointer)
    348 
    349 
    350                                         // The current apprach uses one exception table entry per try block
    351                                         _uleb128_t imatcher;
    352                                         // Get the relative offset to the {...}?
    353                                         cur_ptr = read_uleb128(cur_ptr, &imatcher);
    354 
    355                                         _Unwind_Reason_Code (*matcher)(exception_t *) =
    356                                                 MATCHER_FROM_CONTEXT(context);
    357                                         int index = matcher(shared_stack.current_exception);
    358                                         _Unwind_Reason_Code ret = (0 == index)
    359                                                 ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND;
    360                                         shared_stack.current_handler_index = index;
    361 
    362                                         // Based on the return value, check if we matched the exception
    363                                         if( ret == _URC_HANDLER_FOUND) {
    364                                                 __cfaabi_dbg_print_safe(" handler found\n");
    365                                         } else {
    366                                                 __cfaabi_dbg_print_safe(" no handler\n");
    367                                         }
    368                                         return ret;
     359                // Check for what we must do:
     360                if ( 0 == callsite_landing_pad ) {
     361                        // Nothing to do, move along
     362                        __cfadbg_print_safe(exception, " no landing pad");
     363                } else if (actions & _UA_SEARCH_PHASE) {
     364                        // In search phase, these means we found a potential handler we must check.
     365
     366                        // We have arbitrarily decided that 0 means nothing to do and 1 means there is
     367                        // a potential handler. This doesn't seem to conflict the gcc default behavior.
     368                        if (callsite_action != 0) {
     369                                // Now we want to run some code to see if the handler matches
     370                                // This is the tricky part where we want to the power to run arbitrary code
     371                                // However, generating a new exception table entry and try routine every time
     372                                // is way more expansive than we might like
     373                                // The information we have is :
     374                                //  - The GR (Series of registers)
     375                                //    GR1=GP Global Pointer of frame ref by context
     376                                //  - The instruction pointer
     377                                //  - The instruction pointer info (???)
     378                                //  - The CFA (Canonical Frame Address)
     379                                //  - The BSP (Probably the base stack pointer)
     380
     381                                // The current apprach uses one exception table entry per try block
     382                                _uleb128_t imatcher;
     383                                // Get the relative offset to the {...}?
     384                                cur_ptr = read_uleb128(cur_ptr, &imatcher);
     385
     386#                               if defined( __x86_64 )
     387                                _Unwind_Word match_pos = _Unwind_GetCFA(unwind_context) + 8;
     388#                               elif defined( __i386 )
     389                                _Unwind_Word match_pos = _Unwind_GetCFA(unwind_context) + 24;
     390#                               endif
     391                                int (*matcher)(exception_t *) = *(int(**)(exception_t *))match_pos;
     392
     393                                int index = matcher(context->current_exception);
     394                                _Unwind_Reason_Code ret = (0 == index)
     395                                        ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND;
     396                                context->current_handler_index = index;
     397
     398                                // Based on the return value, check if we matched the exception
     399                                if (ret == _URC_HANDLER_FOUND) {
     400                                        __cfadbg_print_safe(exception, " handler found\n");
     401                                } else {
     402                                        __cfadbg_print_safe(exception, " no handler\n");
    369403                                }
    370 
    371                                 // This is only a cleanup handler, ignore it
    372                                 __cfaabi_dbg_print_safe(" no action");
     404                                return ret;
    373405                        }
    374                         else if (actions & _UA_CLEANUP_PHASE) {
    375 
    376                                 if( (callsite_action != 0) && !(actions & _UA_HANDLER_FRAME) ){
    377                                         // If this is a potential exception handler
    378                                         // but not the one that matched the exception in the seach phase,
    379                                         // just ignore it
    380                                         goto UNWIND;
    381                                 }
    382 
    383                                 // We need to run some clean-up or a handler
    384                                 // These statment do the right thing but I don't know any specifics at all
    385                                 _Unwind_SetGR( context, __builtin_eh_return_data_regno(0), (_Unwind_Ptr) unwind_exception );
    386                                 _Unwind_SetGR( context, __builtin_eh_return_data_regno(1), 0 );
    387 
    388                                 // I assume this sets the instruction pointer to the adress of the landing pad
    389                                 // It doesn't actually set it, it only state the value that needs to be set once we return _URC_INSTALL_CONTEXT
    390                                 _Unwind_SetIP( context, ((lsd_info.LPStart) + (callsite_landing_pad)) );
    391 
    392                                 __cfaabi_dbg_print_safe(" action\n");
    393 
    394                                 // Return have some action to run
    395                                 return _URC_INSTALL_CONTEXT;
     406
     407                        // This is only a cleanup handler, ignore it
     408                        __cfadbg_print_safe(exception, " no action");
     409                } else {
     410                        // In clean-up phase, no destructors here but this could be the handler.
     411
     412                        if ( (callsite_action != 0) && !(actions & _UA_HANDLER_FRAME) ){
     413                                // If this is a potential exception handler
     414                                // but not the one that matched the exception in the seach phase,
     415                                // just ignore it
     416                                goto UNWIND;
    396417                        }
     418
     419                        // We need to run some clean-up or a handler
     420                        // These statment do the right thing but I don't know any specifics at all
     421                        _Unwind_SetGR( unwind_context, __builtin_eh_return_data_regno(0),
     422                                (_Unwind_Ptr)unwind_exception );
     423                        _Unwind_SetGR( unwind_context, __builtin_eh_return_data_regno(1), 0 );
     424
     425                        // I assume this sets the instruction pointer to the adress of the landing pad
     426                        // It doesn't actually set it, it only state the value that needs to be set once we
     427                        // return _URC_INSTALL_CONTEXT
     428                        _Unwind_SetIP( unwind_context, ((lsd_info.LPStart) + (callsite_landing_pad)) );
     429
     430                        __cfadbg_print_safe(exception, " action\n");
     431
     432                        // Return have some action to run
     433                        return _URC_INSTALL_CONTEXT;
    397434                }
    398 
    399                 // Nothing to do, move along
    400                 __cfaabi_dbg_print_safe(" no landing pad");
    401435        }
    402436        // No handling found
    403         __cfaabi_dbg_print_safe(" table end reached\n");
     437        __cfadbg_print_safe(exception, " table end reached");
    404438
    405439        UNWIND:
    406         __cfaabi_dbg_print_safe(" unwind\n");
     440        __cfadbg_print_safe(exception, " unwind\n");
    407441
    408442        // Keep unwinding the stack
    409443        return _URC_CONTINUE_UNWIND;
    410444}
     445
     446#pragma GCC push_options
     447#pragma GCC optimize(0)
    411448
    412449// Try statements are hoisted out see comments for details. While this could probably be unique
    413450// and simply linked from libcfa but there is one problem left, see the exception table for details
    414451__attribute__((noinline))
    415 void __cfaabi_ehm__try_terminate(void (*try_block)(),
     452void __cfaehm_try_terminate(void (*try_block)(),
    416453                void (*catch_block)(int index, exception_t * except),
    417454                __attribute__((unused)) int (*match_block)(exception_t * except)) {
     
    419456        //! printf("%p %p %p %p\n", &try_block, &catch_block, &match_block, &xy);
    420457
    421         // Setup statments: These 2 statments won't actually result in any code, they only setup global tables.
    422         // However, they clobber gcc cancellation support from gcc.  We can replace the personality routine but
    423         // replacing the exception table gcc generates is not really doable, it generates labels based on how the
    424         // assembly works.
    425 
    426458        // Setup the personality routine and exception table.
     459        // Unforturnately these clobber gcc cancellation support which means we can't get access to
     460        // the attribute cleanup tables at the same time. We would have to inspect the assembly to
     461        // create a new set ourselves.
    427462#ifdef __PIC__
    428463        asm volatile (".cfi_personality 0x9b,CFA.ref.__gcfa_personality_v0");
     
    449484        // Label which defines the end of the area for which the handler is setup.
    450485        asm volatile (".TRYEND:");
    451         // Label which defines the start of the exception landing pad.  Basically what is called when the exception is
    452         // caught.  Note, if multiple handlers are given, the multiplexing should be done by the generated code, not the
    453         // exception runtime.
     486        // Label which defines the start of the exception landing pad. Basically what is called when
     487        // the exception is caught. Note, if multiple handlers are given, the multiplexing should be
     488        // done by the generated code, not the exception runtime.
    454489        asm volatile (".CATCH:");
    455490
    456491        // Exception handler
    457         catch_block( shared_stack.current_handler_index,
    458                      shared_stack.current_exception );
     492        // Note: Saving the exception context on the stack breaks termination exceptions.
     493        catch_block( this_exception_context()->current_handler_index,
     494                     this_exception_context()->current_exception );
    459495}
    460496
     
    464500
    465501#ifdef __PIC__
    466 #if defined( __i386 ) || defined( __x86_64 )
    467502asm (
    468503        // HEADER
     
    481516        // handler landing pad offset and 1 (action code, gcc seems to use 0).
    482517        ".LLSDACSBCFA2:\n"
    483         "       .uleb128 .TRYSTART-__cfaabi_ehm__try_terminate\n"
     518        "       .uleb128 .TRYSTART-__cfaehm_try_terminate\n"
    484519        "       .uleb128 .TRYEND-.TRYSTART\n"
    485         "       .uleb128 .CATCH-__cfaabi_ehm__try_terminate\n"
     520        "       .uleb128 .CATCH-__cfaehm_try_terminate\n"
    486521        "       .uleb128 1\n"
    487522        ".LLSDACSECFA2:\n"
    488523        // TABLE FOOTER
    489524        "       .text\n"
    490         "       .size   __cfaabi_ehm__try_terminate, .-__cfaabi_ehm__try_terminate\n"
     525        "       .size   __cfaehm_try_terminate, .-__cfaehm_try_terminate\n"
    491526);
    492527
     
    507542        "       .quad __gcfa_personality_v0\n"
    508543#else // then __i386
    509         "   .long __gcfa_personality_v0\n"
     544        "       .long __gcfa_personality_v0\n"
    510545#endif
    511546);
    512 #else
    513 #error Exception Handling: unknown architecture for position independent code.
    514 #endif // __i386 || __x86_64
    515547#else // __PIC__
    516 #if defined( __i386 ) || defined( __x86_64 )
    517548asm (
    518549        // HEADER
     
    529560        ".LLSDACSBCFA2:\n"
    530561        //      Handled area start (relative to start of function)
    531         "       .uleb128 .TRYSTART-__cfaabi_ehm__try_terminate\n"
     562        "       .uleb128 .TRYSTART-__cfaehm_try_terminate\n"
    532563        //      Handled area length
    533564        "       .uleb128 .TRYEND-.TRYSTART\n"
    534565        //      Handler landing pad address (relative to start of function)
    535         "       .uleb128 .CATCH-__cfaabi_ehm__try_terminate\n"
     566        "       .uleb128 .CATCH-__cfaehm_try_terminate\n"
    536567        //      Action code, gcc seems to always use 0.
    537568        "       .uleb128 1\n"
     
    539570        ".LLSDACSECFA2:\n"
    540571        "       .text\n"
    541         "       .size   __cfaabi_ehm__try_terminate, .-__cfaabi_ehm__try_terminate\n"
     572        "       .size   __cfaehm_try_terminate, .-__cfaehm_try_terminate\n"
    542573        "       .ident  \"GCC: (Ubuntu 6.2.0-3ubuntu11~16.04) 6.2.0 20160901\"\n"
    543574        "       .section        .note.GNU-stack,\"x\",@progbits\n"
    544575);
    545 #else
    546 #error Exception Handling: unknown architecture for position dependent code.
    547 #endif // __i386 || __x86_64
    548576#endif // __PIC__
    549577
Note: See TracChangeset for help on using the changeset viewer.