Ignore:
Timestamp:
Jan 7, 2021, 3:27:00 PM (5 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
2b4daf2, 64aeca0
Parents:
3c64c668 (diff), eef8dfb (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 park_unpark

File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/exception.c

    r3c64c668 r58fe85a  
    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 Oct 27 16:27:00 2020
     13// Update Count     : 35
    1414//
    1515
     16// Normally we would get this from the CFA prelude.
    1617#include <stddef.h> // for size_t
    1718
     19#include <unwind.h> // for struct _Unwind_Exception {...};
     20
    1821#include "exception.h"
    19 
    20 // Implementation of the secret header.
    2122
    2223#include <stdlib.h>
    2324#include <stdio.h>
    24 #include <unwind.h>
    2525#include <bits/debug.hfa>
    26 
    27 // FIX ME: temporary hack to keep ARM build working
     26#include "concurrency/invoke.h"
     27#include "stdhdr/assert.h"
     28
     29#if defined( __ARM_ARCH )
     30#warning FIX ME: temporary hack to keep ARM build working
    2831#ifndef _URC_FATAL_PHASE1_ERROR
    29 #define _URC_FATAL_PHASE1_ERROR 2
     32#define _URC_FATAL_PHASE1_ERROR 3
    3033#endif // ! _URC_FATAL_PHASE1_ERROR
    3134#ifndef _URC_FATAL_PHASE2_ERROR
    3235#define _URC_FATAL_PHASE2_ERROR 2
    3336#endif // ! _URC_FATAL_PHASE2_ERROR
     37#endif // __ARM_ARCH
    3438
    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,
     
    4757
    4858
    49 // Temperary global exception context. Does not work with concurency.
    50 struct 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};
    57 
    5859// Get the current exception context.
    5960// There can be a single global until multithreading occurs, then each stack
    60 // needs its own. It will have to be updated to handle that.
    61 struct exception_context_t * this_exception_context() {
     61// needs its own. We get this from libcfathreads (no weak attribute).
     62__attribute__((weak)) struct exception_context_t * this_exception_context() {
     63        static struct exception_context_t shared_stack = {NULL, NULL};
    6264        return &shared_stack;
    6365}
    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))
    7666
    7767
    7868// RESUMPTION ================================================================
    7969
    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;
    87 
    88         for ( ; current ; current = current->next) {
    89                 shared_stack.current_resume = current;
    90                 if (current->handler(except)) {
    91                         shared_stack.current_resume = original_head;
    92                         return;
     70static void reset_top_resume(struct __cfaehm_try_resume_node ** store) {
     71        this_exception_context()->top_resume = *store;
     72}
     73
     74void __cfaehm_throw_resume(exception_t * except, void (*defaultHandler)(exception_t *)) {
     75        struct exception_context_t * context = this_exception_context();
     76
     77        __cfadbg_print_safe(exception, "Throwing resumption exception\n");
     78
     79        {
     80                __attribute__((cleanup(reset_top_resume)))
     81                struct __cfaehm_try_resume_node * original_head = context->top_resume;
     82                struct __cfaehm_try_resume_node * current = context->top_resume;
     83
     84                for ( ; current ; current = current->next) {
     85                        context->top_resume = current->next;
     86                        if (current->handler(except)) {
     87                                return;
     88                        }
    9389                }
    94         }
    95 
    96         __cfaabi_dbg_print_safe("Unhandled exception\n");
    97         shared_stack.current_resume = original_head;
    98 
    99         // Fall back to termination:
    100         __cfaabi_ehm__throw_terminate(except);
    101         // TODO: Default handler for resumption.
     90        } // End the search and return to the top of the stack.
     91
     92        // No handler found, fall back to the default operation.
     93        __cfadbg_print_safe(exception, "Unhandled exception\n");
     94        defaultHandler(except);
    10295}
    10396
     
    10699// be added after the node is built but before it is made the top node.
    107100
    108 void __cfaabi_ehm__try_resume_setup(struct __cfaabi_ehm__try_resume_node * node,
     101void __cfaehm_try_resume_setup(struct __cfaehm_try_resume_node * node,
    109102                        _Bool (*handler)(exception_t * except)) {
    110         node->next = shared_stack.top_resume;
     103        struct exception_context_t * context = this_exception_context();
     104        node->next = context->top_resume;
    111105        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;
    117 }
    118 
    119 
    120 // TERMINATION ===============================================================
    121 
    122 // MEMORY MANAGEMENT (still for integers)
    123 // May have to move to cfa for constructors and destructors (references).
    124 
    125 struct __cfaabi_ehm__node {
    126         struct __cfaabi_ehm__node * next;
    127 };
     106        context->top_resume = node;
     107}
     108
     109void __cfaehm_try_resume_cleanup(struct __cfaehm_try_resume_node * node) {
     110        struct exception_context_t * context = this_exception_context();
     111        context->top_resume = node->next;
     112}
     113
     114
     115// MEMORY MANAGEMENT =========================================================
    128116
    129117#define NODE_TO_EXCEPT(node) ((exception_t *)(1 + (node)))
    130 #define EXCEPT_TO_NODE(except) ((struct __cfaabi_ehm__node *)(except) - 1)
     118#define EXCEPT_TO_NODE(except) ((struct __cfaehm_node *)(except) - 1)
     119#define UNWIND_TO_NODE(unwind) ((struct __cfaehm_node *)(unwind))
     120#define NULL_MAP(map, ptr) ((ptr) ? (map(ptr)) : NULL)
     121
     122// How to clean up an exception in various situations.
     123static void __cfaehm_exception_cleanup(
     124                _Unwind_Reason_Code reason,
     125                struct _Unwind_Exception * exception) {
     126        switch (reason) {
     127        case _URC_FOREIGN_EXCEPTION_CAUGHT:
     128                // This one we could clean-up to allow cross-language exceptions.
     129        case _URC_FATAL_PHASE1_ERROR:
     130        case _URC_FATAL_PHASE2_ERROR:
     131        default:
     132                abort();
     133        }
     134}
    131135
    132136// Creates a copy of the indicated exception and sets current_exception to it.
    133 static void __cfaabi_ehm__allocate_exception( exception_t * except ) {
     137static void __cfaehm_allocate_exception( exception_t * except ) {
    134138        struct exception_context_t * context = this_exception_context();
    135139
    136140        // Allocate memory for the exception.
    137         struct __cfaabi_ehm__node * store = malloc(
    138                 sizeof( struct __cfaabi_ehm__node ) + except->virtual_table->size );
     141        struct __cfaehm_node * store = malloc(
     142                sizeof( struct __cfaehm_node ) + except->virtual_table->size );
    139143
    140144        if ( ! store ) {
     
    143147        }
    144148
     149        // Initialize the node:
     150        exception_t * except_store = NODE_TO_EXCEPT(store);
     151        store->unwind_exception.exception_class = __cfaehm_exception_class;
     152        store->unwind_exception.exception_cleanup = __cfaehm_exception_cleanup;
     153        store->handler_index = 0;
     154        except->virtual_table->copy( except_store, except );
     155
    145156        // Add the node to the list:
    146         store->next = EXCEPT_TO_NODE(context->current_exception);
    147         context->current_exception = NODE_TO_EXCEPT(store);
    148 
    149         // Copy the exception to storage.
    150         except->virtual_table->copy( context->current_exception, except );
     157        store->next = NULL_MAP(EXCEPT_TO_NODE, context->current_exception);
     158        context->current_exception = except_store;
    151159}
    152160
    153161// Delete the provided exception, unsetting current_exception if relivant.
    154 static void __cfaabi_ehm__delete_exception( exception_t * except ) {
    155         struct exception_context_t * context = this_exception_context();
    156 
    157         __cfaabi_dbg_print_safe("Deleting Exception\n");
     162static void __cfaehm_delete_exception( exception_t * except ) {
     163        struct exception_context_t * context = this_exception_context();
     164
     165        __cfadbg_print_safe(exception, "Deleting Exception\n");
    158166
    159167        // Remove the exception from the list.
    160         struct __cfaabi_ehm__node * to_free = EXCEPT_TO_NODE(except);
    161         struct __cfaabi_ehm__node * node;
     168        struct __cfaehm_node * to_free = EXCEPT_TO_NODE(except);
     169        struct __cfaehm_node * node;
    162170
    163171        if ( context->current_exception == except ) {
    164172                node = to_free->next;
    165                 context->current_exception = (node) ? NODE_TO_EXCEPT(node) : 0;
     173                context->current_exception = NULL_MAP(NODE_TO_EXCEPT, node);
    166174        } else {
    167175                node = EXCEPT_TO_NODE(context->current_exception);
    168176                // It may always be in the first or second position.
    169                 while( to_free != node->next ) {
     177                while ( to_free != node->next ) {
    170178                        node = node->next;
    171179                }
     
    178186}
    179187
    180 // 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;
     188// CANCELLATION ==============================================================
    188189
    189190// Function needed by force unwind
     
    192193                int version,
    193194                _Unwind_Action actions,
    194                 _Unwind_Exception_Class exceptionClass,
     195                _Unwind_Exception_Class exception_class,
    195196                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;
     197                struct _Unwind_Context * unwind_context,
     198                void * stop_param) {
     199        // Verify actions follow the rules we expect.
     200        verify(actions & _UA_CLEANUP_PHASE);
     201        verify(actions & _UA_FORCE_UNWIND);
     202        verify(!(actions & _UA_SEARCH_PHASE));
     203        verify(!(actions & _UA_HANDLER_FRAME));
     204
     205        if ( actions & _UA_END_OF_STACK ) {
     206                abort();
     207        } else {
     208                return _URC_NO_REASON;
     209        }
     210}
     211
     212__attribute__((weak)) _Unwind_Reason_Code
     213__cfaehm_cancellation_unwind( struct _Unwind_Exception * exception ) {
     214        return _Unwind_ForcedUnwind( exception, _Stop_Fn, (void*)0x22 );
     215}
     216
     217// Cancel the current stack, prefroming approprate clean-up and messaging.
     218void __cfaehm_cancel_stack( exception_t * exception ) {
     219        __cfaehm_allocate_exception( exception );
     220
     221        struct exception_context_t * context = this_exception_context();
     222        struct __cfaehm_node * node = EXCEPT_TO_NODE(context->current_exception);
     223
     224        // Preform clean-up of any extra active exceptions.
     225        while ( node->next ) {
     226                struct __cfaehm_node * to_free = node->next;
     227                node->next = to_free->next;
     228                exception_t * except = NODE_TO_EXCEPT( to_free );
     229                except->virtual_table->free( except );
     230            free( to_free );
     231        }
     232
     233        _Unwind_Reason_Code ret;
     234        ret = __cfaehm_cancellation_unwind( &node->unwind_exception );
     235        printf("UNWIND ERROR %d after force unwind\n", ret);
     236        abort();
     237}
     238
     239
     240// TERMINATION ===============================================================
     241
     242// If this isn't a rethrow (*except==0), delete the provided exception.
     243void __cfaehm_cleanup_terminate( void * except ) {
     244        if ( *(void**)except ) __cfaehm_delete_exception( *(exception_t **)except );
     245}
     246
     247static void __cfaehm_cleanup_default( exception_t ** except ) {
     248        __cfaehm_delete_exception( *except );
     249        *except = NULL;
    202250}
    203251
    204252// The exception that is being thrown must already be stored.
    205 __attribute__((noreturn)) void __cfaabi_ehm__begin_unwind(void) {
    206         if ( ! this_exception_context()->current_exception ) {
     253static void __cfaehm_begin_unwind(void(*defaultHandler)(exception_t *)) {
     254        struct exception_context_t * context = this_exception_context();
     255        if ( NULL == context->current_exception ) {
    207256                printf("UNWIND ERROR missing exception in begin unwind\n");
    208257                abort();
    209258        }
    210 
     259        struct _Unwind_Exception * storage =
     260                &EXCEPT_TO_NODE(context->current_exception)->unwind_exception;
    211261
    212262        // Call stdlibc to raise the exception
    213         _Unwind_Reason_Code ret = _Unwind_RaiseException( &this_exception_storage );
     263        __cfadbg_print_safe(exception, "Begin unwinding (storage &p, context %p)\n", storage, context);
     264        _Unwind_Reason_Code ret = _Unwind_RaiseException( storage );
    214265
    215266        // If we reach here it means something happened. For resumption to work we need to find a way
     
    220271        // the whole stack.
    221272
    222         if( ret == _URC_END_OF_STACK ) {
    223                 // No proper handler was found. This can be handled in many ways, C++ calls std::terminate.
    224                 // Here we force unwind the stack, basically raising a cancellation.
    225                 printf("Uncaught exception %p\n", &this_exception_storage);
    226 
    227                 ret = _Unwind_ForcedUnwind( &this_exception_storage, _Stop_Fn, (void*)0x22 );
    228                 printf("UNWIND ERROR %d after force unwind\n", ret);
     273        // We did not simply reach the end of the stack without finding a handler. This is an error.
     274        if ( ret != _URC_END_OF_STACK ) {
     275                printf("UNWIND ERROR %d after raise exception\n", ret);
    229276                abort();
    230277        }
    231278
    232         // We did not simply reach the end of the stack without finding a handler. This is an error.
    233         printf("UNWIND ERROR %d after raise exception\n", ret);
     279        // No handler found, go to the default operation.
     280        __cfadbg_print_safe(exception, "Uncaught exception %p\n", storage);
     281
     282        __attribute__((cleanup(__cfaehm_cleanup_default)))
     283        exception_t * exception = context->current_exception;
     284        defaultHandler( exception );
     285}
     286
     287void __cfaehm_throw_terminate( exception_t * val, void (*defaultHandler)(exception_t *) ) {
     288        __cfadbg_print_safe(exception, "Throwing termination exception\n");
     289
     290        __cfaehm_allocate_exception( val );
     291        __cfaehm_begin_unwind( defaultHandler );
     292}
     293
     294static __attribute__((noreturn)) void __cfaehm_rethrow_adapter( exception_t * except ) {
     295        // TODO: Print some error message.
     296        (void)except;
    234297        abort();
    235298}
    236299
    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")
    252 
     300void __cfaehm_rethrow_terminate(void) {
     301        __cfadbg_print_safe(exception, "Rethrowing termination exception\n");
     302
     303        __cfaehm_begin_unwind( __cfaehm_rethrow_adapter );
     304        abort();
     305}
     306
     307#if defined( __x86_64 ) || defined( __i386 )
    253308// This is our personality routine. For every stack frame annotated with
    254309// ".cfi_personality 0x3,__gcfa_personality_v0" this function will be called twice when unwinding.
    255310//  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)
     311_Unwind_Reason_Code __gcfa_personality_v0(
     312                int version,
     313                _Unwind_Action actions,
     314                unsigned long long exception_class,
     315                struct _Unwind_Exception * unwind_exception,
     316                struct _Unwind_Context * unwind_context)
    260317{
    261318
    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 
     319        //__cfadbg_print_safe(exception, "CFA: 0x%lx\n", _Unwind_GetCFA(context));
     320        __cfadbg_print_safe(exception, "Personality function (%d, %x, %llu, %p, %p):",
     321                        version, actions, exception_class, unwind_exception, unwind_context);
     322
     323        // Verify that actions follow the rules we expect.
     324        // This function should never be called at the end of the stack.
     325        verify(!(actions & _UA_END_OF_STACK));
     326        // Either only the search phase flag is set or...
    269327        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;
     328                verify(actions == _UA_SEARCH_PHASE);
     329                __cfadbg_print_safe(exception, " lookup phase");
     330        // ... we are in clean-up phase.
     331        } else {
     332                verify(actions & _UA_CLEANUP_PHASE);
     333                __cfadbg_print_safe(exception, " cleanup phase");
     334                // We shouldn't be the handler frame during forced unwind.
     335                if (actions & _UA_HANDLER_FRAME) {
     336                        verify(!(actions & _UA_FORCE_UNWIND));
     337                        __cfadbg_print_safe(exception, " (handler frame)");
     338                } else if (actions & _UA_FORCE_UNWIND) {
     339                        __cfadbg_print_safe(exception, " (force unwind)");
     340                }
    279341        }
    280342
    281343        // 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
     344        const unsigned char * lsd = _Unwind_GetLanguageSpecificData( unwind_context );
     345
     346        if ( !lsd ) {   //Nothing to do, keep unwinding
    285347                printf(" no LSD");
    286348                goto UNWIND;
     
    289351        // Get the instuction pointer and a reading pointer into the exception table
    290352        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 );
     353        const unsigned char * cur_ptr = parse_lsda_header(unwind_context, lsd, &lsd_info);
     354        _Unwind_Ptr instruction_ptr = _Unwind_GetIP(unwind_context);
     355
     356        struct exception_context_t * context = this_exception_context();
    293357
    294358        // Linearly search the table for stuff to do
    295         while( cur_ptr < lsd_info.action_table ) {
     359        while ( cur_ptr < lsd_info.action_table ) {
    296360                _Unwind_Ptr callsite_start;
    297361                _Unwind_Ptr callsite_len;
     
    306370
    307371                // Have we reach the correct frame info yet?
    308                 if( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) {
     372                if ( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) {
    309373#ifdef __CFA_DEBUG_PRINT__
    310374                        void * ls = (void*)lsd_info.Start;
     
    314378                        void * ep = (void*)lsd_info.Start + callsite_start + callsite_len;
    315379                        void * ip = (void*)instruction_ptr;
    316                         __cfaabi_dbg_print_safe("\nfound %p - %p (%p, %p, %p), looking for %p\n",
     380                        __cfadbg_print_safe(exception, "\nfound %p - %p (%p, %p, %p), looking for %p\n",
    317381                                        bp, ep, ls, cs, cl, ip);
    318382#endif // __CFA_DEBUG_PRINT__
     
    321385
    322386                // Have we gone too far?
    323                 if( lsd_info.Start + callsite_start > instruction_ptr ) {
     387                if ( lsd_info.Start + callsite_start > instruction_ptr ) {
    324388                        printf(" gone too far");
    325389                        break;
    326390                }
    327391
    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;
     392                // Check for what we must do:
     393                if ( 0 == callsite_landing_pad ) {
     394                        // Nothing to do, move along
     395                        __cfadbg_print_safe(exception, " no landing pad");
     396                } else if (actions & _UA_SEARCH_PHASE) {
     397                        // In search phase, these means we found a potential handler we must check.
     398
     399                        // We have arbitrarily decided that 0 means nothing to do and 1 means there is
     400                        // a potential handler. This doesn't seem to conflict the gcc default behavior.
     401                        if (callsite_action != 0) {
     402                                // Now we want to run some code to see if the handler matches
     403                                // This is the tricky part where we want to the power to run arbitrary code
     404                                // However, generating a new exception table entry and try routine every time
     405                                // is way more expansive than we might like
     406                                // The information we have is :
     407                                //  - The GR (Series of registers)
     408                                //    GR1=GP Global Pointer of frame ref by context
     409                                //  - The instruction pointer
     410                                //  - The instruction pointer info (???)
     411                                //  - The CFA (Canonical Frame Address)
     412                                //  - The BSP (Probably the base stack pointer)
     413
     414                                // The current apprach uses one exception table entry per try block
     415                                _uleb128_t imatcher;
     416                                // Get the relative offset to the {...}?
     417                                cur_ptr = read_uleb128(cur_ptr, &imatcher);
     418
     419                                _Unwind_Word match_pos =
     420#                               if defined( __x86_64 )
     421                                    _Unwind_GetCFA(unwind_context) + 8;
     422#                               elif defined( __i386 )
     423                                    _Unwind_GetCFA(unwind_context) + 24;
     424#                               elif defined( __ARM_ARCH )
     425#                                   warning FIX ME: check if anything needed for ARM
     426                                    42;
     427#                               endif
     428                                int (*matcher)(exception_t *) = *(int(**)(exception_t *))match_pos;
     429
     430                                int index = matcher(context->current_exception);
     431                                _Unwind_Reason_Code ret = (0 == index)
     432                                        ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND;
     433                                UNWIND_TO_NODE(unwind_exception)->handler_index = index;
     434
     435                                // Based on the return value, check if we matched the exception
     436                                if (ret == _URC_HANDLER_FOUND) {
     437                                        __cfadbg_print_safe(exception, " handler found\n");
     438                                } else {
     439                                        // TODO: Continue the search if there is more in the table.
     440                                        __cfadbg_print_safe(exception, " no handler\n");
    369441                                }
    370 
    371                                 // This is only a cleanup handler, ignore it
    372                                 __cfaabi_dbg_print_safe(" no action");
     442                                return ret;
    373443                        }
    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;
     444
     445                        // This is only a cleanup handler, ignore it
     446                        __cfadbg_print_safe(exception, " no action");
     447                } else {
     448                        // In clean-up phase, no destructors here but this could be the handler.
     449
     450                        if ( (callsite_action != 0) && !(actions & _UA_HANDLER_FRAME) ){
     451                                // If this is a potential exception handler
     452                                // but not the one that matched the exception in the seach phase,
     453                                // just ignore it
     454                                goto UNWIND;
    396455                        }
     456
     457                        // We need to run some clean-up or a handler
     458                        // These statment do the right thing but I don't know any specifics at all
     459                        _Unwind_SetGR( unwind_context, __builtin_eh_return_data_regno(0),
     460                                (_Unwind_Ptr)unwind_exception );
     461                        _Unwind_SetGR( unwind_context, __builtin_eh_return_data_regno(1), 0 );
     462
     463                        // I assume this sets the instruction pointer to the adress of the landing pad
     464                        // It doesn't actually set it, it only state the value that needs to be set once we
     465                        // return _URC_INSTALL_CONTEXT
     466                        _Unwind_SetIP( unwind_context, ((lsd_info.LPStart) + (callsite_landing_pad)) );
     467
     468                        __cfadbg_print_safe(exception, " action\n");
     469
     470                        // Return have some action to run
     471                        return _URC_INSTALL_CONTEXT;
    397472                }
    398 
    399                 // Nothing to do, move along
    400                 __cfaabi_dbg_print_safe(" no landing pad");
    401473        }
    402474        // No handling found
    403         __cfaabi_dbg_print_safe(" table end reached\n");
     475        __cfadbg_print_safe(exception, " table end reached");
    404476
    405477        UNWIND:
    406         __cfaabi_dbg_print_safe(" unwind\n");
     478        __cfadbg_print_safe(exception, " unwind\n");
    407479
    408480        // Keep unwinding the stack
    409481        return _URC_CONTINUE_UNWIND;
    410482}
     483
     484#pragma GCC push_options
     485#pragma GCC optimize(0)
    411486
    412487// Try statements are hoisted out see comments for details. While this could probably be unique
    413488// and simply linked from libcfa but there is one problem left, see the exception table for details
    414489__attribute__((noinline))
    415 void __cfaabi_ehm__try_terminate(void (*try_block)(),
     490void __cfaehm_try_terminate(void (*try_block)(),
    416491                void (*catch_block)(int index, exception_t * except),
    417492                __attribute__((unused)) int (*match_block)(exception_t * except)) {
     
    419494        //! printf("%p %p %p %p\n", &try_block, &catch_block, &match_block, &xy);
    420495
    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 
    426496        // Setup the personality routine and exception table.
     497        // Unforturnately these clobber gcc cancellation support which means we can't get access to
     498        // the attribute cleanup tables at the same time. We would have to inspect the assembly to
     499        // create a new set ourselves.
    427500#ifdef __PIC__
    428501        asm volatile (".cfi_personality 0x9b,CFA.ref.__gcfa_personality_v0");
     
    449522        // Label which defines the end of the area for which the handler is setup.
    450523        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.
     524        // Label which defines the start of the exception landing pad. Basically what is called when
     525        // the exception is caught. Note, if multiple handlers are given, the multiplexing should be
     526        // done by the generated code, not the exception runtime.
    454527        asm volatile (".CATCH:");
    455528
    456529        // Exception handler
    457         catch_block( shared_stack.current_handler_index,
    458                      shared_stack.current_exception );
     530        // Note: Saving the exception context on the stack breaks termination exceptions.
     531        catch_block( EXCEPT_TO_NODE( this_exception_context()->current_exception )->handler_index,
     532                     this_exception_context()->current_exception );
    459533}
    460534
     
    464538
    465539#ifdef __PIC__
    466 #if defined( __i386 ) || defined( __x86_64 )
    467540asm (
    468541        // HEADER
     
    481554        // handler landing pad offset and 1 (action code, gcc seems to use 0).
    482555        ".LLSDACSBCFA2:\n"
    483         "       .uleb128 .TRYSTART-__cfaabi_ehm__try_terminate\n"
     556        "       .uleb128 .TRYSTART-__cfaehm_try_terminate\n"
    484557        "       .uleb128 .TRYEND-.TRYSTART\n"
    485         "       .uleb128 .CATCH-__cfaabi_ehm__try_terminate\n"
     558        "       .uleb128 .CATCH-__cfaehm_try_terminate\n"
    486559        "       .uleb128 1\n"
    487560        ".LLSDACSECFA2:\n"
    488561        // TABLE FOOTER
    489562        "       .text\n"
    490         "       .size   __cfaabi_ehm__try_terminate, .-__cfaabi_ehm__try_terminate\n"
     563        "       .size   __cfaehm_try_terminate, .-__cfaehm_try_terminate\n"
    491564);
    492565
     
    507580        "       .quad __gcfa_personality_v0\n"
    508581#else // then __i386
    509         "   .long __gcfa_personality_v0\n"
     582        "       .long __gcfa_personality_v0\n"
    510583#endif
    511584);
    512 #else
    513 #error Exception Handling: unknown architecture for position independent code.
    514 #endif // __i386 || __x86_64
    515585#else // __PIC__
    516 #if defined( __i386 ) || defined( __x86_64 )
    517586asm (
    518587        // HEADER
     
    529598        ".LLSDACSBCFA2:\n"
    530599        //      Handled area start (relative to start of function)
    531         "       .uleb128 .TRYSTART-__cfaabi_ehm__try_terminate\n"
     600        "       .uleb128 .TRYSTART-__cfaehm_try_terminate\n"
    532601        //      Handled area length
    533602        "       .uleb128 .TRYEND-.TRYSTART\n"
    534603        //      Handler landing pad address (relative to start of function)
    535         "       .uleb128 .CATCH-__cfaabi_ehm__try_terminate\n"
     604        "       .uleb128 .CATCH-__cfaehm_try_terminate\n"
    536605        //      Action code, gcc seems to always use 0.
    537606        "       .uleb128 1\n"
     
    539608        ".LLSDACSECFA2:\n"
    540609        "       .text\n"
    541         "       .size   __cfaabi_ehm__try_terminate, .-__cfaabi_ehm__try_terminate\n"
     610        "       .size   __cfaehm_try_terminate, .-__cfaehm_try_terminate\n"
    542611        "       .ident  \"GCC: (Ubuntu 6.2.0-3ubuntu11~16.04) 6.2.0 20160901\"\n"
    543612        "       .section        .note.GNU-stack,\"x\",@progbits\n"
    544613);
     614#endif // __PIC__
     615
     616#pragma GCC pop_options
     617
     618#elif defined( __ARM_ARCH )
     619_Unwind_Reason_Code __gcfa_personality_v0(
     620                int version,
     621                _Unwind_Action actions,
     622                unsigned long long exception_class,
     623                struct _Unwind_Exception * unwind_exception,
     624                struct _Unwind_Context * unwind_context) {
     625        return _URC_CONTINUE_UNWIND;
     626}
     627
     628__attribute__((noinline))
     629void __cfaehm_try_terminate(void (*try_block)(),
     630                void (*catch_block)(int index, exception_t * except),
     631                __attribute__((unused)) int (*match_block)(exception_t * except)) {
     632}
    545633#else
    546 #error Exception Handling: unknown architecture for position dependent code.
    547 #endif // __i386 || __x86_64
    548 #endif // __PIC__
    549 
    550 #pragma GCC pop_options
     634        #error unsupported hardware architecture
     635#endif // __x86_64 || __i386
Note: See TracChangeset for help on using the changeset viewer.