Changeset 7030dab for libcfa/src/exception.c
- Timestamp:
- Apr 6, 2020, 4:46:28 PM (6 years ago)
- 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. - File:
-
- 1 edited
-
libcfa/src/exception.c (modified) (23 diffs)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/exception.c
r71d6bd8 r7030dab 9 9 // Author : Andrew Beach 10 10 // Created On : Mon Jun 26 15:13:00 2017 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Thu Feb 22 18:17:34 201813 // Update Count : 1 111 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Apr 03 11:57:00 2020 13 // Update Count : 14 14 14 // 15 15 16 // Normally we would get this from the CFA prelude. 16 17 #include <stddef.h> // for size_t 17 18 18 19 #include "exception.h" 19 20 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 21 25 22 26 #include <stdlib.h> … … 27 31 // FIX ME: temporary hack to keep ARM build working 28 32 #ifndef _URC_FATAL_PHASE1_ERROR 29 #define _URC_FATAL_PHASE1_ERROR 233 #define _URC_FATAL_PHASE1_ERROR 3 30 34 #endif // ! _URC_FATAL_PHASE1_ERROR 31 35 #ifndef _URC_FATAL_PHASE2_ERROR … … 35 39 #include "lsda.h" 36 40 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 */ 46 const _Unwind_Exception_Class __cfaehm_exception_class = 0x4c50575500414643; 37 47 38 48 // Base exception vtable is abstract, you should not have base exceptions. 39 struct __cfa abi_ehm__base_exception_t_vtable40 ___cfa abi_ehm__base_exception_t_vtable_instance = {49 struct __cfaehm_base_exception_t_vtable 50 ___cfaehm_base_exception_t_vtable_instance = { 41 51 .parent = NULL, 42 52 .size = 0, … … 49 59 // Temperary global exception context. Does not work with concurency. 50 60 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}; 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}; 57 66 58 67 // Get the current exception context. … … 62 71 return &shared_stack; 63 72 } 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 down72 // 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))76 73 77 74 78 75 // RESUMPTION ================================================================ 79 76 80 void __cfaabi_ehm__throw_resume(exception_t * except) { 77 void __cfaehm_throw_resume(exception_t * except) { 78 struct exception_context_t * context = this_exception_context(); 81 79 82 80 __cfaabi_dbg_print_safe("Throwing resumption exception\n"); 83 81 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; 87 84 88 85 for ( ; current ; current = current->next) { 89 shared_stack.current_resume = current;86 context->top_resume = current->next; 90 87 if (current->handler(except)) { 91 shared_stack.current_resume = original_head;88 context->top_resume = original_head; 92 89 return; 93 90 } … … 95 92 96 93 __cfaabi_dbg_print_safe("Unhandled exception\n"); 97 shared_stack.current_resume = original_head;94 context->top_resume = original_head; 98 95 99 96 // Fall back to termination: 100 __cfa abi_ehm__throw_terminate(except);97 __cfaehm_throw_terminate(except); 101 98 // TODO: Default handler for resumption. 102 99 } 103 100 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 105 void __cfaehm_try_resume_setup(struct __cfaehm_try_resume_node * node, 108 106 _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; 110 109 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 113 void __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; 116 116 } 117 117 … … 122 122 // May have to move to cfa for constructors and destructors (references). 123 123 124 struct __cfaabi_ehm__node { 125 struct __cfaabi_ehm__node * next; 124 // How to clean up an exception in various situations. 125 static 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. 140 static struct _Unwind_Exception this_exception_storage; 141 142 struct __cfaehm_node { 143 struct __cfaehm_node * next; 126 144 }; 127 145 128 146 #define NODE_TO_EXCEPT(node) ((exception_t *)(1 + (node))) 129 #define EXCEPT_TO_NODE(except) ((struct __cfa abi_ehm__node *)(except) - 1)147 #define EXCEPT_TO_NODE(except) ((struct __cfaehm_node *)(except) - 1) 130 148 131 149 // Creates a copy of the indicated exception and sets current_exception to it. 132 static void __cfa abi_ehm__allocate_exception( exception_t * except ) {150 static void __cfaehm_allocate_exception( exception_t * except ) { 133 151 struct exception_context_t * context = this_exception_context(); 134 152 135 153 // Allocate memory for the exception. 136 struct __cfa abi_ehm__node * store = malloc(137 sizeof( struct __cfa abi_ehm__node ) + except->virtual_table->size );154 struct __cfaehm_node * store = malloc( 155 sizeof( struct __cfaehm_node ) + except->virtual_table->size ); 138 156 139 157 if ( ! store ) { … … 148 166 // Copy the exception to storage. 149 167 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; 150 172 } 151 173 152 174 // Delete the provided exception, unsetting current_exception if relivant. 153 static void __cfa abi_ehm__delete_exception( exception_t * except ) {175 static void __cfaehm_delete_exception( exception_t * except ) { 154 176 struct exception_context_t * context = this_exception_context(); 155 177 … … 157 179 158 180 // Remove the exception from the list. 159 struct __cfa abi_ehm__node * to_free = EXCEPT_TO_NODE(except);160 struct __cfa abi_ehm__node * node;181 struct __cfaehm_node * to_free = EXCEPT_TO_NODE(except); 182 struct __cfaehm_node * node; 161 183 162 184 if ( context->current_exception == except ) { … … 166 188 node = EXCEPT_TO_NODE(context->current_exception); 167 189 // It may always be in the first or second position. 168 while ( to_free != node->next ) {190 while ( to_free != node->next ) { 169 191 node = node->next; 170 192 } … … 178 200 179 201 // 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; 202 void __cfaehm_cleanup_terminate( void * except ) { 203 if ( *(void**)except ) __cfaehm_delete_exception( *(exception_t **)except ); 204 } 187 205 188 206 // Function needed by force unwind … … 191 209 int version, 192 210 _Unwind_Action actions, 193 _Unwind_Exception_Class exception Class,211 _Unwind_Exception_Class exception_class, 194 212 struct _Unwind_Exception * unwind_exception, 195 struct _Unwind_Context * context,196 void * s ome_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; 199 217 200 218 return _URC_FATAL_PHASE2_ERROR; … … 202 220 203 221 // The exception that is being thrown must already be stored. 204 __attribute__((noreturn)) void __cfaabi_ehm__begin_unwind(void) {222 static __attribute__((noreturn)) void __cfaehm_begin_unwind(void) { 205 223 if ( ! this_exception_context()->current_exception ) { 206 224 printf("UNWIND ERROR missing exception in begin unwind\n"); … … 208 226 } 209 227 210 211 228 // Call stdlibc to raise the exception 212 229 _Unwind_Reason_Code ret = _Unwind_RaiseException( &this_exception_storage ); 213 230 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. 223 241 printf("Uncaught exception %p\n", &this_exception_storage); 224 242 … … 228 246 } 229 247 230 // We did not simply reach the end of the stack without finding a handler. Something wen't wrong248 // We did not simply reach the end of the stack without finding a handler. This is an error. 231 249 printf("UNWIND ERROR %d after raise exception\n", ret); 232 250 abort(); 233 251 } 234 252 235 void __cfa abi_ehm__throw_terminate( exception_t * val ) {253 void __cfaehm_throw_terminate( exception_t * val ) { 236 254 __cfaabi_dbg_print_safe("Throwing termination exception\n"); 237 255 238 __cfa abi_ehm__allocate_exception( val );239 __cfa abi_ehm__begin_unwind();240 } 241 242 void __cfa abi_ehm__rethrow_terminate(void) {256 __cfaehm_allocate_exception( val ); 257 __cfaehm_begin_unwind(); 258 } 259 260 void __cfaehm_rethrow_terminate(void) { 243 261 __cfaabi_dbg_print_safe("Rethrowing termination exception\n"); 244 262 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) 263 275 { 264 276 265 277 //__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); 267 280 268 281 // 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; 270 283 271 284 if (actions & _UA_SEARCH_PHASE) { … … 282 295 283 296 // 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 unwinding297 const unsigned char * lsd = _Unwind_GetLanguageSpecificData( unwind_context ); 298 299 if ( !lsd ) { //Nothing to do, keep unwinding 287 300 printf(" no LSD"); 288 301 goto UNWIND; … … 291 304 // Get the instuction pointer and a reading pointer into the exception table 292 305 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(); 295 310 296 311 // Linearly search the table for stuff to do 297 while ( cur_ptr < lsd_info.action_table ) {312 while ( cur_ptr < lsd_info.action_table ) { 298 313 _Unwind_Ptr callsite_start; 299 314 _Unwind_Ptr callsite_len; … … 302 317 303 318 // 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); 308 323 309 324 // 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 ) { 311 326 #ifdef __CFA_DEBUG_PRINT__ 312 327 void * ls = (void*)lsd_info.Start; … … 316 331 void * ep = (void*)lsd_info.Start + callsite_start + callsite_len; 317 332 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); 319 335 #endif // __CFA_DEBUG_PRINT__ 320 336 continue; 321 337 } 322 338 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 ) { 325 341 printf(" gone too far"); 326 342 break; 327 343 } 328 344 329 // Something to do?330 if (callsite_landing_pad ) {331 // Which phase are we in332 if (actions & _UA_SEARCH_PHASE) {333 // Search phase, this means we probably found a potential handler and must check if it is a match334 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 behavior337 if (callsite_action != 0) {338 // Now we want to run some code to see if the handler matches339 // This is the tricky part where we want to the power to run arbitrary code340 // However, generating a new exception table entry and try routine every time341 // is way more expansive than we might like342 // The information we have is :343 // - The GR (Series of registers)344 // GR1=GP Global Pointer of frame ref by context345 // - The instruction pointer346 // - 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 block352 _uleb128_t imatcher;353 // Get the relative offset to the354 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 exception367 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"); 373 389 } 374 375 // This is only a cleanup handler, ignore it 376 __cfaabi_dbg_print_safe(" no action"); 390 return ret; 377 391 } 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; 400 403 } 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; 401 420 } 402 403 // Nothing to do, move along404 __cfaabi_dbg_print_safe(" no landing pad");405 421 } 406 422 // No handling found … … 414 430 } 415 431 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 418 437 __attribute__((noinline)) 419 void __cfa abi_ehm__try_terminate(void (*try_block)(),438 void __cfaehm_try_terminate(void (*try_block)(), 420 439 void (*catch_block)(int index, exception_t * except), 421 440 __attribute__((unused)) int (*match_block)(exception_t * except)) { … … 423 442 //! printf("%p %p %p %p\n", &try_block, &catch_block, &match_block, &xy); 424 443 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 431 452 asm volatile (".cfi_personality 0x3,__gcfa_personality_v0"); 432 // Setup the exception table433 453 asm volatile (".cfi_lsda 0x3, .LLSDACFA2"); 454 #endif 434 455 435 456 // Label which defines the start of the area for which the handler is setup. … … 442 463 asm volatile goto ("" : : : : CATCH ); 443 464 444 // Normal return 465 // Normal return for when there is no throw. 445 466 return; 446 467 … … 449 470 // Label which defines the end of the area for which the handler is setup. 450 471 asm volatile (".TRYEND:"); 451 // Label which defines the start of the exception landing pad. Basically what is called when the exception is452 // caught. Note, if multiple handlers are given, the multiplexing should be done by the generated code, not the453 // 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. 454 475 asm volatile (".CATCH:"); 455 476 456 477 // 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__ 465 488 asm ( 466 // HEADER489 // HEADER 467 490 ".LFECFA1:\n" 468 491 " .globl __gcfa_personality_v0\n" 469 492 " .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" 471 495 " .byte 0xff\n" 472 496 " .byte 0xff\n" 473 497 " .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 517 asm ( 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__ 534 asm ( 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" 484 559 " .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" 486 561 ); 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.