File indexing completed on 2026-03-28 07:46:14
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <cfenv>
0010 #include <csignal>
0011 #include <cstddef>
0012 #include <cstdint>
0013 #include <optional>
0014
0015 #include "FpeMonitorPlatform.hpp"
0016 #include "FpeMonitorPlatformDarwinCommon.hpp"
0017
0018 #if !defined(__APPLE__) || !defined(__arm64__)
0019 #error "This translation unit is only valid for macOS arm64"
0020 #endif
0021
0022 namespace ActsPlugins {
0023
0024 namespace {
0025
0026
0027
0028 std::uint32_t darwinArm64TrapMask(int excepts) {
0029 std::uint32_t mask = 0;
0030 if ((excepts & FE_INVALID) != 0) {
0031 mask |= __fpcr_trap_invalid;
0032 }
0033 if ((excepts & FE_DIVBYZERO) != 0) {
0034 mask |= __fpcr_trap_divbyzero;
0035 }
0036 if ((excepts & FE_OVERFLOW) != 0) {
0037 mask |= __fpcr_trap_overflow;
0038 }
0039 if ((excepts & FE_UNDERFLOW) != 0) {
0040 mask |= __fpcr_trap_underflow;
0041 }
0042 if ((excepts & FE_INEXACT) != 0) {
0043 mask |= __fpcr_trap_inexact;
0044 }
0045 return mask;
0046 }
0047
0048 std::optional<FpeType> fpeTypeFromDarwinArm64Esr(std::uint32_t esr) {
0049
0050
0051 constexpr std::uint32_t kEsrExceptionClassShift = 26u;
0052 constexpr std::uint32_t kEsrExceptionClassMask = 0x3fu;
0053 constexpr std::uint32_t kFpExceptionClass = 0x2cu;
0054 const std::uint32_t exceptionClass =
0055 (esr >> kEsrExceptionClassShift) & kEsrExceptionClassMask;
0056 if (exceptionClass != kFpExceptionClass) {
0057 return std::nullopt;
0058 }
0059
0060 const std::uint32_t flags = esr & static_cast<std::uint32_t>(FE_ALL_EXCEPT);
0061 if ((flags & FE_INVALID) != 0) {
0062 return FpeType::FLTINV;
0063 }
0064 if ((flags & FE_DIVBYZERO) != 0) {
0065 return FpeType::FLTDIV;
0066 }
0067 if ((flags & FE_OVERFLOW) != 0) {
0068 return FpeType::FLTOVF;
0069 }
0070 if ((flags & FE_UNDERFLOW) != 0) {
0071 return FpeType::FLTUND;
0072 }
0073 if ((flags & FE_INEXACT) != 0) {
0074 return FpeType::FLTRES;
0075 }
0076 return std::nullopt;
0077 }
0078
0079 }
0080
0081 bool detail::isRuntimeSupported() {
0082
0083
0084 return true;
0085 }
0086
0087 std::optional<FpeType> detail::decodeFpeType(int signal, const siginfo_t* si,
0088 void* ctx) {
0089
0090 if (signal == SIGFPE && si != nullptr) {
0091 return fpeTypeFromSiCode(si->si_code);
0092 }
0093
0094
0095
0096 if (signal == SIGILL && ctx != nullptr) {
0097 auto* uc = static_cast<ucontext_t*>(ctx);
0098 return fpeTypeFromDarwinArm64Esr(uc->uc_mcontext->__es.__esr);
0099 }
0100
0101 return std::nullopt;
0102 }
0103
0104 void detail::clearPendingExceptions(int excepts) {
0105
0106 darwin::clearPendingExceptions(excepts);
0107 }
0108
0109 void detail::enableExceptions(int excepts) {
0110
0111 fenv_t env{};
0112 if (fegetenv(&env) != 0) {
0113 return;
0114 }
0115 env.__fpcr |= static_cast<unsigned long long>(darwinArm64TrapMask(excepts));
0116 env.__fpsr &= ~static_cast<unsigned long long>(FE_ALL_EXCEPT);
0117 fesetenv(&env);
0118 }
0119
0120 void detail::disableExceptions(int excepts) {
0121
0122 fenv_t env{};
0123 if (fegetenv(&env) != 0) {
0124 return;
0125 }
0126 env.__fpcr &= ~static_cast<unsigned long long>(darwinArm64TrapMask(excepts));
0127 fesetenv(&env);
0128 }
0129
0130 void detail::maskTrapsInSignalContext(void* ctx, FpeType type) {
0131
0132
0133 const int excepts = darwin::exceptMaskForType(type);
0134 auto* uc = static_cast<ucontext_t*>(ctx);
0135 uc->uc_mcontext->__ns.__fpcr &=
0136 ~static_cast<std::uint32_t>(darwinArm64TrapMask(excepts));
0137 uc->uc_mcontext->__ns.__fpsr &= ~static_cast<std::uint32_t>(FE_ALL_EXCEPT);
0138 }
0139
0140 std::size_t detail::captureStackFromSignalContext(void* ctx, void* buffer,
0141 std::size_t bufferBytes) {
0142
0143
0144 return darwin::captureStackFromSignalContext(
0145 ctx, buffer, bufferBytes, [](void* rawCtx) {
0146 const auto& uc = *static_cast<ucontext_t*>(rawCtx);
0147 return darwin::RegisterState{
0148 .sp = __darwin_arm_thread_state64_get_sp(uc.uc_mcontext->__ss),
0149 .fp = __darwin_arm_thread_state64_get_fp(uc.uc_mcontext->__ss),
0150 .pc = __darwin_arm_thread_state64_get_pc(uc.uc_mcontext->__ss),
0151 };
0152 });
0153 }
0154
0155 std::size_t detail::safeDumpSkipFrames() {
0156
0157 return 1;
0158 }
0159
0160 bool detail::shouldFailFastOnUnknownSignal() {
0161
0162
0163 return true;
0164 }
0165
0166 void detail::installSignalHandlers(void (*handler)(int, siginfo_t*, void*)) {
0167
0168 struct sigaction action{};
0169 action.sa_sigaction = handler;
0170 action.sa_flags = SA_SIGINFO;
0171 sigaction(SIGFPE, &action, nullptr);
0172 sigaction(SIGILL, &action, nullptr);
0173 }
0174
0175 }