Returns true if exception dispatch should be halted and the execution context restored to NativeContext
| 727 | |
| 728 | // Returns true if exception dispatch should be halted and the execution context restored to NativeContext |
| 729 | bool ResetToConsistentStateImpl(EXCEPTION_RECORD* Exception, CONTEXT* GuestContext, ARM64_NT_CONTEXT* NativeContext) { |
| 730 | const auto CPUArea = GetCPUArea(); |
| 731 | auto Thread = CPUArea.ThreadState(); |
| 732 | FEXCORE_PROFILE_ACCUMULATION(Thread, AccumulatedSignalTime); |
| 733 | LogMan::Msg::DFmt("Exception: Code: {:X} Address: {:X}", Exception->ExceptionCode, reinterpret_cast<uintptr_t>(Exception->ExceptionAddress)); |
| 734 | |
| 735 | if (NativeContext->Pc == reinterpret_cast<uint64_t>(&ExitFunctionSuspendPoint)) { |
| 736 | // A suspend interrupt can occur in ExitFunctionEC before InSimulation is unset and set SuspendDoorbell. If this |
| 737 | // occurs then it is still our duty to cooperatively suspend with an appropriate context. To support this, after |
| 738 | // unsetting InSimulation a brk #0xCAFE instruction will be raised that we can handle here. |
| 739 | NativeContext->Pc += 4; // Skip over the brk instruction when we resume |
| 740 | *CPUArea.Area->SuspendDoorbell = 0; |
| 741 | return true; |
| 742 | } |
| 743 | |
| 744 | if (Exception->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { |
| 745 | const auto FaultAddress = static_cast<uint64_t>(Exception->ExceptionInformation[1]); |
| 746 | |
| 747 | if (FEX::Windows::CallRetStack::HandleAccessViolation(Thread, FaultAddress, NativeContext->X17)) { |
| 748 | return true; |
| 749 | } |
| 750 | |
| 751 | std::scoped_lock Lock(ThreadCreationMutex); |
| 752 | if (InvalidationTracker && InvalidationTracker->HandleRWXAccessViolation(Thread, NativeContext->Pc, FaultAddress)) { |
| 753 | FEXCORE_PROFILE_INSTANT_INCREMENT(Thread, AccumulatedSMCCount, 1); |
| 754 | if (CTX->IsAddressInCodeBuffer(Thread, NativeContext->Pc) && !CTX->IsCurrentBlockSingleInst(CPUArea.ThreadState()) && |
| 755 | CTX->IsAddressInCurrentBlock(Thread, FaultAddress & FEXCore::Utils::FEX_PAGE_MASK, FEXCore::Utils::FEX_PAGE_SIZE)) { |
| 756 | // If we are not patching ourself (single inst block case) and potentially patching the current block, this is inline SMC. Reconstruct the current context (before the SMC write) then single step the write to reduce it to regular SMC. |
| 757 | Exception::ReconstructThreadState(Thread, *NativeContext); |
| 758 | LogMan::Msg::DFmt("Handled inline self-modifying code: pc: {:X} rip: {:X} fault: {:X}", NativeContext->Pc, |
| 759 | Thread->CurrentFrame->State.rip, FaultAddress); |
| 760 | NativeContext->Pc = CPUArea.DispatcherLoopTopEnterECFillSRA(); |
| 761 | NativeContext->Sp = CPUArea.EmulatorStackBase(); |
| 762 | NativeContext->X11 = 1; // Set ENTRY_FILL_SRA_SINGLE_INST_REG to force a single step |
| 763 | NativeContext->X17 = reinterpret_cast<uint64_t>(CPUArea.Area); // Set EC_ENTRY_CPUAREA_REG |
| 764 | } else { |
| 765 | LogMan::Msg::DFmt("Handled self-modifying code: pc: {:X} fault: {:X}", NativeContext->Pc, FaultAddress); |
| 766 | } |
| 767 | |
| 768 | return true; |
| 769 | } |
| 770 | } |
| 771 | |
| 772 | if (!CTX->IsAddressInCodeBuffer(Thread, NativeContext->Pc) && !IsDispatcherAddress(NativeContext->Pc)) { |
| 773 | LogMan::Msg::DFmt("Passing through exception"); |
| 774 | return false; |
| 775 | } |
| 776 | |
| 777 | if (Exception->ExceptionCode == EXCEPTION_DATATYPE_MISALIGNMENT && Exception::HandleUnalignedAccess(*NativeContext)) { |
| 778 | LogMan::Msg::DFmt("Handled unaligned atomic: new pc: {:X}", NativeContext->Pc); |
| 779 | return true; |
| 780 | } |
| 781 | |
| 782 | // The JIT (in CompileBlock) emits code to check the suspend doorbell at the start of every block, and run the following instruction if it is set: |
| 783 | static constexpr uint32_t SuspendTrapMagic {0xD4395FC0}; // brk #0xCAFE |
| 784 | if (Exception->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION && *reinterpret_cast<uint32_t*>(NativeContext->Pc) == SuspendTrapMagic) { |
| 785 | Exception::ReconstructThreadState(Thread, *NativeContext); |
| 786 | *NativeContext = Exception::StoreStateToPackedECContext(Thread, NativeContext->Fpcr, NativeContext->Fpsr); |
no test coverage detected