Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "absl/debugging/internal/vdso_support.h"
00020
00021 #ifdef ABSL_HAVE_VDSO_SUPPORT // defined in vdso_support.h
00022
00023 #include <errno.h>
00024 #include <fcntl.h>
00025 #include <sys/syscall.h>
00026 #include <unistd.h>
00027
00028 #if __GLIBC_PREREQ(2, 16) // GLIBC-2.16 implements getauxval.
00029 #include <sys/auxv.h>
00030 #endif
00031
00032 #include "absl/base/dynamic_annotations.h"
00033 #include "absl/base/internal/raw_logging.h"
00034 #include "absl/base/port.h"
00035
00036 #ifndef AT_SYSINFO_EHDR
00037 #define AT_SYSINFO_EHDR 33 // for crosstoolv10
00038 #endif
00039
00040 namespace absl {
00041 namespace debugging_internal {
00042
00043 ABSL_CONST_INIT
00044 std::atomic<const void *> VDSOSupport::vdso_base_(
00045 debugging_internal::ElfMemImage::kInvalidBase);
00046
00047 std::atomic<VDSOSupport::GetCpuFn> VDSOSupport::getcpu_fn_(&InitAndGetCPU);
00048 VDSOSupport::VDSOSupport()
00049
00050
00051 : image_(vdso_base_.load(std::memory_order_relaxed) ==
00052 debugging_internal::ElfMemImage::kInvalidBase
00053 ? Init()
00054 : vdso_base_.load(std::memory_order_relaxed)) {}
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065 const void *VDSOSupport::Init() {
00066 const auto kInvalidBase = debugging_internal::ElfMemImage::kInvalidBase;
00067 #if __GLIBC_PREREQ(2, 16)
00068 if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) {
00069 errno = 0;
00070 const void *const sysinfo_ehdr =
00071 reinterpret_cast<const void *>(getauxval(AT_SYSINFO_EHDR));
00072 if (errno == 0) {
00073 vdso_base_.store(sysinfo_ehdr, std::memory_order_relaxed);
00074 }
00075 }
00076 #endif // __GLIBC_PREREQ(2, 16)
00077 if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) {
00078
00079
00080
00081
00082 if (RunningOnValgrind()) {
00083 vdso_base_.store(nullptr, std::memory_order_relaxed);
00084 getcpu_fn_.store(&GetCPUViaSyscall, std::memory_order_relaxed);
00085 return nullptr;
00086 }
00087 int fd = open("/proc/self/auxv", O_RDONLY);
00088 if (fd == -1) {
00089
00090 vdso_base_.store(nullptr, std::memory_order_relaxed);
00091 getcpu_fn_.store(&GetCPUViaSyscall, std::memory_order_relaxed);
00092 return nullptr;
00093 }
00094 ElfW(auxv_t) aux;
00095 while (read(fd, &aux, sizeof(aux)) == sizeof(aux)) {
00096 if (aux.a_type == AT_SYSINFO_EHDR) {
00097 vdso_base_.store(reinterpret_cast<void *>(aux.a_un.a_val),
00098 std::memory_order_relaxed);
00099 break;
00100 }
00101 }
00102 close(fd);
00103 if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) {
00104
00105 vdso_base_.store(nullptr, std::memory_order_relaxed);
00106 }
00107 }
00108 GetCpuFn fn = &GetCPUViaSyscall;
00109 if (vdso_base_.load(std::memory_order_relaxed)) {
00110 VDSOSupport vdso;
00111 SymbolInfo info;
00112 if (vdso.LookupSymbol("__vdso_getcpu", "LINUX_2.6", STT_FUNC, &info)) {
00113 fn = reinterpret_cast<GetCpuFn>(const_cast<void *>(info.address));
00114 }
00115 }
00116
00117
00118 getcpu_fn_.store(fn, std::memory_order_relaxed);
00119 return vdso_base_.load(std::memory_order_relaxed);
00120 }
00121
00122 const void *VDSOSupport::SetBase(const void *base) {
00123 ABSL_RAW_CHECK(base != debugging_internal::ElfMemImage::kInvalidBase,
00124 "internal error");
00125 const void *old_base = vdso_base_.load(std::memory_order_relaxed);
00126 vdso_base_.store(base, std::memory_order_relaxed);
00127 image_.Init(base);
00128
00129 getcpu_fn_.store(&InitAndGetCPU, std::memory_order_relaxed);
00130 return old_base;
00131 }
00132
00133 bool VDSOSupport::LookupSymbol(const char *name,
00134 const char *version,
00135 int type,
00136 SymbolInfo *info) const {
00137 return image_.LookupSymbol(name, version, type, info);
00138 }
00139
00140 bool VDSOSupport::LookupSymbolByAddress(const void *address,
00141 SymbolInfo *info_out) const {
00142 return image_.LookupSymbolByAddress(address, info_out);
00143 }
00144
00145
00146 long VDSOSupport::GetCPUViaSyscall(unsigned *cpu,
00147 void *, void *) {
00148 #ifdef SYS_getcpu
00149 return syscall(SYS_getcpu, cpu, nullptr, nullptr);
00150 #else
00151
00152 static_cast<void>(cpu);
00153 errno = ENOSYS;
00154 return -1;
00155 #endif
00156 }
00157
00158
00159 long VDSOSupport::InitAndGetCPU(unsigned *cpu,
00160 void *x, void *y) {
00161 Init();
00162 GetCpuFn fn = getcpu_fn_.load(std::memory_order_relaxed);
00163 ABSL_RAW_CHECK(fn != &InitAndGetCPU, "Init() did not set getcpu_fn_");
00164 return (*fn)(cpu, x, y);
00165 }
00166
00167
00168
00169
00170 ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
00171 int GetCPU() {
00172 unsigned cpu;
00173 int ret_code = (*VDSOSupport::getcpu_fn_)(&cpu, nullptr, nullptr);
00174 return ret_code == 0 ? cpu : ret_code;
00175 }
00176
00177
00178
00179
00180
00181
00182
00183
00184 static class VDSOInitHelper {
00185 public:
00186 VDSOInitHelper() { VDSOSupport::Init(); }
00187 } vdso_init_helper;
00188
00189 }
00190 }
00191
00192 #endif // ABSL_HAVE_VDSO_SUPPORT