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

Reply via email to