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.
main
David Chisnall 6 years ago
parent ec8782e396
commit 76e081dc48

@ -264,7 +264,6 @@ if (MSVC)
endif() endif()
add_library(objc SHARED ${libobjc_C_SRCS} ${libobjc_ASM_SRCS} ${libobjc_OBJC_SRCS} ${libobjc_OBJCXX_SRCS} ${libobjc_ASM_OBJS})
if (ENABLE_OBJCXX) if (ENABLE_OBJCXX)
if (WIN32) if (WIN32)
@ -302,9 +301,15 @@ if (ENABLE_OBJCXX)
set(ENABLE_OBJCXX false) set(ENABLE_OBJCXX false)
endif() endif()
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 ()
endif (ENABLE_OBJCXX) 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 (ENABLE_OBJCXX)
if (NOT CXXRT_IS_STDLIB) if (NOT CXXRT_IS_STDLIB)

@ -0,0 +1,53 @@
#include <stdio.h>
#include <stdlib.h>
#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);
}

@ -20,6 +20,8 @@
#define __builtin_unreachable abort #define __builtin_unreachable abort
#endif #endif
void test_cxx_eh_implementation();
/** /**
* Class of exceptions to distinguish between this and other exception types. * 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; void *object = NULL;
#ifndef NO_OBJCXX #ifndef NO_OBJCXX
if (cxx_exception_class == 0)
{
test_cxx_eh_implementation();
}
if (exceptionClass == cxx_exception_class) if (exceptionClass == cxx_exception_class)
{ {
int objcxx; int objcxx;
@ -486,6 +493,10 @@ BEGIN_PERSONALITY_FUNCTION(__gnustep_objc_personality_v0)
} }
BEGIN_PERSONALITY_FUNCTION(__gnustep_objcxx_personality_v0) BEGIN_PERSONALITY_FUNCTION(__gnustep_objcxx_personality_v0)
if (cxx_exception_class == 0)
{
test_cxx_eh_implementation();
}
if (exceptionClass == objc_exception_class) if (exceptionClass == objc_exception_class)
{ {
struct objc_exception *ex = objc_exception_from_header(exceptionObject); struct objc_exception *ex = objc_exception_from_header(exceptionObject);

@ -0,0 +1,8 @@
void cxx_throw();
int eh_trampoline()
{
struct X { ~X() {} } x;
cxx_throw();
return 0;
}

@ -51,7 +51,20 @@ void *objc_object_for_cxx_exception(void *thrown_exception, int *isValid);
__attribute__((weak)) __attribute__((weak))
void print_type_info(void *thrown_exception); 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 #ifdef __cplusplus
} }

Loading…
Cancel
Save