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 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 @@ -88,6 +95,21 @@ typename DwarfFDECache::entry DwarfFDECache::_initialBuffer[64]; template +typename DwarfFDECache::pint_t * +DwarfFDECache::_sections = _initialSectionsBuffer; + +template +typename DwarfFDECache::pint_t * +DwarfFDECache::_sectionsUsed = _initialSectionsBuffer; + +template +typename DwarfFDECache::pint_t * +DwarfFDECache::_sectionsEnd = &_initialSectionsBuffer[64]; + +template +typename DwarfFDECache::pint_t DwarfFDECache::_initialSectionsBuffer[64]; + +template RWMutex DwarfFDECache::_lock; #ifdef __APPLE__ @@ -144,6 +166,28 @@ } template +void DwarfFDECache::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 void DwarfFDECache::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 +template +void DwarfFDECache::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::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::FDE_Info fdeInfo; + CFI_Parser::CIE_Info cieInfo; + // Only parse and see if it is the right frame here, + // to avoid recursive self-locking. + foundSection = CFI_Parser::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/libunwind.cpp =================================================================== --- src/libunwind.cpp +++ src/libunwind.cpp @@ -339,7 +339,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::addSection((LocalAddressSpace::pint_t)fde); } }