Changeset e4e9173 for doc/working/exception/impl/exception.c
- Timestamp:
- Jun 13, 2017, 4:24:17 PM (7 years ago)
- 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
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/working/exception/impl/exception.c
r35dd0f42 re4e9173 22 22 23 23 void __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); 26 27 27 28 struct __try_resume_node * original_head = shared_stack.current_resume; … … 45 46 } 46 47 47 /* __try_resume_node functions:48 * Currently I was planning to generate this code inline, and even if I don't49 * 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 63 48 64 49 // TERMINATION =============================================================== 65 50 66 51 // 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 58 struct _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 62 static _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 76 void __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 } 67 274 68 275 // Try statements are hoisted out see comments for details … … 141 348 " .size __try_terminate, .-__try_terminate\n" 142 349 " .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" 144 351 ); 145 146 // Global which defines the current exception147 // Currently an int just to make matching easier148 int this_exception;149 150 // We need a piece of storage to raise the exception151 struct _Unwind_Exception this_exception_storage;152 153 // Function needed by force unwind154 // It basically says to unwind the whole stack and then exit when we reach the end of the stack155 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 routine169 void __throw_terminate( int val ) {170 // Store the current exception171 this_exception = val;172 173 // DEBUG174 printf("Throwing exception %d\n", this_exception);175 176 // Call stdlibc to raise the exception177 _Unwind_Reason_Code ret = _Unwind_RaiseException( &this_exception_storage );178 179 // If we reach here it means something happened180 // For resumption to work we need to find a way to return back to here181 // 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 always184 // search the whole stack185 186 if( ret == _URC_END_OF_STACK ) {187 // No proper handler was found188 // This can be handled in several way189 // C++ calls std::terminate190 // Here we force unwind the stack, basically raising a cancellation191 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 wrong200 printf("UNWIND ERROR %d after raise exception\n", ret);201 abort();202 }203 204 // This is our personality routine205 // For every stack frame anotated with ".cfi_personality 0x3,__gcfa_personality_v0"206 // This function will be called twice when unwinding207 // Once in the search phased and once in the cleanup phase208 _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 // DEBUG216 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 // DEBUG222 if (actions & _UA_SEARCH_PHASE) {223 printf(" lookup phase");224 }225 // DEBUG226 else if (actions & _UA_CLEANUP_PHASE) {227 printf(" cleanup phase");228 }229 // Just in case, probably can't actually happen230 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 need236 const unsigned char * lsd = (const unsigned char*) _Unwind_GetLanguageSpecificData( context );237 238 if( !lsd ) { //Nothing to do, keep unwinding239 printf(" no LSD");240 goto UNWIND;241 }242 243 // Get the instuction pointer and a reading pointer into the exception table244 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 do249 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 here256 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 BEGIN264 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 END272 continue;273 }274 275 // Have we gone too far276 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 in284 if (actions & _UA_SEARCH_PHASE) {285 // Search phase, this means we probably found a potential handler and must check if it is a match286 287 // If we have arbitrarily decided that 0 means nothing to do and 1 means there is a potential handler288 // This doesn't seem to conflict the gcc default behavior289 if (callsite_action != 0) {290 // Now we want to run some code to see if the handler matches291 // This is the tricky part where we want to the power to run arbitrary code292 // However, generating a new exception table entry and try routine every time293 // is way more expansive than we might like294 // The information we have is :295 // - The GR (Series of registers)296 // GR1=GP Global Pointer of frame ref by context297 // - The instruction pointer298 // - 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 block304 _uleb128_t imatcher;305 // Get the relative offset to the306 cur_ptr = read_uleb128 (cur_ptr, &imatcher);307 308 // Get a function pointer from the relative offset and call it309 // _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 exception320 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 it326 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 handler332 // but not the one that matched the exception in the seach phase,333 // just ignore it334 goto UNWIND;335 }336 337 // We need to run some clean-up or a handler338 // These statment do the right thing but I don't know any specifics at all339 _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 pad343 // It doesn't actually set it, it only state the value that needs to be set once we return _URC_INSTALL_CONTEXT344 _Unwind_SetIP( context, lsd_info.LPStart + callsite_landing_pad );345 346 // DEBUG347 printf(" action\n");348 349 // Return have some action to run350 return _URC_INSTALL_CONTEXT;351 }352 }353 354 // Nothing to do, move along355 printf(" no landing pad");356 }357 // No handling found358 printf(" table end reached\n");359 360 // DEBUG361 UNWIND:362 printf(" unwind\n");363 364 // Keep unwinding the stack365 return _URC_CONTINUE_UNWIND;366 }
Note: See TracChangeset
for help on using the changeset viewer.