3 Star 0 Fork 0

Gitee 极速下载 / gnustep-objective-c-runtime

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
此仓库是为了提升国内下载速度的镜像仓库,每日同步一次。 原始仓库: https://github.com/gnustep/libobjc2
克隆/下载
eh_personality.c 23.61 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "dwarf_eh.h"
#include "objc/runtime.h"
#include "objc/hooks.h"
#include "objc/objc-exception.h"
#include "class.h"
#include "objcxx_eh.h"
#ifndef DEBUG_EXCEPTIONS
#define DEBUG_LOG(...)
#else
#define DEBUG_LOG(str, ...) fprintf(stderr, str, ## __VA_ARGS__)
#endif
#ifndef __has_builtin
#define __has_builtin(x) 0
#endif
#if !__has_builtin(__builtin_unreachable)
#define __builtin_unreachable abort
#endif
void test_cxx_eh_implementation();
/**
* The Itanium C++ public structure for in-flight exception status.
*/
struct __cxa_eh_globals
{
/**
* The head exception object. By convention, this is actually the end of
* the `__cxa_exception` structure and points to the address of the thrown
* object. This is either an `id*` or a pointer to a C++ type that we're
* not going to look at.
*/
struct __cxa_exception *caughtExceptions;
/**
* The number of in-flight exceptions thrown.
*/
unsigned int uncaughtExceptions;
};
// Weak references to C++ runtime functions. We don't bother testing that
// these are 0 before calling them, because if they are not resolved then we
// should not be in a code path that involves a C++ exception.
__attribute__((weak)) void *__cxa_begin_catch(void *e);
__attribute__((weak)) void __cxa_end_catch(void);
__attribute__((weak)) void __cxa_rethrow(void);
__attribute__((weak)) struct __cxa_eh_globals *__cxa_get_globals(void);
/**
* Class of exceptions to distinguish between this and other exception types.
*/
static const uint64_t objc_exception_class = EXCEPTION_CLASS('G','N','U','C','O','B','J','C');
/**
* Structure used as a header on thrown exceptions.
*/
struct objc_exception
{
/** The selector value to be returned when installing the catch handler.
* Used at the call site to determine which catch() block should execute.
* This is found in phase 1 of unwinding then installed in phase 2.*/
int handlerSwitchValue;
/** The cached landing pad for the catch handler.*/
void *landingPad;
/**
* Next pointer for chained exceptions.
*/
struct objc_exception *next;
/**
* The number of nested catches that may hold this exception. This is
* negative while an exception is being rethrown.
*/
int catch_count;
/** The language-agnostic part of the exception header. */
struct _Unwind_Exception unwindHeader;
/** Thrown object. This is after the unwind header so that the C++
* exception handler can catch this as a foreign exception. */
id object;
/** C++ exception structure. Used for mixed exceptions. When we are in
* Objective-C++ code, we create this structure for passing to the C++
* exception personality function. It will then handle installing
* exceptions for us. */
struct _Unwind_Exception *cxx_exception;
};
struct objc_exception *objc_exception_from_header(struct _Unwind_Exception *ex)
{
return (struct objc_exception*)((char*)ex -
offsetof(struct objc_exception, unwindHeader));
}
typedef enum
{
handler_none,
handler_cleanup,
handler_catchall_id,
handler_catchall,
handler_class
} handler_type;
enum exception_type
{
NONE,
CXX,
OBJC,
FOREIGN,
BOXED_FOREIGN
};
struct thread_data
{
enum exception_type current_exception_type;
BOOL cxxCaughtException;
struct objc_exception *caughtExceptions;
};
static __thread struct thread_data thread_data;
static struct thread_data *get_thread_data(void)
{
return &thread_data;
}
static struct thread_data *get_thread_data_fast(void)
{
return &thread_data;
}
/**
* Saves the result of the landing pad that we have found. For ARM, this is
* stored in the generic unwind structure, while on other platforms it is
* stored in the Objective-C exception.
*/
static void saveLandingPad(struct _Unwind_Context *context,
struct _Unwind_Exception *ucb,
struct objc_exception *ex,
int selector,
dw_eh_ptr_t landingPad)
{
#if defined(__arm__) && !defined(__ARM_DWARF_EH__)
// On ARM, we store the saved exception in the generic part of the structure
ucb->barrier_cache.sp = _Unwind_GetGR(context, 13);
ucb->barrier_cache.bitpattern[1] = (uint32_t)selector;
ucb->barrier_cache.bitpattern[3] = (uint32_t)landingPad;
#else
// Cache the results for the phase 2 unwind, if we found a handler
// and this is not a foreign exception. We can't cache foreign exceptions
// because we don't know their structure (although we could cache C++
// exceptions...)
if (ex)
{
ex->handlerSwitchValue = selector;
ex->landingPad = landingPad;
}
#endif
}
/**
* Loads the saved landing pad. Returns 1 on success, 0 on failure.
*/
static int loadLandingPad(struct _Unwind_Context *context,
struct _Unwind_Exception *ucb,
struct objc_exception *ex,
unsigned long *selector,
dw_eh_ptr_t *landingPad)
{
#if defined(__arm__) && !defined(__ARM_DWARF_EH__)
*selector = ucb->barrier_cache.bitpattern[1];
*landingPad = (dw_eh_ptr_t)ucb->barrier_cache.bitpattern[3];
return 1;
#else
if (ex)
{
*selector = ex->handlerSwitchValue;
*landingPad = ex->landingPad;
return 0;
}
return 0;
#endif
}
static inline _Unwind_Reason_Code continueUnwinding(struct _Unwind_Exception *ex,
struct _Unwind_Context *context)
{
#if defined(__arm__) && !defined(__ARM_DWARF_EH__)
if (__gnu_unwind_frame(ex, context) != _URC_OK) { return _URC_FAILURE; }
#endif
return _URC_CONTINUE_UNWIND;
}
static void cleanup(_Unwind_Reason_Code reason, struct _Unwind_Exception *e)
{
/*
if (header->exceptionDestructor)
header->exceptionDestructor (e + 1);
free((struct objc_exception*) ((char*)e - offsetof(struct objc_exception,
unwindHeader)));
*/
}
void objc_exception_rethrow(struct _Unwind_Exception *e);
/**
* Throws an Objective-C exception. This function is, unfortunately, used for
* rethrowing caught exceptions too, even in @finally() blocks. Unfortunately,
* this means that we have some problems if the exception is boxed.
*/
void objc_exception_throw(id object)
{
struct thread_data *td = get_thread_data();
DEBUG_LOG("Throwing %p, in flight exception: %p\n", object, td->lastThrownObject);
DEBUG_LOG("Exception caught by C++: %d\n", td->cxxCaughtException);
// If C++ caught the exception, then we may need to make C++ rethrow it if
// we want to preserve exception state. Rethrows should be handled with
// objc_exception_rethrow, but clang appears to do the wrong thing for some
// cases.
if (td->cxxCaughtException)
{
struct __cxa_eh_globals *globals = __cxa_get_globals();
if ((globals->caughtExceptions != NULL) &&
(*(id*)globals->caughtExceptions == object))
{
__cxa_rethrow();
}
}
SEL rethrow_sel = sel_registerName("rethrow");
if ((nil != object) &&
(class_respondsToSelector(classForObject(object), rethrow_sel)))
{
DEBUG_LOG("Rethrowing\n");
IMP rethrow = objc_msg_lookup(object, rethrow_sel);
rethrow(object, rethrow_sel);
// Should not be reached! If it is, then the rethrow method actually
// didn't, so we throw it normally.
}
DEBUG_LOG("Throwing %p\n", object);
struct objc_exception *ex = calloc(1, sizeof(struct objc_exception));
ex->unwindHeader.exception_class = objc_exception_class;
ex->unwindHeader.exception_cleanup = cleanup;
ex->object = object;
td->cxxCaughtException = NO;
_Unwind_Reason_Code err = _Unwind_RaiseException(&ex->unwindHeader);
free(ex);
if (_URC_END_OF_STACK == err && 0 != _objc_unexpected_exception)
{
_objc_unexpected_exception(object);
}
DEBUG_LOG("Throw returned %d\n",(int) err);
abort();
}
static Class get_type_table_entry(struct _Unwind_Context *context,
struct dwarf_eh_lsda *lsda,
int filter)
{
dw_eh_ptr_t record = lsda->type_table -
dwarf_size_of_fixed_size_field(lsda->type_table_encoding)*filter;
dw_eh_ptr_t start = record;
int64_t offset = read_value(lsda->type_table_encoding, &record);
if (0 == offset) { return Nil; }
// ...so we need to resolve it
char *class_name = (char*)(intptr_t)resolve_indirect_value(context,
lsda->type_table_encoding, offset, start);
if (0 == class_name) { return Nil; }
DEBUG_LOG("Class name: %s\n", class_name);
if (strcmp("@id", class_name) == 0) { return (Class)1; }
return (Class)objc_getClass(class_name);
}
static BOOL isKindOfClass(Class thrown, Class type)
{
do
{
if (thrown == type)
{
return YES;
}
thrown = class_getSuperclass(thrown);
} while (Nil != thrown);
return NO;
}
static handler_type check_action_record(struct _Unwind_Context *context,
BOOL foreignException,
struct dwarf_eh_lsda *lsda,
dw_eh_ptr_t action_record,
Class thrown_class,
unsigned long *selector)
{
if (!action_record) { return handler_cleanup; }
while (action_record)
{
int filter = read_sleb128(&action_record);
dw_eh_ptr_t action_record_offset_base = action_record;
int displacement = read_sleb128(&action_record);
*selector = filter;
DEBUG_LOG("Filter: %d\n", filter);
if (filter > 0)
{
Class type = get_type_table_entry(context, lsda, filter);
DEBUG_LOG("%p type: %d\n", type, !foreignException);
// Catchall
if (Nil == type)
{
return handler_catchall;
}
// We treat id catches as catchalls when an object is thrown and as
// nothing when a foreign exception is thrown
else if ((Class)1 == type)
{
DEBUG_LOG("Found id catch\n");
if (!foreignException)
{
return handler_catchall_id;
}
}
else if (!foreignException && isKindOfClass(thrown_class, type))
{
DEBUG_LOG("found handler for %s\n", type->name);
return handler_class;
}
else if (thrown_class == type)
{
return handler_class;
}
}
else if (filter == 0)
{
DEBUG_LOG("0 filter\n");
// Cleanup? I think the GNU ABI doesn't actually use this, but it
// would be a good way of indicating a non-id catchall...
return handler_cleanup;
}
else
{
DEBUG_LOG("Filter value: %d\n"
"Your compiler and I disagree on the correct layout of EH data.\n",
filter);
abort();
}
*selector = 0;
action_record = displacement ?
action_record_offset_base + displacement : 0;
}
return handler_none;
}
/**
* The Objective-C exception personality function implementation. This is
* shared by the GCC-compatible and the new implementation.
*
* The key difference is that the new implementation always returns the
* exception object and boxes it.
*/
static inline _Unwind_Reason_Code internal_objc_personality(int version,
_Unwind_Action actions,
uint64_t exceptionClass,
struct _Unwind_Exception *exceptionObject,
struct _Unwind_Context *context,
BOOL isNew)
{
DEBUG_LOG("%s personality function called %p\n", isNew ? "New" : "Old", exceptionObject);
// This personality function is for version 1 of the ABI. If you use it
// with a future version of the ABI, it won't know what to do, so it
// reports a fatal error and give up before it breaks anything.
if (1 != version)
{
return _URC_FATAL_PHASE1_ERROR;
}
struct objc_exception *ex = 0;
#ifdef DEBUG_EXCEPTIONS
char *cls = (char*)&exceptionClass;
#endif
DEBUG_LOG("Class: %c%c%c%c%c%c%c%c\n", cls[7], cls[6], cls[5], cls[4], cls[3], cls[2], cls[1], cls[0]);
// Check if this is a foreign exception. If it is a C++ exception, then we
// have to box it. If it's something else, like a LanguageKit exception
// then we ignore it (for now)
BOOL foreignException = exceptionClass != objc_exception_class;
// Is this a C++ exception containing an Objective-C++ object?
BOOL objcxxException = NO;
// The object to return
void *object = NULL;
#ifndef NO_OBJCXX
if (cxx_exception_class == 0)
{
test_cxx_eh_implementation();
}
if (exceptionClass == cxx_exception_class)
{
int objcxx;
id obj = objc_object_for_cxx_exception(exceptionObject, &objcxx);
objcxxException = objcxx;
if (objcxxException)
{
object = obj;
DEBUG_LOG("ObjC++ object exception %p\n", object);
// This is a foreign exception, buy for the purposes of exception
// matching, we pretend that it isn't.
foreignException = NO;
}
}
#endif
Class thrown_class = Nil;
if (objcxxException)
{
thrown_class = (object == 0) ? Nil : classForObject((id)object);
}
// If it's not a foreign exception, then we know the layout of the
// language-specific exception stuff.
else if (!foreignException)
{
ex = objc_exception_from_header(exceptionObject);
if (ex->object != nil)
{
thrown_class = classForObject(ex->object);
}
}
else if (_objc_class_for_boxing_foreign_exception)
{
thrown_class = _objc_class_for_boxing_foreign_exception(exceptionClass);
DEBUG_LOG("Foreign class: %p\n", thrown_class);
}
unsigned char *lsda_addr = (void*)_Unwind_GetLanguageSpecificData(context);
DEBUG_LOG("LSDA: %p\n", lsda_addr);
// No LSDA implies no landing pads - try the next frame
if (0 == lsda_addr)
{
return continueUnwinding(exceptionObject, context);
}
// These two variables define how the exception will be handled.
struct dwarf_eh_action action = {0};
unsigned long selector = 0;
if (actions & _UA_SEARCH_PHASE)
{
DEBUG_LOG("Search phase...\n");
struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr);
action = dwarf_eh_find_callsite(context, &lsda);
handler_type handler = check_action_record(context, foreignException,
&lsda, action.action_record, thrown_class, &selector);
DEBUG_LOG("handler: %d\n", handler);
// If there's no action record, we've only found a cleanup, so keep
// searching for something real
if (handler == handler_class ||
((handler == handler_catchall_id) && !foreignException) ||
(handler == handler_catchall))
{
saveLandingPad(context, exceptionObject, ex, selector, action.landing_pad);
DEBUG_LOG("Found handler! %d\n", handler);
return _URC_HANDLER_FOUND;
}
return continueUnwinding(exceptionObject, context);
}
DEBUG_LOG("Phase 2: Fight!\n");
// TODO: If this is a C++ exception, we can cache the lookup and cheat a
// bit
if (!(actions & _UA_HANDLER_FRAME))
{
DEBUG_LOG("Not the handler frame, looking up the cleanup again\n");
struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr);
action = dwarf_eh_find_callsite(context, &lsda);
// If there's no cleanup here, continue unwinding.
if (0 == action.landing_pad)
{
return continueUnwinding(exceptionObject, context);
}
handler_type handler = check_action_record(context, foreignException,
&lsda, action.action_record, thrown_class, &selector);
DEBUG_LOG("handler! %d %d\n", (int)handler, (int)selector);
// On ARM, we occasionally get called to install a handler without
// phase 1 running (no idea why, I suspect a bug in the generic
// unwinder), so skip this check.
#if !(defined(__arm__) && !defined(__ARM_DWARF_EH__))
// If this is not a cleanup, ignore it and keep unwinding.
if ((handler != handler_cleanup) && !objcxxException)
{
DEBUG_LOG("Ignoring handler! %d\n",handler);
return continueUnwinding(exceptionObject, context);
}
#endif
DEBUG_LOG("Installing cleanup...\n");
// If there is a cleanup, we need to return the exception structure
// (not the object) to the calling frame. The exception object
object = exceptionObject;
}
else if (foreignException || objcxxException)
{
struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr);
action = dwarf_eh_find_callsite(context, &lsda);
check_action_record(context, foreignException, &lsda,
action.action_record, thrown_class, &selector);
// If it's a foreign exception, then box it. If it's an Objective-C++
// exception, then we need to delete the exception object.
if (foreignException)
{
DEBUG_LOG("Doing the foreign exception thing...\n");
//[thrown_class exceptionWithForeignException: exceptionObject];
SEL box_sel = sel_registerName("exceptionWithForeignException:");
IMP boxfunction = objc_msg_lookup((id)thrown_class, box_sel);
if (!isNew)
{
object = boxfunction((id)thrown_class, box_sel, exceptionObject);
DEBUG_LOG("Boxed as %p\n", object);
}
}
else if (!isNew) // ObjCXX exception
{
_Unwind_DeleteException(exceptionObject);
}
// In the new EH ABI, we call objc_begin_catch() / and
// objc_end_catch(), which will wrap their __cxa* versions.
}
else
{
// Restore the saved info if we saved some last time.
loadLandingPad(context, exceptionObject, ex, &selector, &action.landing_pad);
object = ex->object;
if (!isNew)
{
free(ex);
}
}
_Unwind_SetIP(context, (uintptr_t)action.landing_pad);
_Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
(uintptr_t)(isNew ? exceptionObject : object));
_Unwind_SetGR(context, __builtin_eh_return_data_regno(1), selector);
DEBUG_LOG("Installing context, selector %d\n", (int)selector);
get_thread_data()->cxxCaughtException = NO;
return _URC_INSTALL_CONTEXT;
}
OBJC_PUBLIC
BEGIN_PERSONALITY_FUNCTION(__gnu_objc_personality_v0)
return internal_objc_personality(version, actions, exceptionClass,
exceptionObject, context, NO);
}
OBJC_PUBLIC
BEGIN_PERSONALITY_FUNCTION(__gnustep_objc_personality_v0)
return internal_objc_personality(version, actions, exceptionClass,
exceptionObject, context, YES);
}
OBJC_PUBLIC
BEGIN_PERSONALITY_FUNCTION(__gnustep_objcxx_personality_v0)
#ifndef NO_OBJCXX
if (cxx_exception_class == 0)
{
test_cxx_eh_implementation();
}
if (exceptionClass == objc_exception_class)
{
struct objc_exception *ex = objc_exception_from_header(exceptionObject);
if (0 == ex->cxx_exception)
{
ex->cxx_exception = objc_init_cxx_exception(ex->object);
}
// We now have two copies of the _Unwind_Exception object (which stores
// state for the unwinder) in flight. Make sure that they're in sync.
COPY_EXCEPTION(ex->cxx_exception, exceptionObject);
exceptionObject = ex->cxx_exception;
exceptionClass = cxx_exception_class;
int ret = CALL_PERSONALITY_FUNCTION(__gxx_personality_v0);
COPY_EXCEPTION(exceptionObject, ex->cxx_exception);
if (ret == _URC_INSTALL_CONTEXT)
{
get_thread_data()->cxxCaughtException = YES;
}
return ret;
}
#endif
return CALL_PERSONALITY_FUNCTION(__gxx_personality_v0);
}
OBJC_PUBLIC id objc_begin_catch(struct _Unwind_Exception *exceptionObject)
{
struct thread_data *td = get_thread_data();
DEBUG_LOG("Beginning catch %p\n", exceptionObject);
td->cxxCaughtException = NO;
if (exceptionObject->exception_class == objc_exception_class)
{
td->current_exception_type = OBJC;
struct objc_exception *ex = objc_exception_from_header(exceptionObject);
if (ex->catch_count == 0)
{
// If this is the first catch, add it to the list.
ex->catch_count = 1;
ex->next = td->caughtExceptions;
td->caughtExceptions = ex;
}
else if (ex->catch_count < 0)
{
// If this is being thrown, mark it as caught again and increment
// the refcount
ex->catch_count = -ex->catch_count + 1;
}
else
{
// Otherwise, just increment the catch count
ex->catch_count++;
}
DEBUG_LOG("objc catch\n");
return ex->object;
}
// If we have a foreign exception while we have stacked exceptions, we have
// a problem. We can't chain them, so we follow the example of C++ and
// just abort.
if (td->caughtExceptions != 0)
{
// FIXME: Actually, we can handle a C++ exception if only ObjC
// exceptions are in-flight
abort();
}
#ifndef NO_OBJCXX
// If this is a C++ exception, let the C++ runtime handle it.
if (exceptionObject->exception_class == cxx_exception_class)
{
DEBUG_LOG("c++ catch\n");
td->current_exception_type = CXX;
return __cxa_begin_catch(exceptionObject);
}
#endif
DEBUG_LOG("foreign exception catch\n");
// Box if we have a boxing function.
if (_objc_class_for_boxing_foreign_exception)
{
Class thrown_class =
_objc_class_for_boxing_foreign_exception(exceptionObject->exception_class);
SEL box_sel = sel_registerName("exceptionWithForeignException:");
id(*boxfunction)(Class,SEL,struct _Unwind_Exception*) =
(id(*)(Class,SEL,struct _Unwind_Exception*))objc_msg_lookup((id)thrown_class, box_sel);
if (boxfunction != 0)
{
id boxed = boxfunction(thrown_class, box_sel, exceptionObject);
td->caughtExceptions = (struct objc_exception*)boxed;
td->current_exception_type = BOXED_FOREIGN;
return boxed;
}
}
td->current_exception_type = FOREIGN;
td->caughtExceptions = (struct objc_exception*)exceptionObject;
// If this is some other kind of exception, then assume that the value is
// at the end of the exception header.
return (id)((char*)exceptionObject + sizeof(struct _Unwind_Exception));
}
OBJC_PUBLIC void objc_end_catch(void)
{
struct thread_data *td = get_thread_data_fast();
// If this is a boxed foreign exception then the boxing class is
// responsible for cleaning it up
if (td->current_exception_type == BOXED_FOREIGN)
{
td->caughtExceptions = 0;
td->current_exception_type = NONE;
return;
}
DEBUG_LOG("Ending catch\n");
// If this is a C++ exception, then just let the C++ runtime handle it.
if (td->current_exception_type == CXX)
{
__cxa_end_catch();
td->current_exception_type = OBJC;
return;
}
if (td->current_exception_type == FOREIGN)
{
struct _Unwind_Exception *e = ((struct _Unwind_Exception*)td->caughtExceptions);
e->exception_cleanup(_URC_FOREIGN_EXCEPTION_CAUGHT, e);
td->current_exception_type = NONE;
td->caughtExceptions = 0;
return;
}
// Otherwise we should do the cleanup thing. Nested catches are possible,
// so we only clean up the exception if this is the last reference.
assert(td->caughtExceptions != 0);
struct objc_exception *ex = td->caughtExceptions;
// If this is being rethrown decrement its (negated) catch count, but don't
// delete it even if its catch count would be 0.
if (ex->catch_count < 0)
{
ex->catch_count++;
return;
}
ex->catch_count--;
if (ex->catch_count == 0)
{
td->caughtExceptions = ex->next;
free(ex);
}
}
OBJC_PUBLIC void objc_exception_rethrow(struct _Unwind_Exception *e)
{
struct thread_data *td = get_thread_data_fast();
// If this is an Objective-C exception, then
if (td->current_exception_type == OBJC)
{
struct objc_exception *ex = objc_exception_from_header(e);
assert(e->exception_class == objc_exception_class);
assert(ex == td->caughtExceptions);
assert(ex->catch_count > 0);
// Negate the catch count, so that we can detect that this is a
// rethrown exception in objc_end_catch
ex->catch_count = -ex->catch_count;
_Unwind_Reason_Code err = _Unwind_Resume_or_Rethrow(e);
free(ex);
if (_URC_END_OF_STACK == err && 0 != _objc_unexpected_exception)
{
_objc_unexpected_exception(ex->object);
}
abort();
}
#ifndef NO_OBJCXX
else if (td->current_exception_type == CXX)
{
assert(e->exception_class == cxx_exception_class);
__cxa_rethrow();
}
#endif
if (td->current_exception_type == BOXED_FOREIGN)
{
SEL rethrow_sel = sel_registerName("rethrow");
id object = (id)td->caughtExceptions;
if ((nil != object) &&
(class_respondsToSelector(classForObject(object), rethrow_sel)))
{
DEBUG_LOG("Rethrowing boxed exception\n");
IMP rethrow = objc_msg_lookup(object, rethrow_sel);
rethrow(object, rethrow_sel);
}
}
assert(e == (struct _Unwind_Exception*)td->caughtExceptions);
_Unwind_Resume_or_Rethrow(e);
abort();
}
objc_uncaught_exception_handler objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler handler)
{
return __atomic_exchange_n(&_objc_unexpected_exception, handler, __ATOMIC_SEQ_CST);
}
C/C++
1
https://gitee.com/mirrors/gnustep-objective-c-runtime.git
git@gitee.com:mirrors/gnustep-objective-c-runtime.git
mirrors
gnustep-objective-c-runtime
gnustep-objective-c-runtime
master

搜索帮助

53164aa7 5694891 3bd8fe86 5694891