Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2008, Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 // notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 // copyright notice, this list of conditions and the following disclaimer
     12 // in the documentation and/or other materials provided with the
     13 // distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 // contributors may be used to endorse or promote products derived from
     16 // this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 // ---
     31 // Author: Paul Pluzhnikov
     32 //
     33 // Allow dynamic symbol lookup in the kernel VDSO page.
     34 //
     35 // VDSO stands for "Virtual Dynamic Shared Object" -- a page of
     36 // executable code, which looks like a shared library, but doesn't
     37 // necessarily exist anywhere on disk, and which gets mmap()ed into
     38 // every process by kernels which support VDSO, such as 2.6.x for 32-bit
     39 // executables, and 2.6.24 and above for 64-bit executables.
     40 //
     41 // More details could be found here:
     42 // http://www.trilithium.com/johan/2005/08/linux-gate/
     43 //
     44 // VDSOSupport -- a class representing kernel VDSO (if present).
     45 //
     46 // Example usage:
     47 //  VDSOSupport vdso;
     48 //  VDSOSupport::SymbolInfo info;
     49 //  typedef (*FN)(unsigned *, void *, void *);
     50 //  FN fn = NULL;
     51 //  if (vdso.LookupSymbol("__vdso_getcpu", "LINUX_2.6", STT_FUNC, &info)) {
     52 //     fn = reinterpret_cast<FN>(info.address);
     53 //  }
     54 
     55 #ifndef BASE_VDSO_SUPPORT_H_
     56 #define BASE_VDSO_SUPPORT_H_
     57 
     58 #include <config.h>
     59 #include "base/basictypes.h"
     60 #include "base/elf_mem_image.h"
     61 
     62 #ifdef HAVE_ELF_MEM_IMAGE
     63 
     64 #define HAVE_VDSO_SUPPORT 1
     65 
     66 #include <stdlib.h>     // for NULL
     67 
     68 namespace base {
     69 
     70 // NOTE: this class may be used from within tcmalloc, and can not
     71 // use any memory allocation routines.
     72 class VDSOSupport {
     73  public:
     74   VDSOSupport();
     75 
     76   typedef ElfMemImage::SymbolInfo SymbolInfo;
     77   typedef ElfMemImage::SymbolIterator SymbolIterator;
     78 
     79   // Answers whether we have a vdso at all.
     80   bool IsPresent() const { return image_.IsPresent(); }
     81 
     82   // Allow to iterate over all VDSO symbols.
     83   SymbolIterator begin() const { return image_.begin(); }
     84   SymbolIterator end() const { return image_.end(); }
     85 
     86   // Look up versioned dynamic symbol in the kernel VDSO.
     87   // Returns false if VDSO is not present, or doesn't contain given
     88   // symbol/version/type combination.
     89   // If info_out != NULL, additional details are filled in.
     90   bool LookupSymbol(const char *name, const char *version,
     91                     int symbol_type, SymbolInfo *info_out) const;
     92 
     93   // Find info about symbol (if any) which overlaps given address.
     94   // Returns true if symbol was found; false if VDSO isn't present
     95   // or doesn't have a symbol overlapping given address.
     96   // If info_out != NULL, additional details are filled in.
     97   bool LookupSymbolByAddress(const void *address, SymbolInfo *info_out) const;
     98 
     99   // Used only for testing. Replace real VDSO base with a mock.
    100   // Returns previous value of vdso_base_. After you are done testing,
    101   // you are expected to call SetBase() with previous value, in order to
    102   // reset state to the way it was.
    103   const void *SetBase(const void *s);
    104 
    105   // Computes vdso_base_ and returns it. Should be called as early as
    106   // possible; before any thread creation, chroot or setuid.
    107   static const void *Init();
    108 
    109  private:
    110   // image_ represents VDSO ELF image in memory.
    111   // image_.ehdr_ == NULL implies there is no VDSO.
    112   ElfMemImage image_;
    113 
    114   // Cached value of auxv AT_SYSINFO_EHDR, computed once.
    115   // This is a tri-state:
    116   //   kInvalidBase   => value hasn't been determined yet.
    117   //              0   => there is no VDSO.
    118   //           else   => vma of VDSO Elf{32,64}_Ehdr.
    119   //
    120   // When testing with mock VDSO, low bit is set.
    121   // The low bit is always available because vdso_base_ is
    122   // page-aligned.
    123   static const void *vdso_base_;
    124 
    125   // NOLINT on 'long' because these routines mimic kernel api.
    126   // The 'cache' parameter may be used by some versions of the kernel,
    127   // and should be NULL or point to a static buffer containing at
    128   // least two 'long's.
    129   static long InitAndGetCPU(unsigned *cpu, void *cache,     // NOLINT 'long'.
    130                             void *unused);
    131   static long GetCPUViaSyscall(unsigned *cpu, void *cache,  // NOLINT 'long'.
    132                                void *unused);
    133   typedef long (*GetCpuFn)(unsigned *cpu, void *cache,      // NOLINT 'long'.
    134                            void *unused);
    135 
    136   // This function pointer may point to InitAndGetCPU,
    137   // GetCPUViaSyscall, or __vdso_getcpu at different stages of initialization.
    138   static GetCpuFn getcpu_fn_;
    139 
    140   friend int GetCPU(void);  // Needs access to getcpu_fn_.
    141 
    142   DISALLOW_COPY_AND_ASSIGN(VDSOSupport);
    143 };
    144 
    145 // Same as sched_getcpu() on later glibc versions.
    146 // Return current CPU, using (fast) __vdso_getcpu (at) LINUX_2.6 if present,
    147 // otherwise use syscall(SYS_getcpu,...).
    148 // May return -1 with errno == ENOSYS if the kernel doesn't
    149 // support SYS_getcpu.
    150 int GetCPU();
    151 }  // namespace base
    152 
    153 #endif  // HAVE_ELF_MEM_IMAGE
    154 
    155 #endif  // BASE_VDSO_SUPPORT_H_
    156