OLD | NEW |
1 // Copyright (c) 2008, Google Inc. | 1 // Copyright 2008 Google Inc. All Rights Reserved. |
2 // All rights reserved. | 2 // Author: ppluzhnikov@google.com (Paul Pluzhnikov) |
3 // | 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. | 4 // Allow dynamic symbol lookup in the kernel VDSO page. |
34 // | 5 // |
35 // VDSO stands for "Virtual Dynamic Shared Object" -- a page of | 6 // VDSO stands for "Virtual Dynamic Shared Object" -- a page of |
36 // executable code, which looks like a shared library, but doesn't | 7 // executable code, which looks like a shared library, but doesn't |
37 // necessarily exist anywhere on disk, and which gets mmap()ed into | 8 // 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 | 9 // 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. | 10 // executables, and 2.6.24 and above for 64-bit executables. |
40 // | 11 // |
41 // More details could be found here: | 12 // More details could be found here: |
42 // http://www.trilithium.com/johan/2005/08/linux-gate/ | 13 // http://www.trilithium.com/johan/2005/08/linux-gate/ |
43 // | 14 // |
44 // VDSOSupport -- a class representing kernel VDSO (if present). | 15 // VDSOSupport -- a class representing kernel VDSO (if present). |
45 // | 16 // |
46 // Example usage: | 17 // Example usage: |
47 // VDSOSupport vdso; | 18 // VDSOSupport vdso; |
48 // VDSOSupport::SymbolInfo info; | 19 // VDSOSupport::SymbolInfo info; |
49 // typedef (*FN)(unsigned *, void *, void *); | 20 // typedef (*FN)(unsigned *, void *, void *); |
50 // FN fn = NULL; | 21 // FN fn = NULL; |
51 // if (vdso.LookupSymbol("__vdso_getcpu", "LINUX_2.6", STT_FUNC, &info)) { | 22 // if (vdso.LookupSymbol("__vdso_getcpu", "LINUX_2.6", STT_FUNC, &info)) { |
52 // fn = reinterpret_cast<FN>(info.address); | 23 // fn = reinterpret_cast<FN>(info.address); |
53 // } | 24 // } |
54 | 25 |
55 #ifndef BASE_VDSO_SUPPORT_H_ | 26 #ifndef BASE_VDSO_SUPPORT_H_ |
56 #define BASE_VDSO_SUPPORT_H_ | 27 #define BASE_VDSO_SUPPORT_H_ |
57 | 28 |
58 #include <config.h> | 29 #include <config.h> |
| 30 #ifdef HAVE_FEATURES_H |
| 31 #include <features.h> // for __GLIBC__ |
| 32 #endif |
59 #include "base/basictypes.h" | 33 #include "base/basictypes.h" |
60 #include "base/elf_mem_image.h" | |
61 | 34 |
62 #ifdef HAVE_ELF_MEM_IMAGE | 35 // Maybe one day we can rewrite this file not to require the elf |
| 36 // symbol extensions in glibc, but for right now we need them. |
| 37 #if defined(__ELF__) && defined(__GLIBC__) |
63 | 38 |
64 #define HAVE_VDSO_SUPPORT 1 | 39 #define HAVE_VDSO_SUPPORT 1 |
65 | 40 |
66 #include <stdlib.h> // for NULL | 41 #include <stdlib.h> // for NULL |
| 42 #include <link.h> // for ElfW |
67 | 43 |
68 namespace base { | 44 namespace base { |
69 | 45 |
70 // NOTE: this class may be used from within tcmalloc, and can not | 46 // NOTE: this class may be used from within tcmalloc, and can not |
71 // use any memory allocation routines. | 47 // use any memory allocation routines. |
72 class VDSOSupport { | 48 class VDSOSupport { |
73 public: | 49 public: |
| 50 // Sentinel: there could never be a VDSO at this address. |
| 51 static const void *const kInvalidBase; |
| 52 |
| 53 // Information about a single vdso symbol. |
| 54 // All pointers are into .dynsym, .dynstr, or .text of the VDSO. |
| 55 // Do not free() them or modify through them. |
| 56 struct SymbolInfo { |
| 57 const char *name; // E.g. "__vdso_getcpu" |
| 58 const char *version; // E.g. "LINUX_2.6", could be "" |
| 59 // for unversioned symbol. |
| 60 const void *address; // Relocated symbol address. |
| 61 const ElfW(Sym) *symbol; // Symbol in the dynamic symbol table. |
| 62 }; |
| 63 |
| 64 // Supports iteration over all dynamic symbols. |
| 65 class SymbolIterator { |
| 66 public: |
| 67 friend class VDSOSupport; |
| 68 const SymbolInfo *operator->() const; |
| 69 const SymbolInfo &operator*() const; |
| 70 SymbolIterator& operator++(); |
| 71 bool operator!=(const SymbolIterator &rhs) const; |
| 72 bool operator==(const SymbolIterator &rhs) const; |
| 73 private: |
| 74 SymbolIterator(const void *const image, int index); |
| 75 void Update(int incr); |
| 76 SymbolInfo info_; |
| 77 int index_; |
| 78 const void *const image_; |
| 79 }; |
| 80 |
74 VDSOSupport(); | 81 VDSOSupport(); |
75 | 82 |
76 typedef ElfMemImage::SymbolInfo SymbolInfo; | |
77 typedef ElfMemImage::SymbolIterator SymbolIterator; | |
78 | |
79 // Answers whether we have a vdso at all. | 83 // Answers whether we have a vdso at all. |
80 bool IsPresent() const { return image_.IsPresent(); } | 84 bool IsPresent() const { return image_.IsPresent(); } |
81 | 85 |
82 // Allow to iterate over all VDSO symbols. | 86 // Allow to iterate over all VDSO symbols. |
83 SymbolIterator begin() const { return image_.begin(); } | 87 SymbolIterator begin() const; |
84 SymbolIterator end() const { return image_.end(); } | 88 SymbolIterator end() const; |
85 | 89 |
86 // Look up versioned dynamic symbol in the kernel VDSO. | 90 // Look up versioned dynamic symbol in the kernel VDSO. |
87 // Returns false if VDSO is not present, or doesn't contain given | 91 // Returns false if VDSO is not present, or doesn't contain given |
88 // symbol/version/type combination. | 92 // symbol/version/type combination. |
89 // If info_out != NULL, additional details are filled in. | 93 // If info_out != NULL, additional details are filled in. |
90 bool LookupSymbol(const char *name, const char *version, | 94 bool LookupSymbol(const char *name, const char *version, |
91 int symbol_type, SymbolInfo *info_out) const; | 95 int symbol_type, SymbolInfo *info_out) const; |
92 | 96 |
93 // Find info about symbol (if any) which overlaps given address. | 97 // Find info about symbol (if any) which overlaps given address. |
94 // Returns true if symbol was found; false if VDSO isn't present | 98 // Returns true if symbol was found; false if VDSO isn't present |
95 // or doesn't have a symbol overlapping given address. | 99 // or doesn't have a symbol overlapping given address. |
96 // If info_out != NULL, additional details are filled in. | 100 // If info_out != NULL, additional details are filled in. |
97 bool LookupSymbolByAddress(const void *address, SymbolInfo *info_out) const; | 101 bool LookupSymbolByAddress(const void *address, SymbolInfo *info_out) const; |
98 | 102 |
99 // Used only for testing. Replace real VDSO base with a mock. | 103 // Used only for testing. Replace real VDSO base with a mock. |
100 // Returns previous value of vdso_base_. After you are done testing, | 104 // Returns previous value of vdso_base_. After you are done testing, |
101 // you are expected to call SetBase() with previous value, in order to | 105 // you are expected to call SetBase() with previous value, in order to |
102 // reset state to the way it was. | 106 // reset state to the way it was. |
103 const void *SetBase(const void *s); | 107 const void *SetBase(const void *s); |
104 | 108 |
105 // Computes vdso_base_ and returns it. Should be called as early as | 109 // Computes vdso_base_ and returns it. Should be called as early as |
106 // possible; before any thread creation, chroot or setuid. | 110 // possible; before any thread creation, chroot or setuid. |
107 static const void *Init(); | 111 static const void *Init(); |
108 | 112 |
109 private: | 113 private: |
| 114 // An in-memory ELF image (may not exist on disk). |
| 115 class ElfMemImage { |
| 116 public: |
| 117 explicit ElfMemImage(const void *base); |
| 118 void Init(const void *base); |
| 119 bool IsPresent() const { return ehdr_ != NULL; } |
| 120 const ElfW(Phdr)* GetPhdr(int index) const; |
| 121 const ElfW(Sym)* GetDynsym(int index) const; |
| 122 const ElfW(Versym)* GetVersym(int index) const; |
| 123 const ElfW(Verdef)* GetVerdef(int index) const; |
| 124 const ElfW(Verdaux)* GetVerdefAux(const ElfW(Verdef) *verdef) const; |
| 125 const char* GetDynstr(ElfW(Word) offset) const; |
| 126 const void* GetSymAddr(const ElfW(Sym) *sym) const; |
| 127 const char* GetVerstr(ElfW(Word) offset) const; |
| 128 int GetNumSymbols() const; |
| 129 private: |
| 130 const ElfW(Ehdr) *ehdr_; |
| 131 const ElfW(Sym) *dynsym_; |
| 132 const ElfW(Versym) *versym_; |
| 133 const ElfW(Verdef) *verdef_; |
| 134 const ElfW(Word) *hash_; |
| 135 const char *dynstr_; |
| 136 size_t strsize_; |
| 137 size_t verdefnum_; |
| 138 ElfW(Addr) link_base_; // Link-time base (p_vaddr of first PT_LOAD). |
| 139 }; |
| 140 |
110 // image_ represents VDSO ELF image in memory. | 141 // image_ represents VDSO ELF image in memory. |
111 // image_.ehdr_ == NULL implies there is no VDSO. | 142 // image_.ehdr_ == NULL implies there is no VDSO. |
112 ElfMemImage image_; | 143 ElfMemImage image_; |
113 | 144 |
114 // Cached value of auxv AT_SYSINFO_EHDR, computed once. | 145 // Cached value of auxv AT_SYSINFO_EHDR, computed once. |
115 // This is a tri-state: | 146 // This is a tri-state: |
116 // kInvalidBase => value hasn't been determined yet. | 147 // kInvalidBase => value hasn't been determined yet. |
117 // 0 => there is no VDSO. | 148 // 0 => there is no VDSO. |
118 // else => vma of VDSO Elf{32,64}_Ehdr. | 149 // else => vma of VDSO Elf{32,64}_Ehdr. |
119 // | 150 // |
(...skipping 23 matching lines...) Expand all Loading... |
143 }; | 174 }; |
144 | 175 |
145 // Same as sched_getcpu() on later glibc versions. | 176 // Same as sched_getcpu() on later glibc versions. |
146 // Return current CPU, using (fast) __vdso_getcpu@LINUX_2.6 if present, | 177 // Return current CPU, using (fast) __vdso_getcpu@LINUX_2.6 if present, |
147 // otherwise use syscall(SYS_getcpu,...). | 178 // otherwise use syscall(SYS_getcpu,...). |
148 // May return -1 with errno == ENOSYS if the kernel doesn't | 179 // May return -1 with errno == ENOSYS if the kernel doesn't |
149 // support SYS_getcpu. | 180 // support SYS_getcpu. |
150 int GetCPU(); | 181 int GetCPU(); |
151 } // namespace base | 182 } // namespace base |
152 | 183 |
153 #endif // HAVE_ELF_MEM_IMAGE | 184 #endif // __ELF__ and __GLIBC__ |
154 | 185 |
155 #endif // BASE_VDSO_SUPPORT_H_ | 186 #endif // BASE_VDSO_SUPPORT_H_ |
OLD | NEW |