Changes in / [136f86b:68887f9]
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/exception.c
r136f86b r68887f9 58 58 exception_t * current_exception; 59 59 int current_handler_index; 60 } s hared_stack = {NULL, NULL, 0, 0};60 } static shared_stack = {NULL, NULL, NULL, 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 //}73 68 74 69 … … 76 71 77 72 void __cfaabi_ehm__throw_resume(exception_t * except) { 73 struct exception_context_t * context = this_exception_context(); 78 74 79 75 __cfaabi_dbg_print_safe("Throwing resumption exception\n"); 80 76 81 struct __cfaabi_ehm__try_resume_node * original_head = shared_stack.current_resume;77 struct __cfaabi_ehm__try_resume_node * original_head = context->current_resume; 82 78 struct __cfaabi_ehm__try_resume_node * current = 83 (original_head) ? original_head->next : shared_stack.top_resume;79 (original_head) ? original_head->next : context->top_resume; 84 80 85 81 for ( ; current ; current = current->next) { 86 shared_stack.current_resume = current;82 context->current_resume = current; 87 83 if (current->handler(except)) { 88 shared_stack.current_resume = original_head;84 context->current_resume = original_head; 89 85 return; 90 86 } … … 92 88 93 89 __cfaabi_dbg_print_safe("Unhandled exception\n"); 94 shared_stack.current_resume = original_head;90 context->current_resume = original_head; 95 91 96 92 // Fall back to termination: … … 105 101 void __cfaabi_ehm__try_resume_setup(struct __cfaabi_ehm__try_resume_node * node, 106 102 _Bool (*handler)(exception_t * except)) { 107 node->next = shared_stack.top_resume; 103 struct exception_context_t * context = this_exception_context(); 104 node->next = context->top_resume; 108 105 node->handler = handler; 109 shared_stack.top_resume = node;106 context->top_resume = node; 110 107 } 111 108 112 109 void __cfaabi_ehm__try_resume_cleanup(struct __cfaabi_ehm__try_resume_node * node) { 113 shared_stack.top_resume = node->next; 110 struct exception_context_t * context = this_exception_context(); 111 context->top_resume = node->next; 114 112 } 115 113 … … 164 162 node = EXCEPT_TO_NODE(context->current_exception); 165 163 // It may always be in the first or second position. 166 while ( to_free != node->next ) {164 while ( to_free != node->next ) { 167 165 node = node->next; 168 166 } … … 191 189 _Unwind_Exception_Class exceptionClass, 192 190 struct _Unwind_Exception * unwind_exception, 193 struct _Unwind_Context * context,194 void * s ome_param) {195 if ( actions & _UA_END_OF_STACK ) exit(1);196 if ( actions & _UA_CLEANUP_PHASE ) return _URC_NO_REASON;191 struct _Unwind_Context * unwind_context, 192 void * stop_param) { 193 if ( actions & _UA_END_OF_STACK ) exit(1); 194 if ( actions & _UA_CLEANUP_PHASE ) return _URC_NO_REASON; 197 195 198 196 return _URC_FATAL_PHASE2_ERROR; … … 217 215 // the whole stack. 218 216 219 if ( ret == _URC_END_OF_STACK ) {217 if ( ret == _URC_END_OF_STACK ) { 220 218 // No proper handler was found. This can be handled in many ways, C++ calls std::terminate. 221 219 // Here we force unwind the stack, basically raising a cancellation. … … 251 249 int version, _Unwind_Action actions, unsigned long long exceptionClass, 252 250 struct _Unwind_Exception* unwind_exception, 253 struct _Unwind_Context* context)251 struct _Unwind_Context* unwind_context) 254 252 { 255 253 256 254 //__cfaabi_dbg_print_safe("CFA: 0x%lx\n", _Unwind_GetCFA(context)); 257 255 __cfaabi_dbg_print_safe("Personality function (%d, %x, %llu, %p, %p):", 258 version, actions, exceptionClass, unwind_exception, context);256 version, actions, exceptionClass, unwind_exception, unwind_context); 259 257 260 258 // If we've reached the end of the stack then there is nothing much we can do... 261 if ( actions & _UA_END_OF_STACK) return _URC_END_OF_STACK;259 if (actions & _UA_END_OF_STACK) return _URC_END_OF_STACK; 262 260 263 261 if (actions & _UA_SEARCH_PHASE) { … … 274 272 275 273 // Get a pointer to the language specific data from which we will read what we need 276 const unsigned char * lsd = (const unsigned char*) _Unwind_GetLanguageSpecificData(context );277 278 if ( !lsd ) { //Nothing to do, keep unwinding274 const unsigned char * lsd = _Unwind_GetLanguageSpecificData( unwind_context ); 275 276 if ( !lsd ) { //Nothing to do, keep unwinding 279 277 printf(" no LSD"); 280 278 goto UNWIND; … … 283 281 // Get the instuction pointer and a reading pointer into the exception table 284 282 lsda_header_info lsd_info; 285 const unsigned char * cur_ptr = parse_lsda_header(context, lsd, &lsd_info); 286 _Unwind_Ptr instruction_ptr = _Unwind_GetIP( context ); 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(); 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 // 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; 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"); 368 367 } 369 370 // This is only a cleanup handler, ignore it 371 __cfaabi_dbg_print_safe(" no action"); 368 return ret; 372 369 } 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; 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; 395 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( 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 pad 390 // It doesn't actually set it, it only state the value that needs to be set once we 391 // return _URC_INSTALL_CONTEXT 392 _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 run 397 return _URC_INSTALL_CONTEXT; 396 398 } 397 398 // Nothing to do, move along399 __cfaabi_dbg_print_safe(" no landing pad");400 399 } 401 400 // No handling found … … 421 420 //! printf("%p %p %p %p\n", &try_block, &catch_block, &match_block, &xy); 422 421 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 but425 // replacing the exception table gcc generates is not really doable, it generates labels based on how the426 // assembly works.427 428 422 // Setup the personality routine and exception table. 423 // Unforturnately these clobber gcc cancellation support which means we can't get access to 424 // the attribute cleanup tables at the same time. We would have to inspect the assembly to 425 // create a new set ourselves. 429 426 #ifdef __PIC__ 430 427 asm volatile (".cfi_personality 0x9b,CFA.ref.__gcfa_personality_v0"); … … 451 448 // Label which defines the end of the area for which the handler is setup. 452 449 asm volatile (".TRYEND:"); 453 // Label which defines the start of the exception landing pad. Basically what is called when the exception is454 // caught. Note, if multiple handlers are given, the multiplexing should be done by the generated code, not the455 // exception runtime.450 // Label which defines the start of the exception landing pad. Basically what is called when 451 // the exception is caught. Note, if multiple handlers are given, the multiplexing should be 452 // done by the generated code, not the exception runtime. 456 453 asm volatile (".CATCH:"); 457 454 458 455 // Exception handler 459 catch_block( shared_stack.current_handler_index, 460 shared_stack.current_exception ); 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 ); 461 459 } 462 460
Note: See TracChangeset
for help on using the changeset viewer.