Changes in / [68887f9:136f86b]


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/exception.c

    r68887f9 r136f86b  
    5858    exception_t * current_exception;
    5959    int current_handler_index;
    60 } static shared_stack = {NULL, NULL, NULL, 0};
     60} shared_stack = {NULL, NULL, 0, 0};
    6161
    6262// Get the current exception context.
     
    6666        return &shared_stack;
    6767}
     68//#define SAVE_EXCEPTION_CONTEXT(to_name)
     69//struct exception_context_t * to_name = this_exception_context();
     70//exception * this_exception() {
     71//    return this_exception_context()->current_exception;
     72//}
    6873
    6974
     
    7176
    7277void __cfaabi_ehm__throw_resume(exception_t * except) {
    73         struct exception_context_t * context = this_exception_context();
    7478
    7579        __cfaabi_dbg_print_safe("Throwing resumption exception\n");
    7680
    77         struct __cfaabi_ehm__try_resume_node * original_head = context->current_resume;
     81        struct __cfaabi_ehm__try_resume_node * original_head = shared_stack.current_resume;
    7882        struct __cfaabi_ehm__try_resume_node * current =
    79                 (original_head) ? original_head->next : context->top_resume;
     83                (original_head) ? original_head->next : shared_stack.top_resume;
    8084
    8185        for ( ; current ; current = current->next) {
    82                 context->current_resume = current;
     86                shared_stack.current_resume = current;
    8387                if (current->handler(except)) {
    84                         context->current_resume = original_head;
     88                        shared_stack.current_resume = original_head;
    8589                        return;
    8690                }
     
    8892
    8993        __cfaabi_dbg_print_safe("Unhandled exception\n");
    90         context->current_resume = original_head;
     94        shared_stack.current_resume = original_head;
    9195
    9296        // Fall back to termination:
     
    101105void __cfaabi_ehm__try_resume_setup(struct __cfaabi_ehm__try_resume_node * node,
    102106                        _Bool (*handler)(exception_t * except)) {
    103         struct exception_context_t * context = this_exception_context();
    104         node->next = context->top_resume;
     107        node->next = shared_stack.top_resume;
    105108        node->handler = handler;
    106         context->top_resume = node;
     109        shared_stack.top_resume = node;
    107110}
    108111
    109112void __cfaabi_ehm__try_resume_cleanup(struct __cfaabi_ehm__try_resume_node * node) {
    110         struct exception_context_t * context = this_exception_context();
    111         context->top_resume = node->next;
     113        shared_stack.top_resume = node->next;
    112114}
    113115
     
    162164                node = EXCEPT_TO_NODE(context->current_exception);
    163165                // It may always be in the first or second position.
    164                 while ( to_free != node->next ) {
     166                while( to_free != node->next ) {
    165167                        node = node->next;
    166168                }
     
    189191                _Unwind_Exception_Class exceptionClass,
    190192                struct _Unwind_Exception * unwind_exception,
    191                 struct _Unwind_Context * unwind_context,
    192                 void * stop_param) {
    193         if ( actions & _UA_END_OF_STACK  ) exit(1);
    194         if ( actions & _UA_CLEANUP_PHASE ) return _URC_NO_REASON;
     193                struct _Unwind_Context * context,
     194                void * some_param) {
     195        if( actions & _UA_END_OF_STACK  ) exit(1);
     196        if( actions & _UA_CLEANUP_PHASE ) return _URC_NO_REASON;
    195197
    196198        return _URC_FATAL_PHASE2_ERROR;
     
    215217        // the whole stack.
    216218
    217         if ( ret == _URC_END_OF_STACK ) {
     219        if( ret == _URC_END_OF_STACK ) {
    218220                // No proper handler was found. This can be handled in many ways, C++ calls std::terminate.
    219221                // Here we force unwind the stack, basically raising a cancellation.
     
    249251                int version, _Unwind_Action actions, unsigned long long exceptionClass,
    250252                struct _Unwind_Exception* unwind_exception,
    251                 struct _Unwind_Context* unwind_context)
     253                struct _Unwind_Context* context)
    252254{
    253255
    254256        //__cfaabi_dbg_print_safe("CFA: 0x%lx\n", _Unwind_GetCFA(context));
    255257        __cfaabi_dbg_print_safe("Personality function (%d, %x, %llu, %p, %p):",
    256                         version, actions, exceptionClass, unwind_exception, unwind_context);
     258                        version, actions, exceptionClass, unwind_exception, context);
    257259
    258260        // If we've reached the end of the stack then there is nothing much we can do...
    259         if (actions & _UA_END_OF_STACK) return _URC_END_OF_STACK;
     261        if( actions & _UA_END_OF_STACK ) return _URC_END_OF_STACK;
    260262
    261263        if (actions & _UA_SEARCH_PHASE) {
     
    272274
    273275        // Get a pointer to the language specific data from which we will read what we need
    274         const unsigned char * lsd = _Unwind_GetLanguageSpecificData( unwind_context );
    275 
    276         if ( !lsd ) {   //Nothing to do, keep unwinding
     276        const unsigned char * lsd = (const unsigned char*) _Unwind_GetLanguageSpecificData( context );
     277
     278        if( !lsd ) {    //Nothing to do, keep unwinding
    277279                printf(" no LSD");
    278280                goto UNWIND;
     
    281283        // Get the instuction pointer and a reading pointer into the exception table
    282284        lsda_header_info lsd_info;
    283         const unsigned char * cur_ptr = parse_lsda_header(unwind_context, lsd, &lsd_info);
    284         _Unwind_Ptr instruction_ptr = _Unwind_GetIP(unwind_context);
    285 
    286         struct exception_context_t * context = this_exception_context();
     285        const unsigned char * cur_ptr = parse_lsda_header(context, lsd, &lsd_info);
     286        _Unwind_Ptr instruction_ptr = _Unwind_GetIP( context );
    287287
    288288        // Linearly search the table for stuff to do
    289         while ( cur_ptr < lsd_info.action_table ) {
     289        while( cur_ptr < lsd_info.action_table ) {
    290290                _Unwind_Ptr callsite_start;
    291291                _Unwind_Ptr callsite_len;
     
    300300
    301301                // Have we reach the correct frame info yet?
    302                 if ( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) {
     302                if( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) {
    303303#ifdef __CFA_DEBUG_PRINT__
    304304                        void * ls = (void*)lsd_info.Start;
     
    315315
    316316                // Have we gone too far?
    317                 if ( lsd_info.Start + callsite_start > instruction_ptr ) {
     317                if( lsd_info.Start + callsite_start > instruction_ptr ) {
    318318                        printf(" gone too far");
    319319                        break;
    320320                }
    321321
    322                 // Check for what we must do:
    323                 if ( 0 == callsite_landing_pad ) {
    324                         // Nothing to do, move along
    325                         __cfaabi_dbg_print_safe(" no landing pad");
    326                 } else if (actions & _UA_SEARCH_PHASE) {
    327                         // In search phase, these means we found a potential handler we must check.
    328 
    329                         // We have arbitrarily decided that 0 means nothing to do and 1 means there is
    330                         // a potential handler. This doesn't seem to conflict the gcc default behavior.
    331                         if (callsite_action != 0) {
    332                                 // Now we want to run some code to see if the handler matches
    333                                 // This is the tricky part where we want to the power to run arbitrary code
    334                                 // However, generating a new exception table entry and try routine every time
    335                                 // is way more expansive than we might like
    336                                 // The information we have is :
    337                                 //  - The GR (Series of registers)
    338                                 //    GR1=GP Global Pointer of frame ref by context
    339                                 //  - The instruction pointer
    340                                 //  - The instruction pointer info (???)
    341                                 //  - The CFA (Canonical Frame Address)
    342                                 //  - The BSP (Probably the base stack pointer)
    343 
    344 
    345                                 // The current apprach uses one exception table entry per try block
    346                                 _uleb128_t imatcher;
    347                                 // Get the relative offset to the {...}?
    348                                 cur_ptr = read_uleb128(cur_ptr, &imatcher);
    349 
    350 #                               if defined( __x86_64 )
    351                                 _Unwind_Word match_pos = _Unwind_GetCFA(unwind_context) + 8;
    352 #                               elif defined( __i386 )
    353                                 _Unwind_Word match_pos = _Unwind_GetCFA(unwind_context) + 24;
    354 #                               endif
    355                                 int (*matcher)(exception_t *) = *(int(**)(exception_t *))match_pos;
    356 
    357                                 int index = matcher(context->current_exception);
    358                                 _Unwind_Reason_Code ret = (0 == index)
    359                                         ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND;
    360                                 context->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");
     322                // Something to do?
     323                if( callsite_landing_pad ) {
     324                        // Which phase are we in
     325                        if (actions & _UA_SEARCH_PHASE) {
     326                                // In search phase, these means we found a potential handler we must check.
     327
     328                                // We have arbitrarily decided that 0 means nothing to do and 1 means there is
     329                                // a potential handler. This doesn't seem to conflict the gcc default behavior.
     330                                if (callsite_action != 0) {
     331                                        // Now we want to run some code to see if the handler matches
     332                                        // This is the tricky part where we want to the power to run arbitrary code
     333                                        // However, generating a new exception table entry and try routine every time
     334                                        // is way more expansive than we might like
     335                                        // The information we have is :
     336                                        //  - The GR (Series of registers)
     337                                        //    GR1=GP Global Pointer of frame ref by context
     338                                        //  - The instruction pointer
     339                                        //  - The instruction pointer info (???)
     340                                        //  - The CFA (Canonical Frame Address)
     341                                        //  - The BSP (Probably the base stack pointer)
     342
     343
     344                                        // The current apprach uses one exception table entry per try block
     345                                        _uleb128_t imatcher;
     346                                        // Get the relative offset to the {...}?
     347                                        cur_ptr = read_uleb128(cur_ptr, &imatcher);
     348
     349#                                       if defined( __x86_64 )
     350                                        _Unwind_Word match_pos = _Unwind_GetCFA(context) + 8;
     351#                                       elif defined( __i386 )
     352                                        _Unwind_Word match_pos = _Unwind_GetCFA(context) + 24;
     353#                                       endif
     354                                        int (*matcher)(exception_t *) = *(int(**)(exception_t *))match_pos;
     355
     356                                        int index = matcher(shared_stack.current_exception);
     357                                        _Unwind_Reason_Code ret = (0 == index)
     358                                                ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND;
     359                                        shared_stack.current_handler_index = index;
     360
     361                                        // Based on the return value, check if we matched the exception
     362                                        if( ret == _URC_HANDLER_FOUND) {
     363                                                __cfaabi_dbg_print_safe(" handler found\n");
     364                                        } else {
     365                                                __cfaabi_dbg_print_safe(" no handler\n");
     366                                        }
     367                                        return ret;
    367368                                }
    368                                 return ret;
     369
     370                                // This is only a cleanup handler, ignore it
     371                                __cfaabi_dbg_print_safe(" no action");
    369372                        }
    370 
    371                         // This is only a cleanup handler, ignore it
    372                         __cfaabi_dbg_print_safe(" no action");
    373                 } else if (actions & _UA_CLEANUP_PHASE) {
    374                         // In clean-up phase, no destructors here but this could be the handler.
    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;
     373                        else if (actions & _UA_CLEANUP_PHASE) {
     374
     375                                if( (callsite_action != 0) && !(actions & _UA_HANDLER_FRAME) ){
     376                                        // If this is a potential exception handler
     377                                        // but not the one that matched the exception in the seach phase,
     378                                        // just ignore it
     379                                        goto UNWIND;
     380                                }
     381
     382                                // We need to run some clean-up or a handler
     383                                // These statment do the right thing but I don't know any specifics at all
     384                                _Unwind_SetGR( context, __builtin_eh_return_data_regno(0), (_Unwind_Ptr) unwind_exception );
     385                                _Unwind_SetGR( context, __builtin_eh_return_data_regno(1), 0 );
     386
     387                                // I assume this sets the instruction pointer to the adress of the landing pad
     388                                // It doesn't actually set it, it only state the value that needs to be set once we return _URC_INSTALL_CONTEXT
     389                                _Unwind_SetIP( context, ((lsd_info.LPStart) + (callsite_landing_pad)) );
     390
     391                                __cfaabi_dbg_print_safe(" action\n");
     392
     393                                // Return have some action to run
     394                                return _URC_INSTALL_CONTEXT;
    381395                        }
    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( unwind_context, __builtin_eh_return_data_regno(0),
    386                                 (_Unwind_Ptr)unwind_exception );
    387                         _Unwind_SetGR( unwind_context, __builtin_eh_return_data_regno(1), 0 );
    388 
    389                         // I assume this sets the instruction pointer to the adress of the landing pad
    390                         // It doesn't actually set it, it only state the value that needs to be set once we
    391                         // return _URC_INSTALL_CONTEXT
    392                         _Unwind_SetIP( unwind_context, ((lsd_info.LPStart) + (callsite_landing_pad)) );
    393 
    394                         __cfaabi_dbg_print_safe(" action\n");
    395 
    396                         // Return have some action to run
    397                         return _URC_INSTALL_CONTEXT;
    398396                }
     397
     398                // Nothing to do, move along
     399                __cfaabi_dbg_print_safe(" no landing pad");
    399400        }
    400401        // No handling found
     
    420421        //! printf("%p %p %p %p\n", &try_block, &catch_block, &match_block, &xy);
    421422
     423        // Setup statments: These 2 statments won't actually result in any code, they only setup global tables.
     424        // However, they clobber gcc cancellation support from gcc.  We can replace the personality routine but
     425        // replacing the exception table gcc generates is not really doable, it generates labels based on how the
     426        // assembly works.
     427
    422428        // Setup the personality routine and exception table.
    423         // Unforturnately these clobber gcc cancellation support which means we can't get access to
    424         // the attribute cleanup tables at the same time. We would have to inspect the assembly to
    425         // create a new set ourselves.
    426429#ifdef __PIC__
    427430        asm volatile (".cfi_personality 0x9b,CFA.ref.__gcfa_personality_v0");
     
    448451        // Label which defines the end of the area for which the handler is setup.
    449452        asm volatile (".TRYEND:");
    450         // Label which defines the start of the exception landing pad. Basically what is called when
    451         // the exception is caught. Note, if multiple handlers are given, the multiplexing should be
    452         // done by the generated code, not the exception runtime.
     453        // Label which defines the start of the exception landing pad.  Basically what is called when the exception is
     454        // caught.  Note, if multiple handlers are given, the multiplexing should be done by the generated code, not the
     455        // exception runtime.
    453456        asm volatile (".CATCH:");
    454457
    455458        // Exception handler
    456         // Note: Saving the exception context on the stack breaks termination exceptions.
    457         catch_block( this_exception_context()->current_handler_index,
    458                      this_exception_context()->current_exception );
     459        catch_block( shared_stack.current_handler_index,
     460                     shared_stack.current_exception );
    459461}
    460462
Note: See TracChangeset for help on using the changeset viewer.