1625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes/*
2625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * Copyright (C) 2014 The Android Open Source Project
3625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes *
4625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
5625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * you may not use this file except in compliance with the License.
6625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * You may obtain a copy of the License at
7625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes *
8625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
9625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes *
10625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * Unless required by applicable law or agreed to in writing, software
11625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
12625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * See the License for the specific language governing permissions and
14625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * limitations under the License.
15625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes */
16625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes
1793c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#include "private/bionic_globals.h"
1893c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#include "private/bionic_vdso.h"
19625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes
204ce902c30e087f45c6d6ede2012519e2eea44194Elliott Hughes#if defined(__aarch64__) || defined(__arm__) || defined(__i386__) || defined(__x86_64__)
21625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes
22613f8145087a763e128d58e638bc85799fb06989Elliott Hughes#include <limits.h>
2393c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#include <link.h>
2493c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#include <string.h>
2593c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#include <sys/cdefs.h>
2693c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#include <sys/time.h>
27625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes#include <time.h>
2893c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#include <unistd.h>
2993c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#include "private/KernelArgumentBlock.h"
30625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes
314ce902c30e087f45c6d6ede2012519e2eea44194Elliott Hughes#define AT_SYSINFO_EHDR 33 /* until we have new enough uapi headers... */
324ce902c30e087f45c6d6ede2012519e2eea44194Elliott Hughes
33625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughesint clock_gettime(int clock_id, timespec* tp) {
3493c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao  auto vdso_clock_gettime = reinterpret_cast<decltype(&clock_gettime)>(
3593c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao    __libc_globals->vdso[VDSO_CLOCK_GETTIME].fn);
3693c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao  if (__predict_true(vdso_clock_gettime)) {
3793c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao    return vdso_clock_gettime(clock_id, tp);
3893c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao  }
3993c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao  return __clock_gettime(clock_id, tp);
40625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes}
41625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes
42625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughesint gettimeofday(timeval* tv, struct timezone* tz) {
4393c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao  auto vdso_gettimeofday = reinterpret_cast<decltype(&gettimeofday)>(
4493c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao    __libc_globals->vdso[VDSO_GETTIMEOFDAY].fn);
4593c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao  if (__predict_true(vdso_gettimeofday)) {
4693c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao    return vdso_gettimeofday(tv, tz);
4793c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao  }
4893c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao  return __gettimeofday(tv, tz);
49625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes}
50625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes
5193c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gaovoid __libc_init_vdso(libc_globals* globals, KernelArgumentBlock& args) {
5293c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao  auto&& vdso = globals->vdso;
5393c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao  vdso[VDSO_CLOCK_GETTIME] = { VDSO_CLOCK_GETTIME_SYMBOL,
5493c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao                               reinterpret_cast<void*>(__clock_gettime) };
5593c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao  vdso[VDSO_GETTIMEOFDAY] = { VDSO_GETTIMEOFDAY_SYMBOL,
5693c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao                              reinterpret_cast<void*>(__gettimeofday) };
5793c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao
58625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes  // Do we have a vdso?
5993c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao  uintptr_t vdso_ehdr_addr = args.getauxval(AT_SYSINFO_EHDR);
60625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes  ElfW(Ehdr)* vdso_ehdr = reinterpret_cast<ElfW(Ehdr)*>(vdso_ehdr_addr);
61613f8145087a763e128d58e638bc85799fb06989Elliott Hughes  if (vdso_ehdr == nullptr) {
62625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes    return;
63625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes  }
64625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes
65625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes  // How many symbols does it have?
66625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes  size_t symbol_count = 0;
67625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes  ElfW(Shdr)* vdso_shdr = reinterpret_cast<ElfW(Shdr)*>(vdso_ehdr_addr + vdso_ehdr->e_shoff);
68625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes  for (size_t i = 0; i < vdso_ehdr->e_shnum; ++i) {
69625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes    if (vdso_shdr[i].sh_type == SHT_DYNSYM) {
70625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes      symbol_count = vdso_shdr[i].sh_size / sizeof(ElfW(Sym));
71625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes    }
72625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes  }
73625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes  if (symbol_count == 0) {
74625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes    return;
75625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes  }
76625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes
77625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes  // Where's the dynamic table?
78625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes  ElfW(Addr) vdso_addr = 0;
79613f8145087a763e128d58e638bc85799fb06989Elliott Hughes  ElfW(Dyn)* vdso_dyn = nullptr;
80625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes  ElfW(Phdr)* vdso_phdr = reinterpret_cast<ElfW(Phdr)*>(vdso_ehdr_addr + vdso_ehdr->e_phoff);
81625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes  for (size_t i = 0; i < vdso_ehdr->e_phnum; ++i) {
82625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes    if (vdso_phdr[i].p_type == PT_DYNAMIC) {
83625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes      vdso_dyn = reinterpret_cast<ElfW(Dyn)*>(vdso_ehdr_addr + vdso_phdr[i].p_offset);
84625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes    } else if (vdso_phdr[i].p_type == PT_LOAD) {
85625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes      vdso_addr = vdso_ehdr_addr + vdso_phdr[i].p_offset - vdso_phdr[i].p_vaddr;
86625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes    }
87625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes  }
88613f8145087a763e128d58e638bc85799fb06989Elliott Hughes  if (vdso_addr == 0 || vdso_dyn == nullptr) {
89625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes    return;
90625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes  }
91625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes
92625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes  // Where are the string and symbol tables?
93613f8145087a763e128d58e638bc85799fb06989Elliott Hughes  const char* strtab = nullptr;
94613f8145087a763e128d58e638bc85799fb06989Elliott Hughes  ElfW(Sym)* symtab = nullptr;
95625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes  for (ElfW(Dyn)* d = vdso_dyn; d->d_tag != DT_NULL; ++d) {
96625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes    if (d->d_tag == DT_STRTAB) {
97625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes      strtab = reinterpret_cast<const char*>(vdso_addr + d->d_un.d_ptr);
98625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes    } else if (d->d_tag == DT_SYMTAB) {
99625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes      symtab = reinterpret_cast<ElfW(Sym)*>(vdso_addr + d->d_un.d_ptr);
100625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes    }
101625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes  }
102613f8145087a763e128d58e638bc85799fb06989Elliott Hughes  if (strtab == nullptr || symtab == nullptr) {
103625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes    return;
104625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes  }
105625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes
106625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes  // Are there any symbols we want?
107625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes  for (size_t i = 0; i < symbol_count; ++i) {
108625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes    for (size_t j = 0; j < VDSO_END; ++j) {
10993c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao      if (strcmp(vdso[j].name, strtab + symtab[i].st_name) == 0) {
11093c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao        vdso[j].fn = reinterpret_cast<void*>(vdso_addr + symtab[i].st_value);
111625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes      }
112625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes    }
113625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes  }
114625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes}
115625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes
116625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes#else
117625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes
11893c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gaovoid __libc_init_vdso(libc_globals*, KernelArgumentBlock&) {
119625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes}
120625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes
121625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes#endif
122