1*e4b17023SJohn Marino /* The implementation of exception handling primitives for Objective-C.
2*e4b17023SJohn Marino Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
3*e4b17023SJohn Marino
4*e4b17023SJohn Marino This file is part of GCC.
5*e4b17023SJohn Marino
6*e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify it
7*e4b17023SJohn Marino under the terms of the GNU General Public License as published by the
8*e4b17023SJohn Marino Free Software Foundation; either version 3, or (at your option) any
9*e4b17023SJohn Marino later version.
10*e4b17023SJohn Marino
11*e4b17023SJohn Marino GCC is distributed in the hope that it will be useful, but WITHOUT
12*e4b17023SJohn Marino ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13*e4b17023SJohn Marino FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14*e4b17023SJohn Marino License for more details.
15*e4b17023SJohn Marino
16*e4b17023SJohn Marino Under Section 7 of GPL version 3, you are granted additional
17*e4b17023SJohn Marino permissions described in the GCC Runtime Library Exception, version
18*e4b17023SJohn Marino 3.1, as published by the Free Software Foundation.
19*e4b17023SJohn Marino
20*e4b17023SJohn Marino You should have received a copy of the GNU General Public License and
21*e4b17023SJohn Marino a copy of the GCC Runtime Library Exception along with this program;
22*e4b17023SJohn Marino see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23*e4b17023SJohn Marino <http://www.gnu.org/licenses/>. */
24*e4b17023SJohn Marino
25*e4b17023SJohn Marino #include "objc-private/common.h"
26*e4b17023SJohn Marino #include <stdlib.h>
27*e4b17023SJohn Marino #include "config.h"
28*e4b17023SJohn Marino #include "objc/runtime.h"
29*e4b17023SJohn Marino #include "objc/objc-exception.h"
30*e4b17023SJohn Marino #include "unwind.h"
31*e4b17023SJohn Marino #include "unwind-pe.h"
32*e4b17023SJohn Marino #include <string.h> /* For memcpy */
33*e4b17023SJohn Marino
34*e4b17023SJohn Marino /* 'is_kind_of_exception_matcher' is our default exception matcher -
35*e4b17023SJohn Marino it determines if the object 'exception' is of class 'catch_class',
36*e4b17023SJohn Marino or of a subclass. */
37*e4b17023SJohn Marino static int
is_kind_of_exception_matcher(Class catch_class,id exception)38*e4b17023SJohn Marino is_kind_of_exception_matcher (Class catch_class, id exception)
39*e4b17023SJohn Marino {
40*e4b17023SJohn Marino /* NULL catch_class is catch-all (eg, @catch (id object)). */
41*e4b17023SJohn Marino if (catch_class == Nil)
42*e4b17023SJohn Marino return 1;
43*e4b17023SJohn Marino
44*e4b17023SJohn Marino /* If exception is nil (eg, @throw nil;), then it can only be
45*e4b17023SJohn Marino catched by a catch-all (eg, @catch (id object)). */
46*e4b17023SJohn Marino if (exception != nil)
47*e4b17023SJohn Marino {
48*e4b17023SJohn Marino Class c;
49*e4b17023SJohn Marino
50*e4b17023SJohn Marino for (c = exception->class_pointer; c != Nil;
51*e4b17023SJohn Marino c = class_getSuperclass (c))
52*e4b17023SJohn Marino if (c == catch_class)
53*e4b17023SJohn Marino return 1;
54*e4b17023SJohn Marino }
55*e4b17023SJohn Marino return 0;
56*e4b17023SJohn Marino }
57*e4b17023SJohn Marino
58*e4b17023SJohn Marino /* The exception matcher currently in use. */
59*e4b17023SJohn Marino static objc_exception_matcher
60*e4b17023SJohn Marino __objc_exception_matcher = is_kind_of_exception_matcher;
61*e4b17023SJohn Marino
62*e4b17023SJohn Marino objc_exception_matcher
objc_setExceptionMatcher(objc_exception_matcher new_matcher)63*e4b17023SJohn Marino objc_setExceptionMatcher (objc_exception_matcher new_matcher)
64*e4b17023SJohn Marino {
65*e4b17023SJohn Marino objc_exception_matcher old_matcher = __objc_exception_matcher;
66*e4b17023SJohn Marino __objc_exception_matcher = new_matcher;
67*e4b17023SJohn Marino return old_matcher;
68*e4b17023SJohn Marino }
69*e4b17023SJohn Marino
70*e4b17023SJohn Marino /* The uncaught exception handler currently in use. */
71*e4b17023SJohn Marino static objc_uncaught_exception_handler
72*e4b17023SJohn Marino __objc_uncaught_exception_handler = NULL;
73*e4b17023SJohn Marino
74*e4b17023SJohn Marino objc_uncaught_exception_handler
objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler new_handler)75*e4b17023SJohn Marino objc_setUncaughtExceptionHandler (objc_uncaught_exception_handler
76*e4b17023SJohn Marino new_handler)
77*e4b17023SJohn Marino {
78*e4b17023SJohn Marino objc_uncaught_exception_handler old_handler
79*e4b17023SJohn Marino = __objc_uncaught_exception_handler;
80*e4b17023SJohn Marino __objc_uncaught_exception_handler = new_handler;
81*e4b17023SJohn Marino return old_handler;
82*e4b17023SJohn Marino }
83*e4b17023SJohn Marino
84*e4b17023SJohn Marino
85*e4b17023SJohn Marino
86*e4b17023SJohn Marino #ifdef __ARM_EABI_UNWINDER__
87*e4b17023SJohn Marino
88*e4b17023SJohn Marino const _Unwind_Exception_Class __objc_exception_class
89*e4b17023SJohn Marino = {'G', 'N', 'U', 'C', 'O', 'B', 'J', 'C'};
90*e4b17023SJohn Marino
91*e4b17023SJohn Marino #else
92*e4b17023SJohn Marino
93*e4b17023SJohn Marino /* This is the exception class we report -- "GNUCOBJC". */
94*e4b17023SJohn Marino static const _Unwind_Exception_Class __objc_exception_class
95*e4b17023SJohn Marino = ((((((((_Unwind_Exception_Class) 'G'
96*e4b17023SJohn Marino << 8 | (_Unwind_Exception_Class) 'N')
97*e4b17023SJohn Marino << 8 | (_Unwind_Exception_Class) 'U')
98*e4b17023SJohn Marino << 8 | (_Unwind_Exception_Class) 'C')
99*e4b17023SJohn Marino << 8 | (_Unwind_Exception_Class) 'O')
100*e4b17023SJohn Marino << 8 | (_Unwind_Exception_Class) 'B')
101*e4b17023SJohn Marino << 8 | (_Unwind_Exception_Class) 'J')
102*e4b17023SJohn Marino << 8 | (_Unwind_Exception_Class) 'C');
103*e4b17023SJohn Marino
104*e4b17023SJohn Marino #endif
105*e4b17023SJohn Marino
106*e4b17023SJohn Marino /* This is the object that is passed around by the Objective C runtime
107*e4b17023SJohn Marino to represent the exception in flight. */
108*e4b17023SJohn Marino struct ObjcException
109*e4b17023SJohn Marino {
110*e4b17023SJohn Marino /* This bit is needed in order to interact with the unwind runtime. */
111*e4b17023SJohn Marino struct _Unwind_Exception base;
112*e4b17023SJohn Marino
113*e4b17023SJohn Marino /* The actual object we want to throw. Note: must come immediately
114*e4b17023SJohn Marino after unwind header. */
115*e4b17023SJohn Marino id value;
116*e4b17023SJohn Marino
117*e4b17023SJohn Marino #ifdef __ARM_EABI_UNWINDER__
118*e4b17023SJohn Marino /* Note: we use the barrier cache defined in the unwind control
119*e4b17023SJohn Marino block for ARM EABI. */
120*e4b17023SJohn Marino #else
121*e4b17023SJohn Marino /* Cache some internal unwind data between phase 1 and phase 2. */
122*e4b17023SJohn Marino _Unwind_Ptr landingPad;
123*e4b17023SJohn Marino int handlerSwitchValue;
124*e4b17023SJohn Marino #endif
125*e4b17023SJohn Marino };
126*e4b17023SJohn Marino
127*e4b17023SJohn Marino
128*e4b17023SJohn Marino
129*e4b17023SJohn Marino struct lsda_header_info
130*e4b17023SJohn Marino {
131*e4b17023SJohn Marino _Unwind_Ptr Start;
132*e4b17023SJohn Marino _Unwind_Ptr LPStart;
133*e4b17023SJohn Marino _Unwind_Ptr ttype_base;
134*e4b17023SJohn Marino const unsigned char *TType;
135*e4b17023SJohn Marino const unsigned char *action_table;
136*e4b17023SJohn Marino unsigned char ttype_encoding;
137*e4b17023SJohn Marino unsigned char call_site_encoding;
138*e4b17023SJohn Marino };
139*e4b17023SJohn Marino
140*e4b17023SJohn Marino static const unsigned char *
parse_lsda_header(struct _Unwind_Context * context,const unsigned char * p,struct lsda_header_info * info)141*e4b17023SJohn Marino parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
142*e4b17023SJohn Marino struct lsda_header_info *info)
143*e4b17023SJohn Marino {
144*e4b17023SJohn Marino _uleb128_t tmp;
145*e4b17023SJohn Marino unsigned char lpstart_encoding;
146*e4b17023SJohn Marino
147*e4b17023SJohn Marino info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
148*e4b17023SJohn Marino
149*e4b17023SJohn Marino /* Find @LPStart, the base to which landing pad offsets are
150*e4b17023SJohn Marino relative. */
151*e4b17023SJohn Marino lpstart_encoding = *p++;
152*e4b17023SJohn Marino if (lpstart_encoding != DW_EH_PE_omit)
153*e4b17023SJohn Marino p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
154*e4b17023SJohn Marino else
155*e4b17023SJohn Marino info->LPStart = info->Start;
156*e4b17023SJohn Marino
157*e4b17023SJohn Marino /* Find @TType, the base of the handler and exception spec type
158*e4b17023SJohn Marino data. */
159*e4b17023SJohn Marino info->ttype_encoding = *p++;
160*e4b17023SJohn Marino if (info->ttype_encoding != DW_EH_PE_omit)
161*e4b17023SJohn Marino {
162*e4b17023SJohn Marino #if _GLIBCXX_OVERRIDE_TTYPE_ENCODING
163*e4b17023SJohn Marino /* Older ARM EABI toolchains set this value incorrectly, so use a
164*e4b17023SJohn Marino hardcoded OS-specific format. */
165*e4b17023SJohn Marino info->ttype_encoding = _GLIBCXX_OVERRIDE_TTYPE_ENCODING;
166*e4b17023SJohn Marino #endif
167*e4b17023SJohn Marino p = read_uleb128 (p, &tmp);
168*e4b17023SJohn Marino info->TType = p + tmp;
169*e4b17023SJohn Marino }
170*e4b17023SJohn Marino else
171*e4b17023SJohn Marino info->TType = 0;
172*e4b17023SJohn Marino
173*e4b17023SJohn Marino /* The encoding and length of the call-site table; the action table
174*e4b17023SJohn Marino immediately follows. */
175*e4b17023SJohn Marino info->call_site_encoding = *p++;
176*e4b17023SJohn Marino p = read_uleb128 (p, &tmp);
177*e4b17023SJohn Marino info->action_table = p + tmp;
178*e4b17023SJohn Marino
179*e4b17023SJohn Marino return p;
180*e4b17023SJohn Marino }
181*e4b17023SJohn Marino
182*e4b17023SJohn Marino static Class
get_ttype_entry(struct lsda_header_info * info,_Unwind_Word i)183*e4b17023SJohn Marino get_ttype_entry (struct lsda_header_info *info, _Unwind_Word i)
184*e4b17023SJohn Marino {
185*e4b17023SJohn Marino _Unwind_Ptr ptr;
186*e4b17023SJohn Marino
187*e4b17023SJohn Marino i *= size_of_encoded_value (info->ttype_encoding);
188*e4b17023SJohn Marino read_encoded_value_with_base (info->ttype_encoding, info->ttype_base,
189*e4b17023SJohn Marino info->TType - i, &ptr);
190*e4b17023SJohn Marino
191*e4b17023SJohn Marino /* NULL ptr means catch-all. Note that if the class is not found,
192*e4b17023SJohn Marino this will abort the program. */
193*e4b17023SJohn Marino if (ptr)
194*e4b17023SJohn Marino return objc_getRequiredClass ((const char *) ptr);
195*e4b17023SJohn Marino else
196*e4b17023SJohn Marino return 0;
197*e4b17023SJohn Marino }
198*e4b17023SJohn Marino
199*e4b17023SJohn Marino /* Using a different personality function name causes link failures
200*e4b17023SJohn Marino when trying to mix code using different exception handling
201*e4b17023SJohn Marino models. */
202*e4b17023SJohn Marino #ifdef SJLJ_EXCEPTIONS
203*e4b17023SJohn Marino #define PERSONALITY_FUNCTION __gnu_objc_personality_sj0
204*e4b17023SJohn Marino #define __builtin_eh_return_data_regno(x) x
205*e4b17023SJohn Marino #else
206*e4b17023SJohn Marino #define PERSONALITY_FUNCTION __gnu_objc_personality_v0
207*e4b17023SJohn Marino #endif
208*e4b17023SJohn Marino
209*e4b17023SJohn Marino #ifdef __ARM_EABI_UNWINDER__
210*e4b17023SJohn Marino
211*e4b17023SJohn Marino #define CONTINUE_UNWINDING \
212*e4b17023SJohn Marino do \
213*e4b17023SJohn Marino { \
214*e4b17023SJohn Marino if (__gnu_unwind_frame(ue_header, context) != _URC_OK) \
215*e4b17023SJohn Marino return _URC_FAILURE; \
216*e4b17023SJohn Marino return _URC_CONTINUE_UNWIND; \
217*e4b17023SJohn Marino } \
218*e4b17023SJohn Marino while (0)
219*e4b17023SJohn Marino
220*e4b17023SJohn Marino _Unwind_Reason_Code
PERSONALITY_FUNCTION(_Unwind_State state,struct _Unwind_Exception * ue_header,struct _Unwind_Context * context)221*e4b17023SJohn Marino PERSONALITY_FUNCTION (_Unwind_State state,
222*e4b17023SJohn Marino struct _Unwind_Exception *ue_header,
223*e4b17023SJohn Marino struct _Unwind_Context *context)
224*e4b17023SJohn Marino #else
225*e4b17023SJohn Marino
226*e4b17023SJohn Marino #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
227*e4b17023SJohn Marino
228*e4b17023SJohn Marino _Unwind_Reason_Code
229*e4b17023SJohn Marino PERSONALITY_FUNCTION (int version,
230*e4b17023SJohn Marino _Unwind_Action actions,
231*e4b17023SJohn Marino _Unwind_Exception_Class exception_class,
232*e4b17023SJohn Marino struct _Unwind_Exception *ue_header,
233*e4b17023SJohn Marino struct _Unwind_Context *context)
234*e4b17023SJohn Marino #endif
235*e4b17023SJohn Marino {
236*e4b17023SJohn Marino struct ObjcException *xh = (struct ObjcException *) ue_header;
237*e4b17023SJohn Marino
238*e4b17023SJohn Marino struct lsda_header_info info;
239*e4b17023SJohn Marino const unsigned char *language_specific_data;
240*e4b17023SJohn Marino const unsigned char *action_record;
241*e4b17023SJohn Marino const unsigned char *p;
242*e4b17023SJohn Marino _Unwind_Ptr landing_pad, ip;
243*e4b17023SJohn Marino int handler_switch_value;
244*e4b17023SJohn Marino int saw_cleanup = 0, saw_handler, foreign_exception;
245*e4b17023SJohn Marino void *return_object;
246*e4b17023SJohn Marino int ip_before_insn = 0;
247*e4b17023SJohn Marino
248*e4b17023SJohn Marino #ifdef __ARM_EABI_UNWINDER__
249*e4b17023SJohn Marino _Unwind_Action actions;
250*e4b17023SJohn Marino
251*e4b17023SJohn Marino switch (state & _US_ACTION_MASK)
252*e4b17023SJohn Marino {
253*e4b17023SJohn Marino case _US_VIRTUAL_UNWIND_FRAME:
254*e4b17023SJohn Marino actions = _UA_SEARCH_PHASE;
255*e4b17023SJohn Marino break;
256*e4b17023SJohn Marino
257*e4b17023SJohn Marino case _US_UNWIND_FRAME_STARTING:
258*e4b17023SJohn Marino actions = _UA_CLEANUP_PHASE;
259*e4b17023SJohn Marino if (!(state & _US_FORCE_UNWIND)
260*e4b17023SJohn Marino && ue_header->barrier_cache.sp == _Unwind_GetGR (context, 13))
261*e4b17023SJohn Marino actions |= _UA_HANDLER_FRAME;
262*e4b17023SJohn Marino break;
263*e4b17023SJohn Marino
264*e4b17023SJohn Marino case _US_UNWIND_FRAME_RESUME:
265*e4b17023SJohn Marino CONTINUE_UNWINDING;
266*e4b17023SJohn Marino break;
267*e4b17023SJohn Marino
268*e4b17023SJohn Marino default:
269*e4b17023SJohn Marino abort();
270*e4b17023SJohn Marino }
271*e4b17023SJohn Marino actions |= state & _US_FORCE_UNWIND;
272*e4b17023SJohn Marino
273*e4b17023SJohn Marino /* TODO: Foreign exceptions need some attention (e.g. rethrowing
274*e4b17023SJohn Marino doesn't work). */
275*e4b17023SJohn Marino foreign_exception = 0;
276*e4b17023SJohn Marino
277*e4b17023SJohn Marino /* The dwarf unwinder assumes the context structure holds things
278*e4b17023SJohn Marino like the function and LSDA pointers. The ARM implementation
279*e4b17023SJohn Marino caches these in the exception header (UCB). To avoid rewriting
280*e4b17023SJohn Marino everything we make the virtual IP register point at the UCB. */
281*e4b17023SJohn Marino ip = (_Unwind_Ptr) ue_header;
282*e4b17023SJohn Marino _Unwind_SetGR (context, 12, ip);
283*e4b17023SJohn Marino
284*e4b17023SJohn Marino #else /* !__ARM_EABI_UNWINDER. */
285*e4b17023SJohn Marino /* Interface version check. */
286*e4b17023SJohn Marino if (version != 1)
287*e4b17023SJohn Marino return _URC_FATAL_PHASE1_ERROR;
288*e4b17023SJohn Marino
289*e4b17023SJohn Marino foreign_exception = (exception_class != __objc_exception_class);
290*e4b17023SJohn Marino #endif
291*e4b17023SJohn Marino
292*e4b17023SJohn Marino /* Shortcut for phase 2 found handler for domestic exception. */
293*e4b17023SJohn Marino if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME)
294*e4b17023SJohn Marino && !foreign_exception)
295*e4b17023SJohn Marino {
296*e4b17023SJohn Marino #ifdef __ARM_EABI_UNWINDER__
297*e4b17023SJohn Marino handler_switch_value = (int) ue_header->barrier_cache.bitpattern[1];
298*e4b17023SJohn Marino landing_pad = (_Unwind_Ptr) ue_header->barrier_cache.bitpattern[3];
299*e4b17023SJohn Marino #else
300*e4b17023SJohn Marino handler_switch_value = xh->handlerSwitchValue;
301*e4b17023SJohn Marino landing_pad = xh->landingPad;
302*e4b17023SJohn Marino #endif
303*e4b17023SJohn Marino goto install_context;
304*e4b17023SJohn Marino }
305*e4b17023SJohn Marino
306*e4b17023SJohn Marino language_specific_data = (const unsigned char *)
307*e4b17023SJohn Marino _Unwind_GetLanguageSpecificData (context);
308*e4b17023SJohn Marino
309*e4b17023SJohn Marino /* If no LSDA, then there are no handlers or cleanups. */
310*e4b17023SJohn Marino if (! language_specific_data)
311*e4b17023SJohn Marino CONTINUE_UNWINDING;
312*e4b17023SJohn Marino
313*e4b17023SJohn Marino /* Parse the LSDA header. */
314*e4b17023SJohn Marino p = parse_lsda_header (context, language_specific_data, &info);
315*e4b17023SJohn Marino info.ttype_base = base_of_encoded_value (info.ttype_encoding, context);
316*e4b17023SJohn Marino #ifdef HAVE_GETIPINFO
317*e4b17023SJohn Marino ip = _Unwind_GetIPInfo (context, &ip_before_insn);
318*e4b17023SJohn Marino #else
319*e4b17023SJohn Marino ip = _Unwind_GetIP (context);
320*e4b17023SJohn Marino #endif
321*e4b17023SJohn Marino if (!ip_before_insn)
322*e4b17023SJohn Marino --ip;
323*e4b17023SJohn Marino landing_pad = 0;
324*e4b17023SJohn Marino action_record = 0;
325*e4b17023SJohn Marino handler_switch_value = 0;
326*e4b17023SJohn Marino
327*e4b17023SJohn Marino #ifdef SJLJ_EXCEPTIONS
328*e4b17023SJohn Marino /* The given "IP" is an index into the call-site table, with two
329*e4b17023SJohn Marino exceptions -- -1 means no-action, and 0 means terminate. But
330*e4b17023SJohn Marino since we're using uleb128 values, we've not got random access to
331*e4b17023SJohn Marino the array. */
332*e4b17023SJohn Marino if ((int) ip < 0)
333*e4b17023SJohn Marino return _URC_CONTINUE_UNWIND;
334*e4b17023SJohn Marino else
335*e4b17023SJohn Marino {
336*e4b17023SJohn Marino _uleb128_t cs_lp, cs_action;
337*e4b17023SJohn Marino do
338*e4b17023SJohn Marino {
339*e4b17023SJohn Marino p = read_uleb128 (p, &cs_lp);
340*e4b17023SJohn Marino p = read_uleb128 (p, &cs_action);
341*e4b17023SJohn Marino }
342*e4b17023SJohn Marino while (--ip);
343*e4b17023SJohn Marino
344*e4b17023SJohn Marino /* Can never have null landing pad for sjlj -- that would have
345*e4b17023SJohn Marino been indicated by a -1 call site index. */
346*e4b17023SJohn Marino landing_pad = cs_lp + 1;
347*e4b17023SJohn Marino if (cs_action)
348*e4b17023SJohn Marino action_record = info.action_table + cs_action - 1;
349*e4b17023SJohn Marino goto found_something;
350*e4b17023SJohn Marino }
351*e4b17023SJohn Marino #else
352*e4b17023SJohn Marino /* Search the call-site table for the action associated with this
353*e4b17023SJohn Marino IP. */
354*e4b17023SJohn Marino while (p < info.action_table)
355*e4b17023SJohn Marino {
356*e4b17023SJohn Marino _Unwind_Ptr cs_start, cs_len, cs_lp;
357*e4b17023SJohn Marino _uleb128_t cs_action;
358*e4b17023SJohn Marino
359*e4b17023SJohn Marino /* Note that all call-site encodings are "absolute"
360*e4b17023SJohn Marino displacements. */
361*e4b17023SJohn Marino p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
362*e4b17023SJohn Marino p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
363*e4b17023SJohn Marino p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
364*e4b17023SJohn Marino p = read_uleb128 (p, &cs_action);
365*e4b17023SJohn Marino
366*e4b17023SJohn Marino /* The table is sorted, so if we've passed the ip, stop. */
367*e4b17023SJohn Marino if (ip < info.Start + cs_start)
368*e4b17023SJohn Marino p = info.action_table;
369*e4b17023SJohn Marino else if (ip < info.Start + cs_start + cs_len)
370*e4b17023SJohn Marino {
371*e4b17023SJohn Marino if (cs_lp)
372*e4b17023SJohn Marino landing_pad = info.LPStart + cs_lp;
373*e4b17023SJohn Marino if (cs_action)
374*e4b17023SJohn Marino action_record = info.action_table + cs_action - 1;
375*e4b17023SJohn Marino goto found_something;
376*e4b17023SJohn Marino }
377*e4b17023SJohn Marino }
378*e4b17023SJohn Marino #endif /* SJLJ_EXCEPTIONS */
379*e4b17023SJohn Marino
380*e4b17023SJohn Marino /* If ip is not present in the table, C++ would call terminate. */
381*e4b17023SJohn Marino /* ??? As with Java, it's perhaps better to tweek the LSDA to that
382*e4b17023SJohn Marino no-action is mapped to no-entry. */
383*e4b17023SJohn Marino CONTINUE_UNWINDING;
384*e4b17023SJohn Marino
385*e4b17023SJohn Marino found_something:
386*e4b17023SJohn Marino saw_cleanup = 0;
387*e4b17023SJohn Marino saw_handler = 0;
388*e4b17023SJohn Marino
389*e4b17023SJohn Marino if (landing_pad == 0)
390*e4b17023SJohn Marino {
391*e4b17023SJohn Marino /* If ip is present, and has a null landing pad, there are no
392*e4b17023SJohn Marino cleanups or handlers to be run. */
393*e4b17023SJohn Marino }
394*e4b17023SJohn Marino else if (action_record == 0)
395*e4b17023SJohn Marino {
396*e4b17023SJohn Marino /* If ip is present, has a non-null landing pad, and a null
397*e4b17023SJohn Marino action table offset, then there are only cleanups present.
398*e4b17023SJohn Marino Cleanups use a zero switch value, as set above. */
399*e4b17023SJohn Marino saw_cleanup = 1;
400*e4b17023SJohn Marino }
401*e4b17023SJohn Marino else
402*e4b17023SJohn Marino {
403*e4b17023SJohn Marino /* Otherwise we have a catch handler. */
404*e4b17023SJohn Marino _sleb128_t ar_filter, ar_disp;
405*e4b17023SJohn Marino
406*e4b17023SJohn Marino while (1)
407*e4b17023SJohn Marino {
408*e4b17023SJohn Marino p = action_record;
409*e4b17023SJohn Marino p = read_sleb128 (p, &ar_filter);
410*e4b17023SJohn Marino read_sleb128 (p, &ar_disp);
411*e4b17023SJohn Marino
412*e4b17023SJohn Marino if (ar_filter == 0)
413*e4b17023SJohn Marino {
414*e4b17023SJohn Marino /* Zero filter values are cleanups. */
415*e4b17023SJohn Marino saw_cleanup = 1;
416*e4b17023SJohn Marino }
417*e4b17023SJohn Marino
418*e4b17023SJohn Marino /* During forced unwinding, we only run cleanups. With a
419*e4b17023SJohn Marino foreign exception class, we have no class info to
420*e4b17023SJohn Marino match. */
421*e4b17023SJohn Marino else if ((actions & _UA_FORCE_UNWIND) || foreign_exception)
422*e4b17023SJohn Marino ;
423*e4b17023SJohn Marino
424*e4b17023SJohn Marino else if (ar_filter > 0)
425*e4b17023SJohn Marino {
426*e4b17023SJohn Marino /* Positive filter values are handlers. */
427*e4b17023SJohn Marino Class catch_type = get_ttype_entry (&info, ar_filter);
428*e4b17023SJohn Marino
429*e4b17023SJohn Marino if ((*__objc_exception_matcher) (catch_type, xh->value))
430*e4b17023SJohn Marino {
431*e4b17023SJohn Marino handler_switch_value = ar_filter;
432*e4b17023SJohn Marino saw_handler = 1;
433*e4b17023SJohn Marino break;
434*e4b17023SJohn Marino }
435*e4b17023SJohn Marino }
436*e4b17023SJohn Marino else
437*e4b17023SJohn Marino {
438*e4b17023SJohn Marino /* Negative filter values are exception specifications,
439*e4b17023SJohn Marino which Objective-C does not use. */
440*e4b17023SJohn Marino abort ();
441*e4b17023SJohn Marino }
442*e4b17023SJohn Marino
443*e4b17023SJohn Marino if (ar_disp == 0)
444*e4b17023SJohn Marino break;
445*e4b17023SJohn Marino action_record = p + ar_disp;
446*e4b17023SJohn Marino }
447*e4b17023SJohn Marino }
448*e4b17023SJohn Marino
449*e4b17023SJohn Marino if (! saw_handler && ! saw_cleanup)
450*e4b17023SJohn Marino CONTINUE_UNWINDING;
451*e4b17023SJohn Marino
452*e4b17023SJohn Marino if (actions & _UA_SEARCH_PHASE)
453*e4b17023SJohn Marino {
454*e4b17023SJohn Marino if (!saw_handler)
455*e4b17023SJohn Marino CONTINUE_UNWINDING;
456*e4b17023SJohn Marino
457*e4b17023SJohn Marino /* For domestic exceptions, we cache data from phase 1 for phase
458*e4b17023SJohn Marino 2. */
459*e4b17023SJohn Marino if (!foreign_exception)
460*e4b17023SJohn Marino {
461*e4b17023SJohn Marino #ifdef __ARM_EABI_UNWINDER__
462*e4b17023SJohn Marino ue_header->barrier_cache.sp = _Unwind_GetGR (context, 13);
463*e4b17023SJohn Marino ue_header->barrier_cache.bitpattern[1] = (_uw) handler_switch_value;
464*e4b17023SJohn Marino ue_header->barrier_cache.bitpattern[3] = (_uw) landing_pad;
465*e4b17023SJohn Marino #else
466*e4b17023SJohn Marino xh->handlerSwitchValue = handler_switch_value;
467*e4b17023SJohn Marino xh->landingPad = landing_pad;
468*e4b17023SJohn Marino #endif
469*e4b17023SJohn Marino }
470*e4b17023SJohn Marino return _URC_HANDLER_FOUND;
471*e4b17023SJohn Marino }
472*e4b17023SJohn Marino
473*e4b17023SJohn Marino install_context:
474*e4b17023SJohn Marino if (saw_cleanup == 0)
475*e4b17023SJohn Marino {
476*e4b17023SJohn Marino return_object = xh->value;
477*e4b17023SJohn Marino if (!(actions & _UA_SEARCH_PHASE))
478*e4b17023SJohn Marino _Unwind_DeleteException(&xh->base);
479*e4b17023SJohn Marino }
480*e4b17023SJohn Marino
481*e4b17023SJohn Marino _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
482*e4b17023SJohn Marino __builtin_extend_pointer (saw_cleanup ? xh : return_object));
483*e4b17023SJohn Marino _Unwind_SetGR (context, __builtin_eh_return_data_regno (1),
484*e4b17023SJohn Marino handler_switch_value);
485*e4b17023SJohn Marino _Unwind_SetIP (context, landing_pad);
486*e4b17023SJohn Marino return _URC_INSTALL_CONTEXT;
487*e4b17023SJohn Marino }
488*e4b17023SJohn Marino
489*e4b17023SJohn Marino static void
__objc_exception_cleanup(_Unwind_Reason_Code code,struct _Unwind_Exception * exc)490*e4b17023SJohn Marino __objc_exception_cleanup (_Unwind_Reason_Code code __attribute__((unused)),
491*e4b17023SJohn Marino struct _Unwind_Exception *exc)
492*e4b17023SJohn Marino {
493*e4b17023SJohn Marino free (exc);
494*e4b17023SJohn Marino }
495*e4b17023SJohn Marino
496*e4b17023SJohn Marino void
objc_exception_throw(id exception)497*e4b17023SJohn Marino objc_exception_throw (id exception)
498*e4b17023SJohn Marino {
499*e4b17023SJohn Marino struct ObjcException *header = calloc (1, sizeof (*header));
500*e4b17023SJohn Marino
501*e4b17023SJohn Marino memcpy (&header->base.exception_class, &__objc_exception_class,
502*e4b17023SJohn Marino sizeof (__objc_exception_class));
503*e4b17023SJohn Marino header->base.exception_cleanup = __objc_exception_cleanup;
504*e4b17023SJohn Marino header->value = exception;
505*e4b17023SJohn Marino
506*e4b17023SJohn Marino #ifdef SJLJ_EXCEPTIONS
507*e4b17023SJohn Marino _Unwind_SjLj_RaiseException (&header->base);
508*e4b17023SJohn Marino #else
509*e4b17023SJohn Marino _Unwind_RaiseException (&header->base);
510*e4b17023SJohn Marino #endif
511*e4b17023SJohn Marino
512*e4b17023SJohn Marino /* No exception handler was installed. Call the uncaught exception
513*e4b17023SJohn Marino handler if any is defined. */
514*e4b17023SJohn Marino if (__objc_uncaught_exception_handler != 0)
515*e4b17023SJohn Marino {
516*e4b17023SJohn Marino (*__objc_uncaught_exception_handler) (exception);
517*e4b17023SJohn Marino }
518*e4b17023SJohn Marino
519*e4b17023SJohn Marino abort ();
520*e4b17023SJohn Marino }
521*e4b17023SJohn Marino
522