162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * vdso_test_gettimeofday.c: Sample code to test parse_vdso.c and 462306a36Sopenharmony_ci * vDSO gettimeofday() 562306a36Sopenharmony_ci * Copyright (c) 2014 Andy Lutomirski 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Compile with: 862306a36Sopenharmony_ci * gcc -std=gnu99 vdso_test_gettimeofday.c parse_vdso_gettimeofday.c 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Tested on x86, 32-bit and 64-bit. It may work on other architectures, too. 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <stdint.h> 1462306a36Sopenharmony_ci#include <elf.h> 1562306a36Sopenharmony_ci#include <stdio.h> 1662306a36Sopenharmony_ci#include <sys/auxv.h> 1762306a36Sopenharmony_ci#include <sys/time.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "../kselftest.h" 2062306a36Sopenharmony_ci#include "parse_vdso.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* 2362306a36Sopenharmony_ci * ARM64's vDSO exports its gettimeofday() implementation with a different 2462306a36Sopenharmony_ci * name and version from other architectures, so we need to handle it as 2562306a36Sopenharmony_ci * a special case. 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_ci#if defined(__aarch64__) 2862306a36Sopenharmony_ciconst char *version = "LINUX_2.6.39"; 2962306a36Sopenharmony_ciconst char *name = "__kernel_gettimeofday"; 3062306a36Sopenharmony_ci#elif defined(__riscv) 3162306a36Sopenharmony_ciconst char *version = "LINUX_4.15"; 3262306a36Sopenharmony_ciconst char *name = "__vdso_gettimeofday"; 3362306a36Sopenharmony_ci#else 3462306a36Sopenharmony_ciconst char *version = "LINUX_2.6"; 3562306a36Sopenharmony_ciconst char *name = "__vdso_gettimeofday"; 3662306a36Sopenharmony_ci#endif 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ciint main(int argc, char **argv) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR); 4162306a36Sopenharmony_ci if (!sysinfo_ehdr) { 4262306a36Sopenharmony_ci printf("AT_SYSINFO_EHDR is not present!\n"); 4362306a36Sopenharmony_ci return KSFT_SKIP; 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci vdso_init_from_sysinfo_ehdr(getauxval(AT_SYSINFO_EHDR)); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* Find gettimeofday. */ 4962306a36Sopenharmony_ci typedef long (*gtod_t)(struct timeval *tv, struct timezone *tz); 5062306a36Sopenharmony_ci gtod_t gtod = (gtod_t)vdso_sym(version, name); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if (!gtod) { 5362306a36Sopenharmony_ci printf("Could not find %s\n", name); 5462306a36Sopenharmony_ci return KSFT_SKIP; 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci struct timeval tv; 5862306a36Sopenharmony_ci long ret = gtod(&tv, 0); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci if (ret == 0) { 6162306a36Sopenharmony_ci printf("The time is %lld.%06lld\n", 6262306a36Sopenharmony_ci (long long)tv.tv_sec, (long long)tv.tv_usec); 6362306a36Sopenharmony_ci } else { 6462306a36Sopenharmony_ci printf("%s failed\n", name); 6562306a36Sopenharmony_ci return KSFT_FAIL; 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci return 0; 6962306a36Sopenharmony_ci} 70