#pragma once
#if OS(UNIX)
#include <signal.h>
#include <tuple>
#include <wtf/Function.h>
#include <wtf/Lock.h>
#include <wtf/Optional.h>
#include <wtf/PlatformRegisters.h>
#if HAVE(MACH_EXCEPTIONS)
#include <mach/exception_types.h>
#endif
namespace WTF {
enum class Signal {
Usr,
#if !OS(DARWIN)
Abort,
#endif
FloatingPoint,
Breakpoint, IllegalInstruction,
AccessFault, NumberOfSignals = AccessFault + 2, Unknown = NumberOfSignals
};
inline std::tuple<int, Optional<int>> toSystemSignal(Signal signal)
{
switch (signal) {
case Signal::AccessFault: return std::make_tuple(SIGSEGV, SIGBUS);
case Signal::IllegalInstruction: return std::make_tuple(SIGILL, WTF::nullopt);
case Signal::Usr: return std::make_tuple(SIGILL, WTF::nullopt);
case Signal::FloatingPoint: return std::make_tuple(SIGFPE, WTF::nullopt);
case Signal::Breakpoint: return std::make_tuple(SIGTRAP, WTF::nullopt);
#if !OS(DARWIN)
case Signal::Abort: return std::make_tuple(SIGABRT, WTF::nullopt);
#endif
default: break;
}
RELEASE_ASSERT_NOT_REACHED();
}
inline Signal fromSystemSignal(int signal)
{
switch (signal) {
case SIGSEGV: return Signal::AccessFault;
case SIGBUS: return Signal::AccessFault;
case SIGFPE: return Signal::FloatingPoint;
case SIGTRAP: return Signal::Breakpoint;
case SIGILL: return Signal::IllegalInstruction;
case SIGUSR2: return Signal::Usr;
#if !OS(DARWIN)
case SIGABRT: return Signal::Abort;
#endif
default: return Signal::Unknown;
}
}
enum class SignalAction {
Handled,
NotHandled,
ForceDefault
};
struct SigInfo {
void* faultingAddress { 0 };
};
using SignalHandler = Function<SignalAction(Signal, SigInfo&, PlatformRegisters&)>;
using SignalHandlerMemory = std::aligned_storage<sizeof(SignalHandler), std::alignment_of<SignalHandler>::value>::type;
struct SignalHandlers {
static void initialize();
void add(Signal, SignalHandler&&);
template<typename Func>
void forEachHandler(Signal, const Func&) const;
static constexpr size_t numberOfSignals = static_cast<size_t>(Signal::NumberOfSignals);
static constexpr size_t maxNumberOfHandlers = 4;
static_assert(numberOfSignals < std::numeric_limits<uint8_t>::max());
#if HAVE(MACH_EXCEPTIONS)
mach_port_t exceptionPort;
exception_mask_t addedExceptions;
bool useMach;
#else
static constexpr bool useMach = false;
#endif
uint8_t numberOfHandlers[numberOfSignals];
SignalHandlerMemory handlers[numberOfSignals][maxNumberOfHandlers];
struct sigaction oldActions[numberOfSignals];
};
WTF_EXPORT_PRIVATE void addSignalHandler(Signal, SignalHandler&&);
WTF_EXPORT_PRIVATE void activateSignalHandlersFor(Signal);
#if HAVE(MACH_EXCEPTIONS)
class Thread;
void registerThreadForMachExceptionHandling(Thread&);
void startMachExceptionHandlerThread();
void handleSignalsWithMach();
#endif // HAVE(MACH_EXCEPTIONS)
}
#if HAVE(MACH_EXCEPTIONS)
using WTF::registerThreadForMachExceptionHandling;
using WTF::handleSignalsWithMach;
#endif // HAVE(MACH_EXCEPTIONS)
using WTF::Signal;
using WTF::SigInfo;
using WTF::toSystemSignal;
using WTF::fromSystemSignal;
using WTF::SignalAction;
using WTF::SignalHandler;
using WTF::addSignalHandler;
using WTF::activateSignalHandlersFor;
#endif // OS(UNIX)