OLD | NEW |
1 // Copyright (c) 2008, Google Inc. | 1 // Copyright (c) 2008, Google Inc. |
2 // All rights reserved. | 2 // All rights reserved. |
3 // | 3 // |
4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
6 // met: | 6 // met: |
7 // | 7 // |
8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
(...skipping 22 matching lines...) Expand all Loading... |
33 // Allow dynamic symbol lookup in the kernel VDSO page. | 33 // Allow dynamic symbol lookup in the kernel VDSO page. |
34 // | 34 // |
35 // VDSOSupport -- a class representing kernel VDSO (if present). | 35 // VDSOSupport -- a class representing kernel VDSO (if present). |
36 // | 36 // |
37 | 37 |
38 #include "base/vdso_support.h" | 38 #include "base/vdso_support.h" |
39 | 39 |
40 #ifdef HAVE_VDSO_SUPPORT // defined in vdso_support.h | 40 #ifdef HAVE_VDSO_SUPPORT // defined in vdso_support.h |
41 | 41 |
42 #include <fcntl.h> | 42 #include <fcntl.h> |
| 43 #include <stddef.h> // for std::ptrdiff_t |
43 | 44 |
44 #include "base/atomicops.h" // for MemoryBarrier | 45 #include "base/atomicops.h" // for MemoryBarrier |
45 #include "base/logging.h" | 46 #include "base/logging.h" |
46 #include "base/linux_syscall_support.h" | 47 #include "base/linux_syscall_support.h" |
47 #include "base/dynamic_annotations.h" | 48 #include "base/dynamic_annotations.h" |
48 #include "base/basictypes.h" // for COMPILE_ASSERT | 49 #include "base/basictypes.h" // for COMPILE_ASSERT |
49 | 50 |
50 using base::subtle::MemoryBarrier; | 51 using base::subtle::MemoryBarrier; |
51 | 52 |
52 #ifndef AT_SYSINFO_EHDR | 53 #ifndef AT_SYSINFO_EHDR |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
200 dynstr_ = NULL; | 201 dynstr_ = NULL; |
201 versym_ = NULL; | 202 versym_ = NULL; |
202 verdef_ = NULL; | 203 verdef_ = NULL; |
203 hash_ = NULL; | 204 hash_ = NULL; |
204 strsize_ = 0; | 205 strsize_ = 0; |
205 verdefnum_ = 0; | 206 verdefnum_ = 0; |
206 link_base_ = ~0L; // Sentinel: PT_LOAD .p_vaddr can't possibly be this. | 207 link_base_ = ~0L; // Sentinel: PT_LOAD .p_vaddr can't possibly be this. |
207 if (!base) { | 208 if (!base) { |
208 return; | 209 return; |
209 } | 210 } |
| 211 const intptr_t base_as_uintptr_t = reinterpret_cast<uintptr_t>(base); |
| 212 // Fake VDSO has low bit set. |
| 213 const bool fake_vdso = ((base_as_uintptr_t & 1) != 0); |
| 214 base = reinterpret_cast<const void *>(base_as_uintptr_t & ~1); |
210 const char *const base_as_char = reinterpret_cast<const char *>(base); | 215 const char *const base_as_char = reinterpret_cast<const char *>(base); |
211 if (base_as_char[EI_MAG0] != ELFMAG0 || base_as_char[EI_MAG1] != ELFMAG1 || | 216 if (base_as_char[EI_MAG0] != ELFMAG0 || base_as_char[EI_MAG1] != ELFMAG1 || |
212 base_as_char[EI_MAG2] != ELFMAG2 || base_as_char[EI_MAG3] != ELFMAG3) { | 217 base_as_char[EI_MAG2] != ELFMAG2 || base_as_char[EI_MAG3] != ELFMAG3) { |
213 RAW_DCHECK(false, "no ELF magic"); // at %p", base); | 218 RAW_DCHECK(false, "no ELF magic"); // at %p", base); |
214 return; | 219 return; |
215 } | 220 } |
216 int elf_class = base_as_char[EI_CLASS]; | 221 int elf_class = base_as_char[EI_CLASS]; |
217 if (elf_class != CurrentElfClass::kElfClass) { | 222 if (elf_class != CurrentElfClass::kElfClass) { |
218 DCHECK_EQ(elf_class, CurrentElfClass::kElfClass); | 223 DCHECK_EQ(elf_class, CurrentElfClass::kElfClass); |
219 return; | 224 return; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
259 RAW_DCHECK(dynamic_program_header, "no PT_DYNAMIC in VDSO"); | 264 RAW_DCHECK(dynamic_program_header, "no PT_DYNAMIC in VDSO"); |
260 // Mark this image as not present. Can not recur infinitely. | 265 // Mark this image as not present. Can not recur infinitely. |
261 Init(0); | 266 Init(0); |
262 return; | 267 return; |
263 } | 268 } |
264 std::ptrdiff_t relocation = | 269 std::ptrdiff_t relocation = |
265 base_as_char - reinterpret_cast<const char *>(link_base_); | 270 base_as_char - reinterpret_cast<const char *>(link_base_); |
266 ElfW(Dyn) *dynamic_entry = | 271 ElfW(Dyn) *dynamic_entry = |
267 reinterpret_cast<ElfW(Dyn) *>(dynamic_program_header->p_vaddr + | 272 reinterpret_cast<ElfW(Dyn) *>(dynamic_program_header->p_vaddr + |
268 relocation); | 273 relocation); |
269 bool fake_vdso = false; // Assume we are dealing with the real VDSO. | |
270 for (ElfW(Dyn) *de = dynamic_entry; de->d_tag != DT_NULL; ++de) { | |
271 ElfW(Sxword) tag = de->d_tag; | |
272 if (tag == DT_PLTGOT || tag == DT_RELA || tag == DT_JMPREL || | |
273 tag == DT_NEEDED || tag == DT_RPATH || tag == DT_VERNEED || | |
274 tag == DT_INIT || tag == DT_FINI) { | |
275 /* Real vdso can not reasonably have any of the above entries. */ | |
276 fake_vdso = true; | |
277 break; | |
278 } | |
279 } | |
280 for (; dynamic_entry->d_tag != DT_NULL; ++dynamic_entry) { | 274 for (; dynamic_entry->d_tag != DT_NULL; ++dynamic_entry) { |
281 ElfW(Xword) value = dynamic_entry->d_un.d_val; | 275 ElfW(Xword) value = dynamic_entry->d_un.d_val; |
282 if (fake_vdso) { | 276 if (fake_vdso) { |
283 // A complication: in the real VDSO, dynamic entries are not relocated | 277 // A complication: in the real VDSO, dynamic entries are not relocated |
284 // (it wasn't loaded by a dynamic loader). But when testing with a | 278 // (it wasn't loaded by a dynamic loader). But when testing with a |
285 // "fake" dlopen()ed vdso library, the loader relocates some (but | 279 // "fake" dlopen()ed vdso library, the loader relocates some (but |
286 // not all!) of them before we get here. | 280 // not all!) of them before we get here. |
287 if (dynamic_entry->d_tag == DT_VERDEF) { | 281 if (dynamic_entry->d_tag == DT_VERDEF) { |
288 // The only dynamic entry (of the ones we care about) libc-2.3.6 | 282 // The only dynamic entry (of the ones we care about) libc-2.3.6 |
289 // loader doesn't relocate. | 283 // loader doesn't relocate. |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
388 VDSOSupport vdso; | 382 VDSOSupport vdso; |
389 SymbolInfo info; | 383 SymbolInfo info; |
390 if (vdso.LookupSymbol("__vdso_getcpu", "LINUX_2.6", STT_FUNC, &info)) { | 384 if (vdso.LookupSymbol("__vdso_getcpu", "LINUX_2.6", STT_FUNC, &info)) { |
391 // Casting from an int to a pointer is not legal C++. To emphasize | 385 // Casting from an int to a pointer is not legal C++. To emphasize |
392 // this, we use a C-style cast rather than a C++-style cast. | 386 // this, we use a C-style cast rather than a C++-style cast. |
393 fn = (GetCpuFn)(info.address); | 387 fn = (GetCpuFn)(info.address); |
394 } | 388 } |
395 } | 389 } |
396 // Subtle: this code runs outside of any locks; prevent compiler | 390 // Subtle: this code runs outside of any locks; prevent compiler |
397 // from assigning to getcpu_fn_ more than once. | 391 // from assigning to getcpu_fn_ more than once. |
398 MemoryBarrier(); | 392 base::subtle::MemoryBarrier(); |
399 getcpu_fn_ = fn; | 393 getcpu_fn_ = fn; |
400 return vdso_base_; | 394 return vdso_base_; |
401 } | 395 } |
402 | 396 |
403 const void *VDSOSupport::SetBase(const void *base) { | 397 const void *VDSOSupport::SetBase(const void *base) { |
404 const void *old_base = vdso_base_; | 398 const void *old_base = vdso_base_; |
405 vdso_base_ = base; | 399 vdso_base_ = base; |
406 image_.Init(base); | 400 image_.Init(base); |
407 // Also reset getcpu_fn_, so GetCPU could be tested with simulated VDSO. | 401 // Also reset getcpu_fn_, so GetCPU could be tested with simulated VDSO. |
408 getcpu_fn_ = &InitAndGetCPU; | 402 getcpu_fn_ = &InitAndGetCPU; |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
560 // ensure it here, with a global constructor of our own. This | 554 // ensure it here, with a global constructor of our own. This |
561 // is an allowed exception to the normal rule against non-trivial | 555 // is an allowed exception to the normal rule against non-trivial |
562 // global constructors. | 556 // global constructors. |
563 static class VDSOInitHelper { | 557 static class VDSOInitHelper { |
564 public: | 558 public: |
565 VDSOInitHelper() { VDSOSupport::Init(); } | 559 VDSOInitHelper() { VDSOSupport::Init(); } |
566 } vdso_init_helper; | 560 } vdso_init_helper; |
567 } | 561 } |
568 | 562 |
569 #endif // HAVE_VDSO_SUPPORT | 563 #endif // HAVE_VDSO_SUPPORT |
OLD | NEW |