Ignore:
Timestamp:
Apr 6, 2020, 4:46:28 PM (6 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum, stuck-waitfor-destruct
Children:
e3bc51c
Parents:
71d6bd8 (diff), 057298e (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' into new-ast

File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/exception.c

    r71d6bd8 r7030dab  
    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 : Fri Apr 03 11:57:00 2020
     13// Update Count     : 14
    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>
     
    2731// FIX ME: temporary hack to keep ARM build working
    2832#ifndef _URC_FATAL_PHASE1_ERROR
    29 #define _URC_FATAL_PHASE1_ERROR 2
     33#define _URC_FATAL_PHASE1_ERROR 3
    3034#endif // ! _URC_FATAL_PHASE1_ERROR
    3135#ifndef _URC_FATAL_PHASE2_ERROR
     
    3539#include "lsda.h"
    3640
     41/* The exception class for our exceptions. Because of the vendor component
     42 * its value would not be standard.
     43 * Vendor: UWPL
     44 * Language: CFA\0
     45 */
     46const _Unwind_Exception_Class __cfaehm_exception_class = 0x4c50575500414643;
    3747
    3848// 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 = {
     49struct __cfaehm_base_exception_t_vtable
     50                ___cfaehm_base_exception_t_vtable_instance = {
    4151        .parent = NULL,
    4252        .size = 0,
     
    4959// Temperary global exception context. Does not work with concurency.
    5060struct 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};
     61        struct __cfaehm_try_resume_node * top_resume;
     62
     63        exception_t * current_exception;
     64        int current_handler_index;
     65} static shared_stack = {NULL, NULL, 0};
    5766
    5867// Get the current exception context.
     
    6271        return &shared_stack;
    6372}
    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.  Used in the personality function, way down
    72 // 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))
    7673
    7774
    7875// RESUMPTION ================================================================
    7976
    80 void __cfaabi_ehm__throw_resume(exception_t * except) {
     77void __cfaehm_throw_resume(exception_t * except) {
     78        struct exception_context_t * context = this_exception_context();
    8179
    8280        __cfaabi_dbg_print_safe("Throwing resumption exception\n");
    8381
    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;
     82        struct __cfaehm_try_resume_node * original_head = context->top_resume;
     83        struct __cfaehm_try_resume_node * current = context->top_resume;
    8784
    8885        for ( ; current ; current = current->next) {
    89                 shared_stack.current_resume = current;
     86                context->top_resume = current->next;
    9087                if (current->handler(except)) {
    91                         shared_stack.current_resume = original_head;
     88                        context->top_resume = original_head;
    9289                        return;
    9390                }
     
    9592
    9693        __cfaabi_dbg_print_safe("Unhandled exception\n");
    97         shared_stack.current_resume = original_head;
     94        context->top_resume = original_head;
    9895
    9996        // Fall back to termination:
    100         __cfaabi_ehm__throw_terminate(except);
     97        __cfaehm_throw_terminate(except);
    10198        // TODO: Default handler for resumption.
    10299}
    103100
    104 // Do we control where exceptions get thrown even with concurency?  If not these are not quite thread safe, the cleanup
    105 // hook has to be added after the node is built but before it is made the top node.
    106 
    107 void __cfaabi_ehm__try_resume_setup(struct __cfaabi_ehm__try_resume_node * node,
     101// Do we control where exceptions get thrown even with concurency?
     102// If not these are not quite thread safe, the cleanup hook has to
     103// be added after the node is built but before it is made the top node.
     104
     105void __cfaehm_try_resume_setup(struct __cfaehm_try_resume_node * node,
    108106                        _Bool (*handler)(exception_t * except)) {
    109         node->next = shared_stack.top_resume;
     107        struct exception_context_t * context = this_exception_context();
     108        node->next = context->top_resume;
    110109        node->handler = handler;
    111         shared_stack.top_resume = node;
    112 }
    113 
    114 void __cfaabi_ehm__try_resume_cleanup(struct __cfaabi_ehm__try_resume_node * node) {
    115         shared_stack.top_resume = node->next;
     110        context->top_resume = node;
     111}
     112
     113void __cfaehm_try_resume_cleanup(struct __cfaehm_try_resume_node * node) {
     114        struct exception_context_t * context = this_exception_context();
     115        context->top_resume = node->next;
    116116}
    117117
     
    122122// May have to move to cfa for constructors and destructors (references).
    123123
    124 struct __cfaabi_ehm__node {
    125         struct __cfaabi_ehm__node * next;
     124// How to clean up an exception in various situations.
     125static void __cfaehm_exception_cleanup(
     126                _Unwind_Reason_Code reason,
     127                struct _Unwind_Exception * exception) {
     128        switch (reason) {
     129        case _URC_FOREIGN_EXCEPTION_CAUGHT:
     130                // This one we could clean-up to allow cross-language exceptions.
     131        case _URC_FATAL_PHASE1_ERROR:
     132        case _URC_FATAL_PHASE2_ERROR:
     133        default:
     134                abort();
     135        }
     136}
     137
     138// We need a piece of storage to raise the exception, for now its a single
     139// piece.
     140static struct _Unwind_Exception this_exception_storage;
     141
     142struct __cfaehm_node {
     143        struct __cfaehm_node * next;
    126144};
    127145
    128146#define NODE_TO_EXCEPT(node) ((exception_t *)(1 + (node)))
    129 #define EXCEPT_TO_NODE(except) ((struct __cfaabi_ehm__node *)(except) - 1)
     147#define EXCEPT_TO_NODE(except) ((struct __cfaehm_node *)(except) - 1)
    130148
    131149// Creates a copy of the indicated exception and sets current_exception to it.
    132 static void __cfaabi_ehm__allocate_exception( exception_t * except ) {
     150static void __cfaehm_allocate_exception( exception_t * except ) {
    133151        struct exception_context_t * context = this_exception_context();
    134152
    135153        // Allocate memory for the exception.
    136         struct __cfaabi_ehm__node * store = malloc(
    137                 sizeof( struct __cfaabi_ehm__node ) + except->virtual_table->size );
     154        struct __cfaehm_node * store = malloc(
     155                sizeof( struct __cfaehm_node ) + except->virtual_table->size );
    138156
    139157        if ( ! store ) {
     
    148166        // Copy the exception to storage.
    149167        except->virtual_table->copy( context->current_exception, except );
     168
     169        // Set up the exception storage.
     170        this_exception_storage.exception_class = __cfaehm_exception_class;
     171        this_exception_storage.exception_cleanup = __cfaehm_exception_cleanup;
    150172}
    151173
    152174// Delete the provided exception, unsetting current_exception if relivant.
    153 static void __cfaabi_ehm__delete_exception( exception_t * except ) {
     175static void __cfaehm_delete_exception( exception_t * except ) {
    154176        struct exception_context_t * context = this_exception_context();
    155177
     
    157179
    158180        // Remove the exception from the list.
    159         struct __cfaabi_ehm__node * to_free = EXCEPT_TO_NODE(except);
    160         struct __cfaabi_ehm__node * node;
     181        struct __cfaehm_node * to_free = EXCEPT_TO_NODE(except);
     182        struct __cfaehm_node * node;
    161183
    162184        if ( context->current_exception == except ) {
     
    166188                node = EXCEPT_TO_NODE(context->current_exception);
    167189                // It may always be in the first or second position.
    168                 while( to_free != node->next ) {
     190                while ( to_free != node->next ) {
    169191                        node = node->next;
    170192                }
     
    178200
    179201// If this isn't a rethrow (*except==0), delete the provided exception.
    180 void __cfaabi_ehm__cleanup_terminate( void * except ) {
    181         if ( *(void**)except ) __cfaabi_ehm__delete_exception( *(exception_t **)except );
    182 }
    183 
    184 
    185 // We need a piece of storage to raise the exception
    186 struct _Unwind_Exception this_exception_storage;
     202void __cfaehm_cleanup_terminate( void * except ) {
     203        if ( *(void**)except ) __cfaehm_delete_exception( *(exception_t **)except );
     204}
    187205
    188206// Function needed by force unwind
     
    191209                int version,
    192210                _Unwind_Action actions,
    193                 _Unwind_Exception_Class exceptionClass,
     211                _Unwind_Exception_Class exception_class,
    194212                struct _Unwind_Exception * unwind_exception,
    195                 struct _Unwind_Context * context,
    196                 void * some_param) {
    197         if( actions & _UA_END_OF_STACK  ) exit(1);
    198         if( actions & _UA_CLEANUP_PHASE ) return _URC_NO_REASON;
     213                struct _Unwind_Context * unwind_context,
     214                void * stop_param) {
     215        if ( actions & _UA_END_OF_STACK  ) exit(1);
     216        if ( actions & _UA_CLEANUP_PHASE ) return _URC_NO_REASON;
    199217
    200218        return _URC_FATAL_PHASE2_ERROR;
     
    202220
    203221// The exception that is being thrown must already be stored.
    204 __attribute__((noreturn)) void __cfaabi_ehm__begin_unwind(void) {
     222static __attribute__((noreturn)) void __cfaehm_begin_unwind(void) {
    205223        if ( ! this_exception_context()->current_exception ) {
    206224                printf("UNWIND ERROR missing exception in begin unwind\n");
     
    208226        }
    209227
    210 
    211228        // Call stdlibc to raise the exception
    212229        _Unwind_Reason_Code ret = _Unwind_RaiseException( &this_exception_storage );
    213230
    214         // If we reach here it means something happened.  For resumption to work we need to find a way to return back to
    215         // here.  Most of them will probably boil down to setting a global flag and making the phase 1 either stop or
    216         // fail.  Causing an error on purpose may help avoiding unnecessary work but it might have some weird side
    217         // effects.  If we just pretend no handler was found that would work but may be expensive for no reason since we
    218         // will always search the whole stack.
    219 
    220         if( ret == _URC_END_OF_STACK ) {
    221                 // No proper handler was found.  This can be handled in several way.  C++ calls std::terminate Here we
    222                 // force unwind the stack, basically raising a cancellation.
     231        // If we reach here it means something happened. For resumption to work we need to find a way
     232        // to return back to here. Most of them will probably boil down to setting a global flag and
     233        // making the phase 1 either stop or fail. Causing an error on purpose may help avoiding
     234        // unnecessary work but it might have some weird side effects. If we just pretend no handler
     235        // was found that would work but may be expensive for no reason since we will always search
     236        // the whole stack.
     237
     238        if ( ret == _URC_END_OF_STACK ) {
     239                // No proper handler was found. This can be handled in many ways, C++ calls std::terminate.
     240                // Here we force unwind the stack, basically raising a cancellation.
    223241                printf("Uncaught exception %p\n", &this_exception_storage);
    224242
     
    228246        }
    229247
    230         // We did not simply reach the end of the stack without finding a handler.  Something wen't wrong
     248        // We did not simply reach the end of the stack without finding a handler. This is an error.
    231249        printf("UNWIND ERROR %d after raise exception\n", ret);
    232250        abort();
    233251}
    234252
    235 void __cfaabi_ehm__throw_terminate( exception_t * val ) {
     253void __cfaehm_throw_terminate( exception_t * val ) {
    236254        __cfaabi_dbg_print_safe("Throwing termination exception\n");
    237255
    238         __cfaabi_ehm__allocate_exception( val );
    239         __cfaabi_ehm__begin_unwind();
    240 }
    241 
    242 void __cfaabi_ehm__rethrow_terminate(void) {
     256        __cfaehm_allocate_exception( val );
     257        __cfaehm_begin_unwind();
     258}
     259
     260void __cfaehm_rethrow_terminate(void) {
    243261        __cfaabi_dbg_print_safe("Rethrowing termination exception\n");
    244262
    245         __cfaabi_ehm__begin_unwind();
    246 }
    247 
    248 #if defined(PIC)
    249 #warning Exceptions not yet supported when using Position-Independent Code
    250 __attribute__((noinline))
    251 void __cfaabi_ehm__try_terminate(void (*try_block)(),
    252                 void (*catch_block)(int index, exception_t * except),
    253                 __attribute__((unused)) int (*match_block)(exception_t * except)) {
    254         abort();
    255 }
    256 #else
    257 // This is our personality routine.  For every stack frame anotated with ".cfi_personality 0x3,__gcfa_personality_v0".
    258 // This function will be called twice when unwinding.  Once in the search phased and once in the cleanup phase.
    259 _Unwind_Reason_Code __gcfa_personality_v0 (
    260                 int version, _Unwind_Action actions, unsigned long long exceptionClass,
    261                 struct _Unwind_Exception* unwind_exception,
    262                 struct _Unwind_Context* context)
     263        __cfaehm_begin_unwind();
     264}
     265
     266// This is our personality routine. For every stack frame annotated with
     267// ".cfi_personality 0x3,__gcfa_personality_v0" this function will be called twice when unwinding.
     268//  Once in the search phase and once in the cleanup phase.
     269_Unwind_Reason_Code __gcfa_personality_v0(
     270                int version,
     271                _Unwind_Action actions,
     272                unsigned long long exception_class,
     273                struct _Unwind_Exception * unwind_exception,
     274                struct _Unwind_Context * unwind_context)
    263275{
    264276
    265277        //__cfaabi_dbg_print_safe("CFA: 0x%lx\n", _Unwind_GetCFA(context));
    266         __cfaabi_dbg_print_safe("Personality function (%d, %x, %llu, %p, %p):", version, actions, exceptionClass, unwind_exception, context);
     278        __cfaabi_dbg_print_safe("Personality function (%d, %x, %llu, %p, %p):",
     279                        version, actions, exception_class, unwind_exception, unwind_context);
    267280
    268281        // If we've reached the end of the stack then there is nothing much we can do...
    269         if( actions & _UA_END_OF_STACK ) return _URC_END_OF_STACK;
     282        if (actions & _UA_END_OF_STACK) return _URC_END_OF_STACK;
    270283
    271284        if (actions & _UA_SEARCH_PHASE) {
     
    282295
    283296        // Get a pointer to the language specific data from which we will read what we need
    284         const unsigned char * lsd = (const unsigned char*) _Unwind_GetLanguageSpecificData( context );
    285 
    286         if( !lsd ) {    //Nothing to do, keep unwinding
     297        const unsigned char * lsd = _Unwind_GetLanguageSpecificData( unwind_context );
     298
     299        if ( !lsd ) {   //Nothing to do, keep unwinding
    287300                printf(" no LSD");
    288301                goto UNWIND;
     
    291304        // Get the instuction pointer and a reading pointer into the exception table
    292305        lsda_header_info lsd_info;
    293         const unsigned char * cur_ptr = parse_lsda_header( context, lsd, &lsd_info);
    294         _Unwind_Ptr instruction_ptr = _Unwind_GetIP( context );
     306        const unsigned char * cur_ptr = parse_lsda_header(unwind_context, lsd, &lsd_info);
     307        _Unwind_Ptr instruction_ptr = _Unwind_GetIP(unwind_context);
     308
     309        struct exception_context_t * context = this_exception_context();
    295310
    296311        // Linearly search the table for stuff to do
    297         while( cur_ptr < lsd_info.action_table ) {
     312        while ( cur_ptr < lsd_info.action_table ) {
    298313                _Unwind_Ptr callsite_start;
    299314                _Unwind_Ptr callsite_len;
     
    302317
    303318                // Decode the common stuff we have in here
    304                 cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_start);
    305                 cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_len);
    306                 cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_landing_pad);
    307                 cur_ptr = read_uleb128 (cur_ptr, &callsite_action);
     319                cur_ptr = read_encoded_value(0, lsd_info.call_site_encoding, cur_ptr, &callsite_start);
     320                cur_ptr = read_encoded_value(0, lsd_info.call_site_encoding, cur_ptr, &callsite_len);
     321                cur_ptr = read_encoded_value(0, lsd_info.call_site_encoding, cur_ptr, &callsite_landing_pad);
     322                cur_ptr = read_uleb128(cur_ptr, &callsite_action);
    308323
    309324                // Have we reach the correct frame info yet?
    310                 if( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) {
     325                if ( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) {
    311326#ifdef __CFA_DEBUG_PRINT__
    312327                        void * ls = (void*)lsd_info.Start;
     
    316331                        void * ep = (void*)lsd_info.Start + callsite_start + callsite_len;
    317332                        void * ip = (void*)instruction_ptr;
    318                         __cfaabi_dbg_print_safe("\nfound %p - %p (%p, %p, %p), looking for %p\n", bp, ep, ls, cs, cl, ip);
     333                        __cfaabi_dbg_print_safe("\nfound %p - %p (%p, %p, %p), looking for %p\n",
     334                                        bp, ep, ls, cs, cl, ip);
    319335#endif // __CFA_DEBUG_PRINT__
    320336                        continue;
    321337                }
    322338
    323                 // Have we gone too far
    324                 if( lsd_info.Start + callsite_start > instruction_ptr ) {
     339                // Have we gone too far?
     340                if ( lsd_info.Start + callsite_start > instruction_ptr ) {
    325341                        printf(" gone too far");
    326342                        break;
    327343                }
    328344
    329                 // Something to do?
    330                 if( callsite_landing_pad ) {
    331                         // Which phase are we in
    332                         if (actions & _UA_SEARCH_PHASE) {
    333                                 // Search phase, this means we probably found a potential handler and must check if it is a match
    334 
    335                                 // If we have arbitrarily decided that 0 means nothing to do and 1 means there is a potential handler
    336                                 // This doesn't seem to conflict the gcc default behavior
    337                                 if (callsite_action != 0) {
    338                                         // Now we want to run some code to see if the handler matches
    339                                         // This is the tricky part where we want to the power to run arbitrary code
    340                                         // However, generating a new exception table entry and try routine every time
    341                                         // is way more expansive than we might like
    342                                         // The information we have is :
    343                                         //  - The GR (Series of registers)
    344                                         //    GR1=GP Global Pointer of frame ref by context
    345                                         //  - The instruction pointer
    346                                         //  - The instruction pointer info (???)
    347                                         //  - The CFA (Canonical Frame Address)
    348                                         //  - The BSP (Probably the base stack pointer)
    349 
    350 
    351                                         // The current apprach uses one exception table entry per try block
    352                                         _uleb128_t imatcher;
    353                                         // Get the relative offset to the
    354                                         cur_ptr = read_uleb128 (cur_ptr, &imatcher);
    355 
    356                                         // Get a function pointer from the relative offset and call it
    357                                         // _Unwind_Reason_Code (*matcher)() = (_Unwind_Reason_Code (*)())lsd_info.LPStart + imatcher;
    358 
    359                                         _Unwind_Reason_Code (*matcher)(exception_t *) =
    360                                                 MATCHER_FROM_CONTEXT(context);
    361                                         int index = matcher(shared_stack.current_exception);
    362                                         _Unwind_Reason_Code ret = (0 == index)
    363                                                 ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND;
    364                                         shared_stack.current_handler_index = index;
    365 
    366                                         // Based on the return value, check if we matched the exception
    367                                         if( ret == _URC_HANDLER_FOUND) {
    368                                                 __cfaabi_dbg_print_safe(" handler found\n");
    369                                         } else {
    370                                                 __cfaabi_dbg_print_safe(" no handler\n");
    371                                         }
    372                                         return ret;
     345                // Check for what we must do:
     346                if ( 0 == callsite_landing_pad ) {
     347                        // Nothing to do, move along
     348                        __cfaabi_dbg_print_safe(" no landing pad");
     349                } else if (actions & _UA_SEARCH_PHASE) {
     350                        // In search phase, these means we found a potential handler we must check.
     351
     352                        // We have arbitrarily decided that 0 means nothing to do and 1 means there is
     353                        // a potential handler. This doesn't seem to conflict the gcc default behavior.
     354                        if (callsite_action != 0) {
     355                                // Now we want to run some code to see if the handler matches
     356                                // This is the tricky part where we want to the power to run arbitrary code
     357                                // However, generating a new exception table entry and try routine every time
     358                                // is way more expansive than we might like
     359                                // The information we have is :
     360                                //  - The GR (Series of registers)
     361                                //    GR1=GP Global Pointer of frame ref by context
     362                                //  - The instruction pointer
     363                                //  - The instruction pointer info (???)
     364                                //  - The CFA (Canonical Frame Address)
     365                                //  - The BSP (Probably the base stack pointer)
     366
     367                                // The current apprach uses one exception table entry per try block
     368                                _uleb128_t imatcher;
     369                                // Get the relative offset to the {...}?
     370                                cur_ptr = read_uleb128(cur_ptr, &imatcher);
     371
     372#                               if defined( __x86_64 )
     373                                _Unwind_Word match_pos = _Unwind_GetCFA(unwind_context) + 8;
     374#                               elif defined( __i386 )
     375                                _Unwind_Word match_pos = _Unwind_GetCFA(unwind_context) + 24;
     376#                               endif
     377                                int (*matcher)(exception_t *) = *(int(**)(exception_t *))match_pos;
     378
     379                                int index = matcher(context->current_exception);
     380                                _Unwind_Reason_Code ret = (0 == index)
     381                                        ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND;
     382                                context->current_handler_index = index;
     383
     384                                // Based on the return value, check if we matched the exception
     385                                if (ret == _URC_HANDLER_FOUND) {
     386                                        __cfaabi_dbg_print_safe(" handler found\n");
     387                                } else {
     388                                        __cfaabi_dbg_print_safe(" no handler\n");
    373389                                }
    374 
    375                                 // This is only a cleanup handler, ignore it
    376                                 __cfaabi_dbg_print_safe(" no action");
     390                                return ret;
    377391                        }
    378                         else if (actions & _UA_CLEANUP_PHASE) {
    379 
    380                                 if( (callsite_action != 0) && !(actions & _UA_HANDLER_FRAME) ){
    381                                         // If this is a potential exception handler
    382                                         // but not the one that matched the exception in the seach phase,
    383                                         // just ignore it
    384                                         goto UNWIND;
    385                                 }
    386 
    387                                 // We need to run some clean-up or a handler
    388                                 // These statment do the right thing but I don't know any specifics at all
    389                                 _Unwind_SetGR( context, __builtin_eh_return_data_regno(0), (_Unwind_Ptr) unwind_exception );
    390                                 _Unwind_SetGR( context, __builtin_eh_return_data_regno(1), 0 );
    391 
    392                                 // I assume this sets the instruction pointer to the adress of the landing pad
    393                                 // It doesn't actually set it, it only state the value that needs to be set once we return _URC_INSTALL_CONTEXT
    394                                 _Unwind_SetIP( context, ((lsd_info.LPStart) + (callsite_landing_pad)) );
    395 
    396                                 __cfaabi_dbg_print_safe(" action\n");
    397 
    398                                 // Return have some action to run
    399                                 return _URC_INSTALL_CONTEXT;
     392
     393                        // This is only a cleanup handler, ignore it
     394                        __cfaabi_dbg_print_safe(" no action");
     395                } else if (actions & _UA_CLEANUP_PHASE) {
     396                        // In clean-up phase, no destructors here but this could be the handler.
     397
     398                        if ( (callsite_action != 0) && !(actions & _UA_HANDLER_FRAME) ){
     399                                // If this is a potential exception handler
     400                                // but not the one that matched the exception in the seach phase,
     401                                // just ignore it
     402                                goto UNWIND;
    400403                        }
     404
     405                        // We need to run some clean-up or a handler
     406                        // These statment do the right thing but I don't know any specifics at all
     407                        _Unwind_SetGR( unwind_context, __builtin_eh_return_data_regno(0),
     408                                (_Unwind_Ptr)unwind_exception );
     409                        _Unwind_SetGR( unwind_context, __builtin_eh_return_data_regno(1), 0 );
     410
     411                        // I assume this sets the instruction pointer to the adress of the landing pad
     412                        // It doesn't actually set it, it only state the value that needs to be set once we
     413                        // return _URC_INSTALL_CONTEXT
     414                        _Unwind_SetIP( unwind_context, ((lsd_info.LPStart) + (callsite_landing_pad)) );
     415
     416                        __cfaabi_dbg_print_safe(" action\n");
     417
     418                        // Return have some action to run
     419                        return _URC_INSTALL_CONTEXT;
    401420                }
    402 
    403                 // Nothing to do, move along
    404                 __cfaabi_dbg_print_safe(" no landing pad");
    405421        }
    406422        // No handling found
     
    414430}
    415431
    416 // Try statements are hoisted out see comments for details.  With this could probably be unique and simply linked from
    417 // libcfa but there is one problem left, see the exception table for details
     432#pragma GCC push_options
     433#pragma GCC optimize("O0")
     434
     435// Try statements are hoisted out see comments for details. While this could probably be unique
     436// and simply linked from libcfa but there is one problem left, see the exception table for details
    418437__attribute__((noinline))
    419 void __cfaabi_ehm__try_terminate(void (*try_block)(),
     438void __cfaehm_try_terminate(void (*try_block)(),
    420439                void (*catch_block)(int index, exception_t * except),
    421440                __attribute__((unused)) int (*match_block)(exception_t * except)) {
     
    423442        //! printf("%p %p %p %p\n", &try_block, &catch_block, &match_block, &xy);
    424443
    425         // Setup statments: These 2 statments won't actually result in any code, they only setup global tables.
    426         // However, they clobber gcc cancellation support from gcc.  We can replace the personality routine but
    427         // replacing the exception table gcc generates is not really doable, it generates labels based on how the
    428         // assembly works.
    429 
    430         // Setup the personality routine
     444        // Setup the personality routine and exception table.
     445        // Unforturnately these clobber gcc cancellation support which means we can't get access to
     446        // the attribute cleanup tables at the same time. We would have to inspect the assembly to
     447        // create a new set ourselves.
     448#ifdef __PIC__
     449        asm volatile (".cfi_personality 0x9b,CFA.ref.__gcfa_personality_v0");
     450        asm volatile (".cfi_lsda 0x1b, .LLSDACFA2");
     451#else
    431452        asm volatile (".cfi_personality 0x3,__gcfa_personality_v0");
    432         // Setup the exception table
    433453        asm volatile (".cfi_lsda 0x3, .LLSDACFA2");
     454#endif
    434455
    435456        // Label which defines the start of the area for which the handler is setup.
     
    442463        asm volatile goto ("" : : : : CATCH );
    443464
    444         // Normal return
     465        // Normal return for when there is no throw.
    445466        return;
    446467
     
    449470        // Label which defines the end of the area for which the handler is setup.
    450471        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.
     472        // Label which defines the start of the exception landing pad. Basically what is called when
     473        // the exception is caught. Note, if multiple handlers are given, the multiplexing should be
     474        // done by the generated code, not the exception runtime.
    454475        asm volatile (".CATCH:");
    455476
    456477        // Exception handler
    457         catch_block( shared_stack.current_handler_index,
    458                      shared_stack.current_exception );
    459 }
    460 
    461 // Exception table data we need to generate.  While this is almost generic, the custom data refers to foo_try_match try
    462 // match, which is no way generic.  Some more works need to be done if we want to have a single call to the try routine.
    463 
    464 #if defined( __i386 ) || defined( __x86_64 )
     478        // Note: Saving the exception context on the stack breaks termination exceptions.
     479        catch_block( this_exception_context()->current_handler_index,
     480                     this_exception_context()->current_exception );
     481}
     482
     483// Exception table data we need to generate. While this is almost generic, the custom data refers
     484// to {*}try_terminate, which is no way generic. Some more works need to be done if we want to
     485// have a single call to the try routine.
     486
     487#ifdef __PIC__
    465488asm (
    466         //HEADER
     489        // HEADER
    467490        ".LFECFA1:\n"
    468491        "       .globl  __gcfa_personality_v0\n"
    469492        "       .section        .gcc_except_table,\"a\",@progbits\n"
    470         ".LLSDACFA2:\n"                                                 //TABLE header
     493        // TABLE HEADER (important field is the BODY length at the end)
     494        ".LLSDACFA2:\n"
    471495        "       .byte   0xff\n"
    472496        "       .byte   0xff\n"
    473497        "       .byte   0x1\n"
    474         "       .uleb128 .LLSDACSECFA2-.LLSDACSBCFA2\n"         // BODY length
    475         // Body uses language specific data and therefore could be modified arbitrarily
    476         ".LLSDACSBCFA2:\n"                                              // BODY start
    477         "       .uleb128 .TRYSTART-__cfaabi_ehm__try_terminate\n"               // Handled area start  (relative to start of function)
    478         "       .uleb128 .TRYEND-.TRYSTART\n"                           // Handled area length
    479         "       .uleb128 .CATCH-__cfaabi_ehm__try_terminate\n"                          // Hanlder landing pad adress  (relative to start of function)
    480         "       .uleb128 1\n"                                           // Action code, gcc seems to use always 0
    481         ".LLSDACSECFA2:\n"                                              // BODY end
    482         "       .text\n"                                                        // TABLE footer
    483         "       .size   __cfaabi_ehm__try_terminate, .-__cfaabi_ehm__try_terminate\n"
     498        "       .uleb128 .LLSDACSECFA2-.LLSDACSBCFA2\n"
     499        // BODY (language specific data)
     500        // This uses language specific data and can be modified arbitrarily
     501        // We use handled area offset, handled area length,
     502        // handler landing pad offset and 1 (action code, gcc seems to use 0).
     503        ".LLSDACSBCFA2:\n"
     504        "       .uleb128 .TRYSTART-__cfaehm_try_terminate\n"
     505        "       .uleb128 .TRYEND-.TRYSTART\n"
     506        "       .uleb128 .CATCH-__cfaehm_try_terminate\n"
     507        "       .uleb128 1\n"
     508        ".LLSDACSECFA2:\n"
     509        // TABLE FOOTER
     510        "       .text\n"
     511        "       .size   __cfaehm_try_terminate, .-__cfaehm_try_terminate\n"
     512);
     513
     514// Somehow this piece of helps with the resolution of debug symbols.
     515__attribute__((unused)) static const int dummy = 0;
     516
     517asm (
     518        // Add a hidden symbol which points at the function.
     519        "       .hidden CFA.ref.__gcfa_personality_v0\n"
     520        "       .weak   CFA.ref.__gcfa_personality_v0\n"
     521        // No clue what this does specifically
     522        "       .section        .data.rel.local.CFA.ref.__gcfa_personality_v0,\"awG\",@progbits,CFA.ref.__gcfa_personality_v0,comdat\n"
     523        "       .align 8\n"
     524        "       .type CFA.ref.__gcfa_personality_v0, @object\n"
     525        "       .size CFA.ref.__gcfa_personality_v0, 8\n"
     526        "CFA.ref.__gcfa_personality_v0:\n"
     527#if defined( __x86_64 )
     528        "       .quad __gcfa_personality_v0\n"
     529#else // then __i386
     530        "   .long __gcfa_personality_v0\n"
     531#endif
     532);
     533#else // __PIC__
     534asm (
     535        // HEADER
     536        ".LFECFA1:\n"
     537        "       .globl  __gcfa_personality_v0\n"
     538        "       .section        .gcc_except_table,\"a\",@progbits\n"
     539        // TABLE HEADER (important field is the BODY length at the end)
     540        ".LLSDACFA2:\n"
     541        "       .byte   0xff\n"
     542        "       .byte   0xff\n"
     543        "       .byte   0x1\n"
     544        "       .uleb128 .LLSDACSECFA2-.LLSDACSBCFA2\n"
     545        // BODY (language specific data)
     546        ".LLSDACSBCFA2:\n"
     547        //      Handled area start (relative to start of function)
     548        "       .uleb128 .TRYSTART-__cfaehm_try_terminate\n"
     549        //      Handled area length
     550        "       .uleb128 .TRYEND-.TRYSTART\n"
     551        //      Handler landing pad address (relative to start of function)
     552        "       .uleb128 .CATCH-__cfaehm_try_terminate\n"
     553        //      Action code, gcc seems to always use 0.
     554        "       .uleb128 1\n"
     555        // TABLE FOOTER
     556        ".LLSDACSECFA2:\n"
     557        "       .text\n"
     558        "       .size   __cfaehm_try_terminate, .-__cfaehm_try_terminate\n"
    484559        "       .ident  \"GCC: (Ubuntu 6.2.0-3ubuntu11~16.04) 6.2.0 20160901\"\n"
    485 //      "       .section        .note.GNU-stack,\"x\",@progbits\n"
     560        "       .section        .note.GNU-stack,\"x\",@progbits\n"
    486561);
    487 #endif // __i386 || __x86_64
    488 #endif //PIC
     562#endif // __PIC__
     563
     564#pragma GCC pop_options
Note: See TracChangeset for help on using the changeset viewer.