OSDN Git Service

In libobjc/:
[pf3gnuchains/gcc-fork.git] / libobjc / exception.c
1 /* The implementation of exception handling primitives for Objective-C.
2    Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
6 GCC is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 3, or (at your option) any
9 later version.
10
11 GCC is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
14 License for more details.
15
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
19
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23 <http://www.gnu.org/licenses/>.  */
24
25 #include "objc-private/common.h"
26 #include <stdlib.h>
27 #include "config.h"
28 #include "objc/runtime.h"
29 #include "objc/objc-exception.h"
30 #include "unwind.h"
31 #include "unwind-pe.h"
32 #include <string.h> /* For memcpy */
33
34 /* This hook allows libraries to sepecify special actions when an
35    exception is thrown without a handler in place.  This is deprecated
36    in favour of objc_set_uncaught_exception_handler ().  */
37 void (*_objc_unexpected_exception) (id exception); /* !T:SAFE */
38
39
40 /* 'is_kind_of_exception_matcher' is our default exception matcher -
41    it determines if the object 'exception' is of class 'catch_class',
42    or of a subclass.  */
43 static int
44 is_kind_of_exception_matcher (Class catch_class, id exception)
45 {
46   /* NULL catch_class is catch-all (eg, @catch (id object)).  */
47   if (catch_class == Nil)
48     return 1;
49
50   /* If exception is nil (eg, @throw nil;), then it can only be
51      catched by a catch-all (eg, @catch (id object)).  */
52   if (exception != nil)
53     {
54       Class c;
55
56       for (c = exception->class_pointer; c != Nil; 
57            c = class_getSuperclass (c))
58         if (c == catch_class)
59           return 1;
60     }
61   return 0;
62 }
63
64 /* The exception matcher currently in use.  */
65 static objc_exception_matcher
66 __objc_exception_matcher = is_kind_of_exception_matcher;
67
68 objc_exception_matcher
69 objc_setExceptionMatcher (objc_exception_matcher new_matcher)
70 {
71   objc_exception_matcher old_matcher = __objc_exception_matcher;
72   __objc_exception_matcher = new_matcher;
73   return old_matcher;
74 }
75
76 /* The uncaught exception handler currently in use.  */
77 static objc_uncaught_exception_handler
78 __objc_uncaught_exception_handler = NULL;
79
80 objc_uncaught_exception_handler
81 objc_setUncaughtExceptionHandler (objc_uncaught_exception_handler 
82                                   new_handler)
83 {
84   objc_uncaught_exception_handler old_handler 
85     = __objc_uncaught_exception_handler;
86   __objc_uncaught_exception_handler = new_handler;
87   return old_handler;
88 }
89
90
91 \f
92 #ifdef __ARM_EABI_UNWINDER__
93
94 const _Unwind_Exception_Class __objc_exception_class
95   = {'G', 'N', 'U', 'C', 'O', 'B', 'J', 'C'};
96   
97 #else
98
99 /* This is the exception class we report -- "GNUCOBJC".  */
100 static const _Unwind_Exception_Class __objc_exception_class
101   = ((((((((_Unwind_Exception_Class) 'G'
102             << 8 | (_Unwind_Exception_Class) 'N')
103            << 8 | (_Unwind_Exception_Class) 'U')
104           << 8 | (_Unwind_Exception_Class) 'C')
105          << 8 | (_Unwind_Exception_Class) 'O')
106         << 8 | (_Unwind_Exception_Class) 'B')
107        << 8 | (_Unwind_Exception_Class) 'J')
108       << 8 | (_Unwind_Exception_Class) 'C');
109
110 #endif
111
112 /* This is the object that is passed around by the Objective C runtime
113    to represent the exception in flight.  */
114 struct ObjcException
115 {
116   /* This bit is needed in order to interact with the unwind runtime.  */
117   struct _Unwind_Exception base;
118
119   /* The actual object we want to throw. Note: must come immediately
120      after unwind header.  */
121   id value;
122
123 #ifdef __ARM_EABI_UNWINDER__
124   /* Note: we use the barrier cache defined in the unwind control
125      block for ARM EABI.  */
126 #else
127   /* Cache some internal unwind data between phase 1 and phase 2.  */
128   _Unwind_Ptr landingPad;
129   int handlerSwitchValue;
130 #endif
131 };
132
133 \f
134
135 struct lsda_header_info
136 {
137   _Unwind_Ptr Start;
138   _Unwind_Ptr LPStart;
139   _Unwind_Ptr ttype_base;
140   const unsigned char *TType;
141   const unsigned char *action_table;
142   unsigned char ttype_encoding;
143   unsigned char call_site_encoding;
144 };
145
146 static const unsigned char *
147 parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
148                    struct lsda_header_info *info)
149 {
150   _uleb128_t tmp;
151   unsigned char lpstart_encoding;
152
153   info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
154
155   /* Find @LPStart, the base to which landing pad offsets are
156      relative.  */
157   lpstart_encoding = *p++;
158   if (lpstart_encoding != DW_EH_PE_omit)
159     p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
160   else
161     info->LPStart = info->Start;
162
163   /* Find @TType, the base of the handler and exception spec type
164      data.  */
165   info->ttype_encoding = *p++;
166   if (info->ttype_encoding != DW_EH_PE_omit)
167     {
168       p = read_uleb128 (p, &tmp);
169       info->TType = p + tmp;
170     }
171   else
172     info->TType = 0;
173
174   /* The encoding and length of the call-site table; the action table
175      immediately follows.  */
176   info->call_site_encoding = *p++;
177   p = read_uleb128 (p, &tmp);
178   info->action_table = p + tmp;
179
180   return p;
181 }
182
183 #ifdef __ARM_EABI_UNWINDER__
184
185 static Class
186 get_ttype_entry (struct lsda_header_info *info, _uleb128_t i)
187 {
188   _Unwind_Ptr ptr;
189   
190   ptr = (_Unwind_Ptr) (info->TType - (i * 4));
191   ptr = _Unwind_decode_target2 (ptr);
192
193   /* NULL ptr means catch-all.  Note that if the class is not found,
194      this will abort the program.  */
195   if (ptr)
196     return objc_getRequiredClass ((const char *) ptr);
197   else
198     return 0;
199 }
200
201 #else
202
203 static Class
204 get_ttype_entry (struct lsda_header_info *info, _Unwind_Word i)
205 {
206   _Unwind_Ptr ptr;
207
208   i *= size_of_encoded_value (info->ttype_encoding);
209   read_encoded_value_with_base (info->ttype_encoding, info->ttype_base,
210                                 info->TType - i, &ptr);
211
212   /* NULL ptr means catch-all.  Note that if the class is not found,
213      this will abort the program.  */
214   if (ptr)
215     return objc_getRequiredClass ((const char *) ptr);
216   else
217     return 0;
218 }
219
220 #endif
221
222 /* Using a different personality function name causes link failures
223    when trying to mix code using different exception handling
224    models.  */
225 #ifdef SJLJ_EXCEPTIONS
226 #define PERSONALITY_FUNCTION    __gnu_objc_personality_sj0
227 #define __builtin_eh_return_data_regno(x) x
228 #else
229 #define PERSONALITY_FUNCTION    __gnu_objc_personality_v0
230 #endif
231
232 #ifdef __ARM_EABI_UNWINDER__
233
234 #define CONTINUE_UNWINDING \
235   do                                                            \
236     {                                                           \
237       if (__gnu_unwind_frame(ue_header, context) != _URC_OK)    \
238         return _URC_FAILURE;                                    \
239       return _URC_CONTINUE_UNWIND;                              \
240     }                                                           \
241   while (0)
242
243 _Unwind_Reason_Code
244 PERSONALITY_FUNCTION (_Unwind_State state,
245                       struct _Unwind_Exception *ue_header,
246                       struct _Unwind_Context *context)
247 #else
248
249 #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
250
251 _Unwind_Reason_Code
252 PERSONALITY_FUNCTION (int version,
253                       _Unwind_Action actions,
254                       _Unwind_Exception_Class exception_class,
255                       struct _Unwind_Exception *ue_header,
256                       struct _Unwind_Context *context)
257 #endif
258 {
259   struct ObjcException *xh = (struct ObjcException *) ue_header;
260
261   struct lsda_header_info info;
262   const unsigned char *language_specific_data;
263   const unsigned char *action_record;
264   const unsigned char *p;
265   _Unwind_Ptr landing_pad, ip;
266   int handler_switch_value;
267   int saw_cleanup = 0, saw_handler, foreign_exception;
268   void *return_object;
269   int ip_before_insn = 0;
270
271 #ifdef __ARM_EABI_UNWINDER__
272   _Unwind_Action actions;
273   
274   switch (state & _US_ACTION_MASK)
275     {
276     case _US_VIRTUAL_UNWIND_FRAME:
277       actions = _UA_SEARCH_PHASE;
278       break;
279
280     case _US_UNWIND_FRAME_STARTING:
281       actions = _UA_CLEANUP_PHASE;
282       if (!(state & _US_FORCE_UNWIND)
283           && ue_header->barrier_cache.sp == _Unwind_GetGR (context, 13))
284         actions |= _UA_HANDLER_FRAME;
285       break;
286
287     case _US_UNWIND_FRAME_RESUME:
288       CONTINUE_UNWINDING;
289       break;
290
291     default:
292       abort();
293     }
294   actions |= state & _US_FORCE_UNWIND;
295
296   /* TODO: Foreign exceptions need some attention (e.g. rethrowing
297      doesn't work).  */
298   foreign_exception = 0;
299
300   /* The dwarf unwinder assumes the context structure holds things
301      like the function and LSDA pointers.  The ARM implementation
302      caches these in the exception header (UCB).  To avoid rewriting
303      everything we make the virtual IP register point at the UCB.  */
304   ip = (_Unwind_Ptr) ue_header;
305   _Unwind_SetGR (context, 12, ip);
306
307 #else  /* !__ARM_EABI_UNWINDER.  */
308   /* Interface version check.  */
309   if (version != 1)
310     return _URC_FATAL_PHASE1_ERROR;
311   
312   foreign_exception = (exception_class != __objc_exception_class);
313 #endif
314
315   /* Shortcut for phase 2 found handler for domestic exception.  */
316   if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME)
317       && !foreign_exception)
318     {
319 #ifdef __ARM_EABI_UNWINDER__
320       handler_switch_value = (int) ue_header->barrier_cache.bitpattern[1];
321       landing_pad = (_Unwind_Ptr) ue_header->barrier_cache.bitpattern[3];
322 #else
323       handler_switch_value = xh->handlerSwitchValue;
324       landing_pad = xh->landingPad;
325 #endif
326       goto install_context;
327     }
328
329   language_specific_data = (const unsigned char *)
330     _Unwind_GetLanguageSpecificData (context);
331
332   /* If no LSDA, then there are no handlers or cleanups.  */
333   if (! language_specific_data)
334     CONTINUE_UNWINDING;
335
336   /* Parse the LSDA header.  */
337   p = parse_lsda_header (context, language_specific_data, &info);
338   info.ttype_base = base_of_encoded_value (info.ttype_encoding, context);
339 #ifdef HAVE_GETIPINFO
340   ip = _Unwind_GetIPInfo (context, &ip_before_insn);
341 #else
342   ip = _Unwind_GetIP (context);
343 #endif
344   if (!ip_before_insn)
345     --ip;
346   landing_pad = 0;
347   action_record = 0;
348   handler_switch_value = 0;
349
350 #ifdef SJLJ_EXCEPTIONS
351   /* The given "IP" is an index into the call-site table, with two
352      exceptions -- -1 means no-action, and 0 means terminate.  But
353      since we're using uleb128 values, we've not got random access to
354      the array.  */
355   if ((int) ip < 0)
356     return _URC_CONTINUE_UNWIND;
357   else
358     {
359       _uleb128_t cs_lp, cs_action;
360       do
361         {
362           p = read_uleb128 (p, &cs_lp);
363           p = read_uleb128 (p, &cs_action);
364         }
365       while (--ip);
366
367       /* Can never have null landing pad for sjlj -- that would have
368          been indicated by a -1 call site index.  */
369       landing_pad = cs_lp + 1;
370       if (cs_action)
371         action_record = info.action_table + cs_action - 1;
372       goto found_something;
373     }
374 #else
375   /* Search the call-site table for the action associated with this
376      IP.  */
377   while (p < info.action_table)
378     {
379       _Unwind_Ptr cs_start, cs_len, cs_lp;
380       _uleb128_t cs_action;
381
382       /* Note that all call-site encodings are "absolute"
383          displacements.  */
384       p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
385       p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
386       p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
387       p = read_uleb128 (p, &cs_action);
388
389       /* The table is sorted, so if we've passed the ip, stop.  */
390       if (ip < info.Start + cs_start)
391         p = info.action_table;
392       else if (ip < info.Start + cs_start + cs_len)
393         {
394           if (cs_lp)
395             landing_pad = info.LPStart + cs_lp;
396           if (cs_action)
397             action_record = info.action_table + cs_action - 1;
398           goto found_something;
399         }
400     }
401 #endif /* SJLJ_EXCEPTIONS  */
402
403   /* If ip is not present in the table, C++ would call terminate.  */
404   /* ??? As with Java, it's perhaps better to tweek the LSDA to that
405      no-action is mapped to no-entry.  */
406   CONTINUE_UNWINDING;
407
408  found_something:
409   saw_cleanup = 0;
410   saw_handler = 0;
411
412   if (landing_pad == 0)
413     {
414       /* If ip is present, and has a null landing pad, there are no
415          cleanups or handlers to be run.  */
416     }
417   else if (action_record == 0)
418     {
419       /* If ip is present, has a non-null landing pad, and a null
420          action table offset, then there are only cleanups present.
421          Cleanups use a zero switch value, as set above.  */
422       saw_cleanup = 1;
423     }
424   else
425     {
426       /* Otherwise we have a catch handler.  */
427       _sleb128_t ar_filter, ar_disp;
428
429       while (1)
430         {
431           p = action_record;
432           p = read_sleb128 (p, &ar_filter);
433           read_sleb128 (p, &ar_disp);
434
435           if (ar_filter == 0)
436             {
437               /* Zero filter values are cleanups.  */
438               saw_cleanup = 1;
439             }
440
441           /* During forced unwinding, we only run cleanups.  With a
442              foreign exception class, we have no class info to
443              match.  */
444           else if ((actions & _UA_FORCE_UNWIND) || foreign_exception)
445             ;
446
447           else if (ar_filter > 0)
448             {
449               /* Positive filter values are handlers.  */
450               Class catch_type = get_ttype_entry (&info, ar_filter);
451
452               if ((*__objc_exception_matcher) (catch_type, xh->value))
453                 {
454                   handler_switch_value = ar_filter;
455                   saw_handler = 1;
456                   break;
457                 }
458             }
459           else
460             {
461               /* Negative filter values are exception specifications,
462                  which Objective-C does not use.  */
463               abort ();
464             }
465
466           if (ar_disp == 0)
467             break;
468           action_record = p + ar_disp;
469         }
470     }
471
472   if (! saw_handler && ! saw_cleanup)
473     CONTINUE_UNWINDING;
474
475   if (actions & _UA_SEARCH_PHASE)
476     {
477       if (!saw_handler)
478         CONTINUE_UNWINDING;
479
480       /* For domestic exceptions, we cache data from phase 1 for phase
481          2.  */
482       if (!foreign_exception)
483         {
484 #ifdef __ARM_EABI_UNWINDER__
485           ue_header->barrier_cache.sp = _Unwind_GetGR (context, 13);
486           ue_header->barrier_cache.bitpattern[1] = (_uw) handler_switch_value;
487           ue_header->barrier_cache.bitpattern[3] = (_uw) landing_pad;
488 #else
489           xh->handlerSwitchValue = handler_switch_value;
490           xh->landingPad = landing_pad;
491 #endif
492         }
493       return _URC_HANDLER_FOUND;
494     }
495
496  install_context:
497   if (saw_cleanup == 0)
498     {
499       return_object = xh->value;
500       if (!(actions & _UA_SEARCH_PHASE))
501         _Unwind_DeleteException(&xh->base);
502     }
503   
504   _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
505                  __builtin_extend_pointer (saw_cleanup ? xh : return_object));
506   _Unwind_SetGR (context, __builtin_eh_return_data_regno (1),
507                  handler_switch_value);
508   _Unwind_SetIP (context, landing_pad);
509   return _URC_INSTALL_CONTEXT;
510 }
511
512 static void
513 __objc_exception_cleanup (_Unwind_Reason_Code code __attribute__((unused)),
514                           struct _Unwind_Exception *exc)
515 {
516   free (exc);
517 }
518
519 void
520 objc_exception_throw (id exception)
521 {
522   struct ObjcException *header = calloc (1, sizeof (*header));
523
524   memcpy (&header->base.exception_class, &__objc_exception_class,
525           sizeof (__objc_exception_class));
526   header->base.exception_cleanup = __objc_exception_cleanup;
527   header->value = exception;
528
529 #ifdef SJLJ_EXCEPTIONS
530   _Unwind_SjLj_RaiseException (&header->base);
531 #else
532   _Unwind_RaiseException (&header->base);
533 #endif
534
535   /* No exception handler was installed.  Call the uncaught exception
536      handler if any is defined.  */
537   if (__objc_uncaught_exception_handler != 0)
538     {
539       (*__objc_uncaught_exception_handler) (exception);
540     }
541
542   /* As a last resort support the old, deprecated way of setting an
543      uncaught exception handler.  */
544   if (_objc_unexpected_exception != 0)
545     {
546       (*_objc_unexpected_exception) (exception);
547     }
548
549   abort ();
550 }
551