mirror-llvm-project/libc/test/UnitTest/FPExceptMatcher.cpp
Schrodinger ZHU Yifan 633539bfa1
[libc][freebsd] initialize freebsd support (#124459)
Initialize FreeBSD support. Currently, only overlay build (mainly math
routines) is supported.
This PR mainly define the target entrypoints and basic syscall support.
Different from Linux, FreeBSD's syscall return always consist of two
component:
- return value as arch register
- error flag
On x86-64, the flag is returned via the carry bit state. Hence, for
syscall stubs, we always return a structure containing these two fields.

For math support, the only big difference is that FreeBSD has different
naming convention in some exception macros.

Further fixes for C++ userland are tracked in #197605

Assisted-by: Codex with gpt-5.5 high fast
2026-05-19 13:04:34 -07:00

69 lines
1.8 KiB
C++

//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// FPExceptMatchers.cpp.
///
//===----------------------------------------------------------------------===//
#undef LIBC_MATH_USE_SYSTEM_FENV
#include "FPExceptMatcher.h"
#include "src/__support/macros/config.h"
#include "test/UnitTest/ExecuteFunction.h" // FunctionCaller
#include "test/UnitTest/Test.h"
#include "hdr/types/fenv_t.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include <setjmp.h>
#include <signal.h>
#if LIBC_TEST_HAS_MATCHERS()
namespace LIBC_NAMESPACE_DECL {
namespace testing {
#if defined(_WIN32)
#define sigjmp_buf jmp_buf
#define sigsetjmp(buf, save) setjmp(buf)
#define siglongjmp(buf, val) longjmp(buf, val)
#endif
#ifdef __FreeBSD__
using sighandler_t = __sighandler_t *;
#endif
static thread_local sigjmp_buf jumpBuffer;
static thread_local bool caughtExcept;
static void sigfpeHandler([[maybe_unused]] int sig) {
caughtExcept = true;
siglongjmp(jumpBuffer, -1);
}
FPExceptMatcher::FPExceptMatcher(FunctionCaller *func) {
auto *oldSIGFPEHandler = signal(SIGFPE, &sigfpeHandler);
caughtExcept = false;
fenv_t oldEnv;
fputil::get_env(&oldEnv);
if (sigsetjmp(jumpBuffer, 1) == 0)
func->call();
delete func;
// We restore the previous floating point environment after
// the call to the function which can potentially raise SIGFPE.
fputil::set_env(&oldEnv);
signal(SIGFPE, oldSIGFPEHandler);
exceptionRaised = caughtExcept;
}
} // namespace testing
} // namespace LIBC_NAMESPACE_DECL
#endif // LIBC_TEST_HAS_MATCHERS()