mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 18:00:17 +02:00
84 lines
3.0 KiB
C++
84 lines
3.0 KiB
C++
// SPDX-License-Identifier: MIT
|
|
#pragma once
|
|
|
|
#include <ntstatus.h>
|
|
#include <windef.h>
|
|
#include <winternl.h>
|
|
|
|
#include <FEXCore/Utils/LogManager.h>
|
|
#include <FEXCore/Debug/InternalThreadState.h>
|
|
|
|
namespace FEX::Windows {
|
|
template<typename TReg>
|
|
static inline EXCEPTION_RECORD HandleGuestException(FEXCore::Core::CpuStateFrame::SynchronousFaultDataStruct& Fault,
|
|
const EXCEPTION_RECORD& Src, TReg& Rip, TReg Rax, TReg Cx) {
|
|
EXCEPTION_RECORD Dst = Src;
|
|
Dst.ExceptionAddress = reinterpret_cast<void*>(Rip);
|
|
|
|
if (!Fault.FaultToTopAndGeneratedException) {
|
|
return Dst;
|
|
}
|
|
Fault.FaultToTopAndGeneratedException = false;
|
|
|
|
Dst.ExceptionFlags = 0;
|
|
Dst.NumberParameters = 0;
|
|
|
|
switch (Fault.Signal) {
|
|
case FEXCore::Core::FAULT_SIGILL: Dst.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; return Dst;
|
|
case FEXCore::Core::FAULT_SIGTRAP:
|
|
switch (Fault.TrapNo) {
|
|
case FEXCore::X86State::X86_TRAPNO_DB: Dst.ExceptionCode = EXCEPTION_SINGLE_STEP; return Dst;
|
|
case FEXCore::X86State::X86_TRAPNO_BP:
|
|
Dst.ExceptionAddress = reinterpret_cast<void*>(Rip - 1);
|
|
Dst.ExceptionCode = EXCEPTION_BREAKPOINT;
|
|
Dst.NumberParameters = 1;
|
|
Dst.ExceptionInformation[0] = 0;
|
|
return Dst;
|
|
default: LogMan::Msg::EFmt("Unknown SIGTRAP trap: {}", Fault.TrapNo); break;
|
|
}
|
|
break;
|
|
case FEXCore::Core::FAULT_SIGSEGV:
|
|
switch (Fault.TrapNo) {
|
|
case FEXCore::X86State::X86_TRAPNO_GP:
|
|
if ((Fault.err_code & 0b111) == 0b010) {
|
|
switch (Fault.err_code >> 3) {
|
|
case 0x29:
|
|
Dst.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN;
|
|
Dst.ExceptionAddress = reinterpret_cast<void*>(Rip);
|
|
Dst.NumberParameters = 1;
|
|
Dst.ExceptionInformation[0] = Cx;
|
|
return Dst;
|
|
case 0x2d:
|
|
Rip += 3;
|
|
Dst.ExceptionCode = EXCEPTION_BREAKPOINT;
|
|
Dst.ExceptionAddress = reinterpret_cast<void*>(Rip);
|
|
Dst.NumberParameters = 1;
|
|
Dst.ExceptionInformation[0] = Rax;
|
|
// Note that ExceptionAddress doesn't equal the reported context RIP here, this discrepancy expected and not having it can trigger anti-debug logic.
|
|
return Dst;
|
|
default: LogMan::Msg::EFmt("Unknown interrupt: 0x{:X}", Fault.err_code >> 3); break;
|
|
}
|
|
} else {
|
|
Dst.ExceptionCode = EXCEPTION_PRIV_INSTRUCTION;
|
|
return Dst;
|
|
}
|
|
break;
|
|
case FEXCore::X86State::X86_TRAPNO_OF: Dst.ExceptionCode = EXCEPTION_INT_OVERFLOW; return Dst;
|
|
case FEXCore::X86State::X86_TRAPNO_PF:
|
|
// A page-fault raised by an explicit break in JIT code is always an execute fault
|
|
Dst.NumberParameters = 2;
|
|
Dst.ExceptionInformation[0] = EXCEPTION_EXECUTE_FAULT;
|
|
Dst.ExceptionInformation[1] = Rip;
|
|
return Dst;
|
|
default: LogMan::Msg::EFmt("Unknown SIGSEGV trap: {}", Fault.TrapNo); break;
|
|
}
|
|
break;
|
|
default: LogMan::Msg::EFmt("Unknown signal type: {}", Fault.Signal); break;
|
|
}
|
|
|
|
// Default to SIGILL
|
|
Dst.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
|
|
return Dst;
|
|
}
|
|
} // namespace FEX::Windows
|