mstorsjo created this revision. mstorsjo added reviewers: rnk, compnerd. Previously, the __register_frame function supported registering an FDE for one individual function at a time. The function could also be used registering a full .eh_frame section of a module (which is how libgcc sets up unwinding).
Repository: rUNW libunwind https://reviews.llvm.org/D44494 Files: src/UnwindCursor.hpp src/libunwind.cpp
Index: src/libunwind.cpp =================================================================== --- src/libunwind.cpp +++ src/libunwind.cpp @@ -347,7 +347,9 @@ fdeInfo.pcStart, fdeInfo.pcEnd, fdeInfo.fdeStart); } else { + // This wasn't a plain FDE; then it's probably a full .eh_frame section. _LIBUNWIND_DEBUG_LOG("_unw_add_dynamic_fde: bad fde: %s", message); + DwarfFDECache<LocalAddressSpace>::addSection((LocalAddressSpace::pint_t)fde); } } Index: src/UnwindCursor.hpp =================================================================== --- src/UnwindCursor.hpp +++ src/UnwindCursor.hpp @@ -13,6 +13,7 @@ #define __UNWINDCURSOR_HPP__ #include <algorithm> +#include <functional> #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -44,10 +45,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)); + static void iterateSections(std::function<void (pint_t section)> func); private: @@ -70,6 +73,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 +96,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 +167,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 +200,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 +228,15 @@ } _LIBUNWIND_LOG_IF_FALSE(_lock.unlock()); } + +template <typename A> +void DwarfFDECache<A>::iterateSections(std::function<void (pint_t section)> 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;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits