[libcxx-commits] [PATCH] D130668: [libunwind] Use `_dl_find_eh_frame` if available

Adrian Vogelsgesang via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Thu Jul 28 01:24:09 PDT 2022


avogelsgesang updated this revision to Diff 448260.
avogelsgesang added a comment.

Apply clang-format and fix commit title


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130668/new/

https://reviews.llvm.org/D130668

Files:
  libunwind/src/AddressSpace.hpp


Index: libunwind/src/AddressSpace.hpp
===================================================================
--- libunwind/src/AddressSpace.hpp
+++ libunwind/src/AddressSpace.hpp
@@ -601,6 +601,54 @@
   if (info.arm_section && info.arm_section_length)
     return true;
 #elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
+  // Use DLFO_STRUCT_HAS_EH_DBASE to determine the existence of
+  // `_dl_find_object` Use _LIBUNWIND_SUPPORT_DWARF_INDEX, because libunwind
+  // support for _dl_find_object on other unwind formats is not implemented,
+  // yet.
+#if defined(DLFO_STRUCT_HAS_EH_DBASE) & defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
+  // We look-up `dl_find_object` dynamically at runtime to ensure backwards
+  // compatibility with earlier version of glibc not yet providing it. On older
+  // systems, we gracefully fallback to `dl_iterate_phdr`. Cache the pointer
+  // so we only look it up once. Do manual lock to avoid _cxa_guard_acquire.
+  static decltype(_dl_find_object) *dlFindObject;
+  static bool dlFindObjectChecked = false;
+  if (!dlFindObjectChecked) {
+    dlFindObject = reinterpret_cast<decltype(_dl_find_object) *>(
+        dlsym(RTLD_DEFAULT, "_dl_find_object"));
+    dlFindObjectChecked = true;
+  }
+  // Try to find the unwind info using `dl_find_object`
+  dl_find_object findResult;
+  if (dlFindObject && dlFindObject((void *)targetAddr, &findResult) == 0) {
+    if (findResult.dlfo_eh_frame == nullptr) {
+      // Found an entry for `targetAddr`, but there is no unwind info.
+      return false;
+    }
+    info.dso_base = reinterpret_cast<uintptr_t>(findResult.dlfo_map_start);
+    info.text_segment_length = static_cast<size_t>(
+        (char *)findResult.dlfo_map_end - (char *)findResult.dlfo_map_start);
+    static_assert(DLFO_STRUCT_HAS_EH_DBASE == 0, "unexpected base address");
+
+    // `_dl_find_object` gives us the start but not the size of the
+    // PT_GNU_EH_FRAME section. Setting length to `SIZE_MAX` effectively
+    // disables all range checks.
+    static_assert(DLFO_EH_SEGMENT_TYPE == PT_GNU_EH_FRAME,
+                  "unexpected segment retrieved by `_dl_find_object`");
+    info.dwarf_index_section =
+        reinterpret_cast<uintptr_t>(findResult.dlfo_eh_frame);
+    info.dwarf_index_section_length = SIZE_MAX;
+    EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
+    if (!EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
+            *this, info.dwarf_index_section, SIZE_MAX, hdrInfo)) {
+      return false;
+    }
+    // .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.
+    info.dwarf_section = hdrInfo.eh_frame_ptr;
+    info.dwarf_section_length = SIZE_MAX;
+    return true;
+  }
+#endif
   dl_iterate_cb_data cb_data = {this, &info, targetAddr};
   int found = dl_iterate_phdr(findUnwindSectionsByPhdr, &cb_data);
   return static_cast<bool>(found);


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D130668.448260.patch
Type: text/x-patch
Size: 2918 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/libcxx-commits/attachments/20220728/85b29c91/attachment.bin>


More information about the libcxx-commits mailing list