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
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"
28 #include "objc/objc-api.h"
29 #include "objc/objc-exception.h"
31 #include "unwind-pe.h"
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 ().
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',
45 is_kind_of_exception_matcher (Class catch_class, id exception)
47 /* NULL catch_class is catch-all (eg, @catch (id object)). */
48 if (catch_class == Nil)
51 /* If exception is nil (eg, @throw nil;), then it can only be catched
52 * by a catch-all (eg, @catch (id object)).
58 for (c = exception->class_pointer; c != Nil;
59 c = class_get_super_class (c))
66 /* The exception matcher currently in use. */
67 static objc_exception_matcher
68 __objc_exception_matcher = is_kind_of_exception_matcher;
70 objc_exception_matcher
71 objc_set_exception_matcher (objc_exception_matcher new_matcher)
73 objc_exception_matcher old_matcher = __objc_exception_matcher;
74 __objc_exception_matcher = new_matcher;
78 /* The uncaught exception handler currently in use. */
79 static objc_uncaught_exception_handler
80 __objc_uncaught_exception_handler = NULL;
82 objc_uncaught_exception_handler
83 objc_set_uncaught_exception_handler (objc_uncaught_exception_handler
86 objc_uncaught_exception_handler old_handler
87 = __objc_uncaught_exception_handler;
88 __objc_uncaught_exception_handler = new_handler;
94 #ifdef __ARM_EABI_UNWINDER__
96 const _Unwind_Exception_Class __objc_exception_class
97 = {'G', 'N', 'U', 'C', 'O', 'B', 'J', 'C'};
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');
114 /* This is the object that is passed around by the Objective C runtime
115 to represent the exception in flight. */
119 /* This bit is needed in order to interact with the unwind runtime. */
120 struct _Unwind_Exception base;
122 /* The actual object we want to throw. Note: must come immediately after
126 #ifdef __ARM_EABI_UNWINDER__
127 /* Note: we use the barrier cache defined in the unwind control block for
130 /* Cache some internal unwind data between phase 1 and phase 2. */
131 _Unwind_Ptr landingPad;
132 int handlerSwitchValue;
138 struct lsda_header_info
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;
149 static const unsigned char *
150 parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
151 struct lsda_header_info *info)
154 unsigned char lpstart_encoding;
156 info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
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);
163 info->LPStart = info->Start;
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)
169 p = read_uleb128 (p, &tmp);
170 info->TType = p + tmp;
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;
184 #ifdef __ARM_EABI_UNWINDER__
187 get_ttype_entry (struct lsda_header_info *info, _uleb128_t i)
191 ptr = (_Unwind_Ptr) (info->TType - (i * 4));
192 ptr = _Unwind_decode_target2 (ptr);
195 return objc_get_class ((const char *) ptr);
203 get_ttype_entry (struct lsda_header_info *info, _Unwind_Word i)
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);
211 /* NULL ptr means catch-all. */
213 return objc_get_class ((const char *) ptr);
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
226 #define PERSONALITY_FUNCTION __gnu_objc_personality_v0
229 #ifdef __ARM_EABI_UNWINDER__
231 #define CONTINUE_UNWINDING \
234 if (__gnu_unwind_frame(ue_header, context) != _URC_OK) \
235 return _URC_FAILURE; \
236 return _URC_CONTINUE_UNWIND; \
241 PERSONALITY_FUNCTION (_Unwind_State state,
242 struct _Unwind_Exception *ue_header,
243 struct _Unwind_Context *context)
246 #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
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)
256 struct ObjcException *xh = (struct ObjcException *) ue_header;
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;
266 int ip_before_insn = 0;
268 #ifdef __ARM_EABI_UNWINDER__
269 _Unwind_Action actions;
271 switch (state & _US_ACTION_MASK)
273 case _US_VIRTUAL_UNWIND_FRAME:
274 actions = _UA_SEARCH_PHASE;
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;
284 case _US_UNWIND_FRAME_RESUME:
291 actions |= state & _US_FORCE_UNWIND;
293 /* TODO: Foreign exceptions need some attention (e.g. rethrowing doesn't
295 foreign_exception = 0;
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);
304 #else /* !__ARM_EABI_UNWINDER. */
305 /* Interface version check. */
307 return _URC_FATAL_PHASE1_ERROR;
309 foreign_exception = (exception_class != __objc_exception_class);
312 /* Shortcut for phase 2 found handler for domestic exception. */
313 if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME)
314 && !foreign_exception)
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];
320 handler_switch_value = xh->handlerSwitchValue;
321 landing_pad = xh->landingPad;
323 goto install_context;
326 language_specific_data = (const unsigned char *)
327 _Unwind_GetLanguageSpecificData (context);
329 /* If no LSDA, then there are no handlers or cleanups. */
330 if (! language_specific_data)
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);
339 ip = _Unwind_GetIP (context);
345 handler_switch_value = 0;
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
353 return _URC_CONTINUE_UNWIND;
356 _uleb128_t cs_lp, cs_action;
359 p = read_uleb128 (p, &cs_lp);
360 p = read_uleb128 (p, &cs_action);
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;
368 action_record = info.action_table + cs_action - 1;
369 goto found_something;
372 /* Search the call-site table for the action associated with this IP. */
373 while (p < info.action_table)
375 _Unwind_Ptr cs_start, cs_len, cs_lp;
376 _uleb128_t cs_action;
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);
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)
390 landing_pad = info.LPStart + cs_lp;
392 action_record = info.action_table + cs_action - 1;
393 goto found_something;
396 #endif /* SJLJ_EXCEPTIONS */
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. */
407 if (landing_pad == 0)
409 /* If ip is present, and has a null landing pad, there are
410 no cleanups or handlers to be run. */
412 else if (action_record == 0)
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. */
421 /* Otherwise we have a catch handler. */
422 _sleb128_t ar_filter, ar_disp;
427 p = read_sleb128 (p, &ar_filter);
428 read_sleb128 (p, &ar_disp);
432 /* Zero filter values are cleanups. */
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)
441 else if (ar_filter > 0)
443 /* Positive filter values are handlers. */
445 Class catch_type = get_ttype_entry (&info, ar_filter);
447 if ((*__objc_exception_matcher) (catch_type, xh->value))
449 handler_switch_value = ar_filter;
456 /* Negative filter values are exception specifications,
457 which Objective-C does not use. */
463 action_record = p + ar_disp;
467 if (! saw_handler && ! saw_cleanup)
470 if (actions & _UA_SEARCH_PHASE)
475 /* For domestic exceptions, we cache data from phase 1 for phase 2. */
476 if (!foreign_exception)
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;
483 xh->handlerSwitchValue = handler_switch_value;
484 xh->landingPad = landing_pad;
487 return _URC_HANDLER_FOUND;
491 if (saw_cleanup == 0)
493 return_object = xh->value;
494 if (!(actions & _UA_SEARCH_PHASE))
495 _Unwind_DeleteException(&xh->base);
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;
507 __objc_exception_cleanup (_Unwind_Reason_Code code __attribute__((unused)),
508 struct _Unwind_Exception *exc)
514 objc_exception_throw (id exception)
516 struct ObjcException *header = calloc (1, sizeof (*header));
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;
523 #ifdef SJLJ_EXCEPTIONS
524 _Unwind_SjLj_RaiseException (&header->base);
526 _Unwind_RaiseException (&header->base);
529 /* No exception handler was installed. Call the uncaught exception
530 handler if any is defined.
532 if (__objc_uncaught_exception_handler != 0)
534 (*__objc_uncaught_exception_handler) (exception);
537 /* As a last resort support the old, deprecated way of setting an
538 uncaught exception handler.
540 if (_objc_unexpected_exception != 0)
542 (*_objc_unexpected_exception) (exception);