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