[libunwind] fb1abe0 - [libunwind][DWARF] Fix end of .eh_frame calculation

Ryan Prichard via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 16 19:02:09 PDT 2020


Author: Ryan Prichard
Date: 2020-09-16T19:00:57-07:00
New Revision: fb1abe00635c1ec28e55921709904d5ca2e86a74

URL: https://github.com/llvm/llvm-project/commit/fb1abe00635c1ec28e55921709904d5ca2e86a74
DIFF: https://github.com/llvm/llvm-project/commit/fb1abe00635c1ec28e55921709904d5ca2e86a74.diff

LOG: [libunwind][DWARF] Fix end of .eh_frame calculation

 * When .eh_frame is located using .eh_frame_hdr (PT_GNU_EH_FRAME), the
   start of .eh_frame is known, but not the size. In this case, the
   unwinder must rely on a terminator present at the end of .eh_frame.
   Set dwarf_section_length to UINTPTR_MAX to indicate this.

 * Add a new field, text_segment_length, that the FrameHeaderCache uses
   to track the size of the PT_LOAD segment indicated by dso_base.

 * Compute ehSectionEnd by adding sectionLength to ehSectionStart,
   never to fdeHint.

Fixes PR46829.

Differential Revision: https://reviews.llvm.org/D87750

Added: 
    

Modified: 
    libunwind/src/AddressSpace.hpp
    libunwind/src/DwarfParser.hpp
    libunwind/src/FrameHeaderCache.hpp
    libunwind/src/UnwindCursor.hpp
    libunwind/test/frameheadercache_test.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libunwind/src/AddressSpace.hpp b/libunwind/src/AddressSpace.hpp
index eccc2153c697..26397c28798e 100644
--- a/libunwind/src/AddressSpace.hpp
+++ b/libunwind/src/AddressSpace.hpp
@@ -119,6 +119,10 @@ struct UnwindInfoSections {
   // No dso_base for SEH or ARM EHABI.
   uintptr_t       dso_base;
 #endif
+#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) &&                                 \
+    defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
+  uintptr_t       text_segment_length;
+#endif
 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
   uintptr_t       dwarf_section;
   uintptr_t       dwarf_section_length;
@@ -410,7 +414,7 @@ static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base,
     uintptr_t end = begin + phdr->p_memsz;
     if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
       cbdata->sects->dso_base = begin;
-      cbdata->sects->dwarf_section_length = phdr->p_memsz;
+      cbdata->sects->text_segment_length = phdr->p_memsz;
       return true;
     }
   }
@@ -450,8 +454,12 @@ static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo,
       found_hdr = EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
           *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
           hdrInfo);
-      if (found_hdr)
+      if (found_hdr) {
+        // .eh_frame_hdr records the start of .eh_frame, but not its size.
+        // Rely on a zero terminator to find the end of the section.
         cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
+        cbdata->sects->dwarf_section_length = UINTPTR_MAX;
+      }
     } else if (!found_obj) {
       found_obj = checkAddrInSegment(phdr, image_base, cbdata);
     }
@@ -462,7 +470,6 @@ static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo,
       return 1;
     }
   }
-  cbdata->sects->dwarf_section_length = 0;
   return 0;
 }
 

diff  --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp
index 1ce2cf2943a2..86c0522afd3f 100644
--- a/libunwind/src/DwarfParser.hpp
+++ b/libunwind/src/DwarfParser.hpp
@@ -136,7 +136,7 @@ class CFI_Parser {
   };
 
   static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
-                      uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
+                      uintptr_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
                       CIE_Info *cieInfo);
   static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
                                FDE_Info *fdeInfo, CIE_Info *cieInfo);
@@ -167,7 +167,7 @@ const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
     p += 8;
   }
   if (cfiLength == 0)
-    return "FDE has zero length"; // end marker
+    return "FDE has zero length"; // zero terminator
   uint32_t ciePointer = addressSpace.get32(p);
   if (ciePointer == 0)
     return "FDE is really a CIE"; // this is a CIE not an FDE
@@ -212,11 +212,13 @@ const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
 /// Scan an eh_frame section to find an FDE for a pc
 template <typename A>
 bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
