1 /* The implementation of exception handling primitives for Objective-C.
2 Copyright (C) 2004 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, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, 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. */
28 #include "objc/objc-api.h"
30 #include "unwind-pe.h"
33 /* This is the exception class we report -- "GNUCOBJC". */
34 #define __objc_exception_class \
35 ((((((((_Unwind_Exception_Class) 'G' \
36 << 8 | (_Unwind_Exception_Class) 'N') \
37 << 8 | (_Unwind_Exception_Class) 'U') \
38 << 8 | (_Unwind_Exception_Class) 'C') \
39 << 8 | (_Unwind_Exception_Class) 'O') \
40 << 8 | (_Unwind_Exception_Class) 'B') \
41 << 8 | (_Unwind_Exception_Class) 'J') \
42 << 8 | (_Unwind_Exception_Class) 'C')
44 /* This is the object that is passed around by the Objective C runtime
45 to represent the exception in flight. */
49 /* This bit is needed in order to interact with the unwind runtime. */
50 struct _Unwind_Exception base
;
52 /* The actual object we want to throw. */
55 /* Cache some internal unwind data between phase 1 and phase 2. */
56 _Unwind_Ptr landingPad
;
57 int handlerSwitchValue
;
62 struct lsda_header_info
66 _Unwind_Ptr ttype_base
;
67 const unsigned char *TType
;
68 const unsigned char *action_table
;
69 unsigned char ttype_encoding
;
70 unsigned char call_site_encoding
;
73 static const unsigned char *
74 parse_lsda_header (struct _Unwind_Context
*context
, const unsigned char *p
,
75 struct lsda_header_info
*info
)
78 unsigned char lpstart_encoding
;
80 info
->Start
= (context
? _Unwind_GetRegionStart (context
) : 0);
82 /* Find @LPStart, the base to which landing pad offsets are relative. */
83 lpstart_encoding
= *p
++;
84 if (lpstart_encoding
!= DW_EH_PE_omit
)
85 p
= read_encoded_value (context
, lpstart_encoding
, p
, &info
->LPStart
);
87 info
->LPStart
= info
->Start
;
89 /* Find @TType, the base of the handler and exception spec type data. */
90 info
->ttype_encoding
= *p
++;
91 if (info
->ttype_encoding
!= DW_EH_PE_omit
)
93 p
= read_uleb128 (p
, &tmp
);
94 info
->TType
= p
+ tmp
;
99 /* The encoding and length of the call-site table; the action table
100 immediately follows. */
101 info
->call_site_encoding
= *p
++;
102 p
= read_uleb128 (p
, &tmp
);
103 info
->action_table
= p
+ tmp
;
109 get_ttype_entry (struct lsda_header_info
*info
, _Unwind_Word i
)
113 i
*= size_of_encoded_value (info
->ttype_encoding
);
114 read_encoded_value_with_base (info
->ttype_encoding
, info
->ttype_base
,
115 info
->TType
- i
, &ptr
);
117 /* NULL ptr means catch-all. */
119 return objc_get_class ((const char *) ptr
);
124 /* Like unto the method of the same name on Object, but takes an id. */
125 /* ??? Does this bork the meta-type system? Can/should we look up an
126 isKindOf method on the id? */
129 isKindOf (id value
, Class target
)
133 /* NULL target is catch-all. */
137 for (c
= value
->class_pointer
; c
; c
= class_get_super_class (c
))
143 /* Using a different personality function name causes link failures
144 when trying to mix code using different exception handling models. */
145 #ifdef SJLJ_EXCEPTIONS
146 #define PERSONALITY_FUNCTION __gnu_objc_personality_sj0
147 #define __builtin_eh_return_data_regno(x) x
149 #define PERSONALITY_FUNCTION __gnu_objc_personality_v0
153 PERSONALITY_FUNCTION (int version
,
154 _Unwind_Action actions
,
155 _Unwind_Exception_Class exception_class
,
156 struct _Unwind_Exception
*ue_header
,
157 struct _Unwind_Context
*context
)
159 struct ObjcException
*xh
= (struct ObjcException
*) ue_header
;
161 struct lsda_header_info info
;
162 const unsigned char *language_specific_data
;
163 const unsigned char *action_record
;
164 const unsigned char *p
;
165 _Unwind_Ptr landing_pad
, ip
;
166 int handler_switch_value
;
167 int saw_cleanup
, saw_handler
;
169 /* Interface version check. */
171 return _URC_FATAL_PHASE1_ERROR
;
173 /* Shortcut for phase 2 found handler for domestic exception. */
174 if (actions
== (_UA_CLEANUP_PHASE
| _UA_HANDLER_FRAME
)
175 && exception_class
== __objc_exception_class
)
177 handler_switch_value
= xh
->handlerSwitchValue
;
178 landing_pad
= xh
->landingPad
;
179 goto install_context
;
182 language_specific_data
= (const unsigned char *)
183 _Unwind_GetLanguageSpecificData (context
);
185 /* If no LSDA, then there are no handlers or cleanups. */
186 if (! language_specific_data
)
187 return _URC_CONTINUE_UNWIND
;
189 /* Parse the LSDA header. */
190 p
= parse_lsda_header (context
, language_specific_data
, &info
);
191 info
.ttype_base
= base_of_encoded_value (info
.ttype_encoding
, context
);
192 ip
= _Unwind_GetIP (context
) - 1;
195 handler_switch_value
= 0;
197 #ifdef SJLJ_EXCEPTIONS
198 /* The given "IP" is an index into the call-site table, with two
199 exceptions -- -1 means no-action, and 0 means terminate. But
200 since we're using uleb128 values, we've not got random access
203 return _URC_CONTINUE_UNWIND
;
206 _Unwind_Word cs_lp
, cs_action
;
209 p
= read_uleb128 (p
, &cs_lp
);
210 p
= read_uleb128 (p
, &cs_action
);
214 /* Can never have null landing pad for sjlj -- that would have
215 been indicated by a -1 call site index. */
216 landing_pad
= cs_lp
+ 1;
218 action_record
= info
.action_table
+ cs_action
- 1;
219 goto found_something
;
222 /* Search the call-site table for the action associated with this IP. */
223 while (p
< info
.action_table
)
225 _Unwind_Ptr cs_start
, cs_len
, cs_lp
;
226 _Unwind_Word cs_action
;
228 /* Note that all call-site encodings are "absolute" displacements. */
229 p
= read_encoded_value (0, info
.call_site_encoding
, p
, &cs_start
);
230 p
= read_encoded_value (0, info
.call_site_encoding
, p
, &cs_len
);
231 p
= read_encoded_value (0, info
.call_site_encoding
, p
, &cs_lp
);
232 p
= read_uleb128 (p
, &cs_action
);
234 /* The table is sorted, so if we've passed the ip, stop. */
235 if (ip
< info
.Start
+ cs_start
)
236 p
= info
.action_table
;
237 else if (ip
< info
.Start
+ cs_start
+ cs_len
)
240 landing_pad
= info
.LPStart
+ cs_lp
;
242 action_record
= info
.action_table
+ cs_action
- 1;
243 goto found_something
;
246 #endif /* SJLJ_EXCEPTIONS */
248 /* If ip is not present in the table, C++ would call terminate. */
249 /* ??? As with Java, it's perhaps better to tweek the LSDA to
250 that no-action is mapped to no-entry. */
251 return _URC_CONTINUE_UNWIND
;
257 if (landing_pad
== 0)
259 /* If ip is present, and has a null landing pad, there are
260 no cleanups or handlers to be run. */
262 else if (action_record
== 0)
264 /* If ip is present, has a non-null landing pad, and a null
265 action table offset, then there are only cleanups present.
266 Cleanups use a zero switch value, as set above. */
271 /* Otherwise we have a catch handler. */
272 _Unwind_Sword ar_filter
, ar_disp
;
277 p
= read_sleb128 (p
, &ar_filter
);
278 read_sleb128 (p
, &ar_disp
);
282 /* Zero filter values are cleanups. */
286 /* During forced unwinding, we only run cleanups. With a
287 foreign exception class, we have no class info to match. */
288 else if ((actions
& _UA_FORCE_UNWIND
)
289 || exception_class
!= __objc_exception_class
)
292 else if (ar_filter
> 0)
294 /* Positive filter values are handlers. */
296 Class catch_type
= get_ttype_entry (&info
, ar_filter
);
298 if (isKindOf (xh
->value
, catch_type
))
300 handler_switch_value
= ar_filter
;
307 /* Negative filter values are exception specifications,
308 which Objective-C does not use. */
314 action_record
= p
+ ar_disp
;
318 if (! saw_handler
&& ! saw_cleanup
)
319 return _URC_CONTINUE_UNWIND
;
321 if (actions
& _UA_SEARCH_PHASE
)
324 return _URC_CONTINUE_UNWIND
;
326 /* For domestic exceptions, we cache data from phase 1 for phase 2. */
327 if (exception_class
== __objc_exception_class
)
329 xh
->handlerSwitchValue
= handler_switch_value
;
330 xh
->landingPad
= landing_pad
;
332 return _URC_HANDLER_FOUND
;
336 _Unwind_SetGR (context
, __builtin_eh_return_data_regno (0),
337 __builtin_extend_pointer (xh
->value
));
338 _Unwind_SetGR (context
, __builtin_eh_return_data_regno (1),
339 handler_switch_value
);
340 _Unwind_SetIP (context
, landing_pad
);
341 return _URC_INSTALL_CONTEXT
;
345 __objc_exception_cleanup (_Unwind_Reason_Code code
__attribute__((unused
)),
346 struct _Unwind_Exception
*exc
)
352 objc_exception_throw (id value
)
354 struct ObjcException
*header
= calloc (1, sizeof (*header
));
355 header
->base
.exception_class
= __objc_exception_class
;
356 header
->base
.exception_cleanup
= __objc_exception_cleanup
;
357 header
->value
= value
;
359 #ifdef _GLIBCXX_SJLJ_EXCEPTIONS
360 _Unwind_SjLj_RaiseException (&header
->base
);
362 _Unwind_RaiseException (&header
->base
);
365 /* Some sort of unwinding error. */