Index: libunwind/include/unwind.h =================================================================== --- libunwind/include/unwind.h +++ libunwind/include/unwind.h @@ -106,11 +106,6 @@ long long int :0; /* Enforce the 8-byte alignment */ } __attribute__((__aligned__(8))); -typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) - (_Unwind_State state, - _Unwind_Exception* exceptionObject, - struct _Unwind_Context* context); - typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)( _Unwind_State state, _Unwind_Exception *exceptionObject, struct _Unwind_Context *context); @@ -141,6 +136,11 @@ // alignment for the target"; so do we. } __attribute__((__aligned__)); +typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)( + int version, _Unwind_Action actions, uint64_t exceptionClass, + _Unwind_Exception *exceptionObject, struct _Unwind_Context *context); +#endif + typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) (int version, _Unwind_Action actions, @@ -149,11 +149,6 @@ struct _Unwind_Context* context, void* stop_parameter ); -typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)( - int version, _Unwind_Action actions, uint64_t exceptionClass, - _Unwind_Exception *exceptionObject, struct _Unwind_Context *context); -#endif - #ifdef __cplusplus extern "C" { #endif Index: libunwind/src/Unwind-EHABI.cpp =================================================================== --- libunwind/src/Unwind-EHABI.cpp +++ libunwind/src/Unwind-EHABI.cpp @@ -668,6 +668,109 @@ return _URC_FATAL_PHASE2_ERROR; } +static _Unwind_Reason_Code unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor, + _Unwind_Exception *exception_object, + _Unwind_Stop_Fn stop, void *stop_parameter) { + // See comment at the start of unwind_phase1 regarding VRS integrity. + __unw_init_local(cursor, uc); + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_force(ex_ojb=%p)", + static_cast(exception_object)); + // Walk each frame until we reach where search phase said to stop + while (__unw_step(cursor) > 0) { + + // Update info about this frame. + unw_proc_info_t frameInfo; + if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): __unw_step " + "failed => _URC_END_OF_STACK", + (void *)exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + + // When tracing, print state information. + if (_LIBUNWIND_TRACING_UNWINDING) { + char functionBuf[512]; + const char *functionName = functionBuf; + unw_word_t offset; + if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), + &offset) != UNW_ESUCCESS) || + (frameInfo.start_ip + offset > frameInfo.end_ip)) + functionName = ".anonymous."; + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIxPTR + ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR, + (void *)exception_object, frameInfo.start_ip, functionName, + frameInfo.lsda, frameInfo.handler); + } + + // Call stop function at each frame. + _Unwind_Action action = + (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE); + _Unwind_Reason_Code stopResult = + (*stop)(1, action, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)(cursor), stop_parameter); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): stop function returned %d", + (void *)exception_object, stopResult); + if (stopResult != _URC_NO_REASON) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): stopped by stop function", + (void *)exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + + // If there is a personality routine, tell it we are unwinding. + if (frameInfo.handler != 0) { + _Unwind_Personality_Fn p = + (_Unwind_Personality_Fn)(intptr_t)(frameInfo.handler); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): calling personality function %p", + (void *)exception_object, (void *)(uintptr_t)p); + _Unwind_Reason_Code personalityResult = + (*p)(action, exception_object, + (struct _Unwind_Context *)(cursor)); + switch (personalityResult) { + case _URC_CONTINUE_UNWIND: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned " + "_URC_CONTINUE_UNWIND", + (void *)exception_object); + // Destructors called, continue unwinding + break; + case _URC_INSTALL_CONTEXT: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned " + "_URC_INSTALL_CONTEXT", + (void *)exception_object); + // We may get control back if landing pad calls _Unwind_Resume(). + __unw_resume(cursor); + break; + default: + // Personality routine returned an unknown result code. + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned %d, " + "_URC_FATAL_PHASE2_ERROR", + (void *)exception_object, personalityResult); + return _URC_FATAL_PHASE2_ERROR; + } + } + } + + // Call stop function one last time and tell it we've reached the end + // of the stack. + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop " + "function with _UA_END_OF_STACK", + (void *)exception_object); + _Unwind_Action lastAction = + (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK); + (*stop)(1, lastAction, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)(cursor), stop_parameter);; + + // Clean up phase did not resume at the frame that the search phase said it + // would. + return _URC_FATAL_PHASE2_ERROR; +} + /// Called by __cxa_throw. Only returns if there is a fatal error. _LIBUNWIND_EXPORT _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception *exception_object) { @@ -680,6 +783,7 @@ // This field for is for compatibility with GCC to say this isn't a forced // unwind. EHABI #7.2 exception_object->unwinder_cache.reserved1 = 0; + exception_object->unwinder_cache.reserved2 = 0; // phase 1: the search phase _Unwind_Reason_Code phase1 = unwind_phase1(&uc, &cursor, exception_object); @@ -715,10 +819,12 @@ unw_cursor_t cursor; __unw_getcontext(&uc); - // _Unwind_RaiseException on EHABI will always set the reserved1 field to 0, - // which is in the same position as private_1 below. - // TODO(ajwong): Who wronte the above? Why is it true? - unwind_phase2(&uc, &cursor, exception_object, true); + if (exception_object->unwinder_cache.reserved1) + unwind_phase2_forced(&uc, &cursor, exception_object, + (_Unwind_Stop_Fn) exception_object->unwinder_cache.reserved1, + (void*) exception_object->unwinder_cache.reserved2); + else + unwind_phase2(&uc, &cursor, exception_object, true); // Clients assume _Unwind_Resume() does not return, so all we can do is abort. _LIBUNWIND_ABORT("_Unwind_Resume() can't return"); @@ -965,6 +1071,27 @@ _LIBUNWIND_ABORT("unsupported register class"); } +/// Not used by C++. +/// Unwinds stack, calling "stop" function at each frame. +/// Could be used to implement longjmp(). +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_ForcedUnwind(_Unwind_Exception *exception_object, + _Unwind_Stop_Fn stop, void *stop_parameter) { + _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)", + (void *)exception_object, (void *)(uintptr_t)stop); + unw_context_t uc; + unw_cursor_t cursor; + __unw_getcontext(&uc); + + // Mark that this is a forced unwind, so _Unwind_Resume() can do + // the right thing. + exception_object->unwinder_cache.reserved1 = (uintptr_t) stop; + exception_object->unwinder_cache.reserved2 = (uintptr_t) stop_parameter; + + // do it + return unwind_phase2_forced(&uc, &cursor, exception_object, stop, stop_parameter); +} + /// Called by personality handler during phase 2 to find the start of the /// function. _LIBUNWIND_EXPORT uintptr_t Index: libunwind/src/UnwindLevel1-gcc-ext.c =================================================================== --- libunwind/src/UnwindLevel1-gcc-ext.c +++ libunwind/src/UnwindLevel1-gcc-ext.c @@ -28,28 +28,23 @@ #define private_1 private_[0] #endif -/// Called by __cxa_rethrow(). -_LIBUNWIND_EXPORT _Unwind_Reason_Code -_Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object) { #if defined(_LIBUNWIND_ARM_EHABI) - _LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%ld", - (void *)exception_object, - (long)exception_object->unwinder_cache.reserved1); +#define PRIVATE_1 unwinder_cache.reserved1 #else - _LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%" PRIdPTR, - (void *)exception_object, - (intptr_t)exception_object->private_1); +#define PRIVATE_1 private_1 #endif -#if defined(_LIBUNWIND_ARM_EHABI) - // _Unwind_RaiseException on EHABI will always set the reserved1 field to 0, - // which is in the same position as private_1 below. - return _Unwind_RaiseException(exception_object); -#else +/// Called by __cxa_rethrow(). +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object) { +_LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%" PRIdPTR, + (void *)exception_object, + (intptr_t)exception_object->PRIVATE_1); + // If this is non-forced and a stopping place was found, then this is a // re-throw. // Call _Unwind_RaiseException() as if this was a new exception - if (exception_object->private_1 == 0) { + if (exception_object->PRIVATE_1 == 0) { return _Unwind_RaiseException(exception_object); // Will return if there is no catch clause, so that __cxa_rethrow can call // std::terminate(). @@ -60,7 +55,7 @@ _Unwind_Resume(exception_object); _LIBUNWIND_ABORT("_Unwind_Resume_or_Rethrow() called _Unwind_RaiseException()" " which unexpectedly returned"); -#endif + }