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