Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(106)

Side by Side Diff: libstdc++-v3/libsupc++/eh_pnacl.cc

Issue 27341005: libstdc++: Add support for exception handling using the PNaClSjLjEH LLVM pass (Closed) Base URL: http://git.chromium.org/native_client/pnacl-gcc.git@pnacl
Patch Set: Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « libstdc++-v3/libsupc++/Makefile.in ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1
2 #include <setjmp.h>
3 #include <stdint.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include <typeinfo>
9
10 #include "unwind-cxx.h"
11
12
13 using namespace __cxxabiv1;
14
15 struct exc_result {
16 void *exc;
17 uint32_t exc_type_id;
18 };
19
20 struct unwind_frame {
21 union {
22 jmp_buf jmpbuf;
23 struct exc_result result;
24 };
25 struct unwind_frame *next;
26 uint32_t action_id;
27 };
28
29 struct action_table_entry {
30 int32_t type_filter_id;
31 uint32_t next_action_id;
32 };
33
34 extern std::type_info *const __pnacl_eh_type_table[];
35 extern const struct action_table_entry __pnacl_eh_action_table[];
36 extern const uint32_t __pnacl_eh_filter_table[];
37
38 __thread struct unwind_frame *__pnacl_eh_stack;
39
40
41 static bool get_adjusted_ptr (const std::type_info *catch_type,
42 const std::type_info *throw_type,
43 void **thrown_ptr_p) {
44 if (catch_type == NULL)
45 return true;
46
47 void *thrown_ptr = *thrown_ptr_p;
48
49 // Pointer types need to adjust the actual pointer, not
50 // the pointer to pointer that is the exception object.
51 // This also has the effect of passing pointer types
52 // "by value" through the __cxa_begin_catch return value.
53 if (throw_type->__is_pointer_p ())
54 thrown_ptr = *(void **) thrown_ptr;
55
56 if (catch_type->__do_catch (throw_type, &thrown_ptr, 1)) {
57 *thrown_ptr_p = thrown_ptr;
58 return true;
59 }
60 return false;
61 }
62
63 static int check_exception_spec(const std::type_info *throw_type, void *obj,
64 int32_t filter_id) {
65 const uint32_t *filter_ptr =
66 &__pnacl_eh_filter_table[-filter_id - 1];
67 for (; *filter_ptr != -1; ++filter_ptr) {
68 std::type_info *catch_type = __pnacl_eh_type_table[*filter_ptr];
69 // If any type matches, the overall filter doesn't trigger.
70 // We ignore the modified value of obj.
71 if (get_adjusted_ptr(catch_type, throw_type, &obj))
72 return 1;
73 }
74 // No type matched, so we have an exception specification error.
75 return 0;
76 }
77
78 static int filter_matches(std::type_info *throw_type, void **obj,
79 int32_t filter_id) {
80 if (filter_id < 0)
81 return !check_exception_spec(throw_type, obj, filter_id);
82
83 std::type_info *catch_type = __pnacl_eh_type_table[filter_id];
84 printf(" exception id: type_id=%i -> %p (%s)\n",
85 filter_id, catch_type,
86 catch_type ? catch_type->name() : "catch-all");
87 if (get_adjusted_ptr(catch_type, throw_type, obj)) {
88 printf(" match found (%s match)\n",
89 throw_type == catch_type ? "exact" : "subtype");
90 return 1;
91 } else {
92 return 0;
93 }
94 }
95
96 static void find_match(std::type_info *throw_type, void **obj,
97 struct unwind_frame **result_frame,
98 int *result_filter_id) {
99 while (__pnacl_eh_stack != NULL) {
100 struct unwind_frame *frame = __pnacl_eh_stack;
101 __pnacl_eh_stack = frame->next;
102
103 for (uint32_t action_id = frame->action_id; action_id != 0; ) {
104 const struct action_table_entry *action =
105 &__pnacl_eh_action_table[action_id - 1];
106 if (filter_matches(throw_type, obj, action->type_filter_id)) {
107 // Match found.
108 *result_frame = frame;
109 *result_filter_id = action->type_filter_id;
110 return;
111 }
112 action_id = action->next_action_id;
113 }
114 printf(" no match: trying next frame\n");
115 }
116
117 printf("no match\n");
118 abort();
119 }
120
121 __attribute__((noreturn))
122 static void do_return(struct unwind_frame *frame,
123 void *ue_header, int filter_id) {
124 // We reuse the storage of jmpbuf for the landingpad data, so
125 // save a copy of jmpbuf.
126 jmp_buf jmpbuf_copy;
127 memcpy(&jmpbuf_copy, &frame->jmpbuf, sizeof(jmpbuf_copy));
128
129 frame->result.exc = ue_header;
130 frame->result.exc_type_id = filter_id;
131 longjmp(jmpbuf_copy, 1);
132 abort();
133 }
134
135 static void do_unwinding(struct _Unwind_Exception *ue_header) {
136 __cxa_exception *xh = __get_exception_header_from_ue(ue_header);
137 printf(" thrown type: %p (%s)\n",
138 xh->exceptionType, xh->exceptionType->name());
139
140 void *obj = __get_object_from_ue(ue_header);
141 std::type_info *throw_type = xh->exceptionType;
142
143 struct unwind_frame *frame;
144 int filter_id;
145 find_match(throw_type, &obj, &frame, &filter_id);
146
147 xh->adjustedPtr = obj;
148 xh->handlerSwitchValue = filter_id;
149
150 do_return(frame, ue_header, filter_id);
151 }
152
153 extern "C" _Unwind_Reason_Code
154 __pnacl_eh_sjlj_Unwind_RaiseException(struct _Unwind_Exception *ue_header) {
155 printf("_Unwind_RaiseException: %p\n", ue_header);
156
157 do_unwinding(ue_header);
158 abort();
159 }
160
161 extern "C" void __pnacl_eh_resume(struct _Unwind_Exception *ue_header) {
162 printf("__pnacl_eh_resume() called\n");
163 do_unwinding(ue_header);
164 }
165
166 extern "C" _Unwind_Reason_Code
167 _Unwind_Resume_or_Rethrow(struct _Unwind_Exception *ue_header) {
168 printf("_Unwind_Resume_or_Rethrow: %p\n", ue_header);
169 return _Unwind_RaiseException(ue_header);
170 }
171
172 extern "C" void
173 _Unwind_DeleteException (struct _Unwind_Exception *exc)
174 {
175 if (exc->exception_cleanup)
176 (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc);
177 }
178
179 extern "C" void __pnacl_eh_sjlj_cxa_call_unexpected(_Unwind_Exception *ue_header ) {
180 __cxa_exception *xh = __get_exception_header_from_ue(ue_header);
181 int xh_switch_value = xh->handlerSwitchValue;
182 std::terminate_handler xh_terminate_handler = xh->terminateHandler;
183
184 __cxa_begin_catch(ue_header);
185
186 // This function is a handler for our exception argument. If we exit
187 // by throwing a different exception, we'll need the original cleaned up.
188 struct end_catch_protect
189 {
190 end_catch_protect() { }
191 ~end_catch_protect() { __cxa_end_catch(); }
192 } end_catch_protect_obj;
193
194 // We use the handler function that was cached by __cxa_throw().
195 // libstdc++'s unwind-cxx.h says this is cached because "The C++
196 // standard has entertaining rules wrt calling set_terminate and
197 // set_unexpected in the middle of the exception cleanup process."
198 printf(" calling 'unexpected' handler\n");
199 try {
200 xh->unexpectedHandler();
201 } catch (...) {
202 printf(" 'unexpected' handler threw\n");
203 __cxa_eh_globals *globals = __cxa_get_globals_fast ();
204 __cxa_exception *new_xh = globals->caughtExceptions;
205 void *new_ptr = __get_object_from_ambiguous_exception (new_xh);
206
207 // If this new exception meets the exception spec, allow it.
208 if (check_exception_spec(
209 __get_exception_header_from_obj(new_ptr)->exceptionType,
210 new_ptr, xh_switch_value)) {
211 throw;
212 }
213
214 // If the exception spec allows std::bad_exception, throw that.
215 // We don't have a thrown object to compare against, but since
216 // bad_exception doesn't have virtual bases, that's OK; just pass 0.
217 const std::type_info *bad_exc = &typeid(std::bad_exception);
218 if (check_exception_spec(bad_exc, NULL, xh_switch_value))
219 throw std::bad_exception();
220
221 __terminate (xh_terminate_handler);
222 }
223 printf(" 'unexpected' handler returned\n");
224 std::terminate();
225 }
OLDNEW
« no previous file with comments | « libstdc++-v3/libsupc++/Makefile.in ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698