OSDN Git Service

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