Changes in / [136f86b:68887f9]


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/exception.c

    r136f86b r68887f9  
    5858    exception_t * current_exception;
    5959    int current_handler_index;
    60 } shared_stack = {NULL, NULL, 0, 0};
     60} static shared_stack = {NULL, NULL, NULL, 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 //}
    7368
    7469
     
    7671
    7772void __cfaabi_ehm__throw_resume(exception_t * except) {
     73        struct exception_context_t * context = this_exception_context();
    7874
    7975        __cfaabi_dbg_print_safe("Throwing resumption exception\n");
    8076
    81         struct __cfaabi_ehm__try_resume_node * original_head = shared_stack.current_resume;
     77        struct __cfaabi_ehm__try_resume_node * original_head = context->current_resume;
    8278        struct __cfaabi_ehm__try_resume_node * current =
    83                 (original_head) ? original_head->next : shared_stack.top_resume;
     79                (original_head) ? original_head->next : context->top_resume;
    8480
    8581        for ( ; current ; current = current->next) {
    86                 shared_stack.current_resume = current;
     82                context->current_resume = current;
    8783                if (current->handler(except)) {
    88                         shared_stack.current_resume = original_head;
     84                        context->current_resume = original_head;
    8985                        return;
    9086                }
     
    9288
    9389        __cfaabi_dbg_print_safe("Unhandled exception\n");
    94         shared_stack.current_resume = original_head;
     90        context->current_resume = original_head;
    9591
    9692        // Fall back to termination:
     
    105101void __cfaabi_ehm__try_resume_setup(struct __cfaabi_ehm__try_resume_node * node,
    106102                        _Bool (*handler)(exception_t * except)) {
    107         node->next = shared_stack.top_resume;
     103        struct exception_context_t * context = this_exception_context();
     104        node->next = context->top_resume;
    108105        node->handler = handler;
    109         shared_stack.top_resume = node;
     106        context->top_resume = node;
    110107}
    111108
    112109void __cfaabi_ehm__try_resume_cleanup(struct __cfaabi_ehm__try_resume_node * node) {
    113         shared_stack.top_resume = node->next;
     110        struct exception_context_t * context = this_exception_context();
     111        context->top_resume = node->next;
    114112}
    115113
     
    164162                node = EXCEPT_TO_NODE(context->current_exception);
    165163                // It may always be in the first or second position.
    166                 while( to_free != node->next ) {
     164                while ( to_free != node->next ) {
    167165                        node = node->next;
    168166                }
     
    191189                _Unwind_Exception_Class exceptionClass,
    192190                struct _Unwind_Exception * unwind_exception,
    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;
     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;
    197195
    198196        return _URC_FATAL_PHASE2_ERROR;
     
    217215        // the whole stack.
    218216
    219         if( ret == _URC_END_OF_STACK ) {
     217        if ( ret == _URC_END_OF_STACK ) {
    220218                // No proper handler was found. This can be handled in many ways, C++ calls std::terminate.
    221219                // Here we force unwind the stack, basically raising a cancellation.
     
    251249                int version, _Unwind_Action actions, unsigned long long exceptionClass,
    252250                struct _Unwind_Exception* unwind_exception,
    253                 struct _Unwind_Context* context)
     251                struct _Unwind_Context* unwind_context)
    254252{
    255253
    256254        //__cfaabi_dbg_print_safe("CFA: 0x%lx\n", _Unwind_GetCFA(context));
    257255        __cfaabi_dbg_print_safe("Personality function (%d, %x, %llu, %p, %p):",
    258                         version, actions, exceptionClass, unwind_exception, context);
     256                        version, actions, exceptionClass, unwind_exception, unwind_context);
    259257
    260258        // If we've reached the end of the stack then there is nothing much we can do...
    261         if( actions & _UA_END_OF_STACK ) return _URC_END_OF_STACK;
     259        if (actions & _UA_END_OF_STACK) return _URC_END_OF_STACK;
    262260
    263261        if (actions & _UA_SEARCH_PHASE) {
     
    274272
    275273        // Get a pointer to the language specific data from which we will read what we need
    276         const unsigned char * lsd = (const unsigned char*) _Unwind_GetLanguageSpecificData( context );
    277 
    278         if( !lsd ) {    //Nothing to do, keep unwinding
     274        const unsigned char * lsd = _Unwind_GetLanguageSpecificData( unwind_context );
     275
     276        if ( !lsd ) {   //Nothing to do, keep unwinding
    279277                printf(" no LSD");
    280278                goto UNWIND;
     
    283281        // Get the instuction pointer and a reading pointer into the exception table
    284282        lsda_header_info lsd_info;
    285         const unsigned char * cur_ptr = parse_lsda_header(context, lsd, &lsd_info);
    286         _Unwind_Ptr instruction_ptr = _Unwind_GetIP( context );
     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();
    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                 // 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;
     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");
    368367                                }
    369 
    370                                 // This is only a cleanup handler, ignore it
    371                                 __cfaabi_dbg_print_safe(" no action");
     368                                return ret;
    372369                        }
    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;
     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;
    395381                        }
     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;
    396398                }
    397 
    398                 // Nothing to do, move along
    399                 __cfaabi_dbg_print_safe(" no landing pad");
    400399        }
    401400        // No handling found
     
    421420        //! printf("%p %p %p %p\n", &try_block, &catch_block, &match_block, &xy);
    422421
    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 
    428422        // 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.
    429426#ifdef __PIC__
    430427        asm volatile (".cfi_personality 0x9b,CFA.ref.__gcfa_personality_v0");
     
    451448        // Label which defines the end of the area for which the handler is setup.
    452449        asm volatile (".TRYEND:");
    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.
     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.
    456453        asm volatile (".CATCH:");
    457454
    458455        // Exception handler
    459         catch_block( shared_stack.current_handler_index,
    460                      shared_stack.current_exception );
     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 );
    461459}
    462460
Note: See TracChangeset for help on using the changeset viewer.