From 76e081dc4874d48290b048469c1002569524e00f Mon Sep 17 00:00:00 2001 From: David Chisnall Date: Sun, 26 Apr 2020 13:43:43 +0100 Subject: [PATCH] Initial run-time detection of C++ EH ABI variant. On Itanium C++ ABI platforms, there are a lot of different variations that have subtly different structure layouts. This commit adds a run-time test that throws a C++ exception through a function that has its personality function replaced with a wrapper so that we can inspect a C++ exception in controlled conditions. Initially, this just detects the exception type value used for C++ exceptions. --- CMakeLists.txt | 7 ++++++- cxx_eh_setup.cc | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ eh_personality.c | 11 ++++++++++ eh_trampoline.cc | 8 ++++++++ objcxx_eh.h | 15 +++++++++++++- 5 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 cxx_eh_setup.cc create mode 100644 eh_trampoline.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f8a5bd..de5c5e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -264,7 +264,6 @@ if (MSVC) endif() -add_library(objc SHARED ${libobjc_C_SRCS} ${libobjc_ASM_SRCS} ${libobjc_OBJC_SRCS} ${libobjc_OBJCXX_SRCS} ${libobjc_ASM_OBJS}) if (ENABLE_OBJCXX) if (WIN32) @@ -302,9 +301,15 @@ if (ENABLE_OBJCXX) set(ENABLE_OBJCXX false) endif() endif () + add_custom_command(OUTPUT eh_trampoline.S + COMMAND ${CMAKE_CXX_COMPILER} -fPIC -S "${CMAKE_SOURCE_DIR}/eh_trampoline.cc" -o - -fexceptions -fno-inline | sed "s/__gxx_personality_v0/test_eh_personality/g" > "${CMAKE_BINARY_DIR}/eh_trampoline.S" + MAIN_DEPENDENCY eh_trampoline.cc) + list(APPEND libobjc_ASM_SRCS eh_trampoline.S) + list(APPEND libobjc_CXX_SRCS cxx_eh_setup.cc) endif () endif (ENABLE_OBJCXX) +add_library(objc SHARED ${libobjc_C_SRCS} ${libobjc_ASM_SRCS} ${libobjc_OBJC_SRCS} ${libobjc_OBJCXX_SRCS} ${libobjc_ASM_OBJS}) if (ENABLE_OBJCXX) if (NOT CXXRT_IS_STDLIB) diff --git a/cxx_eh_setup.cc b/cxx_eh_setup.cc new file mode 100644 index 0000000..3164e92 --- /dev/null +++ b/cxx_eh_setup.cc @@ -0,0 +1,53 @@ +#include +#include +#include "objc/runtime.h" +#include "dwarf_eh.h" +#include "objcxx_eh.h" + +void cxx_throw() +{ + throw 1; +} + +int eh_trampoline(); +uint64_t cxx_exception_class; + +namespace +{ +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; +} + +bool done_setup; +} + +extern "C" +BEGIN_PERSONALITY_FUNCTION(test_eh_personality) + fprintf(stderr, "Fake EH personality called\n"); + if (!done_setup) + { + done_setup = true; + cxx_exception_class = exceptionClass; + } + return CALL_PERSONALITY_FUNCTION(__gxx_personality_v0); +} + +extern "C" void test_cxx_eh_implementation() +{ + bool caught = false; + try + { + eh_trampoline(); + } + catch(int) + { + caught = true; + } + assert(caught); +} + diff --git a/eh_personality.c b/eh_personality.c index 3f0f8df..a5db35d 100644 --- a/eh_personality.c +++ b/eh_personality.c @@ -20,6 +20,8 @@ #define __builtin_unreachable abort #endif +void test_cxx_eh_implementation(); + /** * Class of exceptions to distinguish between this and other exception types. @@ -326,6 +328,11 @@ static inline _Unwind_Reason_Code internal_objc_personality(int version, void *object = NULL; #ifndef NO_OBJCXX + if (cxx_exception_class == 0) + { + test_cxx_eh_implementation(); + } + if (exceptionClass == cxx_exception_class) { int objcxx; @@ -486,6 +493,10 @@ BEGIN_PERSONALITY_FUNCTION(__gnustep_objc_personality_v0) } BEGIN_PERSONALITY_FUNCTION(__gnustep_objcxx_personality_v0) + if (cxx_exception_class == 0) + { + test_cxx_eh_implementation(); + } if (exceptionClass == objc_exception_class) { struct objc_exception *ex = objc_exception_from_header(exceptionObject); diff --git a/eh_trampoline.cc b/eh_trampoline.cc new file mode 100644 index 0000000..24be177 --- /dev/null +++ b/eh_trampoline.cc @@ -0,0 +1,8 @@ +void cxx_throw(); + +int eh_trampoline() +{ + struct X { ~X() {} } x; + cxx_throw(); + return 0; +} diff --git a/objcxx_eh.h b/objcxx_eh.h index 1a117df..9dacc95 100644 --- a/objcxx_eh.h +++ b/objcxx_eh.h @@ -51,7 +51,20 @@ void *objc_object_for_cxx_exception(void *thrown_exception, int *isValid); __attribute__((weak)) void print_type_info(void *thrown_exception); -static const uint64_t cxx_exception_class = EXCEPTION_CLASS('G','N','U','C','C','+','+','\0'); +/** + * The exception class that we've detected that C++ runtime library uses. + */ +extern uint64_t cxx_exception_class; + +/** + * The exception class that libsupc++ and libcxxrt use. + */ +const uint64_t gnu_cxx_exception_class = EXCEPTION_CLASS('G','N','U','C','C','+','+','\0'); + +/** + * The exception class that libc++abi uses. + */ +const uint64_t llvm_cxx_exception_class = EXCEPTION_CLASS('C','L','N','G','C','+','+','\0'); #ifdef __cplusplus }