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

Reply via email to