Ignore:
Timestamp:
Jun 13, 2017, 4:24:17 PM (7 years ago)
Author:
Andrew Beach <ajbeach@…>
Branches:
ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
Children:
6a48cc9
Parents:
35dd0f42
Message:

Wrote out more tests for the new exception.h/c files.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • doc/working/exception/impl/exception.c

    r35dd0f42 re4e9173  
    2222
    2323void __throw_resume(exception except) {
    24         void noop() { printf("do nothing\n");}
    25         struct __cleanup_hook __blarg __attribute__((cleanup(noop)));
     24
     25        // DEBUG
     26        printf("Throwing resumption exception %d\n", except);
    2627
    2728        struct __try_resume_node * original_head = shared_stack.current_resume;
     
    4546}
    4647
    47 /* __try_resume_node functions:
    48  * Currently I was planning to generate this code inline, and even if I don't
    49  * putting it in the header so it can be inlined might be worth while.
    50  * And if we put them in Cforall code we can use the operators.
    51  */
    52 void __try_resume_node_new(struct __try_resume_node * node,
    53                 _Bool (*handler)(exception except)) {
    54         node->next = shared_stack.top_resume;
    55         shared_stack.top_resume = node;
    56         node->try_to_handle = handler;
    57 }
    58 
    59 void __try_resume_node_delete(struct __try_resume_node * node) {
    60         shared_stack.top_resume = node->next;
    61 }
    62 
    6348
    6449// TERMINATION ===============================================================
    6550
    6651// Requires -fexceptions to work.
     52
     53// Global which defines the current exception
     54// Currently an int just to make matching easier
     55//int this_exception; (became shared_stack.current_exception)
     56
     57// We need a piece of storage to raise the exception
     58struct _Unwind_Exception this_exception_storage;
     59
     60// Function needed by force unwind
     61// It basically says to unwind the whole stack and then exit when we reach the end of the stack
     62static _Unwind_Reason_Code _Stop_Fn(
     63                int version,
     64                _Unwind_Action actions,
     65                _Unwind_Exception_Class exceptionClass,
     66                struct _Unwind_Exception * unwind_exception,
     67                struct _Unwind_Context * context,
     68                void * some_param) {
     69        if( actions & _UA_END_OF_STACK  ) exit(1);
     70        if( actions & _UA_CLEANUP_PHASE ) return _URC_NO_REASON;
     71
     72        return _URC_FATAL_PHASE2_ERROR;
     73}
     74
     75// Example throw routine
     76void __throw_terminate( int val ) {
     77        // Store the current exception
     78        shared_stack.current_exception = val;
     79
     80        // DEBUG
     81        printf("Throwing termination exception %d\n", val);
     82
     83        // Call stdlibc to raise the exception
     84        _Unwind_Reason_Code ret = _Unwind_RaiseException( &this_exception_storage );
     85
     86        // If we reach here it means something happened
     87        // For resumption to work we need to find a way to return back to here
     88        // Most of them will probably boil down to setting a global flag and making the phase 1 either stop or fail.
     89        // Causing an error on purpose may help avoiding unnecessary work but it might have some weird side effects.
     90        // If we just pretend no handler was found that would work but may be expensive for no reason since we will always
     91        // search the whole stack
     92
     93        if( ret == _URC_END_OF_STACK ) {
     94                // No proper handler was found
     95                // This can be handled in several way
     96                // C++ calls std::terminate
     97                // Here we force unwind the stack, basically raising a cancellation
     98                printf("Uncaught exception %p\n", &this_exception_storage);
     99
     100                ret = _Unwind_ForcedUnwind( &this_exception_storage, _Stop_Fn, (void*)0x22 );
     101                printf("UNWIND ERROR %d after force unwind\n", ret);
     102                abort();
     103        }
     104
     105        // We did not simply reach the end of the stack without finding a handler,
     106        // Something wen't wrong
     107        printf("UNWIND ERROR %d after raise exception\n", ret);
     108        abort();
     109}
     110
     111// This is our personality routine
     112// For every stack frame anotated with ".cfi_personality 0x3,__gcfa_personality_v0"
     113// This function will be called twice when unwinding
     114// Once in the search phased and once in the cleanup phase
     115_Unwind_Reason_Code __gcfa_personality_v0 (
     116                int version, _Unwind_Action actions, unsigned long long exceptionClass,
     117                struct _Unwind_Exception* unwind_exception,
     118                struct _Unwind_Context* context)
     119{
     120
     121        // DEBUG
     122        //printf("CFA: 0x%lx\n", _Unwind_GetCFA(context));
     123        printf("Personality function (%d, %x, %llu, %p, %p):", version, actions, exceptionClass, unwind_exception, context);
     124
     125        // If we've reached the end of the stack then there is nothing much we can do...
     126        if( actions & _UA_END_OF_STACK ) return _URC_END_OF_STACK;
     127
     128        // DEBUG
     129        if (actions & _UA_SEARCH_PHASE) {
     130                printf(" lookup phase");
     131        }
     132        // DEBUG
     133        else if (actions & _UA_CLEANUP_PHASE) {
     134                printf(" cleanup phase");
     135        }
     136        // Just in case, probably can't actually happen
     137        else {
     138                printf(" error\n");
     139                return _URC_FATAL_PHASE1_ERROR;
     140        }
     141
     142        // Get a pointer to the language specific data from which we will read what we need
     143        const unsigned char * lsd = (const unsigned char*) _Unwind_GetLanguageSpecificData( context );
     144
     145        if( !lsd ) {    //Nothing to do, keep unwinding
     146                printf(" no LSD");
     147                goto UNWIND;
     148        }
     149
     150        // Get the instuction pointer and a reading pointer into the exception table
     151        lsda_header_info lsd_info;
     152        const unsigned char * cur_ptr = parse_lsda_header( context, lsd, &lsd_info);
     153        _Unwind_Ptr instruction_ptr = _Unwind_GetIP( context );
     154
     155        // Linearly search the table for stuff to do
     156        while( cur_ptr < lsd_info.action_table ) {
     157                _Unwind_Ptr callsite_start;
     158                _Unwind_Ptr callsite_len;
     159                _Unwind_Ptr callsite_landing_pad;
     160                _uleb128_t  callsite_action;
     161
     162                // Decode the common stuff we have in here
     163                cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_start);
     164                cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_len);
     165                cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_landing_pad);
     166                cur_ptr = read_uleb128 (cur_ptr, &callsite_action);
     167
     168                // Have we reach the correct frame info yet?
     169                if( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) {
     170                        //DEBUG BEGIN
     171                        void * ls = (void*)lsd_info.Start;
     172                        void * cs = (void*)callsite_start;
     173                        void * cl = (void*)callsite_len;
     174                        void * bp = (void*)lsd_info.Start + callsite_start;
     175                        void * ep = (void*)lsd_info.Start + callsite_start + callsite_len;
     176                        void * ip = (void*)instruction_ptr;
     177                        printf("\nfound %p - %p (%p, %p, %p), looking for %p\n", bp, ep, ls, cs, cl, ip);
     178                        //DEBUG END
     179                        continue;
     180                }
     181
     182                // Have we gone too far
     183                if( lsd_info.Start + callsite_start > instruction_ptr ) {
     184                        printf(" gone too far");
     185                        break;
     186                }
     187
     188                // Something to do?
     189                if( callsite_landing_pad ) {
     190                        // Which phase are we in
     191                        if (actions & _UA_SEARCH_PHASE) {
     192                                // Search phase, this means we probably found a potential handler and must check if it is a match
     193
     194                                // If we have arbitrarily decided that 0 means nothing to do and 1 means there is a potential handler
     195                                // This doesn't seem to conflict the gcc default behavior
     196                                if (callsite_action != 0) {
     197                                        // Now we want to run some code to see if the handler matches
     198                                        // This is the tricky part where we want to the power to run arbitrary code
     199                                        // However, generating a new exception table entry and try routine every time
     200                                        // is way more expansive than we might like
     201                                        // The information we have is :
     202                                        //  - The GR (Series of registers)
     203                                        //    GR1=GP Global Pointer of frame ref by context
     204                                        //  - The instruction pointer
     205                                        //  - The instruction pointer info (???)
     206                                        //  - The CFA (Canonical Frame Address)
     207                                        //  - The BSP (Probably the base stack pointer)
     208
     209
     210                                        // The current apprach uses one exception table entry per try block
     211                                        _uleb128_t imatcher;
     212                                        // Get the relative offset to the
     213                                        cur_ptr = read_uleb128 (cur_ptr, &imatcher);
     214
     215                                        // Get a function pointer from the relative offset and call it
     216                                        // _Unwind_Reason_Code (*matcher)() = (_Unwind_Reason_Code (*)())lsd_info.LPStart + imatcher;                                   
     217
     218                                        _Unwind_Reason_Code (*matcher)() =
     219                                                MATCHER_FROM_CONTEXT(context);
     220                                        int index = matcher(shared_stack.current_exception);
     221                                        _Unwind_Reason_Code ret = (0 == index)
     222                                                ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND;
     223                                        shared_stack.current_handler_index = index;
     224
     225
     226                                        // Based on the return value, check if we matched the exception
     227                                        if( ret == _URC_HANDLER_FOUND) printf(" handler found\n");
     228                                        else printf(" no handler\n");
     229                                        return ret;
     230                                }
     231
     232                                // This is only a cleanup handler, ignore it
     233                                printf(" no action");
     234                        }
     235                        else if (actions & _UA_CLEANUP_PHASE) {
     236
     237                                if( (callsite_action != 0) && !(actions & _UA_HANDLER_FRAME) ){
     238                                        // If this is a potential exception handler
     239                                        // but not the one that matched the exception in the seach phase,
     240                                        // just ignore it
     241                                        goto UNWIND;
     242                                }
     243
     244                                // We need to run some clean-up or a handler
     245                                // These statment do the right thing but I don't know any specifics at all
     246                                _Unwind_SetGR( context, __builtin_eh_return_data_regno(0), (_Unwind_Ptr) unwind_exception );
     247                                _Unwind_SetGR( context, __builtin_eh_return_data_regno(1), 0 );
     248
     249                                // I assume this sets the instruction pointer to the adress of the landing pad
     250                                // It doesn't actually set it, it only state the value that needs to be set once we return _URC_INSTALL_CONTEXT
     251                                _Unwind_SetIP( context, lsd_info.LPStart + callsite_landing_pad );
     252
     253                                // DEBUG
     254                                printf(" action\n");
     255
     256                                // Return have some action to run
     257                                return _URC_INSTALL_CONTEXT;
     258                        }
     259                }
     260
     261                // Nothing to do, move along
     262                printf(" no landing pad");
     263        }
     264        // No handling found
     265        printf(" table end reached\n");
     266
     267        // DEBUG
     268        UNWIND:
     269        printf(" unwind\n");
     270
     271        // Keep unwinding the stack
     272        return _URC_CONTINUE_UNWIND;
     273}
    67274
    68275// Try statements are hoisted out see comments for details
     
    141348        "       .size   __try_terminate, .-__try_terminate\n"
    142349        "       .ident  \"GCC: (Ubuntu 6.2.0-3ubuntu11~16.04) 6.2.0 20160901\"\n"
    143         "       .section        .note.GNU-stack,\"x\",@progbits\n"
     350//      "       .section        .note.GNU-stack,\"x\",@progbits\n"
    144351);
    145 
    146 // Global which defines the current exception
    147 // Currently an int just to make matching easier
    148 int this_exception;
    149 
    150 // We need a piece of storage to raise the exception
    151 struct _Unwind_Exception this_exception_storage;
    152 
    153 // Function needed by force unwind
    154 // It basically says to unwind the whole stack and then exit when we reach the end of the stack
    155 static _Unwind_Reason_Code _Stop_Fn(
    156                 int version,
    157                 _Unwind_Action actions,
    158                 _Unwind_Exception_Class exceptionClass,
    159                 struct _Unwind_Exception * unwind_exception,
    160                 struct _Unwind_Context * context,
    161                 void * some_param) {
    162         if( actions & _UA_END_OF_STACK  ) exit(1);
    163         if( actions & _UA_CLEANUP_PHASE ) return _URC_NO_REASON;
    164 
    165         return _URC_FATAL_PHASE2_ERROR;
    166 }
    167 
    168 // Example throw routine
    169 void __throw_terminate( int val ) {
    170         // Store the current exception
    171         this_exception = val;
    172 
    173         // DEBUG
    174         printf("Throwing exception %d\n", this_exception);
    175 
    176         // Call stdlibc to raise the exception
    177         _Unwind_Reason_Code ret = _Unwind_RaiseException( &this_exception_storage );
    178 
    179         // If we reach here it means something happened
    180         // For resumption to work we need to find a way to return back to here
    181         // Most of them will probably boil down to setting a global flag and making the phase 1 either stop or fail.
    182         // Causing an error on purpose may help avoiding unnecessary work but it might have some weird side effects.
    183         // If we just pretend no handler was found that would work but may be expensive for no reason since we will always
    184         // search the whole stack
    185 
    186         if( ret == _URC_END_OF_STACK ) {
    187                 // No proper handler was found
    188                 // This can be handled in several way
    189                 // C++ calls std::terminate
    190                 // Here we force unwind the stack, basically raising a cancellation
    191                 printf("Uncaught exception %p\n", &this_exception_storage);
    192 
    193                 ret = _Unwind_ForcedUnwind( &this_exception_storage, _Stop_Fn, (void*)0x22 );
    194                 printf("UNWIND ERROR %d after force unwind\n", ret);
    195                 abort();
    196         }
    197 
    198         // We did not simply reach the end of the stack without finding a handler,
    199         // Something wen't wrong
    200         printf("UNWIND ERROR %d after raise exception\n", ret);
    201         abort();
    202 }
    203 
    204 // This is our personality routine
    205 // For every stack frame anotated with ".cfi_personality 0x3,__gcfa_personality_v0"
    206 // This function will be called twice when unwinding
    207 // Once in the search phased and once in the cleanup phase
    208 _Unwind_Reason_Code __gcfa_personality_v0 (
    209                 int version, _Unwind_Action actions, unsigned long long exceptionClass,
    210                 struct _Unwind_Exception* unwind_exception,
    211                 struct _Unwind_Context* context)
    212 {
    213         printf("CFA: 0x%lx\n", _Unwind_GetCFA(context));
    214 
    215         // DEBUG
    216         printf("Personality function (%d, %x, %llu, %p, %p):", version, actions, exceptionClass, unwind_exception, context);
    217 
    218         // If we've reached the end of the stack then there is nothing much we can do...
    219         if( actions & _UA_END_OF_STACK ) return _URC_END_OF_STACK;
    220 
    221         // DEBUG
    222         if (actions & _UA_SEARCH_PHASE) {
    223                 printf(" lookup phase");
    224         }
    225         // DEBUG
    226         else if (actions & _UA_CLEANUP_PHASE) {
    227                 printf(" cleanup phase");
    228         }
    229         // Just in case, probably can't actually happen
    230         else {
    231                 printf(" error\n");
    232                 return _URC_FATAL_PHASE1_ERROR;
    233         }
    234 
    235         // Get a pointer to the language specific data from which we will read what we need
    236         const unsigned char * lsd = (const unsigned char*) _Unwind_GetLanguageSpecificData( context );
    237 
    238         if( !lsd ) {    //Nothing to do, keep unwinding
    239                 printf(" no LSD");
    240                 goto UNWIND;
    241         }
    242 
    243         // Get the instuction pointer and a reading pointer into the exception table
    244         lsda_header_info lsd_info;
    245         const unsigned char * cur_ptr = parse_lsda_header( context, lsd, &lsd_info);
    246         _Unwind_Ptr instruction_ptr = _Unwind_GetIP( context );
    247 
    248         // Linearly search the table for stuff to do
    249         while( cur_ptr < lsd_info.action_table ) {
    250                 _Unwind_Ptr callsite_start;
    251                 _Unwind_Ptr callsite_len;
    252                 _Unwind_Ptr callsite_landing_pad;
    253                 _uleb128_t  callsite_action;
    254 
    255                 // Decode the common stuff we have in here
    256                 cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_start);
    257                 cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_len);
    258                 cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_landing_pad);
    259                 cur_ptr = read_uleb128 (cur_ptr, &callsite_action);
    260 
    261                 // Have we reach the correct frame info yet?
    262                 if( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) {
    263                         //DEBUG BEGIN
    264                         void * ls = (void*)lsd_info.Start;
    265                         void * cs = (void*)callsite_start;
    266                         void * cl = (void*)callsite_len;
    267                         void * bp = (void*)lsd_info.Start + callsite_start;
    268                         void * ep = (void*)lsd_info.Start + callsite_start + callsite_len;
    269                         void * ip = (void*)instruction_ptr;
    270                         printf("\nfound %p - %p (%p, %p, %p), looking for %p\n", bp, ep, ls, cs, cl, ip);
    271                         //DEBUG END
    272                         continue;
    273                 }
    274 
    275                 // Have we gone too far
    276                 if( lsd_info.Start + callsite_start > instruction_ptr ) {
    277                         printf(" gone too far");
    278                         break;
    279                 }
    280 
    281                 // Something to do?
    282                 if( callsite_landing_pad ) {
    283                         // Which phase are we in
    284                         if (actions & _UA_SEARCH_PHASE) {
    285                                 // Search phase, this means we probably found a potential handler and must check if it is a match
    286 
    287                                 // If we have arbitrarily decided that 0 means nothing to do and 1 means there is a potential handler
    288                                 // This doesn't seem to conflict the gcc default behavior
    289                                 if (callsite_action != 0) {
    290                                         // Now we want to run some code to see if the handler matches
    291                                         // This is the tricky part where we want to the power to run arbitrary code
    292                                         // However, generating a new exception table entry and try routine every time
    293                                         // is way more expansive than we might like
    294                                         // The information we have is :
    295                                         //  - The GR (Series of registers)
    296                                         //    GR1=GP Global Pointer of frame ref by context
    297                                         //  - The instruction pointer
    298                                         //  - The instruction pointer info (???)
    299                                         //  - The CFA (Canonical Frame Address)
    300                                         //  - The BSP (Probably the base stack pointer)
    301 
    302 
    303                                         // The current apprach uses one exception table entry per try block
    304                                         _uleb128_t imatcher;
    305                                         // Get the relative offset to the
    306                                         cur_ptr = read_uleb128 (cur_ptr, &imatcher);
    307 
    308                                         // Get a function pointer from the relative offset and call it
    309                                         // _Unwind_Reason_Code (*matcher)() = (_Unwind_Reason_Code (*)())lsd_info.LPStart + imatcher;                                   
    310 
    311                                         _Unwind_Reason_Code (*matcher)() =
    312                                                 MATCHER_FROM_CONTEXT(context);
    313                                         int index = matcher(shared_stack.current_exception);
    314                                         _Unwind_Reason_Code ret = (0 == index)
    315                                                 ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND;
    316                                         shared_stack.current_handler_index = index;
    317 
    318 
    319                                         // Based on the return value, check if we matched the exception
    320                                         if( ret == _URC_HANDLER_FOUND) printf(" handler found\n");
    321                                         else printf(" no handler\n");
    322                                         return ret;
    323                                 }
    324 
    325                                 // This is only a cleanup handler, ignore it
    326                                 printf(" no action");
    327                         }
    328                         else if (actions & _UA_CLEANUP_PHASE) {
    329 
    330                                 if( (callsite_action != 0) && !(actions & _UA_HANDLER_FRAME) ){
    331                                         // If this is a potential exception handler
    332                                         // but not the one that matched the exception in the seach phase,
    333                                         // just ignore it
    334                                         goto UNWIND;
    335                                 }
    336 
    337                                 // We need to run some clean-up or a handler
    338                                 // These statment do the right thing but I don't know any specifics at all
    339                                 _Unwind_SetGR( context, __builtin_eh_return_data_regno(0), (_Unwind_Ptr) unwind_exception );
    340                                 _Unwind_SetGR( context, __builtin_eh_return_data_regno(1), 0 );
    341 
    342                                 // I assume this sets the instruction pointer to the adress of the landing pad
    343                                 // It doesn't actually set it, it only state the value that needs to be set once we return _URC_INSTALL_CONTEXT
    344                                 _Unwind_SetIP( context, lsd_info.LPStart + callsite_landing_pad );
    345 
    346                                 // DEBUG
    347                                 printf(" action\n");
    348 
    349                                 // Return have some action to run
    350                                 return _URC_INSTALL_CONTEXT;
    351                         }
    352                 }
    353 
    354                 // Nothing to do, move along
    355                 printf(" no landing pad");
    356         }
    357         // No handling found
    358         printf(" table end reached\n");
    359 
    360         // DEBUG
    361         UNWIND:
    362         printf(" unwind\n");
    363 
    364         // Keep unwinding the stack
    365         return _URC_CONTINUE_UNWIND;
    366 }
Note: See TracChangeset for help on using the changeset viewer.