[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:
parent
18ba57a53a
commit
bab3981608
|
@ -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 =
|
||||
|
|
|
@ -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__)
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue