vdso_support.h
Go to the documentation of this file.
00001 //
00002 // Copyright 2017 The Abseil Authors.
00003 //
00004 // Licensed under the Apache License, Version 2.0 (the "License");
00005 // you may not use this file except in compliance with the License.
00006 // You may obtain a copy of the License at
00007 //
00008 //      https://www.apache.org/licenses/LICENSE-2.0
00009 //
00010 // Unless required by applicable law or agreed to in writing, software
00011 // distributed under the License is distributed on an "AS IS" BASIS,
00012 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013 // See the License for the specific language governing permissions and
00014 // limitations under the License.
00015 //
00016 
00017 // Allow dynamic symbol lookup in the kernel VDSO page.
00018 //
00019 // VDSO stands for "Virtual Dynamic Shared Object" -- a page of
00020 // executable code, which looks like a shared library, but doesn't
00021 // necessarily exist anywhere on disk, and which gets mmap()ed into
00022 // every process by kernels which support VDSO, such as 2.6.x for 32-bit
00023 // executables, and 2.6.24 and above for 64-bit executables.
00024 //
00025 // More details could be found here:
00026 // http://www.trilithium.com/johan/2005/08/linux-gate/
00027 //
00028 // VDSOSupport -- a class representing kernel VDSO (if present).
00029 //
00030 // Example usage:
00031 //  VDSOSupport vdso;
00032 //  VDSOSupport::SymbolInfo info;
00033 //  typedef (*FN)(unsigned *, void *, void *);
00034 //  FN fn = nullptr;
00035 //  if (vdso.LookupSymbol("__vdso_getcpu", "LINUX_2.6", STT_FUNC, &info)) {
00036 //     fn = reinterpret_cast<FN>(info.address);
00037 //  }
00038 
00039 #ifndef ABSL_DEBUGGING_INTERNAL_VDSO_SUPPORT_H_
00040 #define ABSL_DEBUGGING_INTERNAL_VDSO_SUPPORT_H_
00041 
00042 #include <atomic>
00043 
00044 #include "absl/base/attributes.h"
00045 #include "absl/debugging/internal/elf_mem_image.h"
00046 
00047 #ifdef ABSL_HAVE_ELF_MEM_IMAGE
00048 
00049 #ifdef ABSL_HAVE_VDSO_SUPPORT
00050 #error ABSL_HAVE_VDSO_SUPPORT cannot be directly set
00051 #else
00052 #define ABSL_HAVE_VDSO_SUPPORT 1
00053 #endif
00054 
00055 namespace absl {
00056 namespace debugging_internal {
00057 
00058 // NOTE: this class may be used from within tcmalloc, and can not
00059 // use any memory allocation routines.
00060 class VDSOSupport {
00061  public:
00062   VDSOSupport();
00063 
00064   typedef ElfMemImage::SymbolInfo SymbolInfo;
00065   typedef ElfMemImage::SymbolIterator SymbolIterator;
00066 
00067   // On PowerPC64 VDSO symbols can either be of type STT_FUNC or STT_NOTYPE
00068   // depending on how the kernel is built.  The kernel is normally built with
00069   // STT_NOTYPE type VDSO symbols.  Let's make things simpler first by using a
00070   // compile-time constant.
00071 #ifdef __powerpc64__
00072   enum { kVDSOSymbolType = STT_NOTYPE };
00073 #else
00074   enum { kVDSOSymbolType = STT_FUNC };
00075 #endif
00076 
00077   // Answers whether we have a vdso at all.
00078   bool IsPresent() const { return image_.IsPresent(); }
00079 
00080   // Allow to iterate over all VDSO symbols.
00081   SymbolIterator begin() const { return image_.begin(); }
00082   SymbolIterator end() const { return image_.end(); }
00083 
00084   // Look up versioned dynamic symbol in the kernel VDSO.
00085   // Returns false if VDSO is not present, or doesn't contain given
00086   // symbol/version/type combination.
00087   // If info_out != nullptr, additional details are filled in.
00088   bool LookupSymbol(const char *name, const char *version,
00089                     int symbol_type, SymbolInfo *info_out) const;
00090 
00091   // Find info about symbol (if any) which overlaps given address.
00092   // Returns true if symbol was found; false if VDSO isn't present
00093   // or doesn't have a symbol overlapping given address.
00094   // If info_out != nullptr, additional details are filled in.
00095   bool LookupSymbolByAddress(const void *address, SymbolInfo *info_out) const;
00096 
00097   // Used only for testing. Replace real VDSO base with a mock.
00098   // Returns previous value of vdso_base_. After you are done testing,
00099   // you are expected to call SetBase() with previous value, in order to
00100   // reset state to the way it was.
00101   const void *SetBase(const void *s);
00102 
00103   // Computes vdso_base_ and returns it. Should be called as early as
00104   // possible; before any thread creation, chroot or setuid.
00105   static const void *Init();
00106 
00107  private:
00108   // image_ represents VDSO ELF image in memory.
00109   // image_.ehdr_ == nullptr implies there is no VDSO.
00110   ElfMemImage image_;
00111 
00112   // Cached value of auxv AT_SYSINFO_EHDR, computed once.
00113   // This is a tri-state:
00114   //   kInvalidBase   => value hasn't been determined yet.
00115   //              0   => there is no VDSO.
00116   //           else   => vma of VDSO Elf{32,64}_Ehdr.
00117   //
00118   // When testing with mock VDSO, low bit is set.
00119   // The low bit is always available because vdso_base_ is
00120   // page-aligned.
00121   static std::atomic<const void *> vdso_base_;
00122 
00123   // NOLINT on 'long' because these routines mimic kernel api.
00124   // The 'cache' parameter may be used by some versions of the kernel,
00125   // and should be nullptr or point to a static buffer containing at
00126   // least two 'long's.
00127   static long InitAndGetCPU(unsigned *cpu, void *cache,     // NOLINT 'long'.
00128                             void *unused);
00129   static long GetCPUViaSyscall(unsigned *cpu, void *cache,  // NOLINT 'long'.
00130                                void *unused);
00131   typedef long (*GetCpuFn)(unsigned *cpu, void *cache,      // NOLINT 'long'.
00132                            void *unused);
00133 
00134   // This function pointer may point to InitAndGetCPU,
00135   // GetCPUViaSyscall, or __vdso_getcpu at different stages of initialization.
00136   ABSL_CONST_INIT static std::atomic<GetCpuFn> getcpu_fn_;
00137 
00138   friend int GetCPU(void);  // Needs access to getcpu_fn_.
00139 
00140   VDSOSupport(const VDSOSupport&) = delete;
00141   VDSOSupport& operator=(const VDSOSupport&) = delete;
00142 };
00143 
00144 // Same as sched_getcpu() on later glibc versions.
00145 // Return current CPU, using (fast) __vdso_getcpu@LINUX_2.6 if present,
00146 // otherwise use syscall(SYS_getcpu,...).
00147 // May return -1 with errno == ENOSYS if the kernel doesn't
00148 // support SYS_getcpu.
00149 int GetCPU();
00150 
00151 }  // namespace debugging_internal
00152 }  // namespace absl
00153 
00154 #endif  // ABSL_HAVE_ELF_MEM_IMAGE
00155 
00156 #endif  // ABSL_DEBUGGING_INTERNAL_VDSO_SUPPORT_H_


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:42:16