Author: Peter S. Housel Date: 2021-11-18T08:06:46-08:00 New Revision: bab39816085d715e52c2131fa249ccd10178764b
URL: https://github.com/llvm/llvm-project/commit/bab39816085d715e52c2131fa249ccd10178764b DIFF: https://github.com/llvm/llvm-project/commit/bab39816085d715e52c2131fa249ccd10178764b.diff LOG: [libunwind] Add an interface for dynamic .eh_frame registration The libgcc runtime library provides __register_frame and __deregister_frame functions, which can be used by dynamic code generators to register an .eh_frame section, which contains one or more Call Frame Information records, each consisting of a Common Information Entry record followed by one or more Frame Description Entry records. This libunwind library also provides __register_frame and __deregister_frame functions, but they are aliases for __unw_add_dynamic_fde and __unw_remove_dynamic_fde and thus can only take a single FDE. This patch adds __unw_add_dynamic_eh_frame_section and __unw_remove_dynamic_eh_frame_section functions which explicitly use the .eh_frame format. Clients such as the ORCv2 platform and runtime can check for these functions and use them if unwinding is being provided by libunwind, or fall back to __register_frame and __deregister_frame if unwinding is provided by libgcc. Reviewed By: lhames Differential Revision: https://reviews.llvm.org/D111863 Added: Modified: libunwind/src/DwarfParser.hpp libunwind/src/libunwind.cpp libunwind/src/libunwind_ext.h Removed: ################################################################################ diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp index f9896ad03a113..2153a71c2ec02 100644 --- a/libunwind/src/DwarfParser.hpp +++ b/libunwind/src/DwarfParser.hpp @@ -154,7 +154,8 @@ class CFI_Parser { uintptr_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo, CIE_Info *cieInfo); static const char *decodeFDE(A &addressSpace, pint_t fdeStart, - FDE_Info *fdeInfo, CIE_Info *cieInfo); + FDE_Info *fdeInfo, CIE_Info *cieInfo, + bool useCIEInfo = false); static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo, const CIE_Info &cieInfo, pint_t upToPC, int arch, PrologInfo *results); @@ -162,10 +163,14 @@ class CFI_Parser { static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo); }; -/// Parse a FDE into a CIE_Info and an FDE_Info +/// Parse a FDE into a CIE_Info and an FDE_Info. If useCIEInfo is +/// true, treat cieInfo as already-parsed CIE_Info (whose start offset +/// must match the one specified by the FDE) rather than parsing the +/// one indicated within the FDE. template <typename A> const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart, - FDE_Info *fdeInfo, CIE_Info *cieInfo) { + FDE_Info *fdeInfo, CIE_Info *cieInfo, + bool useCIEInfo) { pint_t p = fdeStart; pint_t cfiLength = (pint_t)addressSpace.get32(p); p += 4; @@ -181,9 +186,14 @@ const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart, return "FDE is really a CIE"; // this is a CIE not an FDE pint_t nextCFI = p + cfiLength; pint_t cieStart = p - ciePointer; - const char *err = parseCIE(addressSpace, cieStart, cieInfo); - if (err != NULL) - return err; + if (useCIEInfo) { + if (cieInfo->cieStart != cieStart) + return "CIE start does not match"; + } else { + const char *err = parseCIE(addressSpace, cieStart, cieInfo); + if (err != NULL) + return err; + } p += 4; // Parse pc begin and range. pint_t pcStart = diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp index 2bf31b182cff2..48750ce670fbf 100644 --- a/libunwind/src/libunwind.cpp +++ b/libunwind/src/libunwind.cpp @@ -292,6 +292,35 @@ void __unw_remove_dynamic_fde(unw_word_t fde) { // fde is own mh_group DwarfFDECache<LocalAddressSpace>::removeAllIn((LocalAddressSpace::pint_t)fde); } + +void __unw_add_dynamic_eh_frame_section(unw_word_t eh_frame_start) { + // The eh_frame section start serves as the mh_group + unw_word_t mh_group = eh_frame_start; + CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo; + CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo; + auto p = (LocalAddressSpace::pint_t)eh_frame_start; + while (true) { + if (CFI_Parser<LocalAddressSpace>::decodeFDE( + LocalAddressSpace::sThisAddressSpace, p, &fdeInfo, &cieInfo, + true) == NULL) { + DwarfFDECache<LocalAddressSpace>::add((LocalAddressSpace::pint_t)mh_group, + fdeInfo.pcStart, fdeInfo.pcEnd, + fdeInfo.fdeStart); + p += fdeInfo.fdeLength; + } else if (CFI_Parser<LocalAddressSpace>::parseCIE( + LocalAddressSpace::sThisAddressSpace, p, &cieInfo) == NULL) { + p += cieInfo.cieLength; + } else + return; + } +} + +void __unw_remove_dynamic_eh_frame_section(unw_word_t eh_frame_start) { + // The eh_frame section start serves as the mh_group + DwarfFDECache<LocalAddressSpace>::removeAllIn( + (LocalAddressSpace::pint_t)eh_frame_start); +} + #endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) #endif // !defined(__USING_SJLJ_EXCEPTIONS__) diff --git a/libunwind/src/libunwind_ext.h b/libunwind/src/libunwind_ext.h index a96ae6c2d1c68..7065ffcdaeff5 100644 --- a/libunwind/src/libunwind_ext.h +++ b/libunwind/src/libunwind_ext.h @@ -51,6 +51,9 @@ extern void __unw_iterate_dwarf_unwind_cache(void (*func)( extern void __unw_add_dynamic_fde(unw_word_t fde); extern void __unw_remove_dynamic_fde(unw_word_t fde); +extern void __unw_add_dynamic_eh_frame_section(unw_word_t eh_frame_start); +extern void __unw_remove_dynamic_eh_frame_section(unw_word_t eh_frame_start); + #if defined(_LIBUNWIND_ARM_EHABI) extern const uint32_t* decode_eht_entry(const uint32_t*, size_t*, size_t*); extern _Unwind_Reason_Code _Unwind_VRS_Interpret(_Unwind_Context *context, _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits