vdso_support.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. //
  2. // Copyright 2017 The Abseil Authors.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // https://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. //
  16. // Allow dynamic symbol lookup in the kernel VDSO page.
  17. //
  18. // VDSO stands for "Virtual Dynamic Shared Object" -- a page of
  19. // executable code, which looks like a shared library, but doesn't
  20. // necessarily exist anywhere on disk, and which gets mmap()ed into
  21. // every process by kernels which support VDSO, such as 2.6.x for 32-bit
  22. // executables, and 2.6.24 and above for 64-bit executables.
  23. //
  24. // More details could be found here:
  25. // http://www.trilithium.com/johan/2005/08/linux-gate/
  26. //
  27. // VDSOSupport -- a class representing kernel VDSO (if present).
  28. //
  29. // Example usage:
  30. // VDSOSupport vdso;
  31. // VDSOSupport::SymbolInfo info;
  32. // typedef (*FN)(unsigned *, void *, void *);
  33. // FN fn = nullptr;
  34. // if (vdso.LookupSymbol("__vdso_getcpu", "LINUX_2.6", STT_FUNC, &info)) {
  35. // fn = reinterpret_cast<FN>(info.address);
  36. // }
  37. #ifndef ABSL_DEBUGGING_INTERNAL_VDSO_SUPPORT_H_
  38. #define ABSL_DEBUGGING_INTERNAL_VDSO_SUPPORT_H_
  39. #include <atomic>
  40. #include "absl/base/attributes.h"
  41. #include "absl/debugging/internal/elf_mem_image.h"
  42. #ifdef ABSL_HAVE_ELF_MEM_IMAGE
  43. #ifdef ABSL_HAVE_VDSO_SUPPORT
  44. #error ABSL_HAVE_VDSO_SUPPORT cannot be directly set
  45. #else
  46. #define ABSL_HAVE_VDSO_SUPPORT 1
  47. #endif
  48. namespace absl {
  49. ABSL_NAMESPACE_BEGIN
  50. namespace debugging_internal {
  51. // NOTE: this class may be used from within tcmalloc, and can not
  52. // use any memory allocation routines.
  53. class VDSOSupport {
  54. public:
  55. VDSOSupport();
  56. typedef ElfMemImage::SymbolInfo SymbolInfo;
  57. typedef ElfMemImage::SymbolIterator SymbolIterator;
  58. // On PowerPC64 VDSO symbols can either be of type STT_FUNC or STT_NOTYPE
  59. // depending on how the kernel is built. The kernel is normally built with
  60. // STT_NOTYPE type VDSO symbols. Let's make things simpler first by using a
  61. // compile-time constant.
  62. #ifdef __powerpc64__
  63. enum { kVDSOSymbolType = STT_NOTYPE };
  64. #else
  65. enum { kVDSOSymbolType = STT_FUNC };
  66. #endif
  67. // Answers whether we have a vdso at all.
  68. bool IsPresent() const { return image_.IsPresent(); }
  69. // Allow to iterate over all VDSO symbols.
  70. SymbolIterator begin() const { return image_.begin(); }
  71. SymbolIterator end() const { return image_.end(); }
  72. // Look up versioned dynamic symbol in the kernel VDSO.
  73. // Returns false if VDSO is not present, or doesn't contain given
  74. // symbol/version/type combination.
  75. // If info_out != nullptr, additional details are filled in.
  76. bool LookupSymbol(const char *name, const char *version,
  77. int symbol_type, SymbolInfo *info_out) const;
  78. // Find info about symbol (if any) which overlaps given address.
  79. // Returns true if symbol was found; false if VDSO isn't present
  80. // or doesn't have a symbol overlapping given address.
  81. // If info_out != nullptr, additional details are filled in.
  82. bool LookupSymbolByAddress(const void *address, SymbolInfo *info_out) const;
  83. // Used only for testing. Replace real VDSO base with a mock.
  84. // Returns previous value of vdso_base_. After you are done testing,
  85. // you are expected to call SetBase() with previous value, in order to
  86. // reset state to the way it was.
  87. const void *SetBase(const void *s);
  88. // Computes vdso_base_ and returns it. Should be called as early as
  89. // possible; before any thread creation, chroot or setuid.
  90. static const void *Init();
  91. private:
  92. // image_ represents VDSO ELF image in memory.
  93. // image_.ehdr_ == nullptr implies there is no VDSO.
  94. ElfMemImage image_;
  95. // Cached value of auxv AT_SYSINFO_EHDR, computed once.
  96. // This is a tri-state:
  97. // kInvalidBase => value hasn't been determined yet.
  98. // 0 => there is no VDSO.
  99. // else => vma of VDSO Elf{32,64}_Ehdr.
  100. //
  101. // When testing with mock VDSO, low bit is set.
  102. // The low bit is always available because vdso_base_ is
  103. // page-aligned.
  104. static std::atomic<const void *> vdso_base_;
  105. // NOLINT on 'long' because these routines mimic kernel api.
  106. // The 'cache' parameter may be used by some versions of the kernel,
  107. // and should be nullptr or point to a static buffer containing at
  108. // least two 'long's.
  109. static long InitAndGetCPU(unsigned *cpu, void *cache, // NOLINT 'long'.
  110. void *unused);
  111. static long GetCPUViaSyscall(unsigned *cpu, void *cache, // NOLINT 'long'.
  112. void *unused);
  113. typedef long (*GetCpuFn)(unsigned *cpu, void *cache, // NOLINT 'long'.
  114. void *unused);
  115. // This function pointer may point to InitAndGetCPU,
  116. // GetCPUViaSyscall, or __vdso_getcpu at different stages of initialization.
  117. ABSL_CONST_INIT static std::atomic<GetCpuFn> getcpu_fn_;
  118. friend int GetCPU(void); // Needs access to getcpu_fn_.
  119. VDSOSupport(const VDSOSupport&) = delete;
  120. VDSOSupport& operator=(const VDSOSupport&) = delete;
  121. };
  122. // Same as sched_getcpu() on later glibc versions.
  123. // Return current CPU, using (fast) __vdso_getcpu@LINUX_2.6 if present,
  124. // otherwise use syscall(SYS_getcpu,...).
  125. // May return -1 with errno == ENOSYS if the kernel doesn't
  126. // support SYS_getcpu.
  127. int GetCPU();
  128. } // namespace debugging_internal
  129. ABSL_NAMESPACE_END
  130. } // namespace absl
  131. #endif // ABSL_HAVE_ELF_MEM_IMAGE
  132. #endif // ABSL_DEBUGGING_INTERNAL_VDSO_SUPPORT_H_