]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-exception.mm
objc4-750.tar.gz
[apple/objc4.git] / runtime / objc-exception.mm
1 /*
2 * Copyright (c) 2002-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #if !__OBJC2__
25
26 /***********************************************************************
27 * 32-bit implementation
28 **********************************************************************/
29
30 #include "objc-private.h"
31 #include <stdlib.h>
32 #include <setjmp.h>
33 #include <execinfo.h>
34
35 #include "objc-exception.h"
36
37 static objc_exception_functions_t xtab;
38
39 // forward declaration
40 static void set_default_handlers();
41
42
43 /*
44 * Exported functions
45 */
46
47 // get table; version tells how many
48 void objc_exception_get_functions(objc_exception_functions_t *table) {
49 // only version 0 supported at this point
50 if (table && table->version == 0)
51 *table = xtab;
52 }
53
54 // set table
55 void objc_exception_set_functions(objc_exception_functions_t *table) {
56 // only version 0 supported at this point
57 if (table && table->version == 0)
58 xtab = *table;
59 }
60
61 /*
62 * The following functions are
63 * synthesized by the compiler upon encountering language constructs
64 */
65
66 void objc_exception_throw(id exception) {
67 if (!xtab.throw_exc) {
68 set_default_handlers();
69 }
70
71 if (PrintExceptionThrow) {
72 _objc_inform("EXCEPTIONS: throwing %p (%s)",
73 (void*)exception, object_getClassName(exception));
74 void* callstack[500];
75 int frameCount = backtrace(callstack, 500);
76 backtrace_symbols_fd(callstack, frameCount, fileno(stderr));
77 }
78
79 OBJC_RUNTIME_OBJC_EXCEPTION_THROW(exception); // dtrace probe to log throw activity.
80 xtab.throw_exc(exception);
81 _objc_fatal("objc_exception_throw failed");
82 }
83
84 void objc_exception_try_enter(void *localExceptionData) {
85 if (!xtab.throw_exc) {
86 set_default_handlers();
87 }
88 xtab.try_enter(localExceptionData);
89 }
90
91
92 void objc_exception_try_exit(void *localExceptionData) {
93 if (!xtab.throw_exc) {
94 set_default_handlers();
95 }
96 xtab.try_exit(localExceptionData);
97 }
98
99
100 id objc_exception_extract(void *localExceptionData) {
101 if (!xtab.throw_exc) {
102 set_default_handlers();
103 }
104 return xtab.extract(localExceptionData);
105 }
106
107
108 int objc_exception_match(Class exceptionClass, id exception) {
109 if (!xtab.throw_exc) {
110 set_default_handlers();
111 }
112 return xtab.match(exceptionClass, exception);
113 }
114
115
116 // quick and dirty exception handling code
117 // default implementation - mostly a toy for use outside/before Foundation
118 // provides its implementation
119 // Perhaps the default implementation should just complain loudly and quit
120
121
122 extern void _objc_inform(const char *fmt, ...);
123
124 typedef struct { jmp_buf buf; void *pointers[4]; } LocalData_t;
125
126 typedef struct _threadChain {
127 LocalData_t *topHandler;
128 objc_thread_t perThreadID;
129 struct _threadChain *next;
130 }
131 ThreadChainLink_t;
132
133 static ThreadChainLink_t ThreadChainLink;
134
135 static ThreadChainLink_t *getChainLink() {
136 // follow links until thread_self() found (someday) XXX
137 objc_thread_t self = thread_self();
138 ThreadChainLink_t *walker = &ThreadChainLink;
139 while (walker->perThreadID != self) {
140 if (walker->next != nil) {
141 walker = walker->next;
142 continue;
143 }
144 // create a new one
145 // XXX not thread safe (!)
146 // XXX Also, we don't register to deallocate on thread death
147 walker->next = (ThreadChainLink_t *)malloc(sizeof(ThreadChainLink_t));
148 walker = walker->next;
149 walker->next = nil;
150 walker->topHandler = nil;
151 walker->perThreadID = self;
152 }
153 return walker;
154 }
155
156 static void default_try_enter(void *localExceptionData) {
157 LocalData_t *data = (LocalData_t *)localExceptionData;
158 ThreadChainLink_t *chainLink = getChainLink();
159 data->pointers[1] = chainLink->topHandler;
160 chainLink->topHandler = data;
161 if (PrintExceptions) _objc_inform("EXCEPTIONS: entered try block %p\n", chainLink->topHandler);
162 }
163
164 static void default_throw(id value) {
165 ThreadChainLink_t *chainLink = getChainLink();
166 LocalData_t *led;
167 if (value == nil) {
168 if (PrintExceptions) _objc_inform("EXCEPTIONS: objc_exception_throw with nil value\n");
169 return;
170 }
171 if (chainLink == nil) {
172 if (PrintExceptions) _objc_inform("EXCEPTIONS: No handler in place!\n");
173 return;
174 }
175 if (PrintExceptions) _objc_inform("EXCEPTIONS: exception thrown, going to handler block %p\n", chainLink->topHandler);
176 led = chainLink->topHandler;
177 chainLink->topHandler = (LocalData_t *)
178 led->pointers[1]; // pop top handler
179 led->pointers[0] = value; // store exception that is thrown
180 #if TARGET_OS_WIN32
181 longjmp(led->buf, 1);
182 #else
183 _longjmp(led->buf, 1);
184 #endif
185 }
186
187 static void default_try_exit(void *led) {
188 ThreadChainLink_t *chainLink = getChainLink();
189 if (!chainLink || led != chainLink->topHandler) {
190 if (PrintExceptions) _objc_inform("EXCEPTIONS: *** mismatched try block exit handlers\n");
191 return;
192 }
193 if (PrintExceptions) _objc_inform("EXCEPTIONS: removing try block handler %p\n", chainLink->topHandler);
194 chainLink->topHandler = (LocalData_t *)
195 chainLink->topHandler->pointers[1]; // pop top handler
196 }
197
198 static id default_extract(void *localExceptionData) {
199 LocalData_t *led = (LocalData_t *)localExceptionData;
200 return (id)led->pointers[0];
201 }
202
203 static int default_match(Class exceptionClass, id exception) {
204 //return [exception isKindOfClass:exceptionClass];
205 Class cls;
206 for (cls = exception->getIsa(); nil != cls; cls = cls->superclass)
207 if (cls == exceptionClass) return 1;
208 return 0;
209 }
210
211 static void set_default_handlers() {
212 objc_exception_functions_t default_functions = {
213 0, default_throw, default_try_enter, default_try_exit, default_extract, default_match };
214
215 // should this always print?
216 if (PrintExceptions) _objc_inform("EXCEPTIONS: *** Setting default (non-Foundation) exception mechanism\n");
217 objc_exception_set_functions(&default_functions);
218 }
219
220
221 void exception_init(void)
222 {
223 // nothing to do
224 }
225
226 void _destroyAltHandlerList(struct alt_handler_list *list)
227 {
228 // nothing to do
229 }
230
231
232 // !__OBJC2__
233 #else
234 // __OBJC2__
235
236 /***********************************************************************
237 * 64-bit implementation.
238 **********************************************************************/
239
240 #include "objc-private.h"
241 #include <objc/objc-abi.h>
242 #include <objc/objc-exception.h>
243 #include <objc/NSObject.h>
244 #include <execinfo.h>
245
246 // unwind library types and functions
247 // Mostly adapted from Itanium C++ ABI: Exception Handling
248 // http://www.codesourcery.com/cxx-abi/abi-eh.html
249
250 struct _Unwind_Exception;
251 struct _Unwind_Context;
252
253 typedef int _Unwind_Action;
254 enum : _Unwind_Action {
255 _UA_SEARCH_PHASE = 1,
256 _UA_CLEANUP_PHASE = 2,
257 _UA_HANDLER_FRAME = 4,
258 _UA_FORCE_UNWIND = 8
259 };
260
261 typedef int _Unwind_Reason_Code;
262 enum : _Unwind_Reason_Code {
263 _URC_NO_REASON = 0,
264 _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
265 _URC_FATAL_PHASE2_ERROR = 2,
266 _URC_FATAL_PHASE1_ERROR = 3,
267 _URC_NORMAL_STOP = 4,
268 _URC_END_OF_STACK = 5,
269 _URC_HANDLER_FOUND = 6,
270 _URC_INSTALL_CONTEXT = 7,
271 _URC_CONTINUE_UNWIND = 8
272 };
273
274 struct dwarf_eh_bases
275 {
276 uintptr_t tbase;
277 uintptr_t dbase;
278 uintptr_t func;
279 };
280
281 OBJC_EXTERN uintptr_t _Unwind_GetIP (struct _Unwind_Context *);
282 OBJC_EXTERN uintptr_t _Unwind_GetCFA (struct _Unwind_Context *);
283 OBJC_EXTERN uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context *);
284
285
286 // C++ runtime types and functions
287 // copied from cxxabi.h
288
289 OBJC_EXTERN void *__cxa_allocate_exception(size_t thrown_size);
290 OBJC_EXTERN void __cxa_throw(void *exc, void *typeinfo, void (*destructor)(void *)) __attribute__((noreturn));
291 OBJC_EXTERN void *__cxa_begin_catch(void *exc);
292 OBJC_EXTERN void __cxa_end_catch(void);
293 OBJC_EXTERN void __cxa_rethrow(void);
294 OBJC_EXTERN void *__cxa_current_exception_type(void);
295
296 #if SUPPORT_ZEROCOST_EXCEPTIONS
297 # define CXX_PERSONALITY __gxx_personality_v0
298 #else
299 # define CXX_PERSONALITY __gxx_personality_sj0
300 #endif
301
302 OBJC_EXTERN _Unwind_Reason_Code
303 CXX_PERSONALITY(int version,
304 _Unwind_Action actions,
305 uint64_t exceptionClass,
306 struct _Unwind_Exception *exceptionObject,
307 struct _Unwind_Context *context);
308
309
310 // objc's internal exception types and data
311
312 struct objc_typeinfo {
313 // Position of vtable and name fields must match C++ typeinfo object
314 const void ** __ptrauth_cxx_vtable_pointer vtable; // objc_ehtype_vtable+2
315 const char *name; // c++ typeinfo string
316
317 Class cls_unremapped;
318 };
319
320 struct objc_exception {
321 id obj;
322 struct objc_typeinfo tinfo;
323 };
324
325
326 extern "C" void _objc_exception_noop(void) { }
327 extern "C" bool _objc_exception_false(void) { return 0; }
328 // extern "C" bool _objc_exception_true(void) { return 1; }
329 extern "C" void _objc_exception_abort1(void) {
330 _objc_fatal("unexpected call into objc exception typeinfo vtable %d", 1);
331 }
332 extern "C" void _objc_exception_abort2(void) {
333 _objc_fatal("unexpected call into objc exception typeinfo vtable %d", 2);
334 }
335 extern "C" void _objc_exception_abort3(void) {
336 _objc_fatal("unexpected call into objc exception typeinfo vtable %d", 3);
337 }
338 extern "C" void _objc_exception_abort4(void) {
339 _objc_fatal("unexpected call into objc exception typeinfo vtable %d", 4);
340 }
341
342 extern "C" bool _objc_exception_do_catch(struct objc_typeinfo *catch_tinfo,
343 struct objc_typeinfo *throw_tinfo,
344 void **throw_obj_p,
345 unsigned outer);
346
347 // C++ pointers to vtables are signed with no extra data.
348 // C++ vtable entries are signed with a number derived from the function name.
349 // For this fake vtable, we hardcode number as deciphered from the
350 // assembly output during libc++abi's build.
351 #if __has_feature(ptrauth_calls)
352 # define VTABLE_PTR_AUTH "@AUTH(da, 0)"
353 # define VTABLE_ENTRY_AUTH(x) "@AUTH(ia," #x ",addr)"
354 #else
355 # define VTABLE_PTR_AUTH ""
356 # define VTABLE_ENTRY_AUTH(x) ""
357 #endif
358
359 #if __LP64__
360 # define PTR ".quad "
361 # define TWOPTRSIZE "16"
362 #else
363 # define PTR ".long "
364 # define TWOPTRSIZE "8"
365 #endif
366
367 // Hand-built vtable for objc exception typeinfo.
368 // "OLD" is GNU libcpp, "NEW" is libc++abi.
369
370 asm(
371 "\n .cstring"
372 "\n l_.id_str: .asciz \"id\""
373
374 "\n .section __DATA,__const"
375 "\n .globl _OBJC_EHTYPE_id"
376 "\n .globl _objc_ehtype_vtable"
377 "\n .p2align 4"
378
379 "\n _OBJC_EHTYPE_id:"
380 "\n " PTR "(_objc_ehtype_vtable+" TWOPTRSIZE ") " VTABLE_PTR_AUTH
381 "\n " PTR "l_.id_str"
382 "\n " PTR "0"
383
384 "\n _objc_ehtype_vtable:"
385 "\n " PTR "0"
386 // typeinfo's typeinfo - fixme hack
387 "\n " PTR "_OBJC_EHTYPE_id"
388 // destructor and in-place destructor
389 "\n " PTR "__objc_exception_noop" VTABLE_ENTRY_AUTH(52634)
390 "\n " PTR "__objc_exception_noop" VTABLE_ENTRY_AUTH(10344)
391 // OLD __is_pointer_p
392 "\n " PTR "__objc_exception_noop" VTABLE_ENTRY_AUTH(6889)
393 // OLD __is_function_p
394 "\n " PTR "__objc_exception_noop" VTABLE_ENTRY_AUTH(23080)
395 // OLD __do_catch, NEW can_catch
396 "\n " PTR "__objc_exception_do_catch" VTABLE_ENTRY_AUTH(27434)
397 // OLD __do_upcast, NEW search_above_dst
398 "\n " PTR "__objc_exception_false" VTABLE_ENTRY_AUTH(48481)
399 // NEW search_below_dst
400 "\n " PTR "__objc_exception_false" VTABLE_ENTRY_AUTH(41165)
401 // NEW has_unambiguous_public_base (fixme need this?)
402 "\n " PTR "__objc_exception_abort1" VTABLE_ENTRY_AUTH(14357)
403 // paranoia: die if libcxxabi adds anything else
404 "\n " PTR "__objc_exception_abort2"
405 "\n " PTR "__objc_exception_abort3"
406 "\n " PTR "__objc_exception_abort4"
407 );
408
409
410
411 /***********************************************************************
412 * Foundation customization
413 **********************************************************************/
414
415 /***********************************************************************
416 * _objc_default_exception_preprocessor
417 * Default exception preprocessor. Expected to be overridden by Foundation.
418 **********************************************************************/
419 static id _objc_default_exception_preprocessor(id exception)
420 {
421 return exception;
422 }
423 static objc_exception_preprocessor exception_preprocessor = _objc_default_exception_preprocessor;
424
425
426 /***********************************************************************
427 * _objc_default_exception_matcher
428 * Default exception matcher. Expected to be overridden by Foundation.
429 **********************************************************************/
430 static int _objc_default_exception_matcher(Class catch_cls, id exception)
431 {
432 Class cls;
433 for (cls = exception->getIsa();
434 cls != nil;
435 cls = cls->superclass)
436 {
437 if (cls == catch_cls) return 1;
438 }
439
440 return 0;
441 }
442 static objc_exception_matcher exception_matcher = _objc_default_exception_matcher;
443
444
445 /***********************************************************************
446 * _objc_default_uncaught_exception_handler
447 * Default uncaught exception handler. Expected to be overridden by Foundation.
448 **********************************************************************/
449 static void _objc_default_uncaught_exception_handler(id exception)
450 {
451 }
452 static objc_uncaught_exception_handler uncaught_handler = _objc_default_uncaught_exception_handler;
453
454
455 /***********************************************************************
456 * objc_setExceptionPreprocessor
457 * Set a handler for preprocessing Objective-C exceptions.
458 * Returns the previous handler.
459 **********************************************************************/
460 objc_exception_preprocessor
461 objc_setExceptionPreprocessor(objc_exception_preprocessor fn)
462 {
463 objc_exception_preprocessor result = exception_preprocessor;
464 exception_preprocessor = fn;
465 return result;
466 }
467
468
469 /***********************************************************************
470 * objc_setExceptionMatcher
471 * Set a handler for matching Objective-C exceptions.
472 * Returns the previous handler.
473 **********************************************************************/
474 objc_exception_matcher
475 objc_setExceptionMatcher(objc_exception_matcher fn)
476 {
477 objc_exception_matcher result = exception_matcher;
478 exception_matcher = fn;
479 return result;
480 }
481
482
483 /***********************************************************************
484 * objc_setUncaughtExceptionHandler
485 * Set a handler for uncaught Objective-C exceptions.
486 * Returns the previous handler.
487 **********************************************************************/
488 objc_uncaught_exception_handler
489 objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler fn)
490 {
491 objc_uncaught_exception_handler result = uncaught_handler;
492 uncaught_handler = fn;
493 return result;
494 }
495
496
497 /***********************************************************************
498 * Exception personality
499 **********************************************************************/
500
501 static void call_alt_handlers(struct _Unwind_Context *ctx);
502
503 _Unwind_Reason_Code
504 __objc_personality_v0(int version,
505 _Unwind_Action actions,
506 uint64_t exceptionClass,
507 struct _Unwind_Exception *exceptionObject,
508 struct _Unwind_Context *context)
509 {
510 bool unwinding = ((actions & _UA_CLEANUP_PHASE) ||
511 (actions & _UA_FORCE_UNWIND));
512
513 if (PrintExceptions) {
514 _objc_inform("EXCEPTIONS: %s through frame [ip=%p sp=%p] "
515 "for exception %p",
516 unwinding ? "unwinding" : "searching",
517 (void*)(_Unwind_GetIP(context)-1),
518 (void*)_Unwind_GetCFA(context), exceptionObject);
519 }
520
521 // If we're executing the unwind, call this frame's alt handlers, if any.
522 if (unwinding) {
523 call_alt_handlers(context);
524 }
525
526 // Let C++ handle the unwind itself.
527 return CXX_PERSONALITY(version, actions, exceptionClass,
528 exceptionObject, context);
529 }
530
531
532 /***********************************************************************
533 * Compiler ABI
534 **********************************************************************/
535
536 static void _objc_exception_destructor(void *exc_gen)
537 {
538 // Release the retain from objc_exception_throw().
539
540 struct objc_exception *exc = (struct objc_exception *)exc_gen;
541 id obj = exc->obj;
542
543 if (PrintExceptions) {
544 _objc_inform("EXCEPTIONS: releasing completed exception %p (object %p, a %s)",
545 exc, obj, object_getClassName(obj));
546 }
547
548 [obj release];
549 }
550
551
552 void objc_exception_throw(id obj)
553 {
554 struct objc_exception *exc = (struct objc_exception *)
555 __cxa_allocate_exception(sizeof(struct objc_exception));
556
557 obj = (*exception_preprocessor)(obj);
558
559 // Retain the exception object during unwinding
560 // because otherwise an autorelease pool pop can cause a crash
561 [obj retain];
562
563 exc->obj = obj;
564 exc->tinfo.vtable = objc_ehtype_vtable+2;
565 exc->tinfo.name = object_getClassName(obj);
566 exc->tinfo.cls_unremapped = obj ? obj->getIsa() : Nil;
567
568 if (PrintExceptions) {
569 _objc_inform("EXCEPTIONS: throwing %p (object %p, a %s)",
570 exc, (void*)obj, object_getClassName(obj));
571 }
572
573 if (PrintExceptionThrow) {
574 if (!PrintExceptions)
575 _objc_inform("EXCEPTIONS: throwing %p (object %p, a %s)",
576 exc, (void*)obj, object_getClassName(obj));
577 void* callstack[500];
578 int frameCount = backtrace(callstack, 500);
579 backtrace_symbols_fd(callstack, frameCount, fileno(stderr));
580 }
581
582 OBJC_RUNTIME_OBJC_EXCEPTION_THROW(obj); // dtrace probe to log throw activity
583 __cxa_throw(exc, &exc->tinfo, &_objc_exception_destructor);
584 __builtin_trap();
585 }
586
587
588 void objc_exception_rethrow(void)
589 {
590 // exception_preprocessor doesn't get another bite of the apple
591 if (PrintExceptions) {
592 _objc_inform("EXCEPTIONS: rethrowing current exception");
593 }
594
595 OBJC_RUNTIME_OBJC_EXCEPTION_RETHROW(); // dtrace probe to log throw activity.
596 __cxa_rethrow();
597 __builtin_trap();
598 }
599
600
601 id objc_begin_catch(void *exc_gen)
602 {
603 if (PrintExceptions) {
604 _objc_inform("EXCEPTIONS: handling exception %p at %p",
605 exc_gen, __builtin_return_address(0));
606 }
607 // NOT actually an id in the catch(...) case!
608 return (id)__cxa_begin_catch(exc_gen);
609 }
610
611
612 void objc_end_catch(void)
613 {
614 if (PrintExceptions) {
615 _objc_inform("EXCEPTIONS: finishing handler");
616 }
617 __cxa_end_catch();
618 }
619
620
621 // `outer` is not passed by the new libcxxabi
622 bool _objc_exception_do_catch(struct objc_typeinfo *catch_tinfo,
623 struct objc_typeinfo *throw_tinfo,
624 void **throw_obj_p,
625 unsigned outer UNAVAILABLE_ATTRIBUTE)
626 {
627 id exception;
628
629 if (throw_tinfo->vtable != objc_ehtype_vtable+2) {
630 // Only objc types can be caught here.
631 if (PrintExceptions) _objc_inform("EXCEPTIONS: skipping catch(?)");
632 return false;
633 }
634
635 // Adjust exception pointer.
636 // Old libcppabi: we lied about __is_pointer_p() so we have to do it here
637 // New libcxxabi: we have to do it here regardless
638 *throw_obj_p = **(void***)throw_obj_p;
639
640 // `catch (id)` always catches objc types.
641 if (catch_tinfo == &OBJC_EHTYPE_id) {
642 if (PrintExceptions) _objc_inform("EXCEPTIONS: catch(id)");
643 return true;
644 }
645
646 exception = *(id *)throw_obj_p;
647
648 Class handler_cls = _class_remap(catch_tinfo->cls_unremapped);
649 if (!handler_cls) {
650 // catch handler's class is weak-linked and missing. Not a match.
651 }
652 else if ((*exception_matcher)(handler_cls, exception)) {
653 if (PrintExceptions) _objc_inform("EXCEPTIONS: catch(%s)",
654 handler_cls->nameForLogging());
655 return true;
656 }
657
658 if (PrintExceptions) _objc_inform("EXCEPTIONS: skipping catch(%s)",
659 handler_cls->nameForLogging());
660
661 return false;
662 }
663
664
665 /***********************************************************************
666 * _objc_terminate
667 * Custom std::terminate handler.
668 *
669 * The uncaught exception callback is implemented as a std::terminate handler.
670 * 1. Check if there's an active exception
671 * 2. If so, check if it's an Objective-C exception
672 * 3. If so, call our registered callback with the object.
673 * 4. Finally, call the previous terminate handler.
674 **********************************************************************/
675 static void (*old_terminate)(void) = nil;
676 static void _objc_terminate(void)
677 {
678 if (PrintExceptions) {
679 _objc_inform("EXCEPTIONS: terminating");
680 }
681
682 if (! __cxa_current_exception_type()) {
683 // No current exception.
684 (*old_terminate)();
685 }
686 else {
687 // There is a current exception. Check if it's an objc exception.
688 @try {
689 __cxa_rethrow();
690 } @catch (id e) {
691 // It's an objc object. Call Foundation's handler, if any.
692 (*uncaught_handler)((id)e);
693 (*old_terminate)();
694 } @catch (...) {
695 // It's not an objc object. Continue to C++ terminate.
696 (*old_terminate)();
697 }
698 }
699 }
700
701
702 /***********************************************************************
703 * objc_terminate
704 * Calls std::terminate for clients who don't link to C++ themselves.
705 * Called by the compiler if an exception is thrown
706 * from a context where exceptions may not be thrown.
707 **********************************************************************/
708 void objc_terminate(void)
709 {
710 std::terminate();
711 }
712
713
714 /***********************************************************************
715 * alt handler support - zerocost implementation only
716 **********************************************************************/
717
718 #if !SUPPORT_ALT_HANDLERS
719
720 void _destroyAltHandlerList(struct alt_handler_list *list)
721 {
722 }
723
724 static void call_alt_handlers(struct _Unwind_Context *ctx)
725 {
726 // unsupported in sjlj environments
727 }
728
729 #else
730
731 #include <libunwind.h>
732 #include <execinfo.h>
733 #include <dispatch/dispatch.h>
734
735 // Dwarf eh data encodings
736 #define DW_EH_PE_omit 0xff // no data follows
737
738 #define DW_EH_PE_absptr 0x00
739 #define DW_EH_PE_uleb128 0x01
740 #define DW_EH_PE_udata2 0x02
741 #define DW_EH_PE_udata4 0x03
742 #define DW_EH_PE_udata8 0x04
743 #define DW_EH_PE_sleb128 0x09
744 #define DW_EH_PE_sdata2 0x0A
745 #define DW_EH_PE_sdata4 0x0B
746 #define DW_EH_PE_sdata8 0x0C
747
748 #define DW_EH_PE_pcrel 0x10
749 #define DW_EH_PE_textrel 0x20
750 #define DW_EH_PE_datarel 0x30
751 #define DW_EH_PE_funcrel 0x40
752 #define DW_EH_PE_aligned 0x50 // fixme
753
754 #define DW_EH_PE_indirect 0x80 // gcc extension
755
756
757 /***********************************************************************
758 * read_uleb
759 * Read a LEB-encoded unsigned integer from the address stored in *pp.
760 * Increments *pp past the bytes read.
761 * Adapted from DWARF Debugging Information Format 1.1, appendix 4
762 **********************************************************************/
763 static uintptr_t read_uleb(uintptr_t *pp)
764 {
765 uintptr_t result = 0;
766 uintptr_t shift = 0;
767 unsigned char byte;
768 do {
769 byte = *(const unsigned char *)(*pp)++;
770 result |= (byte & 0x7f) << shift;
771 shift += 7;
772 } while (byte & 0x80);
773 return result;
774 }
775
776
777 /***********************************************************************
778 * read_sleb
779 * Read a LEB-encoded signed integer from the address stored in *pp.
780 * Increments *pp past the bytes read.
781 * Adapted from DWARF Debugging Information Format 1.1, appendix 4
782 **********************************************************************/
783 static intptr_t read_sleb(uintptr_t *pp)
784 {
785 uintptr_t result = 0;
786 uintptr_t shift = 0;
787 unsigned char byte;
788 do {
789 byte = *(const unsigned char *)(*pp)++;
790 result |= (byte & 0x7f) << shift;
791 shift += 7;
792 } while (byte & 0x80);
793 if ((shift < 8*sizeof(intptr_t)) && (byte & 0x40)) {
794 result |= ((intptr_t)-1) << shift;
795 }
796 return result;
797 }
798
799
800 /***********************************************************************
801 * read_address
802 * Reads an encoded address from the address stored in *pp.
803 * Increments *pp past the bytes read.
804 * The data is interpreted according to the given dwarf encoding
805 * and base addresses.
806 **********************************************************************/
807 static uintptr_t read_address(uintptr_t *pp,
808 const struct dwarf_eh_bases *bases,
809 unsigned char encoding)
810 {
811 uintptr_t result = 0;
812 uintptr_t oldp = *pp;
813
814 // fixme need DW_EH_PE_aligned?
815
816 #define READ(type) \
817 result = *(type *)(*pp); \
818 *pp += sizeof(type);
819
820 if (encoding == DW_EH_PE_omit) return 0;
821
822 switch (encoding & 0x0f) {
823 case DW_EH_PE_absptr:
824 READ(uintptr_t);
825 break;
826 case DW_EH_PE_uleb128:
827 result = read_uleb(pp);
828 break;
829 case DW_EH_PE_udata2:
830 READ(uint16_t);
831 break;
832 case DW_EH_PE_udata4:
833 READ(uint32_t);
834 break;
835 #if __LP64__
836 case DW_EH_PE_udata8:
837 READ(uint64_t);
838 break;
839 #endif
840 case DW_EH_PE_sleb128:
841 result = read_sleb(pp);
842 break;
843 case DW_EH_PE_sdata2:
844 READ(int16_t);
845 break;
846 case DW_EH_PE_sdata4:
847 READ(int32_t);
848 break;
849 #if __LP64__
850 case DW_EH_PE_sdata8:
851 READ(int64_t);
852 break;
853 #endif
854 default:
855 _objc_inform("unknown DWARF EH encoding 0x%x at %p",
856 encoding, (void *)*pp);
857 break;
858 }
859
860 #undef READ
861
862 if (result) {
863 switch (encoding & 0x70) {
864 case DW_EH_PE_pcrel:
865 // fixme correct?
866 result += (uintptr_t)oldp;
867 break;
868 case DW_EH_PE_textrel:
869 result += bases->tbase;
870 break;
871 case DW_EH_PE_datarel:
872 result += bases->dbase;
873 break;
874 case DW_EH_PE_funcrel:
875 result += bases->func;
876 break;
877 case DW_EH_PE_aligned:
878 _objc_inform("unknown DWARF EH encoding 0x%x at %p",
879 encoding, (void *)*pp);
880 break;
881 default:
882 // no adjustment
883 break;
884 }
885
886 if (encoding & DW_EH_PE_indirect) {
887 result = *(uintptr_t *)result;
888 }
889 }
890
891 return (uintptr_t)result;
892 }
893
894
895 struct frame_ips {
896 uintptr_t start;
897 uintptr_t end;
898 };
899 struct frame_range {
900 uintptr_t ip_start;
901 uintptr_t ip_end;
902 uintptr_t cfa;
903 // precise ranges within ip_start..ip_end; nil or {0,0} terminated
904 frame_ips *ips;
905 };
906
907
908 static bool isObjCExceptionCatcher(uintptr_t lsda, uintptr_t ip,
909 const struct dwarf_eh_bases* bases,
910 struct frame_range *frame)
911 {
912 unsigned char LPStart_enc = *(const unsigned char *)lsda++;
913
914 if (LPStart_enc != DW_EH_PE_omit) {
915 read_address(&lsda, bases, LPStart_enc); // LPStart
916 }
917
918 unsigned char TType_enc = *(const unsigned char *)lsda++;
919 if (TType_enc != DW_EH_PE_omit) {
920 read_uleb(&lsda); // TType
921 }
922
923 unsigned char call_site_enc = *(const unsigned char *)lsda++;
924 uintptr_t length = read_uleb(&lsda);
925 uintptr_t call_site_table = lsda;
926 uintptr_t call_site_table_end = call_site_table + length;
927 uintptr_t action_record_table = call_site_table_end;
928
929 uintptr_t action_record = 0;
930 uintptr_t p = call_site_table;
931
932 uintptr_t try_start;
933 uintptr_t try_end;
934 uintptr_t try_landing_pad;
935
936 while (p < call_site_table_end) {
937 uintptr_t start = read_address(&p, bases, call_site_enc)+bases->func;
938 uintptr_t len = read_address(&p, bases, call_site_enc);
939 uintptr_t pad = read_address(&p, bases, call_site_enc);
940 uintptr_t action = read_uleb(&p);
941
942 if (ip < start) {
943 // no more source ranges
944 return false;
945 }
946 else if (ip < start + len) {
947 // found the range
948 if (!pad) return false; // ...but it has no landing pad
949 // found the landing pad
950 action_record = action ? action_record_table + action - 1 : 0;
951 try_start = start;
952 try_end = start + len;
953 try_landing_pad = pad;
954 break;
955 }
956 }
957
958 if (!action_record) return false; // no catch handlers
959
960 // has handlers, destructors, and/or throws specifications
961 // Use this frame if it has any handlers
962 bool has_handler = false;
963 p = action_record;
964 intptr_t offset;
965 do {
966 intptr_t filter = read_sleb(&p);
967 uintptr_t temp = p;
968 offset = read_sleb(&temp);
969 p += offset;
970
971 if (filter < 0) {
972 // throws specification - ignore
973 } else if (filter == 0) {
974 // destructor - ignore
975 } else /* filter >= 0 */ {
976 // catch handler - use this frame
977 has_handler = true;
978 break;
979 }
980 } while (offset);
981
982 if (!has_handler) return false;
983
984 // Count the number of source ranges with the same landing pad as our match
985 unsigned int range_count = 0;
986 p = call_site_table;
987 while (p < call_site_table_end) {
988 /*start*/ read_address(&p, bases, call_site_enc)/*+bases->func*/;
989 /*len*/ read_address(&p, bases, call_site_enc);
990 uintptr_t pad = read_address(&p, bases, call_site_enc);
991 /*action*/ read_uleb(&p);
992
993 if (pad == try_landing_pad) {
994 range_count++;
995 }
996 }
997
998 if (range_count == 1) {
999 // No other source ranges with the same landing pad. We're done here.
1000 frame->ips = nil;
1001 }
1002 else {
1003 // Record all ranges with the same landing pad as our match.
1004 frame->ips = (frame_ips *)
1005 malloc((range_count + 1) * sizeof(frame->ips[0]));
1006 unsigned int r = 0;
1007 p = call_site_table;
1008 while (p < call_site_table_end) {
1009 uintptr_t start = read_address(&p, bases, call_site_enc)+bases->func;
1010 uintptr_t len = read_address(&p, bases, call_site_enc);
1011 uintptr_t pad = read_address(&p, bases, call_site_enc);
1012 /*action*/ read_uleb(&p);
1013
1014 if (pad == try_landing_pad) {
1015 if (start < try_start) try_start = start;
1016 if (start+len > try_end) try_end = start+len;
1017 frame->ips[r].start = start;
1018 frame->ips[r].end = start+len;
1019 r++;
1020 }
1021 }
1022
1023 frame->ips[r].start = 0;
1024 frame->ips[r].end = 0;
1025 }
1026
1027 frame->ip_start = try_start;
1028 frame->ip_end = try_end;
1029
1030 return true;
1031 }
1032
1033
1034 static struct frame_range findHandler(void)
1035 {
1036 // walk stack looking for frame with objc catch handler
1037 unw_context_t uc;
1038 unw_cursor_t cursor;
1039 unw_proc_info_t info;
1040 unw_getcontext(&uc);
1041 unw_init_local(&cursor, &uc);
1042 while ( (unw_step(&cursor) > 0) && (unw_get_proc_info(&cursor, &info) == UNW_ESUCCESS) ) {
1043 // must use objc personality handler
1044 if ( info.handler != (uintptr_t)__objc_personality_v0 )
1045 continue;
1046 // must have landing pad
1047 if ( info.lsda == 0 )
1048 continue;
1049 // must have landing pad that catches objc exceptions
1050 struct dwarf_eh_bases bases;
1051 bases.tbase = 0; // from unwind-dw2-fde-darwin.c:examine_objects()
1052 bases.dbase = 0; // from unwind-dw2-fde-darwin.c:examine_objects()
1053 bases.func = info.start_ip;
1054 unw_word_t ip;
1055 unw_get_reg(&cursor, UNW_REG_IP, &ip);
1056 ip -= 1;
1057 struct frame_range try_range = {0, 0, 0, 0};
1058 if ( isObjCExceptionCatcher(info.lsda, ip, &bases, &try_range) ) {
1059 unw_word_t cfa;
1060 unw_get_reg(&cursor, UNW_REG_SP, &cfa);
1061 try_range.cfa = cfa;
1062 return try_range;
1063 }
1064 }
1065
1066 return (struct frame_range){0, 0, 0, 0};
1067 }
1068
1069
1070 // This data structure assumes the number of
1071 // active alt handlers per frame is small.
1072
1073 // for OBJC_DEBUG_ALT_HANDLERS, record the call to objc_addExceptionHandler.
1074 #define BACKTRACE_COUNT 46
1075 #define THREADNAME_COUNT 64
1076 struct alt_handler_debug {
1077 uintptr_t token;
1078 int backtraceSize;
1079 void *backtrace[BACKTRACE_COUNT];
1080 char thread[THREADNAME_COUNT];
1081 char queue[THREADNAME_COUNT];
1082 };
1083
1084 struct alt_handler_data {
1085 struct frame_range frame;
1086 objc_exception_handler fn;
1087 void *context;
1088 struct alt_handler_debug *debug;
1089 };
1090
1091 struct alt_handler_list {
1092 unsigned int allocated;
1093 unsigned int used;
1094 struct alt_handler_data *handlers;
1095 struct alt_handler_list *next_DEBUGONLY;
1096 };
1097
1098 static struct alt_handler_list *DebugLists;
1099 static uintptr_t DebugCounter;
1100
1101 __attribute__((noinline, noreturn))
1102 void alt_handler_error(uintptr_t token);
1103
1104 static struct alt_handler_list *
1105 fetch_handler_list(bool create)
1106 {
1107 _objc_pthread_data *data = _objc_fetch_pthread_data(create);
1108 if (!data) return nil;
1109
1110 struct alt_handler_list *list = data->handlerList;
1111 if (!list) {
1112 if (!create) return nil;
1113 list = (struct alt_handler_list *)calloc(1, sizeof(*list));
1114 data->handlerList = list;
1115
1116 if (DebugAltHandlers) {
1117 // Save this list so the debug code can find it from other threads
1118 mutex_locker_t lock(AltHandlerDebugLock);
1119 list->next_DEBUGONLY = DebugLists;
1120 DebugLists = list;
1121 }
1122 }
1123
1124 return list;
1125 }
1126
1127
1128 void _destroyAltHandlerList(struct alt_handler_list *list)
1129 {
1130 if (list) {
1131 if (DebugAltHandlers) {
1132 // Detach from the list-of-lists.
1133 mutex_locker_t lock(AltHandlerDebugLock);
1134 struct alt_handler_list **listp = &DebugLists;
1135 while (*listp && *listp != list) listp = &(*listp)->next_DEBUGONLY;
1136 if (*listp) *listp = (*listp)->next_DEBUGONLY;
1137 }
1138
1139 if (list->handlers) {
1140 for (unsigned int i = 0; i < list->allocated; i++) {
1141 if (list->handlers[i].frame.ips) {
1142 free(list->handlers[i].frame.ips);
1143 }
1144 }
1145 free(list->handlers);
1146 }
1147 free(list);
1148 }
1149 }
1150
1151
1152 uintptr_t objc_addExceptionHandler(objc_exception_handler fn, void *context)
1153 {
1154 // Find the closest enclosing frame with objc catch handlers
1155 struct frame_range target_frame = findHandler();
1156 if (!target_frame.ip_start) {
1157 // No suitable enclosing handler found.
1158 return 0;
1159 }
1160
1161 // Record this alt handler for the discovered frame.
1162 struct alt_handler_list *list = fetch_handler_list(YES);
1163 unsigned int i = 0;
1164
1165 if (list->used == list->allocated) {
1166 list->allocated = list->allocated*2 ?: 4;
1167 list->handlers = (struct alt_handler_data *)
1168 realloc(list->handlers,
1169 list->allocated * sizeof(list->handlers[0]));
1170 bzero(&list->handlers[list->used], (list->allocated - list->used) * sizeof(list->handlers[0]));
1171 i = list->used;
1172 }
1173 else {
1174 for (i = 0; i < list->allocated; i++) {
1175 if (list->handlers[i].frame.ip_start == 0 &&
1176 list->handlers[i].frame.ip_end == 0 &&
1177 list->handlers[i].frame.cfa == 0)
1178 {
1179 break;
1180 }
1181 }
1182 if (i == list->allocated) {
1183 _objc_fatal("alt handlers in objc runtime are buggy!");
1184 }
1185 }
1186
1187 struct alt_handler_data *data = &list->handlers[i];
1188
1189 data->frame = target_frame;
1190 data->fn = fn;
1191 data->context = context;
1192 list->used++;
1193
1194 uintptr_t token = i+1;
1195
1196 if (DebugAltHandlers) {
1197 // Record backtrace in case this handler is misused later.
1198 mutex_locker_t lock(AltHandlerDebugLock);
1199
1200 token = DebugCounter++;
1201 if (token == 0) token = DebugCounter++;
1202
1203 if (!data->debug) {
1204 data->debug = (struct alt_handler_debug *)
1205 calloc(sizeof(*data->debug), 1);
1206 } else {
1207 bzero(data->debug, sizeof(*data->debug));
1208 }
1209
1210 pthread_getname_np(pthread_self(), data->debug->thread, THREADNAME_COUNT);
1211 strlcpy(data->debug->queue,
1212 dispatch_queue_get_label(dispatch_get_current_queue()),
1213 THREADNAME_COUNT);
1214 data->debug->backtraceSize =
1215 backtrace(data->debug->backtrace, BACKTRACE_COUNT);
1216 data->debug->token = token;
1217 }
1218
1219 if (PrintAltHandlers) {
1220 _objc_inform("ALT HANDLERS: installing alt handler #%lu %p(%p) on "
1221 "frame [ip=%p..%p sp=%p]", (unsigned long)token,
1222 data->fn, data->context, (void *)data->frame.ip_start,
1223 (void *)data->frame.ip_end, (void *)data->frame.cfa);
1224 if (data->frame.ips) {
1225 unsigned int r = 0;
1226 while (1) {
1227 uintptr_t start = data->frame.ips[r].start;
1228 uintptr_t end = data->frame.ips[r].end;
1229 r++;
1230 if (start == 0 && end == 0) break;
1231 _objc_inform("ALT HANDLERS: ip=%p..%p",
1232 (void*)start, (void*)end);
1233 }
1234 }
1235 }
1236
1237 if (list->used > 1000) {
1238 static int warned = 0;
1239 if (!warned) {
1240 _objc_inform("ALT HANDLERS: *** over 1000 alt handlers installed; "
1241 "this is probably a bug");
1242 warned = 1;
1243 }
1244 }
1245
1246 return token;
1247 }
1248
1249
1250 void objc_removeExceptionHandler(uintptr_t token)
1251 {
1252 if (!token) {
1253 // objc_addExceptionHandler failed
1254 return;
1255 }
1256
1257 struct alt_handler_list *list = fetch_handler_list(NO);
1258 if (!list || !list->handlers) {
1259 // no alt handlers active
1260 alt_handler_error(token);
1261 }
1262
1263 uintptr_t i = token-1;
1264
1265 if (DebugAltHandlers) {
1266 // search for the token instead of using token-1
1267 for (i = 0; i < list->allocated; i++) {
1268 struct alt_handler_data *data = &list->handlers[i];
1269 if (data->debug && data->debug->token == token) break;
1270 }
1271 }
1272
1273 if (i >= list->allocated) {
1274 // token out of range
1275 alt_handler_error(token);
1276 }
1277
1278 struct alt_handler_data *data = &list->handlers[i];
1279
1280 if (data->frame.ip_start == 0 && data->frame.ip_end == 0 && data->frame.cfa == 0) {
1281 // token in range, but invalid
1282 alt_handler_error(token);
1283 }
1284
1285 if (PrintAltHandlers) {
1286 _objc_inform("ALT HANDLERS: removing alt handler #%lu %p(%p) on "
1287 "frame [ip=%p..%p sp=%p]", (unsigned long)token,
1288 data->fn, data->context, (void *)data->frame.ip_start,
1289 (void *)data->frame.ip_end, (void *)data->frame.cfa);
1290 }
1291
1292 if (data->debug) free(data->debug);
1293 if (data->frame.ips) free(data->frame.ips);
1294 bzero(data, sizeof(*data));
1295 list->used--;
1296 }
1297
1298
1299 BREAKPOINT_FUNCTION(
1300 void objc_alt_handler_error(void));
1301
1302 __attribute__((noinline, noreturn))
1303 void alt_handler_error(uintptr_t token)
1304 {
1305 _objc_inform
1306 ("objc_removeExceptionHandler() called with unknown alt handler; "
1307 "this is probably a bug in multithreaded AppKit use. "
1308 "Set environment variable OBJC_DEBUG_ALT_HANDLERS=YES "
1309 "or break in objc_alt_handler_error() to debug.");
1310
1311 if (DebugAltHandlers) {
1312 AltHandlerDebugLock.lock();
1313
1314 // Search other threads' alt handler lists for this handler.
1315 struct alt_handler_list *list;
1316 for (list = DebugLists; list; list = list->next_DEBUGONLY) {
1317 unsigned h;
1318 for (h = 0; h < list->allocated; h++) {
1319 struct alt_handler_data *data = &list->handlers[h];
1320 if (data->debug && data->debug->token == token) {
1321 // found it
1322 int i;
1323
1324 // Build a string from the recorded backtrace
1325 char *symbolString;
1326 char **symbols =
1327 backtrace_symbols(data->debug->backtrace,
1328 data->debug->backtraceSize);
1329 size_t len = 1;
1330 for (i = 0; i < data->debug->backtraceSize; i++){
1331 len += 4 + strlen(symbols[i]) + 1;
1332 }
1333 symbolString = (char *)calloc(len, 1);
1334 for (i = 0; i < data->debug->backtraceSize; i++){
1335 strcat(symbolString, " ");
1336 strcat(symbolString, symbols[i]);
1337 strcat(symbolString, "\n");
1338 }
1339
1340 free(symbols);
1341
1342 _objc_inform_now_and_on_crash
1343 ("The matching objc_addExceptionHandler() was called "
1344 "by:\nThread '%s': Dispatch queue: '%s': \n%s",
1345 data->debug->thread, data->debug->queue, symbolString);
1346
1347 goto done;
1348 }
1349 }
1350 }
1351 done:
1352 AltHandlerDebugLock.unlock();
1353 }
1354
1355
1356 objc_alt_handler_error();
1357
1358 _objc_fatal
1359 ("objc_removeExceptionHandler() called with unknown alt handler; "
1360 "this is probably a bug in multithreaded AppKit use. ");
1361 }
1362
1363 // called in order registered, to match 32-bit _NSAddAltHandler2
1364 // fixme reverse registration order matches c++ destructors better
1365 static void call_alt_handlers(struct _Unwind_Context *ctx)
1366 {
1367 uintptr_t ip = _Unwind_GetIP(ctx) - 1;
1368 uintptr_t cfa = _Unwind_GetCFA(ctx);
1369 unsigned int i;
1370
1371 struct alt_handler_list *list = fetch_handler_list(NO);
1372 if (!list || list->used == 0) return;
1373
1374 for (i = 0; i < list->allocated; i++) {
1375 struct alt_handler_data *data = &list->handlers[i];
1376 if (ip >= data->frame.ip_start && ip < data->frame.ip_end && data->frame.cfa == cfa)
1377 {
1378 if (data->frame.ips) {
1379 unsigned int r = 0;
1380 bool found;
1381 while (1) {
1382 uintptr_t start = data->frame.ips[r].start;
1383 uintptr_t end = data->frame.ips[r].end;
1384 r++;
1385 if (start == 0 && end == 0) {
1386 found = false;
1387 break;
1388 }
1389 if (ip >= start && ip < end) {
1390 found = true;
1391 break;
1392 }
1393 }
1394 if (!found) continue;
1395 }
1396
1397 // Copy and clear before the callback, in case the
1398 // callback manipulates the alt handler list.
1399 struct alt_handler_data copy = *data;
1400 bzero(data, sizeof(*data));
1401 list->used--;
1402 if (PrintExceptions || PrintAltHandlers) {
1403 _objc_inform("EXCEPTIONS: calling alt handler %p(%p) from "
1404 "frame [ip=%p..%p sp=%p]", copy.fn, copy.context,
1405 (void *)copy.frame.ip_start,
1406 (void *)copy.frame.ip_end,
1407 (void *)copy.frame.cfa);
1408 }
1409 if (copy.fn) (*copy.fn)(nil, copy.context);
1410 if (copy.frame.ips) free(copy.frame.ips);
1411 }
1412 }
1413 }
1414
1415 // SUPPORT_ALT_HANDLERS
1416 #endif
1417
1418
1419 /***********************************************************************
1420 * exception_init
1421 * Initialize libobjc's exception handling system.
1422 * Called by map_images().
1423 **********************************************************************/
1424 void exception_init(void)
1425 {
1426 old_terminate = std::set_terminate(&_objc_terminate);
1427 }
1428
1429
1430 // __OBJC2__
1431 #endif
1432
1433 // Define this everywhere even if it isn't used, to simplify fork() safety code
1434 mutex_t AltHandlerDebugLock;