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 68namespace base { 69 70// NOTE: this class may be used from within tcmalloc, and can not 71// use any memory allocation routines. 72class 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@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. 150int GetCPU(); 151} // namespace base 152 153#endif // HAVE_ELF_MEM_IMAGE 154 155#endif // BASE_VDSO_SUPPORT_H_ 156