diff --git a/libcxxabi/include/zos/unwind.h b/libcxxabi/include/zos/unwind.h new file mode 100644 --- /dev/null +++ b/libcxxabi/include/zos/unwind.h @@ -0,0 +1,63 @@ +#ifndef _UNWIND_H +#define _UNWIND_H + +typedef enum { + _URC_NO_REASON = 0, + _URC_OK = 0, + _URC_FOREIGN_EXCEPTION_CAUGHT = 1, + _URC_FATAL_PHASE2_ERROR = 2, + _URC_FATAL_PHASE1_ERROR = 3, + _URC_NORMAL_STOP = 4, + _URC_END_OF_STACK = 5, + _URC_HANDLER_FOUND = 6, + _URC_INSTALL_CONTEXT = 7, + _URC_CONTINUE_UNWIND = 8, +} _Unwind_Reason_Code; + +typedef enum { + _UA_SEARCH_PHASE = 1, + _UA_CLEANUP_PHASE = 2, + _UA_HANDLER_FRAME = 4, + _UA_FORCE_UNWIND = 8, + _UA_END_OF_STACK = 16 // gcc extension to C++ ABI +} _Unwind_Action; + +struct _Unwind_Exception; +struct _Unwind_Context; + +typedef void (*_Unwind_Exception_Cleanup_Fn) + (_Unwind_Reason_Code reason, struct _Unwind_Exception *exc); + +struct _Unwind_Exception { + char reserved[160] __attribute__ ((aligned(8))); + uint64_t exception_class; + _Unwind_Exception_Cleanup_Fn exception_cleanup; +}; + +#if __cplusplus +extern "C" +{ +#endif +_Unwind_Reason_Code _Unwind_RaiseException( struct _Unwind_Exception *exception_object ); +void _Unwind_Resume (struct _Unwind_Exception *exception_object); +void _Unwind_DeleteException (struct _Unwind_Exception *exception_object); +uintptr_t _Unwind_GetIP(void *ctx); +void _Unwind_SetIP (void *context, uint64_t new_value); +uintptr_t _Unwind_GetRegionStart(void *ctx); + +void _Unwind_SetGR (struct _Unwind_Context *context, int index, uint64_t new_value); +uintptr_t _Unwind_GetGR (void *context, int index); + +void *_Unwind_StackPtr(void *ctx); +void* _Unwind_GetLandingPad(void *ctx); +void _Unwind_SetLandingPad(void *ctx, void *landingpad); +void *_Unwind_GetExceptionAddress(void *ctx); +void _Unwind_SetExceptionAddress(void *ctx, void *exception); +unsigned int _Unwind_GetTypeSelector(void *ctx); +void _Unwind_SetTypeSelector(void *ctx, unsigned int ttypeIndex); + +struct _Unwind_Exception *_UnwindZOS_PopException(); +#if __cplusplus +} +#endif +#endif diff --git a/libcxxabi/src/CMakeLists.txt b/libcxxabi/src/CMakeLists.txt --- a/libcxxabi/src/CMakeLists.txt +++ b/libcxxabi/src/CMakeLists.txt @@ -46,6 +46,13 @@ ../include/cxxabi.h ) +if (ZOS) + list(APPEND LIBCXXABI_HEADERS + ../include/zos/unwind.h + ) + include_directories("../include/zos/") +endif() + # Add all the headers to the project for IDEs. if (MSVC_IDE OR XCODE) # Force them all into the headers dir on MSVC, otherwise they end up at diff --git a/libcxxabi/src/cxa_exception.cpp b/libcxxabi/src/cxa_exception.cpp --- a/libcxxabi/src/cxa_exception.cpp +++ b/libcxxabi/src/cxa_exception.cpp @@ -431,6 +431,11 @@ ( static_cast<_Unwind_Exception*>(unwind_exception) ); + +#if defined(__MVS__) + _UnwindZOS_PopException(); +#endif + if (native_exception) { // Increment the handler count, removing the flag about being rethrown diff --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp --- a/libcxxabi/src/cxa_personality.cpp +++ b/libcxxabi/src/cxa_personality.cpp @@ -563,6 +563,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, bool native_exception, _Unwind_Exception *unwind_exception, + const uint8_t *lsda, _Unwind_Context *context) { // Initialize results to found nothing but an error results.ttypeIndex = 0; @@ -601,8 +602,6 @@ results.reason = _URC_FATAL_PHASE1_ERROR; return; } - // Start scan by getting exception table address - const uint8_t *lsda = (const uint8_t *)_Unwind_GetLanguageSpecificData(context); if (lsda == 0) { // There is no exception table @@ -884,15 +883,29 @@ #ifdef __USING_SJLJ_EXCEPTIONS__ __gxx_personality_sj0 #else +#ifdef __MVS__ +__zos_cxx_personality_v2 +#else __gxx_personality_v0 #endif #endif - (int version, _Unwind_Action actions, uint64_t exceptionClass, - _Unwind_Exception* unwind_exception, _Unwind_Context* context) +#endif + (int version, _Unwind_Action actions, +#if defined(__MVS__) + const uint8_t* lsda, +#else + uint64_t exceptionClass, +#endif + _Unwind_Exception* unwind_exception, + _Unwind_Context* context) { if (version != 1 || unwind_exception == 0 || context == 0) return _URC_FATAL_PHASE1_ERROR; +#if defined(__MVS__) + uint64_t exceptionClass = unwind_exception->exception_class; +#endif + bool native_exception = (exceptionClass & get_vendor_and_language) == (kOurExceptionClass & get_vendor_and_language); scan_results results; @@ -915,7 +928,11 @@ } // In other cases we need to scan LSDA. - scan_eh_tab(results, actions, native_exception, unwind_exception, context); +#if !defined(__MVS__) + const uint8_t *lsda = (const uint8_t *)_Unwind_GetLanguageSpecificData(context); +#endif + scan_eh_tab(results, actions, native_exception, unwind_exception, lsda, context); + if (results.reason == _URC_CONTINUE_UNWIND || results.reason == _URC_FATAL_PHASE1_ERROR) return results.reason; @@ -1018,13 +1035,14 @@ state &= ~_US_FORCE_UNWIND; scan_results results; + const uint8_t *lsda = (const uint8_t *)_Unwind_GetLanguageSpecificData(context); switch (state) { case _US_VIRTUAL_UNWIND_FRAME: if (is_force_unwinding) return continue_unwind(unwind_exception, context); // Phase 1 search: All we're looking for in phase 1 is a handler that halts unwinding - scan_eh_tab(results, _UA_SEARCH_PHASE, native_exception, unwind_exception, context); + scan_eh_tab(results, _UA_SEARCH_PHASE, native_exception, unwind_exception, lsda, context); if (results.reason == _URC_HANDLER_FOUND) { unwind_exception->barrier_cache.sp = _Unwind_GetGR(context, REG_SP); @@ -1057,7 +1075,7 @@ { // Search for the catching handler again for the foreign exception. scan_eh_tab(results, static_cast<_Unwind_Action>(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME), - native_exception, unwind_exception, context); + native_exception, unwind_exception, lsda, context); if (results.reason != _URC_HANDLER_FOUND) // phase1 search should guarantee to find one call_terminate(native_exception, unwind_exception); } @@ -1070,7 +1088,7 @@ // Either we didn't do a phase 1 search (due to forced unwinding), or // phase 1 reported no catching-handlers. // Search for a (non-catching) cleanup - scan_eh_tab(results, _UA_CLEANUP_PHASE, native_exception, unwind_exception, context); + scan_eh_tab(results, _UA_CLEANUP_PHASE, native_exception, unwind_exception, lsda, context); if (results.reason == _URC_HANDLER_FOUND) { // Found a non-catching handler