From 064a6e96c78713c7985aaaee61ffd9ed25cda3d4 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Sun, 6 Sep 2026 15:09:18 +0200 Subject: [PATCH] ARM64EC: Use NtRaiseException to raise guest exception Instead of returning to KiUserExceptionDispatcher, which doesn't send a debug event. --- Source/Windows/ARM64EC/Module.cpp | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/Source/Windows/ARM64EC/Module.cpp b/Source/Windows/ARM64EC/Module.cpp index fa3a994bc..7b0469257 100644 --- a/Source/Windows/ARM64EC/Module.cpp +++ b/Source/Windows/ARM64EC/Module.cpp @@ -484,18 +484,15 @@ static ARM64_NT_CONTEXT StoreStateToPackedECContext(FEXCore::Core::InternalThrea } static void RethrowGuestException(const EXCEPTION_RECORD& Rec, ARM64_NT_CONTEXT& Context) { - const auto& Config = SignalDelegator->GetConfig(); auto* Thread = GetCPUArea().ThreadState(); auto& Fault = Thread->CurrentFrame->SynchronousFaultData; - uint64_t GuestSp = Context.X[Config.SRAGPRMapping[static_cast(FEXCore::X86State::REG_RSP)]]; - auto* Args = reinterpret_cast(FEXCore::AlignDown(GuestSp, 64)) - 1; LogMan::Msg::DFmt("Reconstructing context"); if (!IsDispatcherAddress(Context.Pc)) { ReconstructThreadState(Thread, Context); } - Args->Context = StoreStateToPackedECContext(Thread, Context.Fpcr, Context.Fpsr); - LogMan::Msg::DFmt("pc: {:X} rip: {:X}", Context.Pc, Args->Context.Pc); + ARM64_NT_CONTEXT GuestContext = StoreStateToPackedECContext(Thread, Context.Fpcr, Context.Fpsr); + LogMan::Msg::DFmt("pc: {:X} rip: {:X}", Context.Pc, GuestContext.Pc); // X64 Windows always clears TF, DF and AF when handling an exception, restoring after. // Current ARM64EC windows can only restore NZCV+SS when returning from an exception and other flags are left untouched from the handler context. @@ -505,19 +502,15 @@ static void RethrowGuestException(const EXCEPTION_RECORD& Rec, ARM64_NT_CONTEXT& CTX->SetFlagsFromCompactedEFLAGS(Thread, EFlags); BOOL FirstChance = TRUE; - Args->Rec = FEX::Windows::HandleGuestException(Fault, Rec, Args->Context.Pc, Args->Context.X8, Args->Context.X0, FirstChance); - if (Args->Rec.ExceptionCode == EXCEPTION_SINGLE_STEP) { - Args->Context.Cpsr &= ~(1 << 21); // PSTATE.SS - } else if (Args->Rec.ExceptionCode == EXCEPTION_BREAKPOINT) { + EXCEPTION_RECORD GuestRec = FEX::Windows::HandleGuestException(Fault, Rec, GuestContext.Pc, GuestContext.X8, GuestContext.X0, FirstChance); + if (GuestRec.ExceptionCode == EXCEPTION_SINGLE_STEP) { + GuestContext.Cpsr &= ~(1 << 21); // PSTATE.SS + } else if (GuestRec.ExceptionCode == EXCEPTION_BREAKPOINT) { // INT3 will set RIP to the instruction following it, undo this (any edge cases with multibyte instructions that trigger breakpoints are bugs present in Windows also) - Args->Context.Pc -= 1; + GuestContext.Pc -= 1; } - if (!FirstChance) { - NtRaiseExceptionNative(&Args->Rec, &Args->Context, FirstChance); - } - Context.Sp = reinterpret_cast(Args); - Context.Pc = KiUserExceptionDispatcher; + NtRaiseExceptionNative(&GuestRec, &GuestContext, FirstChance); } class ECSyscallHandler : public FEXCore::HLE::SyscallHandler, public FEXCore::Allocator::FEXAllocOperators {