diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp --- a/libunwind/src/DwarfParser.hpp +++ b/libunwind/src/DwarfParser.hpp @@ -154,7 +154,8 @@ 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 @@ 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 const char *CFI_Parser::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 @@ 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 --- a/libunwind/src/libunwind.cpp +++ b/libunwind/src/libunwind.cpp @@ -292,6 +292,35 @@ // fde is own mh_group DwarfFDECache::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::CIE_Info cieInfo; + CFI_Parser::FDE_Info fdeInfo; + auto p = (LocalAddressSpace::pint_t)eh_frame_start; + while (true) { + if (CFI_Parser::decodeFDE( + LocalAddressSpace::sThisAddressSpace, p, &fdeInfo, &cieInfo, + true) == NULL) { + DwarfFDECache::add((LocalAddressSpace::pint_t)mh_group, + fdeInfo.pcStart, fdeInfo.pcEnd, + fdeInfo.fdeStart); + p += fdeInfo.fdeLength; + } else if (CFI_Parser::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::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 --- a/libunwind/src/libunwind_ext.h +++ b/libunwind/src/libunwind_ext.h @@ -51,6 +51,9 @@ 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,