]>
Commit | Line | Data |
---|---|---|
ee9dd372 TT |
1 | // Functions for Exception Support for Java. |
2 | ||
52a11cbf | 3 | /* Copyright (C) 1998, 1999, 2001 Free Software Foundation |
ee9dd372 TT |
4 | |
5 | This file is part of libgcj. | |
6 | ||
7 | This software is copyrighted work licensed under the terms of the | |
8 | Libgcj License. Please consult the file "LIBGCJ_LICENSE" for | |
9 | details. */ | |
10 | ||
11 | #include <config.h> | |
12 | ||
ee9dd372 | 13 | #include <stddef.h> |
9b8c19b4 | 14 | #include <cstdlib> |
ee9dd372 TT |
15 | |
16 | #include <java/lang/Class.h> | |
17 | #include <java/lang/NullPointerException.h> | |
27e934d8 | 18 | #include <gcj/cni.h> |
ee9dd372 TT |
19 | #include <jvm.h> |
20 | ||
52a11cbf | 21 | #include "unwind.h" |
ee9dd372 | 22 | |
1f4eb17d | 23 | #include <gc.h> |
ee9dd372 | 24 | |
52a11cbf RH |
25 | \f |
26 | struct alignment_test_struct | |
27 | { | |
28 | char space; | |
29 | char end[0] __attribute__((aligned)); | |
30 | }; | |
ee9dd372 | 31 | |
52a11cbf | 32 | struct java_exception_header |
ee9dd372 | 33 | { |
52a11cbf RH |
34 | /* Cache handler details between Phase 1 and Phase 2. */ |
35 | _Unwind_Ptr landingPad; | |
36 | int handlerSwitchValue; | |
ee9dd372 | 37 | |
52a11cbf RH |
38 | /* The object being thrown. Compiled code expects this to be immediately |
39 | before the generic exception header. Which is complicated by the fact | |
40 | that _Unwind_Exception is ((aligned)). */ | |
41 | ||
42 | char pad[sizeof(jthrowable) < sizeof(alignment_test_struct) | |
43 | ? sizeof(alignment_test_struct) - sizeof(jthrowable) : 0] | |
44 | __attribute__((aligned)); | |
45 | ||
46 | jthrowable value; | |
ee9dd372 | 47 | |
52a11cbf RH |
48 | /* The generic exception header. */ |
49 | _Unwind_Exception unwindHeader; | |
50 | }; | |
51 | ||
52 | // This is the exception class we report -- "GNUCJAVA". | |
53 | const _Unwind_Exception_Class __gcj_exception_class | |
54 | = ((((((((_Unwind_Exception_Class) 'G' | |
55 | << 8 | (_Unwind_Exception_Class) 'N') | |
56 | << 8 | (_Unwind_Exception_Class) 'U') | |
57 | << 8 | (_Unwind_Exception_Class) 'C') | |
58 | << 8 | (_Unwind_Exception_Class) 'J') | |
59 | << 8 | (_Unwind_Exception_Class) 'A') | |
60 | << 8 | (_Unwind_Exception_Class) 'V') | |
61 | << 8 | (_Unwind_Exception_Class) 'A'); | |
62 | ||
63 | ||
64 | static inline java_exception_header * | |
65 | get_exception_header_from_ue (_Unwind_Exception *exc) | |
66 | { | |
67 | return reinterpret_cast<java_exception_header *>(exc + 1) - 1; | |
ee9dd372 TT |
68 | } |
69 | ||
52a11cbf RH |
70 | /* Perform a throw, Java style. Throw will unwind through this call, |
71 | so there better not be any handlers or exception thrown here. */ | |
ee9dd372 | 72 | |
52a11cbf RH |
73 | extern "C" void |
74 | _Jv_Throw (jthrowable value) | |
ee9dd372 | 75 | { |
52a11cbf RH |
76 | /* FIXME: Use the proper API to the collector. */ |
77 | java_exception_header *xh | |
78 | = static_cast<java_exception_header *>(GC_malloc (sizeof (*xh))); | |
79 | ||
80 | if (value == NULL) | |
81 | value = new java::lang::NullPointerException (); | |
82 | xh->value = value; | |
ee9dd372 | 83 | |
52a11cbf RH |
84 | xh->unwindHeader.exception_class = __gcj_exception_class; |
85 | xh->unwindHeader.exception_cleanup = NULL; | |
ee9dd372 | 86 | |
52a11cbf RH |
87 | /* We're happy with setjmp/longjmp exceptions or region-based |
88 | exception handlers: entry points are provided here for both. */ | |
89 | _Unwind_Reason_Code code; | |
90 | #ifdef SJLJ_EXCEPTIONS | |
91 | code = _Unwind_SjLj_RaiseException (&xh->unwindHeader); | |
92 | #else | |
93 | code = _Unwind_RaiseException (&xh->unwindHeader); | |
94 | #endif | |
ee9dd372 | 95 | |
212a2676 RH |
96 | /* If code == _URC_END_OF_STACK, then we reached top of stack without |
97 | finding a handler for the exception. Since each thread is run in | |
98 | a try/catch, this oughtn't happen. If code is something else, we | |
99 | encountered some sort of heinous lossage from which we could not | |
100 | recover. As is the way of such things, almost certainly we will have | |
101 | crashed before now, rather than actually being able to diagnose the | |
102 | problem. */ | |
9b8c19b4 | 103 | std::abort (); |
ee9dd372 TT |
104 | } |
105 | ||
52a11cbf | 106 | \f |
5f2fa730 | 107 | #include "unwind-pe.h" |
52a11cbf RH |
108 | \f |
109 | struct lsda_header_info | |
110 | { | |
111 | _Unwind_Ptr Start; | |
112 | _Unwind_Ptr LPStart; | |
113 | const unsigned char *TType; | |
114 | const unsigned char *action_table; | |
115 | unsigned char ttype_encoding; | |
116 | unsigned char call_site_encoding; | |
117 | }; | |
118 | ||
119 | static const unsigned char * | |
120 | parse_lsda_header (_Unwind_Context *context, const unsigned char *p, | |
121 | lsda_header_info *info) | |
122 | { | |
123 | _Unwind_Ptr tmp; | |
124 | unsigned char lpstart_encoding; | |
125 | ||
126 | info->Start = (context ? _Unwind_GetRegionStart (context) : 0); | |
ee9dd372 | 127 | |
52a11cbf RH |
128 | // Find @LPStart, the base to which landing pad offsets are relative. |
129 | lpstart_encoding = *p++; | |
130 | if (lpstart_encoding != DW_EH_PE_omit) | |
131 | p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart); | |
132 | else | |
133 | info->LPStart = info->Start; | |
134 | ||
135 | // Find @TType, the base of the handler and exception spec type data. | |
136 | info->ttype_encoding = *p++; | |
137 | if (info->ttype_encoding != DW_EH_PE_omit) | |
138 | { | |
139 | p = read_uleb128 (p, &tmp); | |
140 | info->TType = p + tmp; | |
141 | } | |
142 | else | |
143 | info->TType = 0; | |
144 | ||
145 | // The encoding and length of the call-site table; the action table | |
146 | // immediately follows. | |
147 | info->call_site_encoding = *p++; | |
148 | p = read_uleb128 (p, &tmp); | |
149 | info->action_table = p + tmp; | |
150 | ||
151 | return p; | |
152 | } | |
153 | ||
154 | static jclass | |
155 | get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i) | |
ee9dd372 | 156 | { |
52a11cbf RH |
157 | _Unwind_Ptr ptr; |
158 | ||
159 | i *= size_of_encoded_value (info->ttype_encoding); | |
160 | read_encoded_value (context, info->ttype_encoding, info->TType - i, &ptr); | |
161 | ||
162 | return reinterpret_cast<jclass>(ptr); | |
ee9dd372 TT |
163 | } |
164 | ||
3cf88fb4 | 165 | |
52a11cbf RH |
166 | // Using a different personality function name causes link failures |
167 | // when trying to mix code using different exception handling models. | |
b3208f56 | 168 | #ifdef SJLJ_EXCEPTIONS |
52a11cbf RH |
169 | #define PERSONALITY_FUNCTION __gcj_personality_sj0 |
170 | #define __builtin_eh_return_data_regno(x) x | |
171 | #else | |
172 | #define PERSONALITY_FUNCTION __gcj_personality_v0 | |
b3208f56 RH |
173 | #endif |
174 | ||
52a11cbf RH |
175 | extern "C" _Unwind_Reason_Code |
176 | PERSONALITY_FUNCTION (int version, | |
177 | _Unwind_Action actions, | |
178 | _Unwind_Exception_Class exception_class, | |
179 | struct _Unwind_Exception *ue_header, | |
180 | struct _Unwind_Context *context) | |
ee9dd372 | 181 | { |
52a11cbf RH |
182 | java_exception_header *xh = get_exception_header_from_ue (ue_header); |
183 | ||
184 | lsda_header_info info; | |
185 | const unsigned char *language_specific_data; | |
186 | const unsigned char *action_record; | |
187 | const unsigned char *p; | |
188 | _Unwind_Ptr landing_pad, ip; | |
189 | int handler_switch_value; | |
190 | bool saw_cleanup; | |
191 | bool saw_handler; | |
192 | ||
193 | ||
194 | // Interface version check. | |
195 | if (version != 1) | |
196 | return _URC_FATAL_PHASE1_ERROR; | |
197 | ||
198 | // Shortcut for phase 2 found handler for domestic exception. | |
199 | if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME) | |
200 | && exception_class == __gcj_exception_class) | |
ee9dd372 | 201 | { |
52a11cbf RH |
202 | handler_switch_value = xh->handlerSwitchValue; |
203 | landing_pad = xh->landingPad; | |
204 | goto install_context; | |
ee9dd372 | 205 | } |
3cf88fb4 | 206 | |
52a11cbf RH |
207 | // FIXME: In Phase 1, record _Unwind_GetIP in xh->obj as a part of |
208 | // the stack trace for this exception. This will only collect Java | |
209 | // frames, but perhaps that is acceptable. | |
210 | // FIXME2: _Unwind_GetIP is nonsensical for SJLJ, being a call-site | |
211 | // index instead of a PC value. We could perhaps arrange for | |
212 | // _Unwind_GetRegionStart to return context->fc->jbuf[1], which | |
213 | // is the address of the handler label for __builtin_longjmp, but | |
214 | // there is no solution for DONT_USE_BUILTIN_SETJMP. | |
215 | ||
216 | language_specific_data = (const unsigned char *) | |
217 | _Unwind_GetLanguageSpecificData (context); | |
218 | ||
219 | // If no LSDA, then there are no handlers or cleanups. | |
220 | if (! language_specific_data) | |
221 | return _URC_CONTINUE_UNWIND; | |
222 | ||
223 | // Parse the LSDA header. | |
224 | p = parse_lsda_header (context, language_specific_data, &info); | |
225 | ip = _Unwind_GetIP (context) - 1; | |
226 | landing_pad = 0; | |
227 | action_record = 0; | |
228 | handler_switch_value = 0; | |
229 | ||
3cf88fb4 | 230 | #ifdef SJLJ_EXCEPTIONS |
52a11cbf RH |
231 | // The given "IP" is an index into the call-site table, with two |
232 | // exceptions -- -1 means no-action, and 0 means terminate. But | |
233 | // since we're using uleb128 values, we've not got random access | |
234 | // to the array. | |
235 | if ((int) ip <= 0) | |
236 | return _URC_CONTINUE_UNWIND; | |
237 | else | |
238 | { | |
239 | _Unwind_Ptr cs_lp, cs_action; | |
240 | do | |
241 | { | |
242 | p = read_uleb128 (p, &cs_lp); | |
243 | p = read_uleb128 (p, &cs_action); | |
244 | } | |
245 | while (--ip); | |
246 | ||
247 | // Can never have null landing pad for sjlj -- that would have | |
248 | // been indicated by a -1 call site index. | |
249 | landing_pad = cs_lp + 1; | |
250 | if (cs_action) | |
251 | action_record = info.action_table + cs_action - 1; | |
252 | goto found_something; | |
253 | } | |
3cf88fb4 | 254 | #else |
52a11cbf RH |
255 | // Search the call-site table for the action associated with this IP. |
256 | while (p < info.action_table) | |
257 | { | |
258 | _Unwind_Ptr cs_start, cs_len, cs_lp, cs_action; | |
259 | ||
260 | // Note that all call-site encodings are "absolute" displacements. | |
261 | p = read_encoded_value (0, info.call_site_encoding, p, &cs_start); | |
262 | p = read_encoded_value (0, info.call_site_encoding, p, &cs_len); | |
263 | p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp); | |
264 | p = read_uleb128 (p, &cs_action); | |
265 | ||
266 | // The table is sorted, so if we've passed the ip, stop. | |
267 | if (ip < info.Start + cs_start) | |
268 | p = info.action_table; | |
269 | else if (ip < info.Start + cs_start + cs_len) | |
270 | { | |
271 | if (cs_lp) | |
272 | landing_pad = info.LPStart + cs_lp; | |
273 | if (cs_action) | |
274 | action_record = info.action_table + cs_action - 1; | |
275 | goto found_something; | |
276 | } | |
277 | } | |
278 | #endif // SJLJ_EXCEPTIONS | |
878885b4 | 279 | |
52a11cbf RH |
280 | // If ip is not present in the table, C++ would call terminate. |
281 | // ??? It is perhaps better to tweek the LSDA so that no-action | |
282 | // is mapped to no-entry for Java. | |
283 | return _URC_CONTINUE_UNWIND; | |
878885b4 | 284 | |
52a11cbf RH |
285 | found_something: |
286 | saw_cleanup = false; | |
287 | saw_handler = false; | |
878885b4 | 288 | |
52a11cbf | 289 | if (landing_pad == 0) |
878885b4 | 290 | { |
52a11cbf RH |
291 | // If ip is present, and has a null landing pad, there are |
292 | // no cleanups or handlers to be run. | |
293 | } | |
294 | else if (action_record == 0) | |
295 | { | |
296 | // If ip is present, has a non-null landing pad, and a null | |
297 | // action table offset, then there are only cleanups present. | |
298 | // Cleanups use a zero switch value, as set above. | |
299 | saw_cleanup = true; | |
300 | } | |
301 | else | |
302 | { | |
303 | // Otherwise we have a catch handler. | |
304 | signed long ar_filter, ar_disp; | |
305 | ||
306 | while (1) | |
307 | { | |
308 | _Unwind_Ptr tmp; | |
309 | ||
310 | p = action_record; | |
311 | p = read_sleb128 (p, &tmp); ar_filter = tmp; | |
312 | read_sleb128 (p, &tmp); ar_disp = tmp; | |
313 | ||
314 | if (ar_filter == 0) | |
315 | { | |
316 | // Zero filter values are cleanups. | |
317 | saw_cleanup = true; | |
318 | } | |
319 | ||
320 | // During forced unwinding, we only run cleanups. With a | |
321 | // foreign exception class, we have no class info to match. | |
322 | else if ((actions & _UA_FORCE_UNWIND) | |
323 | || exception_class != __gcj_exception_class) | |
324 | ; | |
325 | ||
326 | else if (ar_filter > 0) | |
327 | { | |
328 | // Positive filter values are handlers. | |
329 | ||
330 | jclass catch_type = get_ttype_entry (context, &info, ar_filter); | |
331 | ||
332 | // The catch_type is either a (java::lang::Class*) or | |
333 | // is one more than a (Utf8Const*). | |
334 | if ((size_t)catch_type & 1) | |
335 | catch_type = _Jv_FindClass ((Utf8Const*)catch_type - 1, NULL); | |
336 | ||
337 | if (_Jv_IsInstanceOf (xh->value, catch_type)) | |
338 | { | |
339 | handler_switch_value = ar_filter; | |
340 | saw_handler = true; | |
341 | break; | |
342 | } | |
343 | } | |
344 | else | |
345 | { | |
346 | // Negative filter values are exception specifications, | |
347 | // which Java does not use. | |
348 | // ??? Perhaps better to make them an index into a table | |
349 | // of null-terminated strings instead of playing games | |
350 | // with Utf8Const+1 as above. | |
9b8c19b4 | 351 | std::abort (); |
52a11cbf RH |
352 | } |
353 | ||
354 | if (ar_disp == 0) | |
355 | break; | |
356 | action_record = p + ar_disp; | |
357 | } | |
878885b4 | 358 | } |
878885b4 | 359 | |
52a11cbf RH |
360 | if (! saw_handler && ! saw_cleanup) |
361 | return _URC_CONTINUE_UNWIND; | |
878885b4 | 362 | |
52a11cbf RH |
363 | if (actions & _UA_SEARCH_PHASE) |
364 | { | |
365 | if (! saw_handler) | |
366 | return _URC_CONTINUE_UNWIND; | |
367 | ||
368 | // For domestic exceptions, we cache data from phase 1 for phase 2. | |
369 | if (exception_class == __gcj_exception_class) | |
370 | { | |
371 | xh->handlerSwitchValue = handler_switch_value; | |
372 | xh->landingPad = landing_pad; | |
373 | } | |
374 | return _URC_HANDLER_FOUND; | |
375 | } | |
878885b4 | 376 | |
52a11cbf RH |
377 | install_context: |
378 | _Unwind_SetGR (context, __builtin_eh_return_data_regno (0), | |
379 | (_Unwind_Ptr) &xh->unwindHeader); | |
380 | _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), | |
381 | handler_switch_value); | |
382 | _Unwind_SetIP (context, landing_pad); | |
383 | return _URC_INSTALL_CONTEXT; | |
878885b4 | 384 | } |