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