brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.0 KiB · 71892a0 Raw
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=*/&param,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