-                            uint32_t sectionLength, pint_t fdeHint,
+                            uintptr_t sectionLength, pint_t fdeHint,
                             FDE_Info *fdeInfo, CIE_Info *cieInfo) {
   //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
   pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
-  const pint_t ehSectionEnd = p + sectionLength;
+  const pint_t ehSectionEnd = (sectionLength == UINTPTR_MAX)
+                                  ? static_cast<pint_t>(-1)
+                                  : (ehSectionStart + sectionLength);
   while (p < ehSectionEnd) {
     pint_t currentCFI = p;
     //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
@@ -228,7 +230,7 @@ bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
       p += 8;
     }
     if (cfiLength == 0)
-      return false; // end marker
+      return false; // zero terminator
     uint32_t id = addressSpace.get32(p);
     if (id == 0) {
       // Skip over CIEs.

diff  --git a/libunwind/src/FrameHeaderCache.hpp b/libunwind/src/FrameHeaderCache.hpp
index 813fcd408b26..54d5d33c3cd7 100644
--- a/libunwind/src/FrameHeaderCache.hpp
+++ b/libunwind/src/FrameHeaderCache.hpp
@@ -32,7 +32,7 @@
 class _LIBUNWIND_HIDDEN FrameHeaderCache {
   struct CacheEntry {
     uintptr_t LowPC() { return Info.dso_base; };
-    uintptr_t HighPC() { return Info.dso_base + Info.dwarf_section_length; };
+    uintptr_t HighPC() { return Info.dso_base + Info.text_segment_length; };
     UnwindInfoSections Info;
     CacheEntry *Next;
   };

diff  --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index 206b5e398321..9f8fa65107b4 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -1517,7 +1517,7 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
   // If compact encoding table gave offset into dwarf section, go directly there
   if (fdeSectionOffsetHint != 0) {
     foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
-                                    (uint32_t)sects.dwarf_section_length,
+                                    sects.dwarf_section_length,
                                     sects.dwarf_section + fdeSectionOffsetHint,
                                     &fdeInfo, &cieInfo);
   }
@@ -1534,7 +1534,7 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
     if (cachedFDE != 0) {
       foundFDE =
           CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
-                                 (uint32_t)sects.dwarf_section_length,
+                                 sects.dwarf_section_length,
                                  cachedFDE, &fdeInfo, &cieInfo);
       foundInCache = foundFDE;
     }
@@ -1542,7 +1542,7 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
   if (!foundFDE) {
     // Still not found, do full scan of __eh_frame section.
     foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
-                                      (uint32_t)sects.dwarf_section_length, 0,
+                                      sects.dwarf_section_length, 0,
                                       &fdeInfo, &cieInfo);
   }
   if (foundFDE) {

diff  --git a/libunwind/test/frameheadercache_test.pass.cpp b/libunwind/test/frameheadercache_test.pass.cpp
index 7f2d8e22b9f5..15c7c67c58ea 100644
--- a/libunwind/test/frameheadercache_test.pass.cpp
+++ b/libunwind/test/frameheadercache_test.pass.cpp
@@ -16,7 +16,7 @@
 #include "../src/AddressSpace.hpp"
 
 #define kBaseAddr 0xFFF000
-#define kDwarfSectionLength 0xFF
+#define kTextSegmentLength 0xFF
 
 using namespace libunwind;
 
@@ -32,7 +32,7 @@ int main() {
 
   UnwindInfoSections UIS;
   UIS.dso_base = kBaseAddr;
-  UIS.dwarf_section_length = kDwarfSectionLength;
+  UIS.text_segment_length = kTextSegmentLength;
   dl_iterate_cb_data CBData;
   // Unused by the cache.
   CBData.addressSpace = nullptr;
@@ -58,7 +58,7 @@ int main() {
     abort();
   // Add enough things to the cache that the entry is evicted.
   for (int i = 0; i < 9; i++) {
-    UIS.dso_base = kBaseAddr + (kDwarfSectionLength * i);
+    UIS.dso_base = kBaseAddr + (kTextSegmentLength * i);
     FHC.add(&UIS);
   }
   CBData.targetAddr = kBaseAddr;


        


More information about the cfe-commits mailing list