[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
This commit is contained in:
Peter S. Housel 2021-10-14 13:31:05 -07:00
parent 18ba57a53a
commit bab3981608
3 changed files with 48 additions and 6 deletions

View file

@ -154,7 +154,8 @@ public:
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 @@ public:
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 =

View file

@ -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__)

View file

@ -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,