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