xref: /dflybsd-src/contrib/gcc-4.7/libobjc/exception.c (revision 04febcfb30580676d3e95f58a16c5137ee478b32)
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