Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-03-28 07:46:14

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #include <cfenv>
0010 #include <csignal>
0011 #include <cstddef>
0012 #include <optional>
0013 
0014 #include "FpeMonitorPlatform.hpp"
0015 #include "FpeMonitorPlatformDarwinCommon.hpp"
0016 
0017 #if !defined(__APPLE__) || !defined(__x86_64__)
0018 #error "This translation unit is only valid for macOS x86_64"
0019 #endif
0020 
0021 namespace ActsPlugins {
0022 
0023 // Darwin x86_64 has full trap support via the legacy x87 control word plus
0024 // SSE MXCSR, so runtime support is always available on this build target.
0025 bool detail::isRuntimeSupported() {
0026   return true;
0027 }
0028 
0029 std::optional<FpeType> detail::decodeFpeType(int signal, const siginfo_t* si,
0030                                              void* ctx) {
0031   // On this platform we only install a SIGFPE handler; si_code is enough to
0032   // classify all FPE kinds we track.
0033   static_cast<void>(ctx);
0034   if (signal != SIGFPE || si == nullptr) {
0035     return std::nullopt;
0036   }
0037   return fpeTypeFromSiCode(si->si_code);
0038 }
0039 
0040 void detail::clearPendingExceptions(int excepts) {
0041   // Clear sticky exception state before enabling traps to avoid immediate
0042   // retriggering from stale flags.
0043   darwin::clearPendingExceptions(excepts);
0044 }
0045 
0046 void detail::enableExceptions(int excepts) {
0047   // Darwin x86_64 mirrors Linux semantics:
0048   // - x87 control word: trap enabled when corresponding mask bit is cleared
0049   // - MXCSR: trap enabled when corresponding mask bit [7:12] is cleared
0050   fenv_t env{};
0051   if (fegetenv(&env) != 0) {
0052     return;
0053   }
0054   env.__control &= ~static_cast<unsigned short>(excepts);
0055   env.__mxcsr &= ~(static_cast<unsigned int>(excepts) << 7u);
0056   env.__status &= ~static_cast<unsigned short>(FE_ALL_EXCEPT);
0057   env.__mxcsr &= ~static_cast<unsigned int>(FE_ALL_EXCEPT);
0058   fesetenv(&env);
0059 }
0060 
0061 void detail::disableExceptions(int excepts) {
0062   // Restore masking for requested exceptions in both x87 and SSE domains.
0063   fenv_t env{};
0064   if (fegetenv(&env) != 0) {
0065     return;
0066   }
0067   env.__control |= static_cast<unsigned short>(excepts);
0068   env.__mxcsr |= (static_cast<unsigned int>(excepts) << 7u);
0069   fesetenv(&env);
0070 }
0071 
0072 void detail::maskTrapsInSignalContext(void* ctx, FpeType type) {
0073   // We mask only the trap that fired in the interrupted context so the faulting
0074   // instruction can be unwound safely, then clear status flags in both units.
0075   const int excepts = darwin::exceptMaskForType(type);
0076   auto* uc = static_cast<ucontext_t*>(ctx);
0077   uc->uc_mcontext->__fs.__fpu_fcw |= static_cast<unsigned short>(excepts);
0078   uc->uc_mcontext->__fs.__fpu_fsw &=
0079       ~static_cast<unsigned short>(FE_ALL_EXCEPT);
0080   uc->uc_mcontext->__fs.__fpu_mxcsr |=
0081       (static_cast<unsigned int>(excepts) << 7u);
0082   uc->uc_mcontext->__fs.__fpu_mxcsr &=
0083       ~static_cast<unsigned int>(FE_ALL_EXCEPT);
0084 }
0085 
0086 std::size_t detail::captureStackFromSignalContext(void* ctx, void* buffer,
0087                                                   std::size_t bufferBytes) {
0088   // Use the shared Darwin frame-walker and provide x86_64 register extraction
0089   // from the interrupted thread state.
0090   return darwin::captureStackFromSignalContext(
0091       ctx, buffer, bufferBytes, [](void* rawCtx) {
0092         const auto& uc = *static_cast<ucontext_t*>(rawCtx);
0093         return darwin::RegisterState{
0094             .sp = uc.uc_mcontext->__ss.__rsp,
0095             .fp = uc.uc_mcontext->__ss.__rbp,
0096             .pc = uc.uc_mcontext->__ss.__rip,
0097         };
0098       });
0099 }
0100 
0101 std::size_t detail::safeDumpSkipFrames() {
0102   // Skip one frame to hide the monitor's own dump helper from final traces.
0103   return 1;
0104 }
0105 
0106 bool detail::shouldFailFastOnUnknownSignal() {
0107   // x86_64 should only see SIGFPE with known si_code values. Unknowns are
0108   // treated as non-fatal to preserve backward compatibility.
0109   return false;
0110 }
0111 
0112 void detail::installSignalHandlers(void (*handler)(int, siginfo_t*, void*)) {
0113   // A single SIGFPE handler is sufficient on Darwin x86_64.
0114   struct sigaction action{};
0115   action.sa_sigaction = handler;
0116   action.sa_flags = SA_SIGINFO;
0117   sigaction(SIGFPE, &action, nullptr);
0118 }
0119 
0120 }  // namespace ActsPlugins