OSDN Git Service

* unwind-dw2-fde-glibc.c (base_from_cb_data,
[pf3gnuchains/gcc-fork.git] / libjava / exception.cc
1 // Functions for Exception Support for Java.
2
3 /* Copyright (C) 1998, 1999, 2001, 2002  Free Software Foundation
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
13 #include <stddef.h>
14 #include <stdlib.h>
15
16 #include <java/lang/Class.h>
17 #include <java/lang/NullPointerException.h>
18 #include <gnu/gcj/RawData.h> 
19 #include <gcj/cni.h>
20 #include <jvm.h>
21
22 // Sometimes we compile libjava without libstdc++-v3. Therefore make
23 // sure we use stdlib.h's abort().
24 #define gcc_unreachable() ::abort ()
25 #include "unwind.h"
26
27 struct alignment_test_struct
28 {
29   char space;
30   char end[0] __attribute__((aligned));
31 };
32
33 struct java_exception_header
34 {
35   /* Cache handler details between Phase 1 and Phase 2.  */
36   _Unwind_Ptr landingPad;
37   int handlerSwitchValue;
38
39   /* The object being thrown.  Compiled code expects this to be immediately
40      before the generic exception header.  Which is complicated by the fact
41      that _Unwind_Exception is ((aligned)).  */
42
43   char pad[sizeof(jthrowable) < sizeof(alignment_test_struct)
44            ? sizeof(alignment_test_struct) - sizeof(jthrowable) : 0]
45     __attribute__((aligned));
46
47   jthrowable value;
48
49   /* The generic exception header.  */
50   _Unwind_Exception unwindHeader;
51 };
52
53 // This is the exception class we report -- "GNUCJAVA".
54 const _Unwind_Exception_Class __gcj_exception_class
55 = ((((((((_Unwind_Exception_Class) 'G' 
56          << 8 | (_Unwind_Exception_Class) 'N')
57         << 8 | (_Unwind_Exception_Class) 'U')
58        << 8 | (_Unwind_Exception_Class) 'C')
59       << 8 | (_Unwind_Exception_Class) 'J')
60      << 8 | (_Unwind_Exception_Class) 'A')
61     << 8 | (_Unwind_Exception_Class) 'V')
62    << 8 | (_Unwind_Exception_Class) 'A');
63
64
65 static inline java_exception_header *
66 get_exception_header_from_ue (_Unwind_Exception *exc)
67 {
68   return reinterpret_cast<java_exception_header *>(exc + 1) - 1;
69 }
70
71 /* Perform a throw, Java style. Throw will unwind through this call,
72    so there better not be any handlers or exception thrown here. */
73
74 extern "C" void
75 _Jv_Throw (jthrowable value)
76 {
77   java_exception_header *xh
78     = static_cast<java_exception_header *>(_Jv_AllocRawObj (sizeof (*xh)));
79
80   if (value == NULL)
81     value = new java::lang::NullPointerException ();
82   xh->value = value;
83
84   xh->unwindHeader.exception_class = __gcj_exception_class;
85   xh->unwindHeader.exception_cleanup = NULL;
86
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
95
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.  */
103   abort();
104 }
105
106 \f
107 #include "unwind-pe.h"
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_Word tmp;
124   unsigned char lpstart_encoding;
125
126   info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
127
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 void **
155 get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i)
156 {
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<void **>(ptr);
163 }
164
165
166 // Using a different personality function name causes link failures
167 // when trying to mix code using different exception handling models.
168 #ifdef SJLJ_EXCEPTIONS
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
173 #endif
174
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)
181 {
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)
201     {
202       handler_switch_value = xh->handlerSwitchValue;
203       landing_pad = xh->landingPad;
204       goto install_context;
205     }
206
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
230 #ifdef SJLJ_EXCEPTIONS
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_Word 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     }
254 #else
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;
259       _Unwind_Word cs_action;
260
261       // Note that all call-site encodings are "absolute" displacements.
262       p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
263       p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
264       p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
265       p = read_uleb128 (p, &cs_action);
266
267       // The table is sorted, so if we've passed the ip, stop.
268       if (ip < info.Start + cs_start)
269         p = info.action_table;
270       else if (ip < info.Start + cs_start + cs_len)
271         {
272           if (cs_lp)
273             landing_pad = info.LPStart + cs_lp;
274           if (cs_action)
275             action_record = info.action_table + cs_action - 1;
276           goto found_something;
277         }
278     }
279 #endif // SJLJ_EXCEPTIONS
280
281   // If ip is not present in the table, C++ would call terminate.
282   // ??? It is perhaps better to tweek the LSDA so that no-action
283   // is mapped to no-entry for Java.
284   return _URC_CONTINUE_UNWIND;
285
286  found_something:
287   saw_cleanup = false;
288   saw_handler = false;
289
290   if (landing_pad == 0)
291     {
292       // If ip is present, and has a null landing pad, there are
293       // no cleanups or handlers to be run.
294     }
295   else if (action_record == 0)
296     {
297       // If ip is present, has a non-null landing pad, and a null
298       // action table offset, then there are only cleanups present.
299       // Cleanups use a zero switch value, as set above.
300       saw_cleanup = true;
301     }
302   else
303     {
304       // Otherwise we have a catch handler.
305       _Unwind_Sword ar_filter, ar_disp;
306
307       while (1)
308         {
309           p = action_record;
310           p = read_sleb128 (p, &ar_filter);
311           read_sleb128 (p, &ar_disp);
312
313           if (ar_filter == 0)
314             {
315               // Zero filter values are cleanups.
316               saw_cleanup = true;
317             }
318
319           // During forced unwinding, we only run cleanups.  With a
320           // foreign exception class, we have no class info to match.
321           else if ((actions & _UA_FORCE_UNWIND)
322               || exception_class != __gcj_exception_class)
323             ;
324
325           else if (ar_filter > 0)
326             {
327               // Positive filter values are handlers.
328
329               void **catch_word = get_ttype_entry (context, &info, ar_filter);
330               jclass catch_type = (jclass)*catch_word;
331
332               // FIXME: This line is a kludge to work around exception
333               // handlers written in C++, which don't yet use indirect
334               // dispatch.
335               if (catch_type == *(void **)&java::lang::Class::class$)
336                 catch_type = (jclass)catch_word;
337
338               if (_Jv_IsInstanceOf (xh->value, catch_type))
339                 {
340                   handler_switch_value = ar_filter;
341                   saw_handler = true;
342                   break;
343                 }
344             }
345           else
346             {
347               // Negative filter values are exception specifications,
348               // which Java does not use.
349               // ??? Perhaps better to make them an index into a table
350               // of null-terminated strings instead of playing games
351               // with Utf8Const+1 as above.
352               abort ();
353             }
354
355           if (ar_disp == 0)
356             break;
357           action_record = p + ar_disp;
358         }
359     }
360
361   if (! saw_handler && ! saw_cleanup)
362     return _URC_CONTINUE_UNWIND;
363
364   if (actions & _UA_SEARCH_PHASE)
365     {
366       if (! saw_handler)
367         return _URC_CONTINUE_UNWIND;
368
369       // For domestic exceptions, we cache data from phase 1 for phase 2.
370       if (exception_class == __gcj_exception_class)
371         {
372           xh->handlerSwitchValue = handler_switch_value;
373           xh->landingPad = landing_pad;
374         }
375       return _URC_HANDLER_FOUND;
376     }
377
378  install_context:
379   _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
380                  (_Unwind_Ptr) &xh->unwindHeader);
381   _Unwind_SetGR (context, __builtin_eh_return_data_regno (1),
382                  handler_switch_value);
383   _Unwind_SetIP (context, landing_pad);
384   return _URC_INSTALL_CONTEXT;
385 }