From 957334382cd12ec07b46c0ddfdcc220731f6d80f Mon Sep 17 00:00:00 2001 From: Harald van Dijk Date: Sun, 15 Aug 2021 13:35:53 +0100 Subject: [PATCH] [ExecutionEngine] Check for libunwind before calling __register_frame libgcc and libunwind have different flavours of __register_frame. Both flavours are already correctly handled, except that the code to handle the libunwind flavour is guarded by __APPLE__. This change uses the presence of __unw_add_dynamic_fde in libunwind instead to detect whether libunwind is used, rather than hardcoding it as Apple vs. non-Apple. Fixes PR44074. Thanks to Albert Jin and Chris Schafmeister for identifying the problem. Reviewed By: lhames Differential Revision: https://reviews.llvm.org/D106129 --- llvm/cmake/config-ix.cmake | 1 + llvm/cmake/unwind.h | 1 + llvm/include/llvm/Config/config.h.cmake | 3 ++ .../Orc/TargetProcess/RegisterEHFrames.cpp | 28 +++++++++++-------- .../RuntimeDyld/RTDyldMemoryManager.cpp | 4 ++- 5 files changed, 24 insertions(+), 13 deletions(-) diff --git a/llvm/cmake/config-ix.cmake b/llvm/cmake/config-ix.cmake index dd0aaadb47c7..6da2012728ad 100644 --- a/llvm/cmake/config-ix.cmake +++ b/llvm/cmake/config-ix.cmake @@ -211,6 +211,7 @@ endif() # Determine whether we can register EH tables. check_symbol_exists(__register_frame "${CMAKE_CURRENT_LIST_DIR}/unwind.h" HAVE_REGISTER_FRAME) check_symbol_exists(__deregister_frame "${CMAKE_CURRENT_LIST_DIR}/unwind.h" HAVE_DEREGISTER_FRAME) +check_symbol_exists(__unw_add_dynamic_fde "${CMAKE_CURRENT_LIST_DIR}/unwind.h" HAVE_UNW_ADD_DYNAMIC_FDE) check_symbol_exists(_Unwind_Backtrace "unwind.h" HAVE__UNWIND_BACKTRACE) check_symbol_exists(getpagesize unistd.h HAVE_GETPAGESIZE) diff --git a/llvm/cmake/unwind.h b/llvm/cmake/unwind.h index e7f53465f9ce..52243f2af787 100644 --- a/llvm/cmake/unwind.h +++ b/llvm/cmake/unwind.h @@ -5,3 +5,4 @@ // exist in the runtime. extern void __register_frame(const void *fde); // NOLINT extern void __deregister_frame(const void *fde); // NOLINT +extern void __unw_add_dynamic_fde(); // NOLINT diff --git a/llvm/include/llvm/Config/config.h.cmake b/llvm/include/llvm/Config/config.h.cmake index 8d58ec9d665b..d7cd44b5db36 100644 --- a/llvm/include/llvm/Config/config.h.cmake +++ b/llvm/include/llvm/Config/config.h.cmake @@ -64,6 +64,9 @@ /* Define to 1 if we can deregister EH frames on this platform. */ #cmakedefine HAVE_DEREGISTER_FRAME ${HAVE_DEREGISTER_FRAME} +/* Define if __unw_add_dynamic_fde() is available on this platform. */ +#cmakedefine HAVE_UNW_ADD_DYNAMIC_FDE ${HAVE_UNW_ADD_DYNAMIC_FDE} + /* Define to 1 if you have the header file. */ #cmakedefine HAVE_ERRNO_H ${HAVE_ERRNO_H} diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.cpp index db002a34b444..6f891afabfdc 100644 --- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.cpp +++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.cpp @@ -85,11 +85,11 @@ static Error deregisterFrameWrapper(const void *P) { } #endif -#ifdef __APPLE__ +#ifdef HAVE_UNW_ADD_DYNAMIC_FDE template -Error walkAppleEHFrameSection(const char *const SectionStart, - size_t SectionSize, HandleFDEFn HandleFDE) { +Error walkLibunwindEHFrameSection(const char *const SectionStart, + size_t SectionSize, HandleFDEFn HandleFDE) { const char *CurCFIRecord = SectionStart; const char *End = SectionStart + SectionSize; uint64_t Size = *reinterpret_cast(CurCFIRecord); @@ -123,16 +123,19 @@ Error walkAppleEHFrameSection(const char *const SectionStart, return Error::success(); } -#endif // __APPLE__ +#endif // HAVE_UNW_ADD_DYNAMIC_FDE Error registerEHFrameSection(const void *EHFrameSectionAddr, size_t EHFrameSectionSize) { -#ifdef __APPLE__ - // On Darwin __register_frame has to be called for each FDE entry. - return walkAppleEHFrameSection(static_cast(EHFrameSectionAddr), - EHFrameSectionSize, registerFrameWrapper); + /* libgcc and libunwind __register_frame behave differently. We use the + * presence of __unw_add_dynamic_fde to detect libunwind. */ +#ifdef HAVE_UNW_ADD_DYNAMIC_FDE + // With libunwind, __register_frame has to be called for each FDE entry. + return walkLibunwindEHFrameSection( + static_cast(EHFrameSectionAddr), EHFrameSectionSize, + registerFrameWrapper); #else - // On Linux __register_frame takes a single argument: + // With libgcc, __register_frame takes a single argument: // a pointer to the start of the .eh_frame section. // How can it find the end? Because crtendS.o is linked @@ -143,9 +146,10 @@ Error registerEHFrameSection(const void *EHFrameSectionAddr, Error deregisterEHFrameSection(const void *EHFrameSectionAddr, size_t EHFrameSectionSize) { -#ifdef __APPLE__ - return walkAppleEHFrameSection(static_cast(EHFrameSectionAddr), - EHFrameSectionSize, deregisterFrameWrapper); +#ifdef HAVE_UNW_ADD_DYNAMIC_FDE + return walkLibunwindEHFrameSection( + static_cast(EHFrameSectionAddr), EHFrameSectionSize, + deregisterFrameWrapper); #else return deregisterFrameWrapper(EHFrameSectionAddr); #endif diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp index b6ccd02405c1..252e20c3c38c 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp @@ -67,7 +67,9 @@ static void __deregister_frame(void *p) { } #endif -#ifdef __APPLE__ +/* libgcc and libunwind __register_frame behave differently. We use the presence + * of __unw_add_dynamic_fde to detect libunwind. */ +#ifdef HAVE_UNW_ADD_DYNAMIC_FDE static const char *processFDE(const char *Entry, bool isDeregister) { const char *P = Entry;