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"
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 ().
38 void (*_objc_unexpected_exception
) (id exception
); /* !T:SAFE */
41 /* 'is_kind_of_exception_matcher' is our default exception matcher -
42 it determines if the object 'exception' is of class 'catch_class',
46 is_kind_of_exception_matcher (Class catch_class
, id exception
)
48 /* NULL catch_class is catch-all (eg, @catch (id object)). */
49 if (catch_class
== Nil
)
52 /* If exception is nil (eg, @throw nil;), then it can only be catched
53 * by a catch-all (eg, @catch (id object)).
59 for (c
= exception
->class_pointer
; c
!= Nil
;
60 c
= class_get_super_class (c
))
67 /* The exception matcher currently in use. */
68 static objc_exception_matcher
69 __objc_exception_matcher
= is_kind_of_exception_matcher
;
71 objc_exception_matcher
72 objc_set_exception_matcher (objc_exception_matcher new_matcher
)
74 objc_exception_matcher old_matcher
= __objc_exception_matcher
;
75 __objc_exception_matcher
= new_matcher
;
79 /* The uncaught exception handler currently in use. */
80 static objc_uncaught_exception_handler
81 __objc_uncaught_exception_handler
= NULL
;
83 objc_uncaught_exception_handler
84 objc_set_uncaught_exception_handler (objc_uncaught_exception_handler
87 objc_uncaught_exception_handler old_handler
88 = __objc_uncaught_exception_handler
;
89 __objc_uncaught_exception_handler
= new_handler
;
95 #ifdef __ARM_EABI_UNWINDER__
97 const _Unwind_Exception_Class __objc_exception_class
98 = {'G', 'N', 'U', 'C', 'O', 'B', 'J', 'C'};
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');
115 /* This is the object that is passed around by the Objective C runtime
116 to represent the exception in flight. */
120 /* This bit is needed in order to interact with the unwind runtime. */
121 struct _Unwind_Exception base
;
123 /* The actual object we want to throw. Note: must come immediately after
127 #ifdef __ARM_EABI_UNWINDER__
128 /* Note: we use the barrier cache defined in the unwind control block for
131 /* Cache some internal unwind data between phase 1 and phase 2. */
132 _Unwind_Ptr landingPad
;
133 int handlerSwitchValue
;
139 struct lsda_header_info
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
;
150 static const unsigned char *
151 parse_lsda_header (struct _Unwind_Context
*context
, const unsigned char *p
,
152 struct lsda_header_info
*info
)
155 unsigned char lpstart_encoding
;
157 info
->Start
= (context
? _Unwind_GetRegionStart (context
) : 0);
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
);
164 info
->LPStart
= info
->Start
;
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
)
170 p
= read_uleb128 (p
, &tmp
);
171 info
->TType
= p
+ tmp
;
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
;
185 #ifdef __ARM_EABI_UNWINDER__
188 get_ttype_entry (struct lsda_header_info
*info
, _uleb128_t i
)
192 ptr
= (_Unwind_Ptr
) (info
->TType
- (i
* 4));
193 ptr
= _Unwind_decode_target2 (ptr
);
196 return objc_get_class ((const char *) ptr
);
204 get_ttype_entry (struct lsda_header_info
*info
, _Unwind_Word i
)
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. */
214 return objc_get_class ((const char *) ptr
);
221 /* Using a different personality function name causes link failures
222 when trying to mix code using different exception handling models. */
223 #ifdef SJLJ_EXCEPTIONS
224 #define PERSONALITY_FUNCTION __gnu_objc_personality_sj0
225 #define __builtin_eh_return_data_regno(x) x
227 #define PERSONALITY_FUNCTION __gnu_objc_personality_v0
230 #ifdef __ARM_EABI_UNWINDER__
232 #define CONTINUE_UNWINDING \
235 if (__gnu_unwind_frame(ue_header, context) != _URC_OK) \
236 return _URC_FAILURE; \
237 return _URC_CONTINUE_UNWIND; \
242 PERSONALITY_FUNCTION (_Unwind_State state
,
243 struct _Unwind_Exception
*ue_header
,
244 struct _Unwind_Context
*context
)
247 #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
250 PERSONALITY_FUNCTION (int version
,
251 _Unwind_Action actions
,
252 _Unwind_Exception_Class exception_class
,
253 struct _Unwind_Exception
*ue_header
,
254 struct _Unwind_Context
*context
)
257 struct ObjcException
*xh
= (struct ObjcException
*) ue_header
;
259 struct lsda_header_info info
;
260 const unsigned char *language_specific_data
;
261 const unsigned char *action_record
;
262 const unsigned char *p
;
263 _Unwind_Ptr landing_pad
, ip
;
264 int handler_switch_value
;
265 int saw_cleanup
= 0, saw_handler
, foreign_exception
;
267 int ip_before_insn
= 0;
269 #ifdef __ARM_EABI_UNWINDER__
270 _Unwind_Action actions
;
272 switch (state
& _US_ACTION_MASK
)
274 case _US_VIRTUAL_UNWIND_FRAME
:
275 actions
= _UA_SEARCH_PHASE
;
278 case _US_UNWIND_FRAME_STARTING
:
279 actions
= _UA_CLEANUP_PHASE
;
280 if (!(state
& _US_FORCE_UNWIND
)
281 && ue_header
->barrier_cache
.sp
== _Unwind_GetGR (context
, 13))
282 actions
|= _UA_HANDLER_FRAME
;
285 case _US_UNWIND_FRAME_RESUME
:
292 actions
|= state
& _US_FORCE_UNWIND
;
294 /* TODO: Foreign exceptions need some attention (e.g. rethrowing doesn't
296 foreign_exception
= 0;
298 /* The dwarf unwinder assumes the context structure holds things like the
299 function and LSDA pointers. The ARM implementation caches these in
300 the exception header (UCB). To avoid rewriting everything we make the
301 virtual IP register point at the UCB. */
302 ip
= (_Unwind_Ptr
) ue_header
;
303 _Unwind_SetGR (context
, 12, ip
);
305 #else /* !__ARM_EABI_UNWINDER. */
306 /* Interface version check. */
308 return _URC_FATAL_PHASE1_ERROR
;
310 foreign_exception
= (exception_class
!= __objc_exception_class
);
313 /* Shortcut for phase 2 found handler for domestic exception. */
314 if (actions
== (_UA_CLEANUP_PHASE
| _UA_HANDLER_FRAME
)
315 && !foreign_exception
)
317 #ifdef __ARM_EABI_UNWINDER__
318 handler_switch_value
= (int) ue_header
->barrier_cache
.bitpattern
[1];
319 landing_pad
= (_Unwind_Ptr
) ue_header
->barrier_cache
.bitpattern
[3];
321 handler_switch_value
= xh
->handlerSwitchValue
;
322 landing_pad
= xh
->landingPad
;
324 goto install_context
;
327 language_specific_data
= (const unsigned char *)
328 _Unwind_GetLanguageSpecificData (context
);
330 /* If no LSDA, then there are no handlers or cleanups. */
331 if (! language_specific_data
)
334 /* Parse the LSDA header. */
335 p
= parse_lsda_header (context
, language_specific_data
, &info
);
336 info
.ttype_base
= base_of_encoded_value (info
.ttype_encoding
, context
);
337 #ifdef HAVE_GETIPINFO
338 ip
= _Unwind_GetIPInfo (context
, &ip_before_insn
);
340 ip
= _Unwind_GetIP (context
);
346 handler_switch_value
= 0;
348 #ifdef SJLJ_EXCEPTIONS
349 /* The given "IP" is an index into the call-site table, with two
350 exceptions -- -1 means no-action, and 0 means terminate. But
351 since we're using uleb128 values, we've not got random access
354 return _URC_CONTINUE_UNWIND
;
357 _uleb128_t cs_lp
, cs_action
;
360 p
= read_uleb128 (p
, &cs_lp
);
361 p
= read_uleb128 (p
, &cs_action
);
365 /* Can never have null landing pad for sjlj -- that would have
366 been indicated by a -1 call site index. */
367 landing_pad
= cs_lp
+ 1;
369 action_record
= info
.action_table
+ cs_action
- 1;
370 goto found_something
;
373 /* Search the call-site table for the action associated with this IP. */
374 while (p
< info
.action_table
)
376 _Unwind_Ptr cs_start
, cs_len
, cs_lp
;
377 _uleb128_t cs_action
;
379 /* Note that all call-site encodings are "absolute" displacements. */
380 p
= read_encoded_value (0, info
.call_site_encoding
, p
, &cs_start
);
381 p
= read_encoded_value (0, info
.call_site_encoding
, p
, &cs_len
);
382 p
= read_encoded_value (0, info
.call_site_encoding
, p
, &cs_lp
);
383 p
= read_uleb128 (p
, &cs_action
);
385 /* The table is sorted, so if we've passed the ip, stop. */
386 if (ip
< info
.Start
+ cs_start
)
387 p
= info
.action_table
;
388 else if (ip
< info
.Start
+ cs_start
+ cs_len
)
391 landing_pad
= info
.LPStart
+ cs_lp
;
393 action_record
= info
.action_table
+ cs_action
- 1;
394 goto found_something
;
397 #endif /* SJLJ_EXCEPTIONS */
399 /* If ip is not present in the table, C++ would call terminate. */
400 /* ??? As with Java, it's perhaps better to tweek the LSDA to
401 that no-action is mapped to no-entry. */
408 if (landing_pad
== 0)
410 /* If ip is present, and has a null landing pad, there are
411 no cleanups or handlers to be run. */
413 else if (action_record
== 0)
415 /* If ip is present, has a non-null landing pad, and a null
416 action table offset, then there are only cleanups present.
417 Cleanups use a zero switch value, as set above. */
422 /* Otherwise we have a catch handler. */
423 _sleb128_t ar_filter
, ar_disp
;
428 p
= read_sleb128 (p
, &ar_filter
);
429 read_sleb128 (p
, &ar_disp
);
433 /* Zero filter values are cleanups. */
437 /* During forced unwinding, we only run cleanups. With a
438 foreign exception class, we have no class info to match. */
439 else if ((actions
& _UA_FORCE_UNWIND
) || foreign_exception
)
442 else if (ar_filter
> 0)
444 /* Positive filter values are handlers. */
446 Class catch_type
= get_ttype_entry (&info
, ar_filter
);
448 if ((*__objc_exception_matcher
) (catch_type
, xh
->value
))
450 handler_switch_value
= ar_filter
;
457 /* Negative filter values are exception specifications,
458 which Objective-C does not use. */
464 action_record
= p
+ ar_disp
;
468 if (! saw_handler
&& ! saw_cleanup
)
471 if (actions
& _UA_SEARCH_PHASE
)
476 /* For domestic exceptions, we cache data from phase 1 for phase 2. */
477 if (!foreign_exception
)
479 #ifdef __ARM_EABI_UNWINDER__
480 ue_header
->barrier_cache
.sp
= _Unwind_GetGR (context
, 13);
481 ue_header
->barrier_cache
.bitpattern
[1] = (_uw
) handler_switch_value
;
482 ue_header
->barrier_cache
.bitpattern
[3] = (_uw
) landing_pad
;
484 xh
->handlerSwitchValue
= handler_switch_value
;
485 xh
->landingPad
= landing_pad
;
488 return _URC_HANDLER_FOUND
;
492 if (saw_cleanup
== 0)
494 return_object
= xh
->value
;
495 if (!(actions
& _UA_SEARCH_PHASE
))
496 _Unwind_DeleteException(&xh
->base
);
499 _Unwind_SetGR (context
, __builtin_eh_return_data_regno (0),
500 __builtin_extend_pointer (saw_cleanup
? xh
: return_object
));
501 _Unwind_SetGR (context
, __builtin_eh_return_data_regno (1),
502 handler_switch_value
);
503 _Unwind_SetIP (context
, landing_pad
);
504 return _URC_INSTALL_CONTEXT
;
508 __objc_exception_cleanup (_Unwind_Reason_Code code
__attribute__((unused
)),
509 struct _Unwind_Exception
*exc
)
515 objc_exception_throw (id exception
)
517 struct ObjcException
*header
= calloc (1, sizeof (*header
));
519 memcpy (&header
->base
.exception_class
, &__objc_exception_class
,
520 sizeof (__objc_exception_class
));
521 header
->base
.exception_cleanup
= __objc_exception_cleanup
;
522 header
->value
= exception
;
524 #ifdef SJLJ_EXCEPTIONS
525 _Unwind_SjLj_RaiseException (&header
->base
);
527 _Unwind_RaiseException (&header
->base
);
530 /* No exception handler was installed. Call the uncaught exception
531 handler if any is defined.
533 if (__objc_uncaught_exception_handler
!= 0)
535 (*__objc_uncaught_exception_handler
) (exception
);
538 /* As a last resort support the old, deprecated way of setting an
539 uncaught exception handler.
541 if (_objc_unexpected_exception
!= 0)
543 (*_objc_unexpected_exception
) (exception
);