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