2011-02-06 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / libobjc / exception.c
blob1ffb80b5352d0f33b2772583c2d17c467f32399b
1 /* The implementation of exception handling primitives for Objective-C.
2 Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
4 This file is part of GCC.
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.
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.
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.
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/>. */
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 */
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 */
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)
46 /* NULL catch_class is catch-all (eg, @catch (id object)). */
47 if (catch_class == Nil)
48 return 1;
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)
54 Class c;
56 for (c = exception->class_pointer; c != Nil;
57 c = class_getSuperclass (c))
58 if (c == catch_class)
59 return 1;
61 return 0;
64 /* The exception matcher currently in use. */
65 static objc_exception_matcher
66 __objc_exception_matcher = is_kind_of_exception_matcher;
68 objc_exception_matcher
69 objc_setExceptionMatcher (objc_exception_matcher new_matcher)
71 objc_exception_matcher old_matcher = __objc_exception_matcher;
72 __objc_exception_matcher = new_matcher;
73 return old_matcher;
76 /* The uncaught exception handler currently in use. */
77 static objc_uncaught_exception_handler
78 __objc_uncaught_exception_handler = NULL;
80 objc_uncaught_exception_handler
81 objc_setUncaughtExceptionHandler (objc_uncaught_exception_handler
82 new_handler)
84 objc_uncaught_exception_handler old_handler
85 = __objc_uncaught_exception_handler;
86 __objc_uncaught_exception_handler = new_handler;
87 return old_handler;
92 #ifdef __ARM_EABI_UNWINDER__
94 const _Unwind_Exception_Class __objc_exception_class
95 = {'G', 'N', 'U', 'C', 'O', 'B', 'J', 'C'};
97 #else
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');
110 #endif
112 /* This is the object that is passed around by the Objective C runtime
113 to represent the exception in flight. */
114 struct ObjcException
116 /* This bit is needed in order to interact with the unwind runtime. */
117 struct _Unwind_Exception base;
119 /* The actual object we want to throw. Note: must come immediately
120 after unwind header. */
121 id value;
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
135 struct lsda_header_info
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;
146 static const unsigned char *
147 parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
148 struct lsda_header_info *info)
150 _uleb128_t tmp;
151 unsigned char lpstart_encoding;
153 info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
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;
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)
168 p = read_uleb128 (p, &tmp);
169 info->TType = p + tmp;
171 else
172 info->TType = 0;
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;
180 return p;
183 #ifdef __ARM_EABI_UNWINDER__
185 static Class
186 get_ttype_entry (struct lsda_header_info *info, _uleb128_t i)
188 _Unwind_Ptr ptr;
190 ptr = (_Unwind_Ptr) (info->TType - (i * 4));
191 ptr = _Unwind_decode_target2 (ptr);
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;
201 #else
203 static Class
204 get_ttype_entry (struct lsda_header_info *info, _Unwind_Word i)
206 _Unwind_Ptr ptr;
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);
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;
220 #endif
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
232 #ifdef __ARM_EABI_UNWINDER__
234 #define CONTINUE_UNWINDING \
235 do \
237 if (__gnu_unwind_frame(ue_header, context) != _URC_OK) \
238 return _URC_FAILURE; \
239 return _URC_CONTINUE_UNWIND; \
241 while (0)
243 _Unwind_Reason_Code
244 PERSONALITY_FUNCTION (_Unwind_State state,
245 struct _Unwind_Exception *ue_header,
246 struct _Unwind_Context *context)
247 #else
249 #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
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
259 struct ObjcException *xh = (struct ObjcException *) ue_header;
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;
271 #ifdef __ARM_EABI_UNWINDER__
272 _Unwind_Action actions;
274 switch (state & _US_ACTION_MASK)
276 case _US_VIRTUAL_UNWIND_FRAME:
277 actions = _UA_SEARCH_PHASE;
278 break;
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;
287 case _US_UNWIND_FRAME_RESUME:
288 CONTINUE_UNWINDING;
289 break;
291 default:
292 abort();
294 actions |= state & _US_FORCE_UNWIND;
296 /* TODO: Foreign exceptions need some attention (e.g. rethrowing
297 doesn't work). */
298 foreign_exception = 0;
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);
307 #else /* !__ARM_EABI_UNWINDER. */
308 /* Interface version check. */
309 if (version != 1)
310 return _URC_FATAL_PHASE1_ERROR;
312 foreign_exception = (exception_class != __objc_exception_class);
313 #endif
315 /* Shortcut for phase 2 found handler for domestic exception. */
316 if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME)
317 && !foreign_exception)
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;
329 language_specific_data = (const unsigned char *)
330 _Unwind_GetLanguageSpecificData (context);
332 /* If no LSDA, then there are no handlers or cleanups. */
333 if (! language_specific_data)
334 CONTINUE_UNWINDING;
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;
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
359 _uleb128_t cs_lp, cs_action;
362 p = read_uleb128 (p, &cs_lp);
363 p = read_uleb128 (p, &cs_action);
365 while (--ip);
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;
374 #else
375 /* Search the call-site table for the action associated with this
376 IP. */
377 while (p < info.action_table)
379 _Unwind_Ptr cs_start, cs_len, cs_lp;
380 _uleb128_t cs_action;
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);
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)
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;
401 #endif /* SJLJ_EXCEPTIONS */
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;
408 found_something:
409 saw_cleanup = 0;
410 saw_handler = 0;
412 if (landing_pad == 0)
414 /* If ip is present, and has a null landing pad, there are no
415 cleanups or handlers to be run. */
417 else if (action_record == 0)
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;
424 else
426 /* Otherwise we have a catch handler. */
427 _sleb128_t ar_filter, ar_disp;
429 while (1)
431 p = action_record;
432 p = read_sleb128 (p, &ar_filter);
433 read_sleb128 (p, &ar_disp);
435 if (ar_filter == 0)
437 /* Zero filter values are cleanups. */
438 saw_cleanup = 1;
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)
447 else if (ar_filter > 0)
449 /* Positive filter values are handlers. */
450 Class catch_type = get_ttype_entry (&info, ar_filter);
452 if ((*__objc_exception_matcher) (catch_type, xh->value))
454 handler_switch_value = ar_filter;
455 saw_handler = 1;
456 break;
459 else
461 /* Negative filter values are exception specifications,
462 which Objective-C does not use. */
463 abort ();
466 if (ar_disp == 0)
467 break;
468 action_record = p + ar_disp;
472 if (! saw_handler && ! saw_cleanup)
473 CONTINUE_UNWINDING;
475 if (actions & _UA_SEARCH_PHASE)
477 if (!saw_handler)
478 CONTINUE_UNWINDING;
480 /* For domestic exceptions, we cache data from phase 1 for phase
481 2. */
482 if (!foreign_exception)
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
493 return _URC_HANDLER_FOUND;
496 install_context:
497 if (saw_cleanup == 0)
499 return_object = xh->value;
500 if (!(actions & _UA_SEARCH_PHASE))
501 _Unwind_DeleteException(&xh->base);
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;
512 static void
513 __objc_exception_cleanup (_Unwind_Reason_Code code __attribute__((unused)),
514 struct _Unwind_Exception *exc)
516 free (exc);
519 void
520 objc_exception_throw (id exception)
522 struct ObjcException *header = calloc (1, sizeof (*header));
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;
529 #ifdef SJLJ_EXCEPTIONS
530 _Unwind_SjLj_RaiseException (&header->base);
531 #else
532 _Unwind_RaiseException (&header->base);
533 #endif
535 /* No exception handler was installed. Call the uncaught exception
536 handler if any is defined. */
537 if (__objc_uncaught_exception_handler != 0)
539 (*__objc_uncaught_exception_handler) (exception);
542 /* As a last resort support the old, deprecated way of setting an
543 uncaught exception handler. */
544 if (_objc_unexpected_exception != 0)
546 (*_objc_unexpected_exception) (exception);
549 abort ();