[libunwind] r374969 - [libunwind][Android] Improve workaround for PIE zero-dlpi_addr bug

Ryan Prichard via cfe-commits cfe-commits at lists.llvm.org
Tue Oct 15 19:38:47 PDT 2019


Author: rprichard
Date: Tue Oct 15 19:38:47 2019
New Revision: 374969

URL: http://llvm.org/viewvc/llvm-project?rev=374969&view=rev
Log:
[libunwind][Android] Improve workaround for PIE zero-dlpi_addr bug

Summary:
The workaround added in https://reviews.llvm.org/rL299575 appears to be
working around a bug in Android JB 4.1.x and 4.2.x (API 16 and 17).

Starting in API 16, Android added support for PIE binaries, but the
dynamic linker failed to initialize dlpi_addr to the address that the
executable was loaded at. The bug was fixed in Android JB 4.3.x (API 18).

Improve the true load bias calculation:

 * The code was assuming that the first segment would be the PT_PHDR
   segment. I think it's better to be explicit and search for PT_PHDR. (It
   will be almost as fast in practice.)

 * It's more correct to use p_vaddr rather than p_offset. If a PIE
   executable is linked with a non-zero image base (e.g. lld's
   -Wl,--image-base=xxxx), then we must use p_vaddr here.

The "phdr->p_vaddr < image_base" condition seems unnecessary and maybe
slightly wrong. If the OS were to load a binary at an address smaller than
a vaddr in the binary, we would still want to do this workaround.

The workaround is safe when the linker bug isn't present, because it
should calculate an image_base equal to dlpi_addr. Note that with API 21
and up, this workaround should never activate for dynamically-linked
objects, because non-PIE executables aren't allowed.

Consolidate the fix into a single block of code that calculates the true
image base, and make it clear that the fix no longer applies after API 18.

See https://github.com/android/ndk/issues/505 for details.

Reviewers: mclow.lists, srhines, danalbert, compnerd

Reviewed By: compnerd

Subscribers: srhines, krytarowski, christof, libcxx-commits

Tags: #libc

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

Modified:
    libunwind/trunk/src/AddressSpace.hpp

Modified: libunwind/trunk/src/AddressSpace.hpp
URL: http://llvm.org/viewvc/llvm-project/libunwind/trunk/src/AddressSpace.hpp?rev=374969&r1=374968&r2=374969&view=diff
==============================================================================
--- libunwind/trunk/src/AddressSpace.hpp (original)
+++ libunwind/trunk/src/AddressSpace.hpp Tue Oct 15 19:38:47 2019
@@ -497,32 +497,40 @@ inline bool LocalAddressSpace::findUnwin
 #if !defined(Elf_Phdr)
         typedef ElfW(Phdr) Elf_Phdr;
 #endif
+#if !defined(Elf_Addr)
+        typedef ElfW(Addr) Elf_Addr;
+#endif
+
+        Elf_Addr image_base = pinfo->dlpi_addr;
+
+#if defined(__ANDROID__) && __ANDROID_API__ < 18
+        if (image_base == 0) {
+          // Normally, an image base of 0 indicates a non-PIE executable. On
+          // versions of Android prior to API 18, the dynamic linker reported a
+          // dlpi_addr of 0 for PIE executables. Compute the true image base
+          // using the PT_PHDR segment.
+          // See https://github.com/android/ndk/issues/505.
+          for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
+            const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
+            if (phdr->p_type == PT_PHDR) {
+              image_base = reinterpret_cast<Elf_Addr>(pinfo->dlpi_phdr) -
+                  phdr->p_vaddr;
+              break;
+            }
+          }
+        }
+#endif
 
  #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
   #if !defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
    #error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform."
   #endif
         size_t object_length;
-#if defined(__ANDROID__)
-#if !defined(Elf_Addr)
-        typedef ElfW(Addr) Elf_Addr;
-#endif
-        Elf_Addr image_base =
-            pinfo->dlpi_phnum
-                ? reinterpret_cast<Elf_Addr>(pinfo->dlpi_phdr) -
-                      reinterpret_cast<const Elf_Phdr *>(pinfo->dlpi_phdr)
-                          ->p_offset
-                : 0;
-#endif
 
         for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
           const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
           if (phdr->p_type == PT_LOAD) {
-            uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr;
-#if defined(__ANDROID__)
-            if (pinfo->dlpi_addr == 0 && phdr->p_vaddr < image_base)
-              begin = begin + image_base;
-#endif
+            uintptr_t begin = image_base + phdr->p_vaddr;
             uintptr_t end = begin + phdr->p_memsz;
             if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
               cbdata->sects->dso_base = begin;
@@ -531,11 +539,7 @@ inline bool LocalAddressSpace::findUnwin
             }
           } else if (phdr->p_type == PT_GNU_EH_FRAME) {
             EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
-            uintptr_t eh_frame_hdr_start = pinfo->dlpi_addr + phdr->p_vaddr;
-#if defined(__ANDROID__)
-            if (pinfo->dlpi_addr == 0 && phdr->p_vaddr < image_base)
-              eh_frame_hdr_start = eh_frame_hdr_start + image_base;
-#endif
+            uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr;
             cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
             cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
             found_hdr = EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
@@ -556,12 +560,12 @@ inline bool LocalAddressSpace::findUnwin
         for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
           const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
           if (phdr->p_type == PT_LOAD) {
-            uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr;
+            uintptr_t begin = image_base + phdr->p_vaddr;
             uintptr_t end = begin + phdr->p_memsz;
             if (cbdata->targetAddr >= begin && cbdata->targetAddr < end)
               found_obj = true;
           } else if (phdr->p_type == PT_ARM_EXIDX) {
-            uintptr_t exidx_start = pinfo->dlpi_addr + phdr->p_vaddr;
+            uintptr_t exidx_start = image_base + phdr->p_vaddr;
             cbdata->sects->arm_section = exidx_start;
             cbdata->sects->arm_section_length = phdr->p_memsz;
             found_hdr = true;




More information about the cfe-commits mailing list