From 830bd347c59dc2a86ffd08c433ebd298d095c26e Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Fri, 15 Nov 2024 23:52:09 +0000 Subject: [PATCH] WOW64: Set the software CPU area flag This is required for wow64.dll to setup the cross-process queue that is used to pass through e.g. memory unmap events. --- Source/Windows/ARM64EC/Module.cpp | 3 +++ Source/Windows/Common/Exception.h | 7 +++---- Source/Windows/WOW64/Module.cpp | 8 ++++++++ Source/Windows/include/winternl.h | 13 +++++++++++++ 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/Source/Windows/ARM64EC/Module.cpp b/Source/Windows/ARM64EC/Module.cpp index 63569445c..a0714c704 100644 --- a/Source/Windows/ARM64EC/Module.cpp +++ b/Source/Windows/ARM64EC/Module.cpp @@ -449,6 +449,9 @@ static void RethrowGuestException(const EXCEPTION_RECORD& Rec, ARM64_NT_CONTEXT& Args->Rec = FEX::Windows::HandleGuestException(Fault, Rec, Args->Context.Pc, Args->Context.X8); if (Args->Rec.ExceptionCode == EXCEPTION_SINGLE_STEP) { Args->Context.Cpsr &= ~(1 << 21); // PSTATE.SS + } else if (Args->Rec.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; } Context.Sp = reinterpret_cast(Args); diff --git a/Source/Windows/Common/Exception.h b/Source/Windows/Common/Exception.h index b2671bcb6..3098628fd 100644 --- a/Source/Windows/Common/Exception.h +++ b/Source/Windows/Common/Exception.h @@ -29,8 +29,7 @@ HandleGuestException(FEXCore::Core::CpuStateFrame::SynchronousFaultDataStruct& F switch (Fault.TrapNo) { case FEXCore::X86State::X86_TRAPNO_DB: Dst.ExceptionCode = EXCEPTION_SINGLE_STEP; return Dst; case FEXCore::X86State::X86_TRAPNO_BP: - Rip -= 1; - Dst.ExceptionAddress = reinterpret_cast(Rip); + Dst.ExceptionAddress = reinterpret_cast(Rip - 1); Dst.ExceptionCode = EXCEPTION_BREAKPOINT; Dst.NumberParameters = 1; Dst.ExceptionInformation[0] = 0; @@ -44,9 +43,9 @@ HandleGuestException(FEXCore::Core::CpuStateFrame::SynchronousFaultDataStruct& F if ((Fault.err_code & 0b111) == 0b010) { switch (Fault.err_code >> 3) { case 0x2d: - Rip += 2; + Rip += 3; Dst.ExceptionCode = EXCEPTION_BREAKPOINT; - Dst.ExceptionAddress = reinterpret_cast(Rip + 1); + Dst.ExceptionAddress = reinterpret_cast(Rip); Dst.NumberParameters = 1; Dst.ExceptionInformation[0] = Rax; // RAX // Note that ExceptionAddress doesn't equal the reported context RIP here, this discrepancy expected and not having it can trigger anti-debug logic. diff --git a/Source/Windows/WOW64/Module.cpp b/Source/Windows/WOW64/Module.cpp index b411c4345..2cb5df967 100644 --- a/Source/Windows/WOW64/Module.cpp +++ b/Source/Windows/WOW64/Module.cpp @@ -74,6 +74,10 @@ struct TLS { explicit TLS(_TEB* TEB) : TEB(TEB) {} + WOW64INFO& Wow64Info() const { + return *reinterpret_cast(TEB->TlsSlots[WOW64_TLS_WOW64INFO]); + } + std::atomic& ControlWord() const { // TODO: Change this when libc++ gains std::atomic_ref support return reinterpret_cast&>(TEB->TlsSlots[FEXCore::ToUnderlying(Slot::CONTROL_WORD)]); @@ -479,6 +483,9 @@ void BTCpuProcessInit() { if (Sym) { WineUnixCall = *reinterpret_cast(Sym); } + + // wow64.dll will only initialise the cross-process queue if this is set + GetTLS().Wow64Info().CpuFlags = WOW64_CPUFLAGS_SOFTWARE; } void BTCpuProcessTerm(HANDLE Handle, BOOL After, ULONG Status) {} @@ -705,6 +712,7 @@ bool BTCpuResetToConsistentStateImpl(EXCEPTION_POINTERS* Ptrs) { if (Exception->ExceptionCode == EXCEPTION_SINGLE_STEP) { WowContext.EFlags &= ~(1 << FEXCore::X86State::RFLAG_TF_LOC); } + // wow64.dll will handle adjusting PC in the dispatched context after a breakpoint BTCpuSetContext(GetCurrentThread(), GetCurrentProcess(), nullptr, &WowContext); Context::UnlockJITContext(); diff --git a/Source/Windows/include/winternl.h b/Source/Windows/include/winternl.h index 4566f864c..da486cfe6 100644 --- a/Source/Windows/include/winternl.h +++ b/Source/Windows/include/winternl.h @@ -13,8 +13,11 @@ extern "C" { #define NtCurrentProcess() ((HANDLE) ~(ULONG_PTR)0) #define NtCurrentThread() ((HANDLE) ~(ULONG_PTR)1) +#define WOW64_TLS_WOW64INFO 10 #define WOW64_TLS_MAX_NUMBER 19 +#define WOW64_CPUFLAGS_SOFTWARE 0x02 + #define STATUS_EMULATION_SYSCALL ((NTSTATUS)0x40000039) #ifdef _M_ARM_64EC @@ -342,6 +345,16 @@ typedef struct __TEB { /* win32/win64 */ GUID EffectiveContainerId; /* ff0/1828 */ } __TEB, *__PTEB; +typedef struct _WOW64INFO { + ULONG NativeSystemPageSize; + ULONG CpuFlags; + ULONG Wow64ExecuteFlags; + ULONG unknown; + ULONGLONG SectionHandle; + ULONGLONG CrossProcessWorkList; + USHORT NativeMachineType; + USHORT EmulatedMachineType; +} WOW64INFO; typedef struct _THREAD_BASIC_INFORMATION { NTSTATUS ExitStatus;