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