1 /* The implementation of exception handling primitives for Objective-C.
2 Copyright (C) 2004, 2005, 2007, 2008, 2009 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 2, 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 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING. If not, write to
18 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA. */
21 /* As a special exception, if you link this library with files compiled
22 with GCC to produce an executable, this does not cause the resulting
23 executable to be covered by the GNU General Public License. This
24 exception does not however invalidate any other reasons why the
25 executable file might be covered by the GNU General Public License. */
29 #include "objc/objc-api.h"
31 #include "unwind-pe.h"
34 #ifdef __ARM_EABI_UNWINDER__
36 const _Unwind_Exception_Class __objc_exception_class
37 = {'G', 'N', 'U', 'C', 'O', 'B', 'J', 'C'};
41 /* This is the exception class we report -- "GNUCOBJC". */
42 static const _Unwind_Exception_Class __objc_exception_class
43 = ((((((((_Unwind_Exception_Class
) 'G'
44 << 8 | (_Unwind_Exception_Class
) 'N')
45 << 8 | (_Unwind_Exception_Class
) 'U')
46 << 8 | (_Unwind_Exception_Class
) 'C')
47 << 8 | (_Unwind_Exception_Class
) 'O')
48 << 8 | (_Unwind_Exception_Class
) 'B')
49 << 8 | (_Unwind_Exception_Class
) 'J')
50 << 8 | (_Unwind_Exception_Class
) 'C');
54 /* This is the object that is passed around by the Objective C runtime
55 to represent the exception in flight. */
59 /* This bit is needed in order to interact with the unwind runtime. */
60 struct _Unwind_Exception base
;
62 /* The actual object we want to throw. Note: must come immediately after
66 #ifdef __ARM_EABI_UNWINDER__
67 /* Note: we use the barrier cache defined in the unwind control block for
70 /* Cache some internal unwind data between phase 1 and phase 2. */
71 _Unwind_Ptr landingPad
;
72 int handlerSwitchValue
;
78 struct lsda_header_info
82 _Unwind_Ptr ttype_base
;
83 const unsigned char *TType
;
84 const unsigned char *action_table
;
85 unsigned char ttype_encoding
;
86 unsigned char call_site_encoding
;
89 /* This hook allows libraries to sepecify special actions when an
90 exception is thrown without a handler in place.
92 void (*_objc_unexpected_exception
) (id exception
); /* !T:SAFE */
94 static const unsigned char *
95 parse_lsda_header (struct _Unwind_Context
*context
, const unsigned char *p
,
96 struct lsda_header_info
*info
)
99 unsigned char lpstart_encoding
;
101 info
->Start
= (context
? _Unwind_GetRegionStart (context
) : 0);
103 /* Find @LPStart, the base to which landing pad offsets are relative. */
104 lpstart_encoding
= *p
++;
105 if (lpstart_encoding
!= DW_EH_PE_omit
)
106 p
= read_encoded_value (context
, lpstart_encoding
, p
, &info
->LPStart
);
108 info
->LPStart
= info
->Start
;
110 /* Find @TType, the base of the handler and exception spec type data. */
111 info
->ttype_encoding
= *p
++;
112 if (info
->ttype_encoding
!= DW_EH_PE_omit
)
114 p
= read_uleb128 (p
, &tmp
);
115 info
->TType
= p
+ tmp
;
120 /* The encoding and length of the call-site table; the action table
121 immediately follows. */
122 info
->call_site_encoding
= *p
++;
123 p
= read_uleb128 (p
, &tmp
);
124 info
->action_table
= p
+ tmp
;
129 #ifdef __ARM_EABI_UNWINDER__
132 get_ttype_entry (struct lsda_header_info
*info
, _uleb128_t i
)
136 ptr
= (_Unwind_Ptr
) (info
->TType
- (i
* 4));
137 ptr
= _Unwind_decode_target2 (ptr
);
140 return objc_get_class ((const char *) ptr
);
148 get_ttype_entry (struct lsda_header_info
*info
, _Unwind_Word i
)
152 i
*= size_of_encoded_value (info
->ttype_encoding
);
153 read_encoded_value_with_base (info
->ttype_encoding
, info
->ttype_base
,
154 info
->TType
- i
, &ptr
);
156 /* NULL ptr means catch-all. */
158 return objc_get_class ((const char *) ptr
);
165 /* Like unto the method of the same name on Object, but takes an id. */
166 /* ??? Does this bork the meta-type system? Can/should we look up an
167 isKindOf method on the id? */
170 isKindOf (id value
, Class target
)
174 /* NULL target is catch-all. */
178 for (c
= value
->class_pointer
; c
; c
= class_get_super_class (c
))
184 /* Using a different personality function name causes link failures
185 when trying to mix code using different exception handling models. */
186 #ifdef SJLJ_EXCEPTIONS
187 #define PERSONALITY_FUNCTION __gnu_objc_personality_sj0
188 #define __builtin_eh_return_data_regno(x) x
190 #define PERSONALITY_FUNCTION __gnu_objc_personality_v0
193 #ifdef __ARM_EABI_UNWINDER__
195 #define CONTINUE_UNWINDING \
198 if (__gnu_unwind_frame(ue_header, context) != _URC_OK) \
199 return _URC_FAILURE; \
200 return _URC_CONTINUE_UNWIND; \
205 PERSONALITY_FUNCTION (_Unwind_State state
,
206 struct _Unwind_Exception
*ue_header
,
207 struct _Unwind_Context
*context
)
210 #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
213 PERSONALITY_FUNCTION (int version
,
214 _Unwind_Action actions
,
215 _Unwind_Exception_Class exception_class
,
216 struct _Unwind_Exception
*ue_header
,
217 struct _Unwind_Context
*context
)
220 struct ObjcException
*xh
= (struct ObjcException
*) ue_header
;
222 struct lsda_header_info info
;
223 const unsigned char *language_specific_data
;
224 const unsigned char *action_record
;
225 const unsigned char *p
;
226 _Unwind_Ptr landing_pad
, ip
;
227 int handler_switch_value
;
228 int saw_cleanup
= 0, saw_handler
, foreign_exception
;
230 int ip_before_insn
= 0;
232 #ifdef __ARM_EABI_UNWINDER__
233 _Unwind_Action actions
;
235 switch (state
& _US_ACTION_MASK
)
237 case _US_VIRTUAL_UNWIND_FRAME
:
238 actions
= _UA_SEARCH_PHASE
;
241 case _US_UNWIND_FRAME_STARTING
:
242 actions
= _UA_CLEANUP_PHASE
;
243 if (!(state
& _US_FORCE_UNWIND
)
244 && ue_header
->barrier_cache
.sp
== _Unwind_GetGR (context
, 13))
245 actions
|= _UA_HANDLER_FRAME
;
248 case _US_UNWIND_FRAME_RESUME
:
255 actions
|= state
& _US_FORCE_UNWIND
;
257 /* TODO: Foreign exceptions need some attention (e.g. rethrowing doesn't
259 foreign_exception
= 0;
261 /* The dwarf unwinder assumes the context structure holds things like the
262 function and LSDA pointers. The ARM implementation caches these in
263 the exception header (UCB). To avoid rewriting everything we make the
264 virtual IP register point at the UCB. */
265 ip
= (_Unwind_Ptr
) ue_header
;
266 _Unwind_SetGR (context
, 12, ip
);
268 #else /* !__ARM_EABI_UNWINDER. */
269 /* Interface version check. */
271 return _URC_FATAL_PHASE1_ERROR
;
273 foreign_exception
= (exception_class
!= __objc_exception_class
);
276 /* Shortcut for phase 2 found handler for domestic exception. */
277 if (actions
== (_UA_CLEANUP_PHASE
| _UA_HANDLER_FRAME
)
278 && !foreign_exception
)
280 #ifdef __ARM_EABI_UNWINDER__
281 handler_switch_value
= (int) ue_header
->barrier_cache
.bitpattern
[1];
282 landing_pad
= (_Unwind_Ptr
) ue_header
->barrier_cache
.bitpattern
[3];
284 handler_switch_value
= xh
->handlerSwitchValue
;
285 landing_pad
= xh
->landingPad
;
287 goto install_context
;
290 language_specific_data
= (const unsigned char *)
291 _Unwind_GetLanguageSpecificData (context
);
293 /* If no LSDA, then there are no handlers or cleanups. */
294 if (! language_specific_data
)
297 /* Parse the LSDA header. */
298 p
= parse_lsda_header (context
, language_specific_data
, &info
);
299 info
.ttype_base
= base_of_encoded_value (info
.ttype_encoding
, context
);
300 #ifdef HAVE_GETIPINFO
301 ip
= _Unwind_GetIPInfo (context
, &ip_before_insn
);
303 ip
= _Unwind_GetIP (context
);
309 handler_switch_value
= 0;
311 #ifdef SJLJ_EXCEPTIONS
312 /* The given "IP" is an index into the call-site table, with two
313 exceptions -- -1 means no-action, and 0 means terminate. But
314 since we're using uleb128 values, we've not got random access
317 return _URC_CONTINUE_UNWIND
;
320 _uleb128_t cs_lp
, cs_action
;
323 p
= read_uleb128 (p
, &cs_lp
);
324 p
= read_uleb128 (p
, &cs_action
);
328 /* Can never have null landing pad for sjlj -- that would have
329 been indicated by a -1 call site index. */
330 landing_pad
= cs_lp
+ 1;
332 action_record
= info
.action_table
+ cs_action
- 1;
333 goto found_something
;
336 /* Search the call-site table for the action associated with this IP. */
337 while (p
< info
.action_table
)
339 _Unwind_Ptr cs_start
, cs_len
, cs_lp
;
340 _uleb128_t cs_action
;
342 /* Note that all call-site encodings are "absolute" displacements. */
343 p
= read_encoded_value (0, info
.call_site_encoding
, p
, &cs_start
);
344 p
= read_encoded_value (0, info
.call_site_encoding
, p
, &cs_len
);
345 p
= read_encoded_value (0, info
.call_site_encoding
, p
, &cs_lp
);
346 p
= read_uleb128 (p
, &cs_action
);
348 /* The table is sorted, so if we've passed the ip, stop. */
349 if (ip
< info
.Start
+ cs_start
)
350 p
= info
.action_table
;
351 else if (ip
< info
.Start
+ cs_start
+ cs_len
)
354 landing_pad
= info
.LPStart
+ cs_lp
;
356 action_record
= info
.action_table
+ cs_action
- 1;
357 goto found_something
;
360 #endif /* SJLJ_EXCEPTIONS */
362 /* If ip is not present in the table, C++ would call terminate. */
363 /* ??? As with Java, it's perhaps better to tweek the LSDA to
364 that no-action is mapped to no-entry. */
371 if (landing_pad
== 0)
373 /* If ip is present, and has a null landing pad, there are
374 no cleanups or handlers to be run. */
376 else if (action_record
== 0)
378 /* If ip is present, has a non-null landing pad, and a null
379 action table offset, then there are only cleanups present.
380 Cleanups use a zero switch value, as set above. */
385 /* Otherwise we have a catch handler. */
386 _sleb128_t ar_filter
, ar_disp
;
391 p
= read_sleb128 (p
, &ar_filter
);
392 read_sleb128 (p
, &ar_disp
);
396 /* Zero filter values are cleanups. */
400 /* During forced unwinding, we only run cleanups. With a
401 foreign exception class, we have no class info to match. */
402 else if ((actions
& _UA_FORCE_UNWIND
) || foreign_exception
)
405 else if (ar_filter
> 0)
407 /* Positive filter values are handlers. */
409 Class catch_type
= get_ttype_entry (&info
, ar_filter
);
411 if (isKindOf (xh
->value
, catch_type
))
413 handler_switch_value
= ar_filter
;
420 /* Negative filter values are exception specifications,
421 which Objective-C does not use. */
427 action_record
= p
+ ar_disp
;
431 if (! saw_handler
&& ! saw_cleanup
)
434 if (actions
& _UA_SEARCH_PHASE
)
439 /* For domestic exceptions, we cache data from phase 1 for phase 2. */
440 if (!foreign_exception
)
442 #ifdef __ARM_EABI_UNWINDER__
443 ue_header
->barrier_cache
.sp
= _Unwind_GetGR (context
, 13);
444 ue_header
->barrier_cache
.bitpattern
[1] = (_uw
) handler_switch_value
;
445 ue_header
->barrier_cache
.bitpattern
[3] = (_uw
) landing_pad
;
447 xh
->handlerSwitchValue
= handler_switch_value
;
448 xh
->landingPad
= landing_pad
;
451 return _URC_HANDLER_FOUND
;
455 if (saw_cleanup
== 0)
457 return_object
= xh
->value
;
458 if (!(actions
& _UA_SEARCH_PHASE
))
459 _Unwind_DeleteException(&xh
->base
);
462 _Unwind_SetGR (context
, __builtin_eh_return_data_regno (0),
463 __builtin_extend_pointer (saw_cleanup
? xh
: return_object
));
464 _Unwind_SetGR (context
, __builtin_eh_return_data_regno (1),
465 handler_switch_value
);
466 _Unwind_SetIP (context
, landing_pad
);
467 return _URC_INSTALL_CONTEXT
;
471 __objc_exception_cleanup (_Unwind_Reason_Code code
__attribute__((unused
)),
472 struct _Unwind_Exception
*exc
)
478 objc_exception_throw (id value
)
480 struct ObjcException
*header
= calloc (1, sizeof (*header
));
482 memcpy (&header
->base
.exception_class
, &__objc_exception_class
,
483 sizeof (__objc_exception_class
));
484 header
->base
.exception_cleanup
= __objc_exception_cleanup
;
485 header
->value
= value
;
487 #ifdef SJLJ_EXCEPTIONS
488 _Unwind_SjLj_RaiseException (&header
->base
);
490 _Unwind_RaiseException (&header
->base
);
493 /* Some sort of unwinding error. */
494 if (_objc_unexpected_exception
!= 0)
496 (*_objc_unexpected_exception
) (value
);