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