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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits