Skip to content

Commit

Permalink
[ExecutionEngine] Check for libunwind before calling __register_frame
Browse files Browse the repository at this point in the history
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 <albert.jin@gmail.com> and Chris Schafmeister
<chris.schaf@verizon.net> for identifying the problem.

Reviewed By: lhames

Differential Revision: https://reviews.llvm.org/D106129
  • Loading branch information
hvdijk committed Aug 15, 2021
1 parent ccd7dda commit 9573343
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 13 deletions.
1 change: 1 addition & 0 deletions llvm/cmake/config-ix.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions llvm/cmake/unwind.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 3 additions & 0 deletions llvm/include/llvm/Config/config.h.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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 <errno.h> header file. */
#cmakedefine HAVE_ERRNO_H ${HAVE_ERRNO_H}

Expand Down
28 changes: 16 additions & 12 deletions llvm/lib/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,11 @@ static Error deregisterFrameWrapper(const void *P) {
}
#endif

#ifdef __APPLE__
#ifdef HAVE_UNW_ADD_DYNAMIC_FDE

template <typename HandleFDEFn>
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<const uint32_t *>(CurCFIRecord);
Expand Down Expand Up @@ -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<const char *>(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<const char *>(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
Expand All @@ -143,9 +146,10 @@ Error registerEHFrameSection(const void *EHFrameSectionAddr,

Error deregisterEHFrameSection(const void *EHFrameSectionAddr,
size_t EHFrameSectionSize) {
#ifdef __APPLE__
return walkAppleEHFrameSection(static_cast<const char *>(EHFrameSectionAddr),
EHFrameSectionSize, deregisterFrameWrapper);
#ifdef HAVE_UNW_ADD_DYNAMIC_FDE
return walkLibunwindEHFrameSection(
static_cast<const char *>(EHFrameSectionAddr), EHFrameSectionSize,
deregisterFrameWrapper);
#else
return deregisterFrameWrapper(EHFrameSectionAddr);
#endif
Expand Down
4 changes: 3 additions & 1 deletion llvm/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 9573343

Please sign in to comment.