SignalDelegator: Split out SIGSEGV handler

This needs to run before the TestCodeHarness's frontend handler.
This commit is contained in:
Ryan Houdek committed 2025-11-10 11:53:40 -08:00
1 parent b8c17a843c
commit cb9af0b86a
2 files changed
+37 -25

No files matched your search

@@ -574,13 +574,22 @@ uint64_t SignalDelegator::GetNewSigMask(int Signal) const {
return NewMask;
}
bool SignalDelegator::HandleFrontendSIGSEGV(FEXCore::Core::InternalThreadState* Thread, int Signal, void* Info, void* UContext) {
auto SigInfo = *static_cast<siginfo_t*>(Info);
if (FaultSafeUserMemAccess::TryHandleSafeFault(Signal, SigInfo, UContext)) {
ERROR_AND_DIE_FMT("Received invalid data to syscall. Crashing now!");
}
return false;
}
void SignalDelegator::HandleGuestSignal(FEX::HLE::ThreadStateObject* ThreadObject, int Signal, void* Info, void* UContext) {
auto Thread = ThreadObject->Thread;
ucontext_t* _context = (ucontext_t*)UContext;
auto SigInfo = *static_cast<siginfo_t*>(Info);
auto MustDeferSignal = (Thread->CurrentFrame->State.DeferredSignalRefCount.Load() != 0);
if (Signal == SIGSEGV && SigInfo.si_code == SEGV_ACCERR && SigInfo.si_addr == reinterpret_cast<void*>(&Thread->InterruptFaultPage)) {
if (!MustDeferSignal) {
// We just reached the end of the outermost signal-deferring section and faulted to check for pending signals.
@@ -622,35 +631,31 @@ void SignalDelegator::HandleGuestSignal(FEX::HLE::ThreadStateObject* ThreadObjec
ERROR_AND_DIE_FMT("X86 shouldn't hit this InterruptFaultPage");
#endif
}
} else if (FaultSafeUserMemAccess::TryHandleSafeFault(Signal, SigInfo, UContext)) {
ERROR_AND_DIE_FMT("Received invalid data to syscall. Crashing now!");
} else {
if (IsAsyncSignal(&SigInfo, Signal) && MustDeferSignal) {
// If the signal is asynchronous (as determined by si_code) and FEX is in a state of needing
// to defer the signal, then add the signal to the thread's signal queue.
LOGMAN_THROW_A_FMT(ThreadObject->SignalInfo.DeferredSignalFrames.size() != ThreadObject->SignalInfo.DeferredSignalFrames.capacity(),
"Deferred signals vector hit "
"capacity size. This will "
"likely crash! Asserting now!");
} else if (IsAsyncSignal(&SigInfo, Signal) && MustDeferSignal) {
// If the signal is asynchronous (as determined by si_code) and FEX is in a state of needing
// to defer the signal, then add the signal to the thread's signal queue.
LOGMAN_THROW_A_FMT(ThreadObject->SignalInfo.DeferredSignalFrames.size() != ThreadObject->SignalInfo.DeferredSignalFrames.capacity(),
"Deferred signals vector hit "
"capacity size. This will "
"likely crash! Asserting now!");
ThreadObject->SignalInfo.DeferredSignalFrames.emplace_back(ThreadStateObject::DeferredSignalState {
.Info = SigInfo,
.Signal = Signal,
.SigMask = _context->uc_sigmask.__val[0],
});
ThreadObject->SignalInfo.DeferredSignalFrames.emplace_back(ThreadStateObject::DeferredSignalState {
.Info = SigInfo,
.Signal = Signal,
.SigMask = _context->uc_sigmask.__val[0],
});
uint64_t NewMask = GetNewSigMask(Signal);
uint64_t NewMask = GetNewSigMask(Signal);
// Update our host signal mask so we don't hit race conditions with signals
// This allows us to maintain the expected signal mask through the guest signal handling and then all the way back again
memcpy(&_context->uc_sigmask, &NewMask, sizeof(uint64_t));
// Update our host signal mask so we don't hit race conditions with signals
// This allows us to maintain the expected signal mask through the guest signal handling and then all the way back again
memcpy(&_context->uc_sigmask, &NewMask, sizeof(uint64_t));
// Now update the faulting page permissions so it will fault on write.
mprotect(reinterpret_cast<void*>(&Thread->InterruptFaultPage), sizeof(Thread->InterruptFaultPage), PROT_NONE);
// Now update the faulting page permissions so it will fault on write.
mprotect(reinterpret_cast<void*>(&Thread->InterruptFaultPage), sizeof(Thread->InterruptFaultPage), PROT_NONE);
// Postpone the remainder of signal handling logic until we process the SIGSEGV triggered by writing to InterruptFaultPage.
return;
}
// Postpone the remainder of signal handling logic until we process the SIGSEGV triggered by writing to InterruptFaultPage.
return;
}
// Check for masked signals
@@ -935,8 +940,14 @@ SignalDelegator::SignalDelegator(FEXCore::Context::Context* _CTX, const std::str
return FEX::HLE::ThreadManager::GetStateObjectFromFEXCoreThread(Thread)->SignalInfo.Delegator->HandleSIGILL(Thread, Signal, info, ucontext);
};
const auto SigsegvHandler = [](FEXCore::Core::InternalThreadState* Thread, int Signal, void* info, void* ucontext) -> bool {
return FEX::HLE::ThreadManager::GetStateObjectFromFEXCoreThread(Thread)->SignalInfo.Delegator->HandleFrontendSIGSEGV(Thread, Signal,
info, ucontext);
};
// Register SIGILL signal handler.
RegisterHostSignalHandler(SIGILL, SigillHandler, true);
RegisterHostSignalHandler(SIGSEGV, SigsegvHandler, true);
#ifdef _M_ARM_64
// Register SIGBUS signal handler.
@@ -147,6 +147,7 @@ public:
private:
// Called from the thunk handler to handle the signal
void HandleGuestSignal(FEX::HLE::ThreadStateObject* ThreadObject, int Signal, void* Info, void* UContext);
bool HandleFrontendSIGSEGV(FEXCore::Core::InternalThreadState* Thread, int Signal, void* Info, void* UContext);
/**
* @brief Registers a signal handler for the host to handle a signal