| Index: third_party/tcmalloc/chromium/src/base/elf_mem_image.cc
|
| diff --git a/third_party/tcmalloc/chromium/src/base/vdso_support.cc b/third_party/tcmalloc/chromium/src/base/elf_mem_image.cc
|
| similarity index 67%
|
| copy from third_party/tcmalloc/chromium/src/base/vdso_support.cc
|
| copy to third_party/tcmalloc/chromium/src/base/elf_mem_image.cc
|
| index 444be26aa56f0f683ff641f1cc8f8c239b0d20a0..2949343700d57761480da81cfaf92847062768bd 100644
|
| --- a/third_party/tcmalloc/chromium/src/base/vdso_support.cc
|
| +++ b/third_party/tcmalloc/chromium/src/base/elf_mem_image.cc
|
| @@ -1,10 +1,10 @@
|
| // Copyright (c) 2008, Google Inc.
|
| // All rights reserved.
|
| -//
|
| +//
|
| // Redistribution and use in source and binary forms, with or without
|
| // modification, are permitted provided that the following conditions are
|
| // met:
|
| -//
|
| +//
|
| // * Redistributions of source code must retain the above copyright
|
| // notice, this list of conditions and the following disclaimer.
|
| // * Redistributions in binary form must reproduce the above
|
| @@ -14,7 +14,7 @@
|
| // * Neither the name of Google Inc. nor the names of its
|
| // contributors may be used to endorse or promote products derived from
|
| // this software without specific prior written permission.
|
| -//
|
| +//
|
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| @@ -30,29 +30,15 @@
|
| // ---
|
| // Author: Paul Pluzhnikov
|
| //
|
| -// Allow dynamic symbol lookup in the kernel VDSO page.
|
| +// Allow dynamic symbol lookup in an in-memory Elf image.
|
| //
|
| -// VDSOSupport -- a class representing kernel VDSO (if present).
|
| -//
|
| -
|
| -#include "base/vdso_support.h"
|
|
|
| -#ifdef HAVE_VDSO_SUPPORT // defined in vdso_support.h
|
| +#include "base/elf_mem_image.h"
|
|
|
| -#include <fcntl.h>
|
| -#include <stddef.h> // for std::ptrdiff_t
|
| +#ifdef HAVE_ELF_MEM_IMAGE // defined in elf_mem_image.h
|
|
|
| -#include "base/atomicops.h" // for MemoryBarrier
|
| +#include <stddef.h> // for size_t, ptrdiff_t
|
| #include "base/logging.h"
|
| -#include "base/linux_syscall_support.h"
|
| -#include "base/dynamic_annotations.h"
|
| -#include "base/basictypes.h" // for COMPILE_ASSERT
|
| -
|
| -using base::subtle::MemoryBarrier;
|
| -
|
| -#ifndef AT_SYSINFO_EHDR
|
| -#define AT_SYSINFO_EHDR 33
|
| -#endif
|
|
|
| // From binutils/include/elf/common.h (this doesn't appear to be documented
|
| // anywhere else).
|
| @@ -121,18 +107,15 @@ const T* GetTableElement(const ElfW(Ehdr) *ehdr,
|
| }
|
| } // namespace
|
|
|
| -const void *const VDSOSupport::kInvalidBase =
|
| +const void *const ElfMemImage::kInvalidBase =
|
| reinterpret_cast<const void *>(~0L);
|
|
|
| -const void *VDSOSupport::vdso_base_ = kInvalidBase;
|
| -VDSOSupport::GetCpuFn VDSOSupport::getcpu_fn_ = &InitAndGetCPU;
|
| -
|
| -VDSOSupport::ElfMemImage::ElfMemImage(const void *base) {
|
| +ElfMemImage::ElfMemImage(const void *base) {
|
| CHECK(base != kInvalidBase);
|
| Init(base);
|
| }
|
|
|
| -int VDSOSupport::ElfMemImage::GetNumSymbols() const {
|
| +int ElfMemImage::GetNumSymbols() const {
|
| if (!hash_) {
|
| return 0;
|
| }
|
| @@ -140,17 +123,17 @@ int VDSOSupport::ElfMemImage::GetNumSymbols() const {
|
| return hash_[1];
|
| }
|
|
|
| -const ElfW(Sym) *VDSOSupport::ElfMemImage::GetDynsym(int index) const {
|
| +const ElfW(Sym) *ElfMemImage::GetDynsym(int index) const {
|
| CHECK_LT(index, GetNumSymbols());
|
| return dynsym_ + index;
|
| }
|
|
|
| -const ElfW(Versym) *VDSOSupport::ElfMemImage::GetVersym(int index) const {
|
| +const ElfW(Versym) *ElfMemImage::GetVersym(int index) const {
|
| CHECK_LT(index, GetNumSymbols());
|
| return versym_ + index;
|
| }
|
|
|
| -const ElfW(Phdr) *VDSOSupport::ElfMemImage::GetPhdr(int index) const {
|
| +const ElfW(Phdr) *ElfMemImage::GetPhdr(int index) const {
|
| CHECK_LT(index, ehdr_->e_phnum);
|
| return GetTableElement<ElfW(Phdr)>(ehdr_,
|
| ehdr_->e_phoff,
|
| @@ -158,12 +141,12 @@ const ElfW(Phdr) *VDSOSupport::ElfMemImage::GetPhdr(int index) const {
|
| index);
|
| }
|
|
|
| -const char *VDSOSupport::ElfMemImage::GetDynstr(ElfW(Word) offset) const {
|
| +const char *ElfMemImage::GetDynstr(ElfW(Word) offset) const {
|
| CHECK_LT(offset, strsize_);
|
| return dynstr_ + offset;
|
| }
|
|
|
| -const void *VDSOSupport::ElfMemImage::GetSymAddr(const ElfW(Sym) *sym) const {
|
| +const void *ElfMemImage::GetSymAddr(const ElfW(Sym) *sym) const {
|
| if (sym->st_shndx == SHN_UNDEF || sym->st_shndx >= SHN_LORESERVE) {
|
| // Symbol corresponds to "special" (e.g. SHN_ABS) section.
|
| return reinterpret_cast<const void *>(sym->st_value);
|
| @@ -172,7 +155,7 @@ const void *VDSOSupport::ElfMemImage::GetSymAddr(const ElfW(Sym) *sym) const {
|
| return GetTableElement<char>(ehdr_, 0, 1, sym->st_value) - link_base_;
|
| }
|
|
|
| -const ElfW(Verdef) *VDSOSupport::ElfMemImage::GetVerdef(int index) const {
|
| +const ElfW(Verdef) *ElfMemImage::GetVerdef(int index) const {
|
| CHECK_LE(index, verdefnum_);
|
| const ElfW(Verdef) *version_definition = verdef_;
|
| while (version_definition->vd_ndx < index && version_definition->vd_next) {
|
| @@ -185,17 +168,17 @@ const ElfW(Verdef) *VDSOSupport::ElfMemImage::GetVerdef(int index) const {
|
| return version_definition->vd_ndx == index ? version_definition : NULL;
|
| }
|
|
|
| -const ElfW(Verdaux) *VDSOSupport::ElfMemImage::GetVerdefAux(
|
| +const ElfW(Verdaux) *ElfMemImage::GetVerdefAux(
|
| const ElfW(Verdef) *verdef) const {
|
| return reinterpret_cast<const ElfW(Verdaux) *>(verdef+1);
|
| }
|
|
|
| -const char *VDSOSupport::ElfMemImage::GetVerstr(ElfW(Word) offset) const {
|
| +const char *ElfMemImage::GetVerstr(ElfW(Word) offset) const {
|
| CHECK_LT(offset, strsize_);
|
| return dynstr_ + offset;
|
| }
|
|
|
| -void VDSOSupport::ElfMemImage::Init(const void *base) {
|
| +void ElfMemImage::Init(const void *base) {
|
| ehdr_ = NULL;
|
| dynsym_ = NULL;
|
| dynstr_ = NULL;
|
| @@ -266,7 +249,7 @@ void VDSOSupport::ElfMemImage::Init(const void *base) {
|
| Init(0);
|
| return;
|
| }
|
| - std::ptrdiff_t relocation =
|
| + ptrdiff_t relocation =
|
| base_as_char - reinterpret_cast<const char *>(link_base_);
|
| ElfW(Dyn) *dynamic_entry =
|
| reinterpret_cast<ElfW(Dyn) *>(dynamic_program_header->p_vaddr +
|
| @@ -329,81 +312,7 @@ void VDSOSupport::ElfMemImage::Init(const void *base) {
|
| }
|
| }
|
|
|
| -VDSOSupport::VDSOSupport()
|
| - // If vdso_base_ is still set to kInvalidBase, we got here
|
| - // before VDSOSupport::Init has been called. Call it now.
|
| - : image_(vdso_base_ == kInvalidBase ? Init() : vdso_base_) {
|
| -}
|
| -
|
| -// NOTE: we can't use GoogleOnceInit() below, because we can be
|
| -// called by tcmalloc, and none of the *once* stuff may be functional yet.
|
| -//
|
| -// In addition, we hope that the VDSOSupportHelper constructor
|
| -// causes this code to run before there are any threads, and before
|
| -// InitGoogle() has executed any chroot or setuid calls.
|
| -//
|
| -// Finally, even if there is a race here, it is harmless, because
|
| -// the operation should be idempotent.
|
| -const void *VDSOSupport::Init() {
|
| - if (vdso_base_ == kInvalidBase) {
|
| - // Valgrind zaps AT_SYSINFO_EHDR and friends from the auxv[]
|
| - // on stack, and so glibc works as if VDSO was not present.
|
| - // But going directly to kernel via /proc/self/auxv below bypasses
|
| - // Valgrind zapping. So we check for Valgrind separately.
|
| - if (RunningOnValgrind()) {
|
| - vdso_base_ = NULL;
|
| - getcpu_fn_ = &GetCPUViaSyscall;
|
| - return NULL;
|
| - }
|
| - int fd = open("/proc/self/auxv", O_RDONLY);
|
| - if (fd == -1) {
|
| - // Kernel too old to have a VDSO.
|
| - vdso_base_ = NULL;
|
| - getcpu_fn_ = &GetCPUViaSyscall;
|
| - return NULL;
|
| - }
|
| - ElfW(auxv_t) aux;
|
| - while (read(fd, &aux, sizeof(aux)) == sizeof(aux)) {
|
| - if (aux.a_type == AT_SYSINFO_EHDR) {
|
| - COMPILE_ASSERT(sizeof(vdso_base_) == sizeof(aux.a_un.a_val),
|
| - unexpected_sizeof_pointer_NE_sizeof_a_val);
|
| - vdso_base_ = reinterpret_cast<void *>(aux.a_un.a_val);
|
| - break;
|
| - }
|
| - }
|
| - close(fd);
|
| - if (vdso_base_ == kInvalidBase) {
|
| - // Didn't find AT_SYSINFO_EHDR in auxv[].
|
| - vdso_base_ = NULL;
|
| - }
|
| - }
|
| - GetCpuFn fn = &GetCPUViaSyscall; // default if VDSO not present.
|
| - if (vdso_base_) {
|
| - VDSOSupport vdso;
|
| - SymbolInfo info;
|
| - if (vdso.LookupSymbol("__vdso_getcpu", "LINUX_2.6", STT_FUNC, &info)) {
|
| - // Casting from an int to a pointer is not legal C++. To emphasize
|
| - // this, we use a C-style cast rather than a C++-style cast.
|
| - fn = (GetCpuFn)(info.address);
|
| - }
|
| - }
|
| - // Subtle: this code runs outside of any locks; prevent compiler
|
| - // from assigning to getcpu_fn_ more than once.
|
| - base::subtle::MemoryBarrier();
|
| - getcpu_fn_ = fn;
|
| - return vdso_base_;
|
| -}
|
| -
|
| -const void *VDSOSupport::SetBase(const void *base) {
|
| - const void *old_base = vdso_base_;
|
| - vdso_base_ = base;
|
| - image_.Init(base);
|
| - // Also reset getcpu_fn_, so GetCPU could be tested with simulated VDSO.
|
| - getcpu_fn_ = &InitAndGetCPU;
|
| - return old_base;
|
| -}
|
| -
|
| -bool VDSOSupport::LookupSymbol(const char *name,
|
| +bool ElfMemImage::LookupSymbol(const char *name,
|
| const char *version,
|
| int type,
|
| SymbolInfo *info) const {
|
| @@ -419,7 +328,7 @@ bool VDSOSupport::LookupSymbol(const char *name,
|
| return false;
|
| }
|
|
|
| -bool VDSOSupport::LookupSymbolByAddress(const void *address,
|
| +bool ElfMemImage::LookupSymbolByAddress(const void *address,
|
| SymbolInfo *info_out) const {
|
| for (SymbolIterator it = begin(); it != end(); ++it) {
|
| const char *const symbol_start =
|
| @@ -445,42 +354,42 @@ bool VDSOSupport::LookupSymbolByAddress(const void *address,
|
| return false;
|
| }
|
|
|
| -VDSOSupport::SymbolIterator::SymbolIterator(const void *const image, int index)
|
| +ElfMemImage::SymbolIterator::SymbolIterator(const void *const image, int index)
|
| : index_(index), image_(image) {
|
| }
|
|
|
| -const VDSOSupport::SymbolInfo *VDSOSupport::SymbolIterator::operator->() const {
|
| +const ElfMemImage::SymbolInfo *ElfMemImage::SymbolIterator::operator->() const {
|
| return &info_;
|
| }
|
|
|
| -const VDSOSupport::SymbolInfo& VDSOSupport::SymbolIterator::operator*() const {
|
| +const ElfMemImage::SymbolInfo& ElfMemImage::SymbolIterator::operator*() const {
|
| return info_;
|
| }
|
|
|
| -bool VDSOSupport::SymbolIterator::operator==(const SymbolIterator &rhs) const {
|
| +bool ElfMemImage::SymbolIterator::operator==(const SymbolIterator &rhs) const {
|
| return this->image_ == rhs.image_ && this->index_ == rhs.index_;
|
| }
|
|
|
| -bool VDSOSupport::SymbolIterator::operator!=(const SymbolIterator &rhs) const {
|
| +bool ElfMemImage::SymbolIterator::operator!=(const SymbolIterator &rhs) const {
|
| return !(*this == rhs);
|
| }
|
|
|
| -VDSOSupport::SymbolIterator &VDSOSupport::SymbolIterator::operator++() {
|
| +ElfMemImage::SymbolIterator &ElfMemImage::SymbolIterator::operator++() {
|
| this->Update(1);
|
| return *this;
|
| }
|
|
|
| -VDSOSupport::SymbolIterator VDSOSupport::begin() const {
|
| - SymbolIterator it(&image_, 0);
|
| +ElfMemImage::SymbolIterator ElfMemImage::begin() const {
|
| + SymbolIterator it(this, 0);
|
| it.Update(0);
|
| return it;
|
| }
|
|
|
| -VDSOSupport::SymbolIterator VDSOSupport::end() const {
|
| - return SymbolIterator(&image_, image_.GetNumSymbols());
|
| +ElfMemImage::SymbolIterator ElfMemImage::end() const {
|
| + return SymbolIterator(this, GetNumSymbols());
|
| }
|
|
|
| -void VDSOSupport::SymbolIterator::Update(int increment) {
|
| +void ElfMemImage::SymbolIterator::Update(int increment) {
|
| const ElfMemImage *image = reinterpret_cast<const ElfMemImage *>(image_);
|
| CHECK(image->IsPresent() || increment == 0);
|
| if (!image->IsPresent()) {
|
| @@ -519,45 +428,6 @@ void VDSOSupport::SymbolIterator::Update(int increment) {
|
| info_.symbol = symbol;
|
| }
|
|
|
| -// NOLINT on 'long' because this routine mimics kernel api.
|
| -long VDSOSupport::GetCPUViaSyscall(unsigned *cpu, void *, void *) { // NOLINT
|
| -#if defined(__NR_getcpu)
|
| - return sys_getcpu(cpu, NULL, NULL);
|
| -#else
|
| - // x86_64 never implemented sys_getcpu(), except as a VDSO call.
|
| - errno = ENOSYS;
|
| - return -1;
|
| -#endif
|
| -}
|
| -
|
| -// Use fast __vdso_getcpu if available.
|
| -long VDSOSupport::InitAndGetCPU(unsigned *cpu, void *x, void *y) { // NOLINT
|
| - Init();
|
| - CHECK_NE(getcpu_fn_, &InitAndGetCPU); // << "Init() did not set getcpu_fn_";
|
| - return (*getcpu_fn_)(cpu, x, y);
|
| -}
|
| -
|
| -// This function must be very fast, and may be called from very
|
| -// low level (e.g. tcmalloc). Hence I avoid things like
|
| -// GoogleOnceInit() and ::operator new.
|
| -int GetCPU(void) {
|
| - unsigned cpu;
|
| - int ret_code = (*VDSOSupport::getcpu_fn_)(&cpu, NULL, NULL);
|
| - return ret_code == 0 ? cpu : ret_code;
|
| -}
|
| -
|
| -// We need to make sure VDSOSupport::Init() is called before
|
| -// the main() runs, since it might do something like setuid or
|
| -// chroot. If VDSOSupport
|
| -// is used in any global constructor, this will happen, since
|
| -// VDSOSupport's constructor calls Init. But if not, we need to
|
| -// ensure it here, with a global constructor of our own. This
|
| -// is an allowed exception to the normal rule against non-trivial
|
| -// global constructors.
|
| -static class VDSOInitHelper {
|
| - public:
|
| - VDSOInitHelper() { VDSOSupport::Init(); }
|
| -} vdso_init_helper;
|
| -}
|
| +} // namespace base
|
|
|
| -#endif // HAVE_VDSO_SUPPORT
|
| +#endif // HAVE_ELF_MEM_IMAGE
|
|
|