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