diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.cpp index ae0015d80..91f099f40 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/GdbServer.cpp @@ -108,12 +108,8 @@ GdbServer::GdbServer(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* ThreadObject->GdbInfo = {}; ThreadObject->GdbInfo->Signal = Signal; - ThreadObject->GdbInfo->SignalPC = ArchHelpers::Context::GetPc(ucontext); this->SignalDelegation->SpillSRA(Thread, ucontext, Thread->CurrentFrame->InSyscallInfo); - memcpy(ThreadObject->GdbInfo->GPRs, ArchHelpers::Context::GetArmGPRs(ucontext), sizeof(ThreadObject->GdbInfo->GPRs)); - ThreadObject->GdbInfo->PState = ArchHelpers::Context::GetArmPState(ucontext); - // Let GDB know that we have a signal this->Break(Thread, Signal); @@ -304,16 +300,8 @@ GdbServer::GDBContextDefinition GdbServer::GenerateContextDefinition(const FEX:: // Encode the GDB context definition memcpy(&GDB.gregs[0], &state.gregs[0], sizeof(GDB.gregs)); - if (ThreadObject->GdbInfo.has_value()) { - GDB.rip = CTX->RestoreRIPFromHostPC(ThreadObject->Thread, ThreadObject->GdbInfo->SignalPC); - - const bool WasInJIT = CTX->IsAddressInCodeBuffer(ThreadObject->Thread, ThreadObject->GdbInfo->SignalPC); - GDB.eflags = CTX->ReconstructCompactedEFLAGS(ThreadObject->Thread, WasInJIT, const_cast(ThreadObject->GdbInfo->GPRs), - ThreadObject->GdbInfo->PState); - } else { - GDB.rip = ThreadObject->Thread->CurrentFrame->State.rip; - GDB.eflags = CTX->ReconstructCompactedEFLAGS(ThreadObject->Thread, false, nullptr, 0); - } + GDB.rip = ThreadObject->Thread->CurrentFrame->State.rip; + GDB.eflags = CTX->ReconstructCompactedEFLAGS(ThreadObject->Thread, false, nullptr, 0); for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_MMS; ++i) { memcpy(&GDB.mm[i], &state.mm[i], sizeof(GDB.mm[i])); diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.cpp index 4984205dd..2666c7bd2 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.cpp @@ -110,6 +110,8 @@ void SignalDelegator::RegisterHostSignalHandler(int Signal, HostSignalDelegatorF void SignalDelegator::SpillSRA(FEXCore::Core::InternalThreadState* Thread, void* ucontext, uint32_t IgnoreMask) { #ifdef _M_ARM_64 + Thread->CurrentFrame->State.rip = CTX->RestoreRIPFromHostPC(Thread, ArchHelpers::Context::GetPc(ucontext)); + for (size_t i = 0; i < Config.SRAGPRCount; i++) { const uint8_t SRAIdxMap = Config.SRAGPRMapping[i]; if (IgnoreMask & (1U << SRAIdxMap)) { @@ -132,6 +134,10 @@ void SignalDelegator::SpillSRA(FEXCore::Core::InternalThreadState* Thread, void* memcpy(&Thread->CurrentFrame->State.xmm.sse.data[i][0], &FPR, sizeof(__uint128_t)); } } + + uint32_t EFlags = + CTX->ReconstructCompactedEFLAGS(Thread, true, ArchHelpers::Context::GetArmGPRs(ucontext), ArchHelpers::Context::GetArmPState(ucontext)); + CTX->SetFlagsFromCompactedEFLAGS(Thread, EFlags); #endif } @@ -354,11 +360,8 @@ bool SignalDelegator::HandleDispatcherGuestSignal(FEXCore::Core::InternalThreadS // siginfo_t siginfo_t* HostSigInfo = reinterpret_cast(info); - // Backup where we think the RIP currently is - ContextBackup->OriginalRIP = CTX->RestoreRIPFromHostPC(Thread, ArchHelpers::Context::GetPc(ucontext)); - // Calculate eflags upfront. - uint32_t eflags = CTX->ReconstructCompactedEFLAGS(Thread, WasInJIT, ArchHelpers::Context::GetArmGPRs(ucontext), - ArchHelpers::Context::GetArmPState(ucontext)); + ContextBackup->OriginalRIP = Thread->CurrentFrame->State.rip; + uint32_t eflags = CTX->ReconstructCompactedEFLAGS(Thread, false, nullptr, 0); if (Is64BitMode) { NewGuestSP = SetupFrame_x64(Thread, ContextBackup, Frame, Signal, HostSigInfo, ucontext, GuestAction, GuestStack, NewGuestSP, eflags); diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/SyscallsSMCTracking.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/SyscallsSMCTracking.cpp index 04281dbd7..7fb91c233 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/SyscallsSMCTracking.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/SyscallsSMCTracking.cpp @@ -15,6 +15,7 @@ $end_info$ #include #include "LinuxSyscalls/Syscalls.h" +#include "LinuxSyscalls/SignalDelegator.h" #include #include @@ -81,6 +82,21 @@ bool SyscallHandler::HandleSegfault(FEXCore::Core::InternalThreadState* Thread, } FEXCORE_PROFILE_INSTANT_INCREMENT(Thread, AccumulatedSMCCount, 1); + + auto CTX = Thread->CTX; + if (CTX->IsAddressInCodeBuffer(Thread, ArchHelpers::Context::GetPc(ucontext)) && !CTX->IsCurrentBlockSingleInst(Thread) && + CTX->IsAddressInCurrentBlock(Thread, FaultAddress & FEXCore::Utils::FEX_PAGE_MASK, FEXCore::Utils::FEX_PAGE_SIZE)) { + // If we are not in a single-instruction block, and the SMC write address could intersect with the current block, + // reconstruct the context and repeat the faulting instruction as a single-instruction block so any SMC it performs + // is immediately picked up. + ThreadObject->SignalInfo.Delegator->SpillSRA(Thread, ucontext, Thread->CurrentFrame->InSyscallInfo & 0xFFFF); + + // Adjust context to return to the dispatcher, reloading SRA from thread state + const auto& Config = ThreadObject->SignalInfo.Delegator->GetConfig(); + ArchHelpers::Context::SetPc(ucontext, Config.AbsoluteLoopTopAddressFillSRA); + ArchHelpers::Context::SetArmReg(ucontext, 1, 1); // Set ENTRY_FILL_SRA_SINGLE_INST_REG to force a single step + } + return true; } } diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.h index 06614c16b..8cc6ddf92 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.h @@ -92,9 +92,6 @@ struct ThreadStateObject : public FEXCore::Allocator::FEXAllocOperators { // GDB signal information struct GdbInfoStruct { int Signal {}; - uint64_t SignalPC {}; - uint64_t GPRs[32]; - uint64_t PState {}; }; std::optional GdbInfo; diff --git a/Source/Tools/TestHarnessRunner/TestHarnessRunner.cpp b/Source/Tools/TestHarnessRunner/TestHarnessRunner.cpp index d200b367b..c4de48866 100644 --- a/Source/Tools/TestHarnessRunner/TestHarnessRunner.cpp +++ b/Source/Tools/TestHarnessRunner/TestHarnessRunner.cpp @@ -300,9 +300,11 @@ int main(int argc, char** argv, char** const envp) { FEX::HLE::x32::CreateHandler(CTX.get(), SignalDelegation.get(), nullptr, std::move(Allocator)); auto DoMmap = [&](uint64_t Address, size_t Size) -> void* { - void* Result = SyscallHandler->GuestMmap(nullptr, (void*)Address, Size, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); + // Map as R-X, then protect as RWX without informing the frontend to avoid unwanted SMC detection + void* Result = + SyscallHandler->GuestMmap(nullptr, (void*)Address, Size, PROT_READ | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); LOGMAN_THROW_A_FMT(Result == reinterpret_cast(Address), "Map Memory mmap failed"); + ::mprotect(Result, Size, PROT_READ | PROT_WRITE | PROT_EXEC); return Result; };