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 #pragma once
0010 
0011 #include <cfenv>
0012 #include <cstddef>
0013 #include <cstdint>
0014 
0015 #include <boost/stacktrace/frame.hpp>
0016 
0017 #include "FpeMonitorPlatform.hpp"
0018 
0019 namespace ActsPlugins::detail::darwin {
0020 
0021 struct RegisterState {
0022   std::uintptr_t sp;
0023   std::uintptr_t fp;
0024   std::uintptr_t pc;
0025 };
0026 
0027 inline int exceptMaskForType(FpeType type) {
0028   using enum FpeType;
0029   switch (type) {
0030     case INTDIV:
0031     case FLTDIV:
0032       return FE_DIVBYZERO;
0033     case INTOVF:
0034     case FLTOVF:
0035       return FE_OVERFLOW;
0036     case FLTUND:
0037       return FE_UNDERFLOW;
0038     case FLTRES:
0039       return FE_INEXACT;
0040     case FLTINV:
0041     case FLTSUB:
0042       return FE_INVALID;
0043     default:
0044       return 0;
0045   }
0046 }
0047 
0048 inline void clearPendingExceptions(int excepts) {
0049   std::feclearexcept(excepts);
0050 }
0051 
0052 template <typename RegisterStateExtractor>
0053 std::size_t captureStackFromSignalContext(void* ctx, void* buffer,
0054                                           std::size_t bufferBytes,
0055                                           RegisterStateExtractor&& extractor) {
0056   // Why this helper exists:
0057   // In a signal handler we need the stack of the interrupted faulting context
0058   // (PC/SP/FP from ucontext), not the stack of the handler itself.
0059   // Generic signal-safe dumps start at the current handler frame and cannot be
0060   // seeded with those saved registers, so they may miss the real fault site or
0061   // include mostly signal trampoline frames. Walking from saved FP/PC gives a
0062   // deterministic trace rooted at the trapping instruction on Darwin.
0063   using NativeFramePtr = boost::stacktrace::frame::native_frame_ptr_t;
0064   auto* frames = static_cast<NativeFramePtr*>(buffer);
0065   const std::size_t maxFrames = bufferBytes / sizeof(NativeFramePtr);
0066   std::size_t count = 0;
0067 
0068   if (ctx == nullptr || maxFrames == 0) {
0069     return 0;
0070   }
0071 
0072   // The platform TU provides arch-specific extraction of SP/FP/PC from the raw
0073   // signal context while this helper keeps the frame-walk logic shared.
0074   const RegisterState state = extractor(ctx);
0075   const std::uintptr_t sp = state.sp;
0076   std::uintptr_t pc = state.pc;
0077   std::uintptr_t fp = state.fp;
0078 
0079   auto push = [&](std::uintptr_t address) {
0080     if (address == 0 || count >= maxFrames) {
0081       return;
0082     }
0083     frames[count++] = reinterpret_cast<NativeFramePtr>(address);
0084   };
0085 
0086   push(pc);
0087 
0088   // Keep unwinding constrained to a finite stack window above SP to avoid
0089   // dereferencing arbitrary memory if the frame chain is corrupted.
0090   constexpr std::uintptr_t kMaxStackWindow = 16 * 1024 * 1024;
0091   auto inStackWindow = [&](std::uintptr_t address) {
0092     if (address < sp || address > sp + kMaxStackWindow) {
0093       return false;
0094     }
0095     return (address % alignof(std::uintptr_t)) == 0;
0096   };
0097 
0098   struct FrameRecord {
0099     std::uintptr_t prevFp;
0100     std::uintptr_t returnAddress;
0101   };
0102 
0103   // Standard frame-pointer chain walk:
0104   //   fp -> {prev_fp, return_address}
0105   // Stops when the chain is non-monotonic, leaves the allowed stack window,
0106   // or we exhaust caller-provided buffer capacity.
0107   while (count < maxFrames && inStackWindow(fp) &&
0108          fp + sizeof(FrameRecord) <= sp + kMaxStackWindow) {
0109     const auto* record = reinterpret_cast<const FrameRecord*>(fp);
0110     const std::uintptr_t prevFp = record->prevFp;
0111     const std::uintptr_t returnAddress = record->returnAddress;
0112     push(returnAddress);
0113 
0114     if (prevFp <= fp || !inStackWindow(prevFp)) {
0115       break;
0116     }
0117     fp = prevFp;
0118   }
0119 
0120   return count * sizeof(NativeFramePtr);
0121 }
0122 
0123 }  // namespace ActsPlugins::detail::darwin