mstorsjo updated this revision to Diff 140410. mstorsjo edited the summary of this revision. mstorsjo added a comment. Herald added a subscriber: JDevlieghere.
Added and using a helper function `isCIE` to avoid using the error return path from `decodeFDE`. Technically, the decision between a full section and a plain FDE probably should be outside of `_unw_add_dynamic_fde`, in `__register_frame` in `UnwindLevel1-gcc-ext.c`. That'd require adding a C wrapper for `isCIE` in `libunwind.cpp` though. https://reviews.llvm.org/D44494 Files: src/DwarfParser.hpp src/UnwindCursor.hpp src/libunwind.cpp
Index: src/libunwind.cpp =================================================================== --- src/libunwind.cpp +++ src/libunwind.cpp @@ -326,20 +326,27 @@ /// IPI: for __register_frame() void _unw_add_dynamic_fde(unw_word_t fde) { - CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo; - CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo; - const char *message = CFI_Parser<LocalAddressSpace>::decodeFDE( - LocalAddressSpace::sThisAddressSpace, - (LocalAddressSpace::pint_t) fde, &fdeInfo, &cieInfo); - if (message == NULL) { - // dynamically registered FDEs don't have a mach_header group they are in. - // Use fde as mh_group - unw_word_t mh_group = fdeInfo.fdeStart; - DwarfFDECache<LocalAddressSpace>::add((LocalAddressSpace::pint_t)mh_group, - fdeInfo.pcStart, fdeInfo.pcEnd, - fdeInfo.fdeStart); + if (CFI_Parser<LocalAddressSpace>::isCIE(LocalAddressSpace::sThisAddressSpace, + (LocalAddressSpace::pint_t) fde)) { + // This wasn't a plain FDE, but it started with a CIE - register a full + // .eh_frame section. + DwarfFDECache<LocalAddressSpace>::addSection((LocalAddressSpace::pint_t)fde); } else { - _LIBUNWIND_DEBUG_LOG("_unw_add_dynamic_fde: bad fde: %s", message); + CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo; + CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo; + const char *message = CFI_Parser<LocalAddressSpace>::decodeFDE( + LocalAddressSpace::sThisAddressSpace, + (LocalAddressSpace::pint_t) fde, &fdeInfo, &cieInfo); + if (message == NULL) { + // dynamically registered FDEs don't have a mach_header group they are in. + // Use fde as mh_group + unw_word_t mh_group = fdeInfo.fdeStart; + DwarfFDECache<LocalAddressSpace>::add((LocalAddressSpace::pint_t)mh_group, + fdeInfo.pcStart, fdeInfo.pcEnd, + fdeInfo.fdeStart); + } else { + _LIBUNWIND_DEBUG_LOG("_unw_add_dynamic_fde: bad fde: %s", message); + } } } Index: src/UnwindCursor.hpp =================================================================== --- src/UnwindCursor.hpp +++ src/UnwindCursor.hpp @@ -44,10 +44,12 @@ public: static pint_t findFDE(pint_t mh, pint_t pc); static void add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde); + static void addSection(pint_t section_start); static void removeAllIn(pint_t mh); static void iterateCacheEntries(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)); + template<typename Func> static void iterateSections(Func func); private: @@ -70,6 +72,11 @@ static entry *_bufferUsed; static entry *_bufferEnd; static entry _initialBuffer[64]; + + static pint_t *_sections; + static pint_t *_sectionsUsed; + static pint_t *_sectionsEnd; + static pint_t _initialSectionsBuffer[64]; }; template <typename A> @@ -88,6 +95,21 @@ typename DwarfFDECache<A>::entry DwarfFDECache<A>::_initialBuffer[64]; template <typename A> +typename DwarfFDECache<A>::pint_t * +DwarfFDECache<A>::_sections = _initialSectionsBuffer; + +template <typename A> +typename DwarfFDECache<A>::pint_t * +DwarfFDECache<A>::_sectionsUsed = _initialSectionsBuffer; + +template <typename A> +typename DwarfFDECache<A>::pint_t * +DwarfFDECache<A>::_sectionsEnd = &_initialSectionsBuffer[64]; + +template <typename A> +typename DwarfFDECache<A>::pint_t DwarfFDECache<A>::_initialSectionsBuffer[64]; + +template <typename A> RWMutex DwarfFDECache<A>::_lock; #ifdef __APPLE__ @@ -144,6 +166,28 @@ } template <typename A> +void DwarfFDECache<A>::addSection(pint_t section_start) { +#if !defined(_LIBUNWIND_NO_HEAP) + _LIBUNWIND_LOG_IF_FALSE(_lock.lock()); + if (_sectionsUsed >= _sectionsEnd) { + size_t oldSize = (size_t)(_sectionsEnd - _sections); + size_t newSize = oldSize * 4; + // Can't use operator new (we are below it). + pint_t *newSections = (pint_t *)malloc(newSize * sizeof(pint_t)); + memcpy(newSections, _sections, oldSize * sizeof(pint_t)); + if (_sections != _initialSectionsBuffer) + free(_sections); + _sections = newSections; + _sectionsUsed = &newSections[oldSize]; + _sectionsEnd = &newSections[newSize]; + } + *_sectionsUsed = section_start; + ++_sectionsUsed; + _LIBUNWIND_LOG_IF_FALSE(_lock.unlock()); +#endif +} + +template <typename A> void DwarfFDECache<A>::removeAllIn(pint_t mh) { _LIBUNWIND_LOG_IF_FALSE(_lock.lock()); entry *d = _buffer; @@ -155,6 +199,15 @@ } } _bufferUsed = d; + pint_t *sectionsDest = _sections; + for (const pint_t *s = _sections; s < _sectionsUsed; ++s) { + if (*s != mh) { + if (sectionsDest != s) + *sectionsDest = *s; + ++sectionsDest; + } + } + _sectionsUsed = sectionsDest; _LIBUNWIND_LOG_IF_FALSE(_lock.unlock()); } @@ -174,6 +227,16 @@ } _LIBUNWIND_LOG_IF_FALSE(_lock.unlock()); } + +template <typename A> +template <typename Func> +void DwarfFDECache<A>::iterateSections(Func func) { + _LIBUNWIND_LOG_IF_FALSE(_lock.lock()); + for (pint_t *p = _sections; p < _sectionsUsed; ++p) { + func(*p); + } + _LIBUNWIND_LOG_IF_FALSE(_lock.unlock()); +} #endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) @@ -1352,6 +1415,28 @@ } } + bool foundSection = false; + DwarfFDECache<A>::iterateSections([&](pint_t section) { + if (foundSection) + return; + sects.dso_base = section; + sects.dwarf_section = section; + sects.dwarf_section_length = ~(pint_t)0 - section; + if (sects.dwarf_section_length > ~(uint32_t)0) + sects.dwarf_section_length = ~(uint32_t)0; + CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo; + CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo; + // Only parse and see if it is the right frame here, + // to avoid recursive self-locking. + foundSection = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section, + (uint32_t)sects.dwarf_section_length, 0, + &fdeInfo, &cieInfo); + }); + // This call will lock the cache when adding a new match; only do this + // outside of the iteration (which also keeps a lock). + if (foundSection && this->getInfoFromDwarfSection(pc, sects)) + return; + // Lastly, ask AddressSpace object about platform specific ways to locate // other FDEs. pint_t fde; Index: src/DwarfParser.hpp =================================================================== --- src/DwarfParser.hpp +++ src/DwarfParser.hpp @@ -96,6 +96,7 @@ PrologInfo info; }; + static bool isCIE(A &addressSpace, pint_t start); static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo, CIE_Info *cieInfo); @@ -115,6 +116,23 @@ PrologInfo *results); }; +/// Check whether this is an FDE or a CIE +template <typename A> +bool CFI_Parser<A>::isCIE(A &addressSpace, pint_t start) { + pint_t p = start; + pint_t cfiLength = (pint_t)addressSpace.get32(p); + p += 4; + if (cfiLength == 0xffffffff) { + // 0xffffffff means length is really next 8 bytes + cfiLength = (pint_t)addressSpace.get64(p); + p += 8; + } + if (cfiLength == 0) + return false; // end marker + uint32_t id = addressSpace.get32(p); + return id == 0; // This is zero for CIEs and nonzero for FDEs. +} + /// Parse a FDE into a CIE_Info and an FDE_Info template <typename A> const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits