Changes in / [68887f9:136f86b]
- File:
-
- 1 edited
-
libcfa/src/exception.c (modified) (15 diffs)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/exception.c
r68887f9 r136f86b 58 58 exception_t * current_exception; 59 59 int current_handler_index; 60 } s tatic shared_stack = {NULL, NULL, NULL, 0};60 } shared_stack = {NULL, NULL, 0, 0}; 61 61 62 62 // Get the current exception context. … … 66 66 return &shared_stack; 67 67 } 68 //#define SAVE_EXCEPTION_CONTEXT(to_name) 69 //struct exception_context_t * to_name = this_exception_context(); 70 //exception * this_exception() { 71 // return this_exception_context()->current_exception; 72 //} 68 73 69 74 … … 71 76 72 77 void __cfaabi_ehm__throw_resume(exception_t * except) { 73 struct exception_context_t * context = this_exception_context();74 78 75 79 __cfaabi_dbg_print_safe("Throwing resumption exception\n"); 76 80 77 struct __cfaabi_ehm__try_resume_node * original_head = context->current_resume;81 struct __cfaabi_ehm__try_resume_node * original_head = shared_stack.current_resume; 78 82 struct __cfaabi_ehm__try_resume_node * current = 79 (original_head) ? original_head->next : context->top_resume;83 (original_head) ? original_head->next : shared_stack.top_resume; 80 84 81 85 for ( ; current ; current = current->next) { 82 context->current_resume = current;86 shared_stack.current_resume = current; 83 87 if (current->handler(except)) { 84 context->current_resume = original_head;88 shared_stack.current_resume = original_head; 85 89 return; 86 90 } … … 88 92 89 93 __cfaabi_dbg_print_safe("Unhandled exception\n"); 90 context->current_resume = original_head;94 shared_stack.current_resume = original_head; 91 95 92 96 // Fall back to termination: … … 101 105 void __cfaabi_ehm__try_resume_setup(struct __cfaabi_ehm__try_resume_node * node, 102 106 _Bool (*handler)(exception_t * except)) { 103 struct exception_context_t * context = this_exception_context(); 104 node->next = context->top_resume; 107 node->next = shared_stack.top_resume; 105 108 node->handler = handler; 106 context->top_resume = node;109 shared_stack.top_resume = node; 107 110 } 108 111 109 112 void __cfaabi_ehm__try_resume_cleanup(struct __cfaabi_ehm__try_resume_node * node) { 110 struct exception_context_t * context = this_exception_context(); 111 context->top_resume = node->next; 113 shared_stack.top_resume = node->next; 112 114 } 113 115 … … 162 164 node = EXCEPT_TO_NODE(context->current_exception); 163 165 // It may always be in the first or second position. 164 while ( to_free != node->next ) {166 while( to_free != node->next ) { 165 167 node = node->next; 166 168 } … … 189 191 _Unwind_Exception_Class exceptionClass, 190 192 struct _Unwind_Exception * unwind_exception, 191 struct _Unwind_Context * unwind_context,192 void * s top_param) {193 if ( actions & _UA_END_OF_STACK ) exit(1);194 if ( actions & _UA_CLEANUP_PHASE ) return _URC_NO_REASON;193 struct _Unwind_Context * context, 194 void * some_param) { 195 if( actions & _UA_END_OF_STACK ) exit(1); 196 if( actions & _UA_CLEANUP_PHASE ) return _URC_NO_REASON; 195 197 196 198 return _URC_FATAL_PHASE2_ERROR; … … 215 217 // the whole stack. 216 218 217 if ( ret == _URC_END_OF_STACK ) {219 if( ret == _URC_END_OF_STACK ) { 218 220 // No proper handler was found. This can be handled in many ways, C++ calls std::terminate. 219 221 // Here we force unwind the stack, basically raising a cancellation. … … 249 251 int version, _Unwind_Action actions, unsigned long long exceptionClass, 250 252 struct _Unwind_Exception* unwind_exception, 251 struct _Unwind_Context* unwind_context)253 struct _Unwind_Context* context) 252 254 { 253 255 254 256 //__cfaabi_dbg_print_safe("CFA: 0x%lx\n", _Unwind_GetCFA(context)); 255 257 __cfaabi_dbg_print_safe("Personality function (%d, %x, %llu, %p, %p):", 256 version, actions, exceptionClass, unwind_exception, unwind_context);258 version, actions, exceptionClass, unwind_exception, context); 257 259 258 260 // If we've reached the end of the stack then there is nothing much we can do... 259 if (actions & _UA_END_OF_STACK) return _URC_END_OF_STACK;261 if( actions & _UA_END_OF_STACK ) return _URC_END_OF_STACK; 260 262 261 263 if (actions & _UA_SEARCH_PHASE) { … … 272 274 273 275 // Get a pointer to the language specific data from which we will read what we need 274 const unsigned char * lsd = _Unwind_GetLanguageSpecificData( unwind_context );275 276 if ( !lsd ) { //Nothing to do, keep unwinding276 const unsigned char * lsd = (const unsigned char*) _Unwind_GetLanguageSpecificData( context ); 277 278 if( !lsd ) { //Nothing to do, keep unwinding 277 279 printf(" no LSD"); 278 280 goto UNWIND; … … 281 283 // Get the instuction pointer and a reading pointer into the exception table 282 284 lsda_header_info lsd_info; 283 const unsigned char * cur_ptr = parse_lsda_header(unwind_context, lsd, &lsd_info); 284 _Unwind_Ptr instruction_ptr = _Unwind_GetIP(unwind_context); 285 286 struct exception_context_t * context = this_exception_context(); 285 const unsigned char * cur_ptr = parse_lsda_header(context, lsd, &lsd_info); 286 _Unwind_Ptr instruction_ptr = _Unwind_GetIP( context ); 287 287 288 288 // Linearly search the table for stuff to do 289 while ( cur_ptr < lsd_info.action_table ) {289 while( cur_ptr < lsd_info.action_table ) { 290 290 _Unwind_Ptr callsite_start; 291 291 _Unwind_Ptr callsite_len; … … 300 300 301 301 // Have we reach the correct frame info yet? 302 if ( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) {302 if( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) { 303 303 #ifdef __CFA_DEBUG_PRINT__ 304 304 void * ls = (void*)lsd_info.Start; … … 315 315 316 316 // Have we gone too far? 317 if ( lsd_info.Start + callsite_start > instruction_ptr ) {317 if( lsd_info.Start + callsite_start > instruction_ptr ) { 318 318 printf(" gone too far"); 319 319 break; 320 320 } 321 321 322 // Check for what we must do: 323 if ( 0 == callsite_landing_pad ) { 324 // Nothing to do, move along 325 __cfaabi_dbg_print_safe(" no landing pad"); 326 } else if (actions & _UA_SEARCH_PHASE) { 327 // In search phase, these means we found a potential handler we must check. 328 329 // We have arbitrarily decided that 0 means nothing to do and 1 means there is 330 // a potential handler. This doesn't seem to conflict the gcc default behavior. 331 if (callsite_action != 0) { 332 // Now we want to run some code to see if the handler matches 333 // This is the tricky part where we want to the power to run arbitrary code 334 // However, generating a new exception table entry and try routine every time 335 // is way more expansive than we might like 336 // The information we have is : 337 // - The GR (Series of registers) 338 // GR1=GP Global Pointer of frame ref by context 339 // - The instruction pointer 340 // - The instruction pointer info (???) 341 // - The CFA (Canonical Frame Address) 342 // - The BSP (Probably the base stack pointer) 343 344 345 // The current apprach uses one exception table entry per try block 346 _uleb128_t imatcher; 347 // Get the relative offset to the {...}? 348 cur_ptr = read_uleb128(cur_ptr, &imatcher); 349 350 # if defined( __x86_64 ) 351 _Unwind_Word match_pos = _Unwind_GetCFA(unwind_context) + 8; 352 # elif defined( __i386 ) 353 _Unwind_Word match_pos = _Unwind_GetCFA(unwind_context) + 24; 354 # endif 355 int (*matcher)(exception_t *) = *(int(**)(exception_t *))match_pos; 356 357 int index = matcher(context->current_exception); 358 _Unwind_Reason_Code ret = (0 == index) 359 ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND; 360 context->current_handler_index = index; 361 362 // Based on the return value, check if we matched the exception 363 if (ret == _URC_HANDLER_FOUND) { 364 __cfaabi_dbg_print_safe(" handler found\n"); 365 } else { 366 __cfaabi_dbg_print_safe(" no handler\n"); 322 // Something to do? 323 if( callsite_landing_pad ) { 324 // Which phase are we in 325 if (actions & _UA_SEARCH_PHASE) { 326 // In search phase, these means we found a potential handler we must check. 327 328 // We have arbitrarily decided that 0 means nothing to do and 1 means there is 329 // a potential handler. This doesn't seem to conflict the gcc default behavior. 330 if (callsite_action != 0) { 331 // Now we want to run some code to see if the handler matches 332 // This is the tricky part where we want to the power to run arbitrary code 333 // However, generating a new exception table entry and try routine every time 334 // is way more expansive than we might like 335 // The information we have is : 336 // - The GR (Series of registers) 337 // GR1=GP Global Pointer of frame ref by context 338 // - The instruction pointer 339 // - The instruction pointer info (???) 340 // - The CFA (Canonical Frame Address) 341 // - The BSP (Probably the base stack pointer) 342 343 344 // The current apprach uses one exception table entry per try block 345 _uleb128_t imatcher; 346 // Get the relative offset to the {...}? 347 cur_ptr = read_uleb128(cur_ptr, &imatcher); 348 349 # if defined( __x86_64 ) 350 _Unwind_Word match_pos = _Unwind_GetCFA(context) + 8; 351 # elif defined( __i386 ) 352 _Unwind_Word match_pos = _Unwind_GetCFA(context) + 24; 353 # endif 354 int (*matcher)(exception_t *) = *(int(**)(exception_t *))match_pos; 355 356 int index = matcher(shared_stack.current_exception); 357 _Unwind_Reason_Code ret = (0 == index) 358 ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND; 359 shared_stack.current_handler_index = index; 360 361 // Based on the return value, check if we matched the exception 362 if( ret == _URC_HANDLER_FOUND) { 363 __cfaabi_dbg_print_safe(" handler found\n"); 364 } else { 365 __cfaabi_dbg_print_safe(" no handler\n"); 366 } 367 return ret; 367 368 } 368 return ret; 369 370 // This is only a cleanup handler, ignore it 371 __cfaabi_dbg_print_safe(" no action"); 369 372 } 370 371 // This is only a cleanup handler, ignore it 372 __cfaabi_dbg_print_safe(" no action"); 373 } else if (actions & _UA_CLEANUP_PHASE) { 374 // In clean-up phase, no destructors here but this could be the handler. 375 376 if ( (callsite_action != 0) && !(actions & _UA_HANDLER_FRAME) ){ 377 // If this is a potential exception handler 378 // but not the one that matched the exception in the seach phase, 379 // just ignore it 380 goto UNWIND; 373 else if (actions & _UA_CLEANUP_PHASE) { 374 375 if( (callsite_action != 0) && !(actions & _UA_HANDLER_FRAME) ){ 376 // If this is a potential exception handler 377 // but not the one that matched the exception in the seach phase, 378 // just ignore it 379 goto UNWIND; 380 } 381 382 // We need to run some clean-up or a handler 383 // These statment do the right thing but I don't know any specifics at all 384 _Unwind_SetGR( context, __builtin_eh_return_data_regno(0), (_Unwind_Ptr) unwind_exception ); 385 _Unwind_SetGR( context, __builtin_eh_return_data_regno(1), 0 ); 386 387 // I assume this sets the instruction pointer to the adress of the landing pad 388 // It doesn't actually set it, it only state the value that needs to be set once we return _URC_INSTALL_CONTEXT 389 _Unwind_SetIP( context, ((lsd_info.LPStart) + (callsite_landing_pad)) ); 390 391 __cfaabi_dbg_print_safe(" action\n"); 392 393 // Return have some action to run 394 return _URC_INSTALL_CONTEXT; 381 395 } 382 383 // We need to run some clean-up or a handler384 // These statment do the right thing but I don't know any specifics at all385 _Unwind_SetGR( unwind_context, __builtin_eh_return_data_regno(0),386 (_Unwind_Ptr)unwind_exception );387 _Unwind_SetGR( unwind_context, __builtin_eh_return_data_regno(1), 0 );388 389 // I assume this sets the instruction pointer to the adress of the landing pad390 // It doesn't actually set it, it only state the value that needs to be set once we391 // return _URC_INSTALL_CONTEXT392 _Unwind_SetIP( unwind_context, ((lsd_info.LPStart) + (callsite_landing_pad)) );393 394 __cfaabi_dbg_print_safe(" action\n");395 396 // Return have some action to run397 return _URC_INSTALL_CONTEXT;398 396 } 397 398 // Nothing to do, move along 399 __cfaabi_dbg_print_safe(" no landing pad"); 399 400 } 400 401 // No handling found … … 420 421 //! printf("%p %p %p %p\n", &try_block, &catch_block, &match_block, &xy); 421 422 423 // Setup statments: These 2 statments won't actually result in any code, they only setup global tables. 424 // However, they clobber gcc cancellation support from gcc. We can replace the personality routine but 425 // replacing the exception table gcc generates is not really doable, it generates labels based on how the 426 // assembly works. 427 422 428 // Setup the personality routine and exception table. 423 // Unforturnately these clobber gcc cancellation support which means we can't get access to424 // the attribute cleanup tables at the same time. We would have to inspect the assembly to425 // create a new set ourselves.426 429 #ifdef __PIC__ 427 430 asm volatile (".cfi_personality 0x9b,CFA.ref.__gcfa_personality_v0"); … … 448 451 // Label which defines the end of the area for which the handler is setup. 449 452 asm volatile (".TRYEND:"); 450 // Label which defines the start of the exception landing pad. Basically what is called when451 // the exception is caught. Note, if multiple handlers are given, the multiplexing should be452 // done by the generated code, not theexception runtime.453 // Label which defines the start of the exception landing pad. Basically what is called when the exception is 454 // caught. Note, if multiple handlers are given, the multiplexing should be done by the generated code, not the 455 // exception runtime. 453 456 asm volatile (".CATCH:"); 454 457 455 458 // Exception handler 456 // Note: Saving the exception context on the stack breaks termination exceptions. 457 catch_block( this_exception_context()->current_handler_index, 458 this_exception_context()->current_exception ); 459 catch_block( shared_stack.current_handler_index, 460 shared_stack.current_exception ); 459 461 } 460 462
Note:
See TracChangeset
for help on using the changeset viewer.