about summary refs log tree commit diff
path: root/absl/debugging
diff options
context:
space:
mode:
Diffstat (limited to 'absl/debugging')
-rw-r--r--absl/debugging/internal/elf_mem_image.cc5
-rw-r--r--absl/debugging/internal/elf_mem_image.h7
-rw-r--r--absl/debugging/internal/stacktrace_x86-inl.inc4
-rw-r--r--absl/debugging/internal/vdso_support.cc73
4 files changed, 56 insertions, 33 deletions
diff --git a/absl/debugging/internal/elf_mem_image.cc b/absl/debugging/internal/elf_mem_image.cc
index f6c6bc07d511..3dfef5e83e57 100644
--- a/absl/debugging/internal/elf_mem_image.cc
+++ b/absl/debugging/internal/elf_mem_image.cc
@@ -75,8 +75,9 @@ const T *GetTableElement(const ElfW(Ehdr) * ehdr, ElfW(Off) table_offset,
 
 }  // namespace
 
-const void *const ElfMemImage::kInvalidBase =
-    reinterpret_cast<const void *>(~0L);
+// The value of this variable doesn't matter; it's used only for its
+// unique address.
+const int ElfMemImage::kInvalidBaseSentinel = 0;
 
 ElfMemImage::ElfMemImage(const void *base) {
   ABSL_RAW_CHECK(base != kInvalidBase, "bad pointer");
diff --git a/absl/debugging/internal/elf_mem_image.h b/absl/debugging/internal/elf_mem_image.h
index 7f3dbb971bd6..20a32a490cb2 100644
--- a/absl/debugging/internal/elf_mem_image.h
+++ b/absl/debugging/internal/elf_mem_image.h
@@ -43,9 +43,14 @@ namespace debug_internal {
 
 // An in-memory ELF image (may not exist on disk).
 class ElfMemImage {
+ private:
+  // Sentinel: there could never be an elf image at &kInvalidBaseSentinel.
+  static const int kInvalidBaseSentinel;
+
  public:
   // Sentinel: there could never be an elf image at this address.
-  static const void *const kInvalidBase;
+  static constexpr const void *const kInvalidBase =
+    static_cast<const void*>(&kInvalidBaseSentinel);
 
   // Information about a single vdso symbol.
   // All pointers are into .dynsym, .dynstr, or .text of the VDSO.
diff --git a/absl/debugging/internal/stacktrace_x86-inl.inc b/absl/debugging/internal/stacktrace_x86-inl.inc
index 6e1af017878e..9bdaa542ce27 100644
--- a/absl/debugging/internal/stacktrace_x86-inl.inc
+++ b/absl/debugging/internal/stacktrace_x86-inl.inc
@@ -114,7 +114,9 @@ static const int kMaxFrameBytes = 100000;
 // vuc is a ucontext_t *.  We use void* to avoid the use
 // of ucontext_t on non-POSIX systems.
 static uintptr_t GetFP(const void *vuc) {
-#if defined(__linux__)
+#if !defined(__linux__)
+  static_cast<void>(vuc);  // Avoid an unused argument compiler warning.
+#else
   if (vuc != nullptr) {
     auto *uc = reinterpret_cast<const ucontext_t *>(vuc);
 #if defined(__i386__)
diff --git a/absl/debugging/internal/vdso_support.cc b/absl/debugging/internal/vdso_support.cc
index 5026e1c1a9c9..815e702f5699 100644
--- a/absl/debugging/internal/vdso_support.cc
+++ b/absl/debugging/internal/vdso_support.cc
@@ -20,10 +20,15 @@
 
 #ifdef ABSL_HAVE_VDSO_SUPPORT     // defined in vdso_support.h
 
+#include <errno.h>
 #include <fcntl.h>
 #include <sys/syscall.h>
 #include <unistd.h>
 
+#if __GLIBC_PREREQ(2, 16)  // GLIBC-2.16 implements getauxval.
+#include <sys/auxv.h>
+#endif
+
 #include "absl/base/dynamic_annotations.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/base/port.h"
@@ -35,8 +40,10 @@
 namespace absl {
 namespace debug_internal {
 
+ABSL_CONST_INIT
 std::atomic<const void *> VDSOSupport::vdso_base_(
     debug_internal::ElfMemImage::kInvalidBase);
+
 std::atomic<VDSOSupport::GetCpuFn> VDSOSupport::getcpu_fn_(&InitAndGetCPU);
 VDSOSupport::VDSOSupport()
     // If vdso_base_ is still set to kInvalidBase, we got here
@@ -56,37 +63,44 @@ VDSOSupport::VDSOSupport()
 // Finally, even if there is a race here, it is harmless, because
 // the operation should be idempotent.
 const void *VDSOSupport::Init() {
-  if (vdso_base_.load(std::memory_order_relaxed) ==
-      debug_internal::ElfMemImage::kInvalidBase) {
-    {
-      // Valgrind zaps AT_SYSINFO_EHDR and friends from the auxv[]
-      // on stack, and so glibc works as if VDSO was not present.
-      // But going directly to kernel via /proc/self/auxv below bypasses
-      // Valgrind zapping. So we check for Valgrind separately.
-      if (RunningOnValgrind()) {
-        vdso_base_.store(nullptr, std::memory_order_relaxed);
-        getcpu_fn_.store(&GetCPUViaSyscall, std::memory_order_relaxed);
-        return nullptr;
-      }
-      int fd = open("/proc/self/auxv", O_RDONLY);
-      if (fd == -1) {
-        // Kernel too old to have a VDSO.
-        vdso_base_.store(nullptr, std::memory_order_relaxed);
-        getcpu_fn_.store(&GetCPUViaSyscall, std::memory_order_relaxed);
-        return nullptr;
-      }
-      ElfW(auxv_t) aux;
-      while (read(fd, &aux, sizeof(aux)) == sizeof(aux)) {
-        if (aux.a_type == AT_SYSINFO_EHDR) {
-          vdso_base_.store(reinterpret_cast<void *>(aux.a_un.a_val),
-                           std::memory_order_relaxed);
-          break;
-        }
+  const auto kInvalidBase = debug_internal::ElfMemImage::kInvalidBase;
+#if __GLIBC_PREREQ(2, 16)
+  if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) {
+    errno = 0;
+    const void *const sysinfo_ehdr =
+        reinterpret_cast<const void *>(getauxval(AT_SYSINFO_EHDR));
+    if (errno == 0) {
+      vdso_base_.store(sysinfo_ehdr, std::memory_order_relaxed);
+    }
+  }
+#endif  // __GLIBC_PREREQ(2, 16)
+  if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) {
+    // Valgrind zaps AT_SYSINFO_EHDR and friends from the auxv[]
+    // on stack, and so glibc works as if VDSO was not present.
+    // But going directly to kernel via /proc/self/auxv below bypasses
+    // Valgrind zapping. So we check for Valgrind separately.
+    if (RunningOnValgrind()) {
+      vdso_base_.store(nullptr, std::memory_order_relaxed);
+      getcpu_fn_.store(&GetCPUViaSyscall, std::memory_order_relaxed);
+      return nullptr;
+    }
+    int fd = open("/proc/self/auxv", O_RDONLY);
+    if (fd == -1) {
+      // Kernel too old to have a VDSO.
+      vdso_base_.store(nullptr, std::memory_order_relaxed);
+      getcpu_fn_.store(&GetCPUViaSyscall, std::memory_order_relaxed);
+      return nullptr;
+    }
+    ElfW(auxv_t) aux;
+    while (read(fd, &aux, sizeof(aux)) == sizeof(aux)) {
+      if (aux.a_type == AT_SYSINFO_EHDR) {
+        vdso_base_.store(reinterpret_cast<void *>(aux.a_un.a_val),
+                         std::memory_order_relaxed);
+        break;
       }
-      close(fd);
     }
-    if (vdso_base_.load(std::memory_order_relaxed) ==
-        debug_internal::ElfMemImage::kInvalidBase) {
+    close(fd);
+    if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) {
       // Didn't find AT_SYSINFO_EHDR in auxv[].
       vdso_base_.store(nullptr, std::memory_order_relaxed);
     }
@@ -135,6 +149,7 @@ long VDSOSupport::GetCPUViaSyscall(unsigned *cpu,  // NOLINT(runtime/int)
   return syscall(SYS_getcpu, cpu, nullptr, nullptr);
 #else
   // x86_64 never implemented sys_getcpu(), except as a VDSO call.
+  static_cast<void>(cpu);  // Avoid an unused argument compiler warning.
   errno = ENOSYS;
   return -1;
 #endif