File indexing completed on 2026-03-28 07:46:14
0001
0002
0003
0004
0005
0006
0007
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
0057
0058
0059
0060
0061
0062
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
0073
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
0089
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
0104
0105
0106
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 }