source: doc/working/exception/impl/except.c@ a4683611

ADT aaron-thesis arm-eh ast-experimental cleanup-dtors deferred_resn demangler enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox new-ast new-ast-unique-expr new-env no_list persistent-indexer pthread-emulation qualifiedEnum resolv-new with_gc
Last change on this file since a4683611 was 4a58895, checked in by Andrew Beach <ajbeach@…>, 8 years ago

Added a proof of consept resumption exception handler. Has comparable speed to the existing termination handler under O2.

  • Property mode set to 100644
File size: 7.6 KB
RevLine 
[ae6f1ec]1#include <stdlib.h>
2#include <stdio.h>
3#include <unwind.h>
4
5#include "lsda.h"
6
7//Global which defines the current exception
8//Currently an int just to make matching easier
9int this_exception;
10
11//This is our personality routine
12//For every stack frame anotated with ".cfi_personality 0x3,__gcfa_personality_v0"
13//This function will be called twice when unwinding
14//Once in the search phased and once in the cleanup phase
15_Unwind_Reason_Code __gcfa_personality_v0 (
16 int version, _Unwind_Action actions, unsigned long long exceptionClass,
17 struct _Unwind_Exception* unwind_exception, struct _Unwind_Context* context)
18{
19 //DEBUG
20 printf("Personality function (%d, %x, %llu, %p, %p):", version, actions, exceptionClass, unwind_exception, context);
21
22 //If we've reached the end of the stack then there is nothing much we can do...
23 if( actions & _UA_END_OF_STACK ) return _URC_END_OF_STACK;
24
25 //DEBUG
26 if (actions & _UA_SEARCH_PHASE) {
27 printf(" lookup phase");
28 }
29 //DEBUG
30 else if (actions & _UA_CLEANUP_PHASE) {
31 printf(" cleanup phase");
32 }
33 //Just in case, probably can't actually happen
34 else {
35 printf(" error\n");
36 return _URC_FATAL_PHASE1_ERROR;
37 }
38
39 //Get a pointer to the language specific data from which we will read what we need
40 const unsigned char * lsd = (const unsigned char*) _Unwind_GetLanguageSpecificData( context );
41
42 if( !lsd ) { //Nothing to do, keep unwinding
43 printf(" no LSD");
44 goto UNWIND;
45 }
46
47 //Get the instuction pointer and a reading pointer into the exception table
48 lsda_header_info lsd_info;
49 const unsigned char * cur_ptr = parse_lsda_header( context, lsd, &lsd_info);
50 _Unwind_Ptr instruction_ptr = _Unwind_GetIP( context );
51
52 //Linearly search the table for stuff to do
53 while( cur_ptr < lsd_info.action_table ) {
54 _Unwind_Ptr callsite_start;
55 _Unwind_Ptr callsite_len;
56 _Unwind_Ptr callsite_landing_pad;
57 _uleb128_t callsite_action;
58
59 //Decode the common stuff we have in here
60 cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_start);
61 cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_len);
62 cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_landing_pad);
63 cur_ptr = read_uleb128 (cur_ptr, &callsite_action);
64
65 //Have we reach the correct frame info yet?
66 if( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) {
67 //DEBUG BEGIN
68 void * ls = (void*)lsd_info.Start;
69 void * cs = (void*)callsite_start;
70 void * cl = (void*)callsite_len;
71 void * bp = (void*)lsd_info.Start + callsite_start;
72 void * ep = (void*)lsd_info.Start + callsite_start + callsite_len;
73 void * ip = (void*)instruction_ptr;
74 printf("\nfound %p - %p (%p, %p, %p), looking for %p\n", bp, ep, ls, cs, cl, ip);
75 //DEBUG END
76 continue;
77 }
78
79 //Have we gone too far
80 if( lsd_info.Start + callsite_start > instruction_ptr ) {
81 printf(" gone too far");
82 break;
83 }
84
85 //Something to do?
86 if( callsite_landing_pad ) {
87 //Which phase are we in
88 if (actions & _UA_SEARCH_PHASE) {
89 //Search phase, this means we probably found a potential handler and must check if it is a match
90
91 //If we have arbitrarily decided that 0 means nothing to do and 1 means there is a potential handler
92 //This doesn't seem to conflict the gcc default behavior
93 if (callsite_action != 0) {
94 //Now we want to run some code to see if the handler matches
95 //This is the tricky part where we want to the power to run arbitrary code
96 //However, generating a new exception table entry and try routine every time
97 //is way more expansive than we might like
98 //The information we have is :
[4a58895]99 // - The GR (Series of registers)
100 // GR1=GP Global Pointer of frame ref by context
[ae6f1ec]101 // - The instruction pointer
102 // - The instruction pointer info (???)
[4a58895]103 // - The CFA (Canonical Frame Address)
[ae6f1ec]104 // - The BSP (Probably the base stack pointer)
105
106
107 //The current apprach uses one exception table entry per try block
108 _uleb128_t imatcher;
109 //Get the relative offset to the
110 cur_ptr = read_uleb128 (cur_ptr, &imatcher);
111
112 //Get a function pointer from the relative offset and call it
113 _Unwind_Reason_Code (*matcher)() = (_Unwind_Reason_Code (*)())lsd_info.LPStart + imatcher;
114 _Unwind_Reason_Code ret = matcher();
115
116 //Based on the return value, check if we matched the exception
117 if( ret == _URC_HANDLER_FOUND) printf(" handler found\n");
118 else printf(" no handler\n");
119 return ret;
120 }
121
122 //This is only a cleanup handler, ignore it
123 printf(" no action");
124 }
125 else if (actions & _UA_CLEANUP_PHASE) {
126
127 if( (callsite_action != 0) && !(actions & _UA_HANDLER_FRAME) ){
128 //If this is a potential exception handler
129 //but not the one that matched the exception in the seach phase,
130 //just ignore it
131 goto UNWIND;
132 }
133
134 //We need to run some clean-up or a handler
135 //These statment do the right thing but I don't know any specifics at all
136 _Unwind_SetGR( context, __builtin_eh_return_data_regno(0), (_Unwind_Ptr) unwind_exception );
137 _Unwind_SetGR( context, __builtin_eh_return_data_regno(1), 0 );
138
139 //I assume this sets the instruction pointer to the adress of the landing pad
140 //It doesn't actually set it, it only state the value that needs to be set once we return _URC_INSTALL_CONTEXT
141 _Unwind_SetIP( context, lsd_info.LPStart + callsite_landing_pad );
142
143 //DEBUG
144 printf(" action\n");
145
146 //Return have some action to run
147 return _URC_INSTALL_CONTEXT;
148 }
149 }
150
151 //Nothing to do, move along
152 printf(" no landing pad");
153 }
154 //No handling found
155 printf(" table end reached\n");
156
157 //DEBUG
158 UNWIND:
159 printf(" unwind\n");
160
161 //Keep unwinding the stack
162 return _URC_CONTINUE_UNWIND;
163}
164
165//We need a piece of storage to raise the exception
166struct _Unwind_Exception this_exception_storage;
167
168//Function needed by force unwind
169//It basically says to unwind the whole stack and then exit when we reach the end of the stack
170static _Unwind_Reason_Code _Stop_Fn(
171 int version,
172 _Unwind_Action actions,
173 _Unwind_Exception_Class exceptionClass,
174 struct _Unwind_Exception * unwind_exception,
175 struct _Unwind_Context * context,
176 void * some_param
177) {
178 if( actions & _UA_END_OF_STACK ) exit(1);
179 if( actions & _UA_CLEANUP_PHASE ) return _URC_NO_REASON;
180
181 return _URC_FATAL_PHASE2_ERROR;
182}
183
184//Example throw routine
185void throw( int val ) {
186 //Store the current exception
187 this_exception = val;
188
189 //DEBUG
190 printf("Throwing exception %d\n", this_exception);
191
192 //Call stdlibc to raise the exception
193 _Unwind_Reason_Code ret = _Unwind_RaiseException( &this_exception_storage );
194
195 //If we reach here it means something happened
196 //For resumption to work we need to find a way to return back to here
197 //Most of them will probably boil down to setting a global flag and making the phase 1 either stop or fail.
198 //Causing an error on purpose may help avoiding unnecessary work but it might have some weird side effects.
199 //If we just pretend no handler was found that would work but may be expensive for no reason since we will always
200 //search the whole stack
201
202 if( ret == _URC_END_OF_STACK ) {
203 //No proper handler was found
204 //This can be handled in several way
205 //C++ calls std::terminate
206 //Here we force unwind the stack, basically raising a cancellation
207 printf("Uncaught exception %p\n", &this_exception_storage);
208
209 ret = _Unwind_ForcedUnwind( &this_exception_storage, _Stop_Fn, (void*)0x22 );
210 printf("UNWIND ERROR %d after force unwind\n", ret);
211 abort();
212 }
213
214 //We did not simply reach the end of the stack without finding a handler,
215 //Something wen't wrong
216 printf("UNWIND ERROR %d after raise exception\n", ret);
217 abort();
[4a58895]218}
Note: See TracBrowser for help on using the repository browser.