Skip to content

Commit 9573343

Browse files
committed
[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 <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
1 parent ccd7dda commit 9573343

File tree

5 files changed

+24
-13
lines changed

5 files changed

+24
-13
lines changed

llvm/cmake/config-ix.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ endif()
211211
# Determine whether we can register EH tables.
212212
check_symbol_exists(__register_frame "${CMAKE_CURRENT_LIST_DIR}/unwind.h" HAVE_REGISTER_FRAME)
213213
check_symbol_exists(__deregister_frame "${CMAKE_CURRENT_LIST_DIR}/unwind.h" HAVE_DEREGISTER_FRAME)
214+
check_symbol_exists(__unw_add_dynamic_fde "${CMAKE_CURRENT_LIST_DIR}/unwind.h" HAVE_UNW_ADD_DYNAMIC_FDE)
214215

215216
check_symbol_exists(_Unwind_Backtrace "unwind.h" HAVE__UNWIND_BACKTRACE)
216217
check_symbol_exists(getpagesize unistd.h HAVE_GETPAGESIZE)

llvm/cmake/unwind.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
// exist in the runtime.
66
extern void __register_frame(const void *fde); // NOLINT
77
extern void __deregister_frame(const void *fde); // NOLINT
8+
extern void __unw_add_dynamic_fde(); // NOLINT

llvm/include/llvm/Config/config.h.cmake

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@
6464
/* Define to 1 if we can deregister EH frames on this platform. */
6565
#cmakedefine HAVE_DEREGISTER_FRAME ${HAVE_DEREGISTER_FRAME}
6666

67+
/* Define if __unw_add_dynamic_fde() is available on this platform. */
68+
#cmakedefine HAVE_UNW_ADD_DYNAMIC_FDE ${HAVE_UNW_ADD_DYNAMIC_FDE}
69+
6770
/* Define to 1 if you have the <errno.h> header file. */
6871
#cmakedefine HAVE_ERRNO_H ${HAVE_ERRNO_H}
6972

llvm/lib/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.cpp

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,11 @@ static Error deregisterFrameWrapper(const void *P) {
8585
}
8686
#endif
8787

88-
#ifdef __APPLE__
88+
#ifdef HAVE_UNW_ADD_DYNAMIC_FDE
8989

9090
template <typename HandleFDEFn>
91-
Error walkAppleEHFrameSection(const char *const SectionStart,
92-
size_t SectionSize, HandleFDEFn HandleFDE) {
91+
Error walkLibunwindEHFrameSection(const char *const SectionStart,
92+
size_t SectionSize, HandleFDEFn HandleFDE) {
9393
const char *CurCFIRecord = SectionStart;
9494
const char *End = SectionStart + SectionSize;
9595
uint64_t Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
@@ -123,16 +123,19 @@ Error walkAppleEHFrameSection(const char *const SectionStart,
123123
return Error::success();
124124
}
125125

126-
#endif // __APPLE__
126+
#endif // HAVE_UNW_ADD_DYNAMIC_FDE
127127

128128
Error registerEHFrameSection(const void *EHFrameSectionAddr,
129129
size_t EHFrameSectionSize) {
130-
#ifdef __APPLE__
131-
// On Darwin __register_frame has to be called for each FDE entry.
132-
return walkAppleEHFrameSection(static_cast<const char *>(EHFrameSectionAddr),
133-
EHFrameSectionSize, registerFrameWrapper);
130+
/* libgcc and libunwind __register_frame behave differently. We use the
131+
* presence of __unw_add_dynamic_fde to detect libunwind. */
132+
#ifdef HAVE_UNW_ADD_DYNAMIC_FDE
133+
// With libunwind, __register_frame has to be called for each FDE entry.
134+
return walkLibunwindEHFrameSection(
135+
static_cast<const char *>(EHFrameSectionAddr), EHFrameSectionSize,
136+
registerFrameWrapper);
134137
#else
135-
// On Linux __register_frame takes a single argument:
138+
// With libgcc, __register_frame takes a single argument:
136139
// a pointer to the start of the .eh_frame section.
137140

138141
// How can it find the end? Because crtendS.o is linked
@@ -143,9 +146,10 @@ Error registerEHFrameSection(const void *EHFrameSectionAddr,
143146

144147
Error deregisterEHFrameSection(const void *EHFrameSectionAddr,
145148
size_t EHFrameSectionSize) {
146-
#ifdef __APPLE__
147-
return walkAppleEHFrameSection(static_cast<const char *>(EHFrameSectionAddr),
148-
EHFrameSectionSize, deregisterFrameWrapper);
149+
#ifdef HAVE_UNW_ADD_DYNAMIC_FDE
150+
return walkLibunwindEHFrameSection(
151+
static_cast<const char *>(EHFrameSectionAddr), EHFrameSectionSize,
152+
deregisterFrameWrapper);
149153
#else
150154
return deregisterFrameWrapper(EHFrameSectionAddr);
151155
#endif

llvm/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ static void __deregister_frame(void *p) {
6767
}
6868
#endif
6969

70-
#ifdef __APPLE__
70+
/* libgcc and libunwind __register_frame behave differently. We use the presence
71+
* of __unw_add_dynamic_fde to detect libunwind. */
72+
#ifdef HAVE_UNW_ADD_DYNAMIC_FDE
7173

7274
static const char *processFDE(const char *Entry, bool isDeregister) {
7375
const char *P = Entry;

0 commit comments

Comments
 (0)