diff --git a/libcxxabi/src/aix_state_tab_eh.inc b/libcxxabi/src/aix_state_tab_eh.inc --- a/libcxxabi/src/aix_state_tab_eh.inc +++ b/libcxxabi/src/aix_state_tab_eh.inc @@ -14,6 +14,10 @@ #include #include +#if !__has_cpp_attribute(clang::optnone) +#error This file requires clang::optnone attribute support +#endif + /* The legacy IBM xlC and xlclang++ compilers use the state table for EH instead of the range table. Destructors, or addresses of the possible catch @@ -183,10 +187,6 @@ number3 = 0x1cedbeef // State table generated by xlclang++ compiler. }; -constexpr uint32_t REG_EXCP_OBJ = 14; // Register to pass the address of the exception - // object from the personality to xlclang++ - // compiled code. - constexpr size_t dtorArgument = 0x02; // Flag to destructor indicating to free // virtual bases, don't delete object. @@ -555,8 +555,16 @@ if (actions & _UA_CLEANUP_PHASE) { // Phase 2 cleanup: if (results.reason == _URC_HANDLER_FOUND) { + // Store the address of unwind_exception in the stack field + // reserved for compilers (SP + 3 * sizeof(uintptr_t)) in the stack of + // the caller of the function containing the landing pad (within the link + // area for the call to the latter) for __xlc_exception_handle() + // to retrieve. + uintptr_t *currentSP = reinterpret_cast(_Unwind_GetGR(context, 1)); + uintptr_t *callersSP = reinterpret_cast(currentSP[0]); + callersSP[3] = reinterpret_cast(unwind_exception); + _LIBCXXABI_TRACE_STATETAB("Handshake: set unwind_exception=%p in stack=%p\n", reinterpret_cast(unwind_exception), reinterpret_cast(callersSP)); // Jump to the handler. - _Unwind_SetGR(context, REG_EXCP_OBJ, reinterpret_cast(unwind_exception)); _Unwind_SetIP(context, results.landingPad); return _URC_INSTALL_CONTEXT; } @@ -633,12 +641,37 @@ __cxa_throw(newexception, const_cast(&typeid(std::bad_exception)), 0); } +// dummy +// This is a dummy function called by __xlc_exception_handle() +// to ensure a stack frame is created for __xlc_exception_handle(). +__attribute__((noinline)) static void dummy() {} + // __xlc_exception_handle // This function is for xlclang++. It returns the address of the exception -// object set in gpr14 by the personality routine for xlclang++ compiled code. +// object stored in the reserved field in the stack of the caller of the +// function that calls __xlc_exception_handle() (within the link area for the +// call to the latter). The address is stored by the personality routine for +// xlclang++ compiled code. The implementation of __xlc_exception_handle() +// assumes a stack frame is created for it. The following ensures this +// assumption holds true: 1) a call to dummy() is made inside +// __xlc_exception_handle(); and 2) optimizations are disabled for this +// function with attribute 'optnone'. Note: this function may not work as +// expected if these are changed. +__attribute__((optnone)) _LIBCXXABI_FUNC_VIS uintptr_t __xlc_exception_handle() { - uintptr_t exceptionObject; - asm("mr %0, 14" : "=r"(exceptionObject)); + // Make a call to dummy() so that the compiler creates a stack frame for + // this function. + dummy(); + + // Get the SP of this function, i.e., __xlc_exception_handle(). + uintptr_t *lastStack; + asm("mr %0, 1" : "=r"(lastStack)); + // Get the SP of the caller of __xlc_exception_handle(). + uintptr_t *callerStack = reinterpret_cast(lastStack[0]); + // Get the SP of the caller of the caller. + uintptr_t *callerStack2 = reinterpret_cast(callerStack[0]); + uintptr_t exceptionObject = callerStack2[3]; + _LIBCXXABI_TRACE_STATETAB("Handshake: exceptionObject=%p from stack=%p\n", reinterpret_cast(exceptionObject), reinterpret_cast(callerStack2)); return exceptionObject; } diff --git a/libcxxabi/test/vendor/ibm/Inputs/aix_xlclang_nested_excp.cpp b/libcxxabi/test/vendor/ibm/Inputs/aix_xlclang_nested_excp.cpp new file mode 100644 --- /dev/null +++ b/libcxxabi/test/vendor/ibm/Inputs/aix_xlclang_nested_excp.cpp @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include + +struct Scary { + ~Scary() { + try { + throw 42; + } catch (int e) { + assert(e == 42); + } + } +}; +int main(void) { + try { + Scary s; + throw 13; + } catch (int e) { // Destructor for 'Scary' runs before + // '__xlc_exception_handle()' is called. + assert(e == 13); + } +} diff --git a/libcxxabi/test/vendor/ibm/Inputs/aix_xlclang_nested_excp_32.o b/libcxxabi/test/vendor/ibm/Inputs/aix_xlclang_nested_excp_32.o new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@