188 lines · cpp
1//===-- Unittests for VDSO ------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "hdr/signal_macros.h"10#include "hdr/time_macros.h"11#include "hdr/types/clockid_t.h"12#include "hdr/types/struct_sigaction.h"13#include "hdr/types/struct_timespec.h"14#include "hdr/types/struct_timeval.h"15#include "hdr/types/time_t.h"16#include "src/__support/OSUtil/linux/vdso.h"17#include "src/__support/OSUtil/syscall.h"18#include "src/__support/macros/properties/architectures.h"19#include "src/signal/raise.h"20#include "src/signal/sigaction.h"21#include "test/UnitTest/ErrnoSetterMatcher.h"22#include "test/UnitTest/Test.h"23#include <linux/time_types.h>24#include <sys/syscall.h>25 26struct riscv_hwprobe {27 int64_t key;28 uint64_t value;29};30 31namespace LIBC_NAMESPACE_DECL {32// For x86_64, we explicitly test some traditional vdso symbols are indeed33// available.34 35TEST(LlvmLibcOSUtilVDSOTest, GetTimeOfDay) {36 vdso::TypedSymbol<vdso::VDSOSym::GetTimeOfDay> symbol;37 if (!symbol)38 return;39 timeval tv;40 EXPECT_EQ(symbol(&tv, nullptr), 0);41 // hopefully people are not building time machines using our libc.42 EXPECT_GT(tv.tv_sec, static_cast<decltype(tv.tv_sec)>(0));43}44 45TEST(LlvmLibcOSUtilVDSOTest, Time) {46 vdso::TypedSymbol<vdso::VDSOSym::Time> symbol;47 if (!symbol)48 return;49 time_t a, b;50 EXPECT_GT(symbol(&a), static_cast<time_t>(0));51 EXPECT_GT(symbol(&b), static_cast<time_t>(0));52 EXPECT_GE(b, a);53}54 55TEST(LlvmLibcOSUtilVDSOTest, ClockGetTime) {56 vdso::TypedSymbol<vdso::VDSOSym::ClockGetTime> symbol;57 if (!symbol)58 return;59 timespec a, b;60 EXPECT_EQ(symbol(CLOCK_MONOTONIC, &a), 0);61 EXPECT_EQ(symbol(CLOCK_MONOTONIC, &b), 0);62 if (a.tv_sec == b.tv_sec) {63 EXPECT_LT(a.tv_nsec, b.tv_nsec);64 } else {65 EXPECT_LT(a.tv_sec, b.tv_sec);66 }67}68 69TEST(LlvmLibcOSUtilVDSOTest, ClockGetTime64) {70 vdso::TypedSymbol<vdso::VDSOSym::ClockGetTime64> symbol;71 if (!symbol)72 return;73 // See kernel API at74 // https://elixir.bootlin.com/linux/latest/source/tools/testing/selftests/vDSO/vdso_test_correctness.c#L15575 __kernel_timespec a, b;76 EXPECT_EQ(symbol(CLOCK_MONOTONIC, &a), 0);77 EXPECT_EQ(symbol(CLOCK_MONOTONIC, &b), 0);78 if (a.tv_sec == b.tv_sec) {79 EXPECT_LT(a.tv_nsec, b.tv_nsec);80 } else {81 EXPECT_LT(a.tv_sec, b.tv_sec);82 }83}84 85TEST(LlvmLibcOSUtilVDSOTest, ClockGetRes) {86 vdso::TypedSymbol<vdso::VDSOSym::ClockGetRes> symbol;87 if (!symbol)88 return;89 timespec res{};90 EXPECT_EQ(symbol(CLOCK_MONOTONIC, &res), 0);91 EXPECT_TRUE(res.tv_sec > 0 || res.tv_nsec > 0);92}93 94TEST(LlvmLibcOSUtilVDSOTest, GetCpu) {95 // The kernel system call has a third argument, which should be passed as96 // nullptr.97 vdso::TypedSymbol<vdso::VDSOSym::GetCpu> symbol;98 if (!symbol)99 return;100 unsigned cpu = static_cast<unsigned>(-1), node = static_cast<unsigned>(-1);101 EXPECT_EQ(symbol(&cpu, &node, nullptr), 0);102 EXPECT_GE(cpu, 0u);103 EXPECT_GE(node, 0u);104}105 106static bool flag = false;107static void sigprof_handler [[gnu::used]] (int) { flag = true; }108 109TEST(LlvmLibcOSUtilVDSOTest, RtSigReturn) {110 using namespace testing::ErrnoSetterMatcher;111 // must use struct since there is a function of the same name in the same112 // scope.113 struct sigaction sa{};114 struct sigaction old_sa{};115 sa.sa_handler = sigprof_handler;116 sa.sa_flags = SA_RESTORER;117 vdso::TypedSymbol<vdso::VDSOSym::RTSigReturn> symbol;118 if (!symbol)119 return;120 sa.sa_restorer = symbol;121 ASSERT_THAT(LIBC_NAMESPACE::sigaction(SIGPROF, &sa, &old_sa), Succeeds());122 raise(SIGPROF);123 ASSERT_TRUE(flag);124 flag = false;125 ASSERT_THAT(LIBC_NAMESPACE::sigaction(SIGPROF, &old_sa, nullptr), Succeeds());126}127 128TEST(LlvmLibcOSUtilVDSOTest, FlushICache) {129 vdso::TypedSymbol<vdso::VDSOSym::FlushICache> symbol;130 if (!symbol)131 return;132 char buf[512];133 // we just check that the flush will not panic the program.134 // the flags part only take 0/1 as up to kernel 6.10, which is used to135 // indicate whether the flush is local to the core or global.136 symbol(buf, buf + sizeof(buf), 0);137 symbol(buf, buf + sizeof(buf), 1);138}139 140// https://docs.kernel.org/6.5/riscv/hwprobe.html141TEST(LlvmLibcOSUtilVDSOTest, RiscvHwProbe) {142 using namespace testing::ErrnoSetterMatcher;143 vdso::TypedSymbol<vdso::VDSOSym::RiscvHwProbe> symbol;144 if (!symbol)145 return;146 // If a key is unknown to the kernel, its key field will be cleared to -1, and147 // its value set to 0. We expect probes.value are all 0.148 // Usermode can supply NULL for cpus and 0 for cpu_count as a shortcut for all149 // online CPUs150 riscv_hwprobe probes[2] = {{-1, 1}, {-1, 1}};151 ASSERT_THAT(symbol(/*pairs=*/probes, /*count=*/2, /*cpusetsize=*/0,152 /*cpuset=*/nullptr,153 /*flags=*/0),154 Succeeds());155 for (auto &probe : probes) {156 EXPECT_EQ(probe.key, static_cast<decltype(probe.key)>(-1));157 EXPECT_EQ(probe.value, static_cast<decltype(probe.value)>(0));158 }159}160 161TEST(LlvmLibcOSUtilVDSOTest, GetRandom) {162 using namespace testing::ErrnoSetterMatcher;163 vdso::TypedSymbol<vdso::VDSOSym::GetRandom> symbol;164 if (!symbol)165 return;166 // This structure exists in kernel UAPI header; but we define it on our own to167 // make sure we can test it even on platform without support.168 struct VGetrandomOpaqueParams {169 uint32_t size_of_opaque_states;170 uint32_t mmap_prot;171 uint32_t mmap_flags;172 uint32_t reserved[13];173 };174 VGetrandomOpaqueParams param{0, 0, 0, {}};175 // When getrandom vDSO symbol is called with special parameters (~0 for state176 // size), it populates the desired configuration into VGetrandomOpaqueParams.177 int res = symbol(178 /*buf=*/nullptr, /*count=*/0, /*flags=*/0,179 /*opaque_states=*/¶m,180 /*size_of_opaque_states=*/~0);181 // Test that the size of the states are correctly populated after a successful182 // call.183 EXPECT_EQ(res, 0);184 EXPECT_GT(param.size_of_opaque_states, 0u);185}186 187} // namespace LIBC_NAMESPACE_DECL188