From d48f527d6d88dfbf87fb75bf66803cf4a0ed1613 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 29 May 2024 20:30:53 +1000 Subject: [PATCH] Common: Tidy up signal handlers Move MacOS into its own file. Fix assertion failure crash dumping. --- cmake/SearchForStuff.cmake | 2 +- common/CMakeLists.txt | 65 +++--- common/CrashHandler.cpp | 111 ++++----- common/CrashHandler.h | 9 + common/Darwin/DarwinMisc.cpp | 131 ++++++++++- common/Darwin/DarwinSemaphore.cpp | 71 ------ common/Darwin/DarwinThreads.cpp | 81 +++++-- common/HostSys.h | 12 +- common/Linux/LnxHostSys.cpp | 372 ++++++++++++------------------ common/Linux/LnxMisc.cpp | 6 +- common/Linux/LnxThreads.cpp | 21 +- common/Semaphore.cpp | 2 +- common/Windows/WinHostSys.cpp | 111 ++++----- common/Windows/WinMisc.cpp | 5 +- common/Windows/WinThreads.cpp | 4 - common/common.vcxproj | 3 - common/common.vcxproj.filters | 9 - pcsx2/vtlb.cpp | 17 +- 18 files changed, 521 insertions(+), 511 deletions(-) delete mode 100644 common/Darwin/DarwinSemaphore.cpp diff --git a/cmake/SearchForStuff.cmake b/cmake/SearchForStuff.cmake index b822d8279a..216517bd26 100644 --- a/cmake/SearchForStuff.cmake +++ b/cmake/SearchForStuff.cmake @@ -69,7 +69,7 @@ else() find_package(Wayland REQUIRED Egl) endif() - find_package(Libbacktrace) + find_package(Libbacktrace REQUIRED) find_package(PkgConfig REQUIRED) pkg_check_modules(DBUS REQUIRED dbus-1) endif() diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 23d6a87423..b1f882f1fd 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -44,15 +44,6 @@ target_sources(common PRIVATE emitter/movs.cpp emitter/simd.cpp emitter/x86emitter.cpp - Darwin/DarwinThreads.cpp - Darwin/DarwinMisc.cpp - Darwin/DarwinSemaphore.cpp - Linux/LnxHostSys.cpp - Linux/LnxThreads.cpp - Linux/LnxMisc.cpp - Windows/WinThreads.cpp - Windows/WinHostSys.cpp - Windows/WinMisc.cpp ) # x86emitter headers @@ -124,34 +115,32 @@ target_sources(common PRIVATE emitter/legacy_types.h emitter/x86emitter.h emitter/x86types.h - Darwin/DarwinMisc.h ) -set_source_files_properties(PrecompiledHeader.cpp PROPERTIES HEADER_FILE_ONLY TRUE) - -if(USE_VTUNE) - target_link_libraries(common PUBLIC Vtune::Vtune) -endif() - if(WIN32) enable_language(ASM_MASM) - target_sources(common PRIVATE FastJmp.asm) - target_link_libraries(common PUBLIC WIL::WIL winmm pathcch) target_sources(common PRIVATE - CrashHandler.cpp - CrashHandler.h FastJmp.asm HTTPDownloaderWinHTTP.cpp HTTPDownloaderWinHTTP.h StackWalker.cpp StackWalker.h + Windows/WinThreads.cpp + Windows/WinHostSys.cpp + Windows/WinMisc.cpp ) -endif() - -if(APPLE) + target_link_libraries(common PUBLIC + WIL::WIL + winmm + pathcch + ) +elseif(APPLE) target_sources(common PRIVATE CocoaTools.mm CocoaTools.h + Darwin/DarwinThreads.cpp + Darwin/DarwinMisc.cpp + Darwin/DarwinMisc.h ) target_compile_options(common PRIVATE -fobjc-arc) target_link_options(common PRIVATE -fobjc-link-runtime) @@ -159,15 +148,27 @@ if(APPLE) "-framework Foundation" "-framework IOKit" ) +else() + target_sources(common PRIVATE + Linux/LnxHostSys.cpp + Linux/LnxThreads.cpp + Linux/LnxMisc.cpp + ) + target_include_directories(common PRIVATE + ${DBUS_INCLUDE_DIRS} + ) + target_link_libraries(common PRIVATE + ${DBUS_LINK_LIBRARIES} + libbacktrace::libbacktrace + X11::X11 + X11::Xrandr + ) endif() -if(UNIX AND NOT APPLE) - target_include_directories(common PRIVATE ${DBUS_INCLUDE_DIRS}) - target_link_libraries(common PRIVATE ${DBUS_LINK_LIBRARIES} X11::X11 X11::Xrandr) - if(TARGET libbacktrace::libbacktrace) - target_compile_definitions(common PRIVATE "HAS_LIBBACKTRACE=1") - target_link_libraries(common PRIVATE libbacktrace::libbacktrace) - endif() +set_source_files_properties(PrecompiledHeader.cpp PROPERTIES HEADER_FILE_ONLY TRUE) + +if(USE_VTUNE) + target_link_libraries(common PUBLIC Vtune::Vtune) endif() if (USE_GCC AND CMAKE_INTERPROCEDURAL_OPTIMIZATION) @@ -181,7 +182,9 @@ if(NOT WIN32) HTTPDownloaderCurl.cpp HTTPDownloaderCurl.h ) - target_link_libraries(common PRIVATE CURL::libcurl) + target_link_libraries(common PRIVATE + CURL::libcurl + ) endif() target_link_libraries(common PRIVATE diff --git a/common/CrashHandler.cpp b/common/CrashHandler.cpp index 74b9930401..667cc92c23 100644 --- a/common/CrashHandler.cpp +++ b/common/CrashHandler.cpp @@ -56,23 +56,31 @@ static bool WriteMinidump(HMODULE hDbgHelp, HANDLE hFile, HANDLE hProcess, DWORD PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, PMINIDUMP_CALLBACK_INFORMATION CallbackParam); - PFNMINIDUMPWRITEDUMP minidump_write_dump = hDbgHelp ? - reinterpret_cast(GetProcAddress(hDbgHelp, "MiniDumpWriteDump")) : - nullptr; + PFNMINIDUMPWRITEDUMP minidump_write_dump = + hDbgHelp ? reinterpret_cast(GetProcAddress(hDbgHelp, "MiniDumpWriteDump")) : nullptr; if (!minidump_write_dump) return false; - MINIDUMP_EXCEPTION_INFORMATION mei; - PMINIDUMP_EXCEPTION_INFORMATION mei_ptr = nullptr; + MINIDUMP_EXCEPTION_INFORMATION mei = {}; if (exception) { mei.ThreadId = thread_id; mei.ExceptionPointers = exception; mei.ClientPointers = FALSE; - mei_ptr = &mei; + return minidump_write_dump(hProcess, process_id, hFile, type, &mei, nullptr, nullptr); } - return minidump_write_dump(hProcess, process_id, hFile, type, mei_ptr, nullptr, nullptr); + __try + { + RaiseException(EXCEPTION_INVALID_HANDLE, 0, 0, nullptr); + } + __except (WriteMinidump(hDbgHelp, hFile, GetCurrentProcess(), GetCurrentProcessId(), GetCurrentThreadId(), + GetExceptionInformation(), type), + EXCEPTION_EXECUTE_HANDLER) + { + } + + return true; } static std::wstring s_write_directory; @@ -168,7 +176,7 @@ void CrashHandler::WriteDumpForCaller() WriteMinidumpAndCallstack(nullptr); } -#elif defined(HAS_LIBBACKTRACE) +#elif !defined(__APPLE__) #include "FileSystem.h" @@ -194,16 +202,13 @@ namespace CrashHandler static void FreeBuffer(BacktraceBuffer* buf); static void AppendToBuffer(BacktraceBuffer* buf, const char* format, ...); static int BacktraceFullCallback(void* data, uintptr_t pc, const char* filename, int lineno, const char* function); - static void CallExistingSignalHandler(int signal, siginfo_t* siginfo, void* ctx); - static void CrashSignalHandler(int signal, siginfo_t* siginfo, void* ctx); + static void LogCallstack(int signal, const void* exception_pc); static std::recursive_mutex s_crash_mutex; static bool s_in_signal_handler = false; static backtrace_state* s_backtrace_state = nullptr; - static struct sigaction s_old_sigbus_action; - static struct sigaction s_old_sigsegv_action; -} +} // namespace CrashHandler const char* CrashHandler::GetSignalName(int signal_no) { @@ -214,7 +219,7 @@ const char* CrashHandler::GetSignalName(int signal_no) case SIGSEGV: return "SIGSEGV"; case SIGBUS: return "SIGBUS"; default: return "UNKNOWN"; - // clang-format on + // clang-format on } } @@ -253,7 +258,8 @@ void CrashHandler::AppendToBuffer(BacktraceBuffer* buf, const char* format, ...) va_end(ap); } -int CrashHandler::BacktraceFullCallback(void* data, uintptr_t pc, const char* filename, int lineno, const char* function) +int CrashHandler::BacktraceFullCallback(void* data, uintptr_t pc, const char* filename, int lineno, + const char* function) { BacktraceBuffer* buf = static_cast(data); AppendToBuffer(buf, " %016p", pc); @@ -261,34 +267,36 @@ int CrashHandler::BacktraceFullCallback(void* data, uintptr_t pc, const char* fi AppendToBuffer(buf, " %s", function); if (filename) AppendToBuffer(buf, " [%s:%d]", filename, lineno); - + AppendToBuffer(buf, "\n"); return 0; } -void CrashHandler::CallExistingSignalHandler(int signal, siginfo_t* siginfo, void* ctx) +void CrashHandler::LogCallstack(int signal, const void* exception_pc) { - const struct sigaction& sa = (signal == SIGBUS) ? s_old_sigbus_action : s_old_sigsegv_action; - if (sa.sa_flags & SA_SIGINFO) - { - sa.sa_sigaction(signal, siginfo, ctx); - } - else if (sa.sa_handler == SIG_DFL) - { - // Re-raising the signal would just queue it, and since we'd restore the handler back to us, - // we'd end up right back here again. So just abort, because that's probably what it'd do anyway. - abort(); - } - else if (sa.sa_handler != SIG_IGN) - { - sa.sa_handler(signal); - } + BacktraceBuffer buf; + AllocateBuffer(&buf); + if (signal != 0 || exception_pc) + AppendToBuffer(&buf, "*************** Unhandled %s at %p ***************\n", GetSignalName(signal), exception_pc); + else + AppendToBuffer(&buf, "*******************************************************************\n"); + + const int rc = backtrace_full(s_backtrace_state, 0, BacktraceFullCallback, nullptr, &buf); + if (rc != 0) + AppendToBuffer(&buf, " backtrace_full() failed: %d\n"); + + AppendToBuffer(&buf, "*******************************************************************\n"); + + if (buf.used > 0) + write(STDERR_FILENO, buf.buffer, buf.used); + + FreeBuffer(&buf); } void CrashHandler::CrashSignalHandler(int signal, siginfo_t* siginfo, void* ctx) { std::unique_lock lock(s_crash_mutex); - + // If we crash somewhere in libbacktrace, don't bother trying again. if (!s_in_signal_handler) { @@ -304,27 +312,17 @@ void CrashHandler::CrashSignalHandler(int signal, siginfo_t* siginfo, void* ctx) void* const exception_pc = nullptr; #endif - BacktraceBuffer buf; - AllocateBuffer(&buf); - AppendToBuffer(&buf, "*************** Unhandled %s at %p ***************\n", GetSignalName(signal), exception_pc); - - const int rc = backtrace_full(s_backtrace_state, 0, BacktraceFullCallback, nullptr, &buf); - if (rc != 0) - AppendToBuffer(&buf, " backtrace_full() failed: %d\n"); - - AppendToBuffer(&buf, "*******************************************************************\n"); - - if (buf.used > 0) - write(STDERR_FILENO, buf.buffer, buf.used); - - FreeBuffer(&buf); + LogCallstack(signal, exception_pc); s_in_signal_handler = false; } - // Chances are we're not going to have anything else to call, but just in case. lock.unlock(); - CallExistingSignalHandler(signal, siginfo, ctx); + + // We can't continue from here. Just bail out and dump core. + std::fputs("Aborting application.\n", stderr); + std::fflush(stderr); + std::abort(); } bool CrashHandler::Install() @@ -333,15 +331,15 @@ bool CrashHandler::Install() s_backtrace_state = backtrace_create_state(progpath.empty() ? nullptr : progpath.c_str(), 0, nullptr, nullptr); if (!s_backtrace_state) return false; - + struct sigaction sa; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_SIGINFO | SA_NODEFER; sa.sa_sigaction = CrashSignalHandler; - if (sigaction(SIGBUS, &sa, &s_old_sigbus_action) != 0) + if (sigaction(SIGBUS, &sa, nullptr) != 0) return false; - if (sigaction(SIGSEGV, &sa, &s_old_sigsegv_action) != 0) + if (sigaction(SIGSEGV, &sa, nullptr) != 0) return false; return true; @@ -353,6 +351,7 @@ void CrashHandler::SetWriteDirectory(std::string_view dump_directory) void CrashHandler::WriteDumpForCaller() { + LogCallstack(0, nullptr); } #else @@ -370,4 +369,12 @@ void CrashHandler::WriteDumpForCaller() { } +void CrashHandler::CrashSignalHandler(int signal, siginfo_t* siginfo, void* ctx) +{ + // We can't continue from here. Just bail out and dump core. + std::fputs("Aborting application.\n", stderr); + std::fflush(stderr); + std::abort(); +} + #endif \ No newline at end of file diff --git a/common/CrashHandler.h b/common/CrashHandler.h index 333d612324..ee6c232a66 100644 --- a/common/CrashHandler.h +++ b/common/CrashHandler.h @@ -3,9 +3,18 @@ #include +#ifndef _WIN32 +#include +#endif + namespace CrashHandler { bool Install(); void SetWriteDirectory(std::string_view dump_directory); void WriteDumpForCaller(); + +#ifndef _WIN32 + // Allow crash handler to be invoked from a signal. + void CrashSignalHandler(int signal, siginfo_t* siginfo, void* ctx); +#endif } // namespace CrashHandler diff --git a/common/Darwin/DarwinMisc.cpp b/common/Darwin/DarwinMisc.cpp index 662ef79aa3..1a9a689e35 100644 --- a/common/Darwin/DarwinMisc.cpp +++ b/common/Darwin/DarwinMisc.cpp @@ -1,11 +1,18 @@ // SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team // SPDX-License-Identifier: LGPL-3.0+ -#if defined(__APPLE__) - +#include "common/Assertions.h" +#include "common/BitUtils.h" +#include "common/Console.h" +#include "common/CrashHandler.h" #include "common/Darwin/DarwinMisc.h" +#include "common/Error.h" +#include "common/Pcsx2Types.h" +#include "common/Threading.h" +#include "common/WindowInfo.h" #include "common/HostSys.h" +#include #include #include #include @@ -17,17 +24,11 @@ #include #include #include +#include #include +#include #include -#include "common/Assertions.h" -#include "common/BitUtils.h" -#include "common/Console.h" -#include "common/Pcsx2Types.h" -#include "common/HostSys.h" -#include "common/Threading.h" -#include "common/WindowInfo.h" - // Darwin (OSX) is a bit different from Linux when requesting properties of // the OS because of its BSD/Mach heritage. Helpfully, most of this code // should translate pretty well to other *BSD systems. (e.g.: the sysctl(3) @@ -399,6 +400,116 @@ void HostSys::EndCodeWrite() pthread_jit_write_protect_np(1); } +[[maybe_unused]] static bool IsStoreInstruction(const void* ptr) +{ + u32 bits; + std::memcpy(&bits, ptr, sizeof(bits)); + + // Based on vixl's disassembler Instruction::IsStore(). + // if (Mask(LoadStoreAnyFMask) != LoadStoreAnyFixed) + if ((bits & 0x0a000000) != 0x08000000) + return false; + + // if (Mask(LoadStorePairAnyFMask) == LoadStorePairAnyFixed) + if ((bits & 0x3a000000) == 0x28000000) + { + // return Mask(LoadStorePairLBit) == 0 + return (bits & (1 << 22)) == 0; + } + + switch (bits & 0xC4C00000) + { + case 0x00000000: // STRB_w + case 0x40000000: // STRH_w + case 0x80000000: // STR_w + case 0xC0000000: // STR_x + case 0x04000000: // STR_b + case 0x44000000: // STR_h + case 0x84000000: // STR_s + case 0xC4000000: // STR_d + case 0x04800000: // STR_q + return true; + + default: + return false; + } +} + +#endif // _M_ARM64 + +namespace PageFaultHandler +{ + static void SignalHandler(int sig, siginfo_t* info, void* ctx); + + static std::recursive_mutex s_exception_handler_mutex; + static bool s_in_exception_handler = false; + static bool s_installed = false; +} // namespace PageFaultHandler + +void PageFaultHandler::SignalHandler(int sig, siginfo_t* info, void* ctx) +{ +#if defined(_M_X86) + void* const exception_address = + reinterpret_cast(static_cast(ctx)->uc_mcontext->__es.__faultvaddr); + void* const exception_pc = reinterpret_cast(static_cast(ctx)->uc_mcontext->__ss.__rip); + const bool is_write = (static_cast(ctx)->uc_mcontext->__es.__err & 2) != 0; +#elif defined(_M_ARM64) + void* const exception_address = reinterpret_cast(static_cast(ctx)->uc_mcontext->__es.__far); + void* const exception_pc = reinterpret_cast(static_cast(ctx)->uc_mcontext->__ss.__pc); + const bool is_write = IsStoreInstruction(exception_pc); #endif + // Executing the handler concurrently from multiple threads wouldn't go down well. + s_exception_handler_mutex.lock(); + + // Prevent recursive exception filtering. + HandlerResult result = HandlerResult::ExecuteNextHandler; + if (!s_in_exception_handler) + { + s_in_exception_handler = true; + result = HandlePageFault(exception_pc, exception_address, is_write); + s_in_exception_handler = false; + } + + s_exception_handler_mutex.unlock(); + + // Resumes execution right where we left off (re-executes instruction that caused the SIGSEGV). + if (result == HandlerResult::ContinueExecution) + return; + + // We couldn't handle it. Pass it off to the crash dumper. + CrashHandler::CrashSignalHandler(sig, info, ctx); +} + +bool PageFaultHandler::Install(Error* error) +{ + std::unique_lock lock(s_exception_handler_mutex); + pxAssertRel(!s_installed, "Page fault handler has already been installed."); + + struct sigaction sa; + + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = SignalHandler; + + // MacOS uses SIGBUS for memory permission violations, as well as SIGSEGV on ARM64. + if (sigaction(SIGBUS, &sa, nullptr) != 0) + { + Error::SetErrno(error, "sigaction() for SIGBUS failed: ", errno); + return false; + } + +#ifdef _M_ARM64 + if (sigaction(SIGSEGV, &sa, nullptr) != 0) + { + Error::SetErrno(error, "sigaction() for SIGSEGV failed: ", errno); + return false; + } #endif + + // Allow us to ignore faults when running under lldb. + task_set_exception_ports(mach_task_self(), EXC_MASK_BAD_ACCESS, MACH_PORT_NULL, EXCEPTION_DEFAULT, 0); + + s_installed = true; + return true; +} diff --git a/common/Darwin/DarwinSemaphore.cpp b/common/Darwin/DarwinSemaphore.cpp deleted file mode 100644 index 03cf1c4bea..0000000000 --- a/common/Darwin/DarwinSemaphore.cpp +++ /dev/null @@ -1,71 +0,0 @@ -// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team -// SPDX-License-Identifier: LGPL-3.0+ - -#if defined(__APPLE__) - -#include -#include // assert -#include // pthread_setcancelstate() -#include // gettimeofday() -#include -#include // semaphore_create() and semaphore_destroy() -#include // semaphore_*() -#include // mach_error_string() -#include // mach_absolute_time() - -#include "common/Threading.h" - -// -------------------------------------------------------------------------------------- -// Semaphore Implementation for Darwin/OSX -// -// Sadly, Darwin/OSX needs its own implementation of Semaphores instead of -// relying on phtreads, because OSX unnamed semaphore (the best kind) -// support is very poor. -// -// This implementation makes use of Mach primitives instead. These are also -// what Grand Central Dispatch (GCD) is based on, as far as I understand: -// http://newosxbook.com/articles/GCD.html. -// -// -------------------------------------------------------------------------------------- - -static void MACH_CHECK(kern_return_t mach_retval) -{ - if (mach_retval != KERN_SUCCESS) - { - fprintf(stderr, "mach error: %s", mach_error_string(mach_retval)); - assert(mach_retval == KERN_SUCCESS); - } -} - -Threading::KernelSemaphore::KernelSemaphore() -{ - MACH_CHECK(semaphore_create(mach_task_self(), &m_sema, SYNC_POLICY_FIFO, 0)); -} - -Threading::KernelSemaphore::~KernelSemaphore() -{ - MACH_CHECK(semaphore_destroy(mach_task_self(), m_sema)); -} - -void Threading::KernelSemaphore::Post() -{ - MACH_CHECK(semaphore_signal(m_sema)); -} - -void Threading::KernelSemaphore::Wait() -{ - MACH_CHECK(semaphore_wait(m_sema)); -} - -bool Threading::KernelSemaphore::TryWait() -{ - mach_timespec_t time = {}; - kern_return_t res = semaphore_timedwait(m_sema, time); - if (res == KERN_OPERATION_TIMED_OUT) - return false; - MACH_CHECK(res); - return true; -} - -#endif - diff --git a/common/Darwin/DarwinThreads.cpp b/common/Darwin/DarwinThreads.cpp index 860a093389..80c4a0a116 100644 --- a/common/Darwin/DarwinThreads.cpp +++ b/common/Darwin/DarwinThreads.cpp @@ -1,19 +1,24 @@ -// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team +// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team // SPDX-License-Identifier: LGPL-3.0+ -#if defined(__APPLE__) - -#include -#include -#include -#include -#include -#include - -#include "common/PrecompiledHeader.h" #include "common/Threading.h" #include "common/Assertions.h" +#include +#include // assert +#include +#include // gettimeofday() +#include +#include +#include +#include // mach_error_string() +#include +#include +#include // mach_absolute_time() +#include // semaphore_*() +#include // semaphore_create() and semaphore_destroy() +#include + // Note: assuming multicore is safer because it forces the interlocked routines to use // the LOCK prefix. The prefix works on single core CPUs fine (but is slow), but not // having the LOCK prefix is very bad indeed. @@ -89,6 +94,58 @@ u64 Threading::GetThreadCpuTime() return us; } +// -------------------------------------------------------------------------------------- +// Semaphore Implementation for Darwin/OSX +// +// Sadly, Darwin/OSX needs its own implementation of Semaphores instead of +// relying on phtreads, because OSX unnamed semaphore (the best kind) +// support is very poor. +// +// This implementation makes use of Mach primitives instead. These are also +// what Grand Central Dispatch (GCD) is based on, as far as I understand: +// http://newosxbook.com/articles/GCD.html. +// +// -------------------------------------------------------------------------------------- + +static void MACH_CHECK(kern_return_t mach_retval) +{ + if (mach_retval != KERN_SUCCESS) + { + fprintf(stderr, "mach error: %s", mach_error_string(mach_retval)); + assert(mach_retval == KERN_SUCCESS); + } +} + +Threading::KernelSemaphore::KernelSemaphore() +{ + MACH_CHECK(semaphore_create(mach_task_self(), &m_sema, SYNC_POLICY_FIFO, 0)); +} + +Threading::KernelSemaphore::~KernelSemaphore() +{ + MACH_CHECK(semaphore_destroy(mach_task_self(), m_sema)); +} + +void Threading::KernelSemaphore::Post() +{ + MACH_CHECK(semaphore_signal(m_sema)); +} + +void Threading::KernelSemaphore::Wait() +{ + MACH_CHECK(semaphore_wait(m_sema)); +} + +bool Threading::KernelSemaphore::TryWait() +{ + mach_timespec_t time = {}; + kern_return_t res = semaphore_timedwait(m_sema, time); + if (res == KERN_OPERATION_TIMED_OUT) + return false; + MACH_CHECK(res); + return true; +} + Threading::ThreadHandle::ThreadHandle() = default; Threading::ThreadHandle::ThreadHandle(const ThreadHandle& handle) @@ -220,5 +277,3 @@ void Threading::SetNameOfCurrentThread(const char* name) { pthread_setname_np(name); } - -#endif diff --git a/common/HostSys.h b/common/HostSys.h index e0b0a8961c..1e7cfe3827 100644 --- a/common/HostSys.h +++ b/common/HostSys.h @@ -123,12 +123,18 @@ namespace HostSys #else void FlushInstructionCache(void* address, u32 size); #endif -} +} // namespace HostSys namespace PageFaultHandler { - bool HandlePageFault(uptr pc, uptr addr, bool is_write); - bool Install(Error* error); + enum class HandlerResult + { + ContinueExecution, + ExecuteNextHandler, + }; + + HandlerResult HandlePageFault(void* exception_pc, void* fault_address, bool is_write); + bool Install(Error* error = nullptr); } // namespace PageFaultHandler class SharedMemoryMappingArea diff --git a/common/Linux/LnxHostSys.cpp b/common/Linux/LnxHostSys.cpp index f0c713b82f..0d2835636e 100644 --- a/common/Linux/LnxHostSys.cpp +++ b/common/Linux/LnxHostSys.cpp @@ -1,229 +1,30 @@ -// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team +// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team // SPDX-License-Identifier: LGPL-3.0+ -#if defined(__APPLE__) -#define _XOPEN_SOURCE -#endif - -#if !defined(_WIN32) -#include -#include -#include -#include -#include -#include - -#include - -#include "fmt/core.h" - #include "common/Assertions.h" #include "common/BitUtils.h" #include "common/Console.h" +#include "common/CrashHandler.h" #include "common/Error.h" #include "common/HostSys.h" -// Apple uses the MAP_ANON define instead of MAP_ANONYMOUS, but they mean -// the same thing. -#if defined(__APPLE__) && !defined(MAP_ANONYMOUS) -#define MAP_ANONYMOUS MAP_ANON -#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fmt/core.h" // FreeBSD does not have MAP_FIXED_NOREPLACE, but does have MAP_EXCL. // MAP_FIXED combined with MAP_EXCL behaves like MAP_FIXED_NOREPLACE. #if defined(__FreeBSD__) && !defined(MAP_FIXED_NOREPLACE) -#define MAP_FIXED_NOREPLACE MAP_FIXED | MAP_EXCL +#define MAP_FIXED_NOREPLACE (MAP_FIXED | MAP_EXCL) #endif -#include -#include -#include -#include - -#ifndef __APPLE__ -#include -#endif - -static std::recursive_mutex s_exception_handler_mutex; -static bool s_in_exception_handler = false; -static bool s_exception_handler_installed = false; - -#ifdef __APPLE__ -#include -#include -#include -#endif - -#if defined(__APPLE__) || defined(__aarch64__) -static struct sigaction s_old_sigbus_action; -#endif -#if !defined(__APPLE__) || defined(__aarch64__) -static struct sigaction s_old_sigsegv_action; -#endif - -#ifdef __aarch64__ -[[maybe_unused]] static bool IsStoreInstruction(uptr ptr) -{ - u32 bits; - std::memcpy(&bits, reinterpret_cast(ptr), sizeof(bits)); - - // Based on vixl's disassembler Instruction::IsStore(). - // if (Mask(LoadStoreAnyFMask) != LoadStoreAnyFixed) - if ((bits & 0x0a000000) != 0x08000000) - return false; - - // if (Mask(LoadStorePairAnyFMask) == LoadStorePairAnyFixed) - if ((bits & 0x3a000000) == 0x28000000) - { - // return Mask(LoadStorePairLBit) == 0 - return (bits & (1 << 22)) == 0; - } - - switch (bits & 0xC4C00000) - { - case 0x00000000: // STRB_w - case 0x40000000: // STRH_w - case 0x80000000: // STR_w - case 0xC0000000: // STR_x - case 0x04000000: // STR_b - case 0x44000000: // STR_h - case 0x84000000: // STR_s - case 0xC4000000: // STR_d - case 0x04800000: // STR_q - return true; - - default: - return false; - } -} -#endif - -static void CallExistingSignalHandler(int signal, siginfo_t* siginfo, void* ctx) -{ -#if defined(__aarch64__) - const struct sigaction& sa = (signal == SIGBUS) ? s_old_sigbus_action : s_old_sigsegv_action; -#elif defined(__APPLE__) - const struct sigaction& sa = s_old_sigbus_action; -#else - const struct sigaction& sa = s_old_sigsegv_action; -#endif - - if (sa.sa_flags & SA_SIGINFO) - { - sa.sa_sigaction(signal, siginfo, ctx); - } - else if (sa.sa_handler == SIG_DFL) - { - // Re-raising the signal would just queue it, and since we'd restore the handler back to us, - // we'd end up right back here again. So just abort, because that's probably what it'd do anyway. - abort(); - } - else if (sa.sa_handler != SIG_IGN) - { - sa.sa_handler(signal); - } -} - -// Linux implementation of SIGSEGV handler. Bind it using sigaction(). -static void SysPageFaultSignalFilter(int signal, siginfo_t* info, void* ctx) -{ - // Executing the handler concurrently from multiple threads wouldn't go down well. - std::unique_lock lock(s_exception_handler_mutex); - - // Prevent recursive exception filtering. - if (s_in_exception_handler) - { - lock.unlock(); - CallExistingSignalHandler(signal, info, ctx); - return; - } - -#if defined(__linux__) - const uptr exception_address = reinterpret_cast(info->si_addr); - #if defined(__x86_64__) - const uptr exception_pc = static_cast(static_cast(ctx)->uc_mcontext.gregs[REG_RIP]); - const bool is_write = (static_cast(ctx)->uc_mcontext.gregs[REG_ERR] & 2) != 0; - #elif defined(__aarch64__) - const uptr exception_pc = static_cast(static_cast(ctx)->uc_mcontext.pc); - const bool is_write = IsStoreInstruction(exception_pc); - #endif -#elif defined(__APPLE__) - #if defined(__x86_64__) - const uptr exception_pc = static_cast(static_cast(ctx)->uc_mcontext->__ss.__rip); - const uptr exception_address = static_cast(static_cast(ctx)->uc_mcontext->__es.__faultvaddr); - const bool is_write = (static_cast(ctx)->uc_mcontext->__es.__err & 2) != 0; - #elif defined(__aarch64__) - const uptr exception_address = static_cast(static_cast(ctx)->uc_mcontext->__es.__far); - const uptr exception_pc = static_cast(static_cast(ctx)->uc_mcontext->__ss.__pc); - const bool is_write = IsStoreInstruction(exception_pc); - #endif -#elif defined(__FreeBSD__) - #if defined(__x86_64__) - const uptr exception_address = static_cast(static_cast(ctx)->uc_mcontext.mc_addr); - const uptr exception_pc = static_cast(static_cast(ctx)->uc_mcontext.mc_rip); - const bool is_write = (static_cast(ctx)->uc_mcontext.mc_err & 2) != 0; - #elif defined(__aarch64__) - const uptr exception_address = static_cast(static_cast(ctx)->uc_mcontext->__es.__far); - const uptr exception_pc = static_cast(static_cast(ctx)->uc_mcontext->__ss.__pc); - const bool is_write = IsStoreInstruction(exception_pc); - #endif -#endif - - s_in_exception_handler = true; - - const bool handled = PageFaultHandler::HandlePageFault(exception_pc, exception_address, is_write); - - s_in_exception_handler = false; - - // Resumes execution right where we left off (re-executes instruction that caused the SIGSEGV). - if (handled) - return; - - // Call old signal handler, which will likely dump core. - lock.unlock(); - CallExistingSignalHandler(signal, info, ctx); -} - -bool PageFaultHandler::Install(Error* error) -{ - std::unique_lock lock(s_exception_handler_mutex); - pxAssertRel(!s_exception_handler_installed, "Page fault handler has already been installed."); - - struct sigaction sa; - - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_SIGINFO; - sa.sa_sigaction = SysPageFaultSignalFilter; -#ifdef __linux__ - // Don't block the signal from executing recursively, we want to fire the original handler. - sa.sa_flags |= SA_NODEFER; -#endif -#if defined(__APPLE__) || defined(__aarch64__) - // MacOS uses SIGBUS for memory permission violations, as well as SIGSEGV on ARM64. - if (sigaction(SIGBUS, &sa, &s_old_sigbus_action) != 0) - { - Error::SetErrno(error, "sigaction() for SIGSEGV failed: ", errno); - return false; - } -#endif -#if !defined(__APPLE__) || defined(__aarch64__) - if (sigaction(SIGSEGV, &sa, &s_old_sigsegv_action) != 0) - { - Error::SetErrno(error, "sigaction() for SIGBUS failed: ", errno); - return false; - } -#endif -#if defined(__APPLE__) && defined(__aarch64__) - // Stops LLDB getting in a EXC_BAD_ACCESS loop when passing page faults to PCSX2. - task_set_exception_ports(mach_task_self(), EXC_MASK_BAD_ACCESS, MACH_PORT_NULL, EXCEPTION_DEFAULT, 0); -#endif - - s_exception_handler_installed = true; - return true; -} - -#ifndef __APPLE__ - static __ri uint LinuxProt(const PageProtectionMode& mode) { u32 lnxmode = 0; @@ -251,11 +52,6 @@ void* HostSys::Mmap(void* base, size_t size, const PageProtectionMode& mode) if (base) flags |= MAP_FIXED_NOREPLACE; -#if defined(__APPLE__) && defined(_M_ARM64) - if (mode.CanExecute()) - flags |= MAP_JIT; -#endif - void* res = mmap(base, size, prot, flags, -1, 0); if (res == MAP_FAILED) return nullptr; @@ -338,15 +134,6 @@ void HostSys::UnmapSharedMemory(void* baseaddr, size_t size) pxFailRel("Failed to unmap shared memory"); } -#ifdef _M_ARM64 - -void HostSys::FlushInstructionCache(void* address, u32 size) -{ - __builtin___clear_cache(reinterpret_cast(address), reinterpret_cast(address) + size); -} - -#endif - SharedMemoryMappingArea::SharedMemoryMappingArea(u8* base_ptr, size_t size, size_t num_pages) : m_base_ptr(base_ptr) , m_size(size) @@ -400,6 +187,137 @@ bool SharedMemoryMappingArea::Unmap(void* map_base, size_t map_size) return true; } -#endif // __APPLE__ +namespace PageFaultHandler +{ + static std::recursive_mutex s_exception_handler_mutex; + static bool s_in_exception_handler = false; + static bool s_installed = false; +} // namespace PageFaultHandler + +#ifdef _M_ARM64 + +void HostSys::FlushInstructionCache(void* address, u32 size) +{ + __builtin___clear_cache(reinterpret_cast(address), reinterpret_cast(address) + size); +} + +[[maybe_unused]] static bool IsStoreInstruction(const void* ptr) +{ + u32 bits; + std::memcpy(&bits, ptr, sizeof(bits)); + + // Based on vixl's disassembler Instruction::IsStore(). + // if (Mask(LoadStoreAnyFMask) != LoadStoreAnyFixed) + if ((bits & 0x0a000000) != 0x08000000) + return false; + + // if (Mask(LoadStorePairAnyFMask) == LoadStorePairAnyFixed) + if ((bits & 0x3a000000) == 0x28000000) + { + // return Mask(LoadStorePairLBit) == 0 + return (bits & (1 << 22)) == 0; + } + + switch (bits & 0xC4C00000) + { + case 0x00000000: // STRB_w + case 0x40000000: // STRH_w + case 0x80000000: // STR_w + case 0xC0000000: // STR_x + case 0x04000000: // STR_b + case 0x44000000: // STR_h + case 0x84000000: // STR_s + case 0xC4000000: // STR_d + case 0x04800000: // STR_q + return true; + + default: + return false; + } +} + +#endif // _M_ARM64 + +namespace PageFaultHandler +{ + static void SignalHandler(int sig, siginfo_t* info, void* ctx); +} // namespace PageFaultHandler + +void PageFaultHandler::SignalHandler(int sig, siginfo_t* info, void* ctx) +{ +#if defined(__linux__) + void* const exception_address = reinterpret_cast(info->si_addr); + +#if defined(_M_X86) + void* const exception_pc = reinterpret_cast(static_cast(ctx)->uc_mcontext.gregs[REG_RIP]); + const bool is_write = (static_cast(ctx)->uc_mcontext.gregs[REG_ERR] & 2) != 0; +#elif defined(_M_ARM64) + void* const exception_pc = reinterpret_cast(static_cast(ctx)->uc_mcontext.pc); + const bool is_write = IsStoreInstruction(exception_pc); +#endif + +#elif defined(__FreeBSD__) + +#if defined(_M_X86) + void* const exception_address = reinterpret_cast(static_cast(ctx)->uc_mcontext.mc_addr); + void* const exception_pc = reinterpret_cast(static_cast(ctx)->uc_mcontext.mc_rip); + const bool is_write = (static_cast(ctx)->uc_mcontext.mc_err & 2) != 0; +#elif defined(_M_ARM64) + void* const exception_address = reinterpret_cast(static_cast(ctx)->uc_mcontext->__es.__far); + void* const exception_pc = reinterpret_cast(static_cast(ctx)->uc_mcontext->__ss.__pc); + const bool is_write = IsStoreInstruction(exception_pc); +#endif #endif + + // Executing the handler concurrently from multiple threads wouldn't go down well. + s_exception_handler_mutex.lock(); + + // Prevent recursive exception filtering. + HandlerResult result = HandlerResult::ExecuteNextHandler; + if (!s_in_exception_handler) + { + s_in_exception_handler = true; + result = HandlePageFault(exception_pc, exception_address, is_write); + s_in_exception_handler = false; + } + + s_exception_handler_mutex.unlock(); + + // Resumes execution right where we left off (re-executes instruction that caused the SIGSEGV). + if (result == HandlerResult::ContinueExecution) + return; + + // We couldn't handle it. Pass it off to the crash dumper. + CrashHandler::CrashSignalHandler(sig, info, ctx); +} + +bool PageFaultHandler::Install(Error* error) +{ + std::unique_lock lock(s_exception_handler_mutex); + pxAssertRel(!s_installed, "Page fault handler has already been installed."); + + struct sigaction sa; + + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO | SA_NODEFER; + sa.sa_sigaction = SignalHandler; + + if (sigaction(SIGSEGV, &sa, nullptr) != 0) + { + Error::SetErrno(error, "sigaction() for SIGSEGV failed: ", errno); + return false; + } + +#ifdef _M_ARM64 + // We can get SIGBUS on ARM64. + if (sigaction(SIGBUS, &sa, nullptr) != 0) + { + Error::SetErrno(error, "sigaction() for SIGBUS failed: ", errno); + return false; + } +#endif + + s_installed = true; + return true; +} diff --git a/common/Linux/LnxMisc.cpp b/common/Linux/LnxMisc.cpp index 71f6f289c4..53bb460435 100644 --- a/common/Linux/LnxMisc.cpp +++ b/common/Linux/LnxMisc.cpp @@ -1,8 +1,6 @@ -// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team +// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team // SPDX-License-Identifier: LGPL-3.0+ -#if !defined(_WIN32) && !defined(__APPLE__) - #include "common/Pcsx2Types.h" #include "common/Console.h" #include "common/HostSys.h" @@ -215,5 +213,3 @@ void Threading::SleepUntil(u64 ticks) ts.tv_nsec = static_cast(ticks % 1000000000ULL); clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, nullptr); } - -#endif diff --git a/common/Linux/LnxThreads.cpp b/common/Linux/LnxThreads.cpp index bc6e719978..fb0e17e6cc 100644 --- a/common/Linux/LnxThreads.cpp +++ b/common/Linux/LnxThreads.cpp @@ -1,11 +1,13 @@ -// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team +// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team // SPDX-License-Identifier: LGPL-3.0+ -#if !defined(_WIN32) && !defined(__APPLE__) #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif +#include "common/Threading.h" +#include "common/Assertions.h" + #include #include @@ -20,20 +22,10 @@ #include #define gettid() syscall(SYS_gettid) #endif - -#elif defined(__unix__) +#else #include #endif -#include "common/Threading.h" -#include "common/Assertions.h" - -#if !defined(__unix__) - -#pragma message("LnxThreads.cpp should only be compiled by projects or makefiles targeted at Linux/BSD distros.") - -#else - // Note: assuming multicore is safer because it forces the interlocked routines to use // the LOCK prefix. The prefix works on single core CPUs fine (but is slow), but not // having the LOCK prefix is very bad indeed. @@ -354,6 +346,3 @@ void Threading::SetNameOfCurrentThread(const char* name) pthread_set_name_np(pthread_self(), name); #endif } - -#endif -#endif diff --git a/common/Semaphore.cpp b/common/Semaphore.cpp index 63f53dc25f..f26930a32a 100644 --- a/common/Semaphore.cpp +++ b/common/Semaphore.cpp @@ -137,7 +137,7 @@ void Threading::WorkSema::Reset() m_state = STATE_RUNNING_0; } -#if !defined(__APPLE__) // macOS implementations are in DarwinSemaphore +#if !defined(__APPLE__) // macOS implementations are in DarwinThreads Threading::KernelSemaphore::KernelSemaphore() { diff --git a/common/Windows/WinHostSys.cpp b/common/Windows/WinHostSys.cpp index 23eea6cbcb..978a97782f 100644 --- a/common/Windows/WinHostSys.cpp +++ b/common/Windows/WinHostSys.cpp @@ -1,8 +1,6 @@ // SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team // SPDX-License-Identifier: LGPL-3.0+ -#if defined(_WIN32) - #include "common/HostSys.h" #include "common/AlignedMalloc.h" #include "common/Assertions.h" @@ -17,57 +15,6 @@ #include -static std::recursive_mutex s_exception_handler_mutex; -static bool s_in_exception_handler = false; -static bool s_exception_handler_installed = false; - -long __stdcall SysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps) -{ - // Executing the handler concurrently from multiple threads wouldn't go down well. - std::unique_lock lock(s_exception_handler_mutex); - - // Prevent recursive exception filtering. - if (s_in_exception_handler) - return EXCEPTION_CONTINUE_SEARCH; - - // Only interested in page faults. - if (eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION) - return EXCEPTION_CONTINUE_SEARCH; - -#if defined(_M_AMD64) - const uptr exception_pc = static_cast(eps->ContextRecord->Rip); -#elif defined(_M_ARM64) - const uptr exception_pc = static_cast(eps->ContextRecord->Pc); -#endif - - const uptr exception_addr = static_cast(eps->ExceptionRecord->ExceptionInformation[1]); - const bool is_write = (eps->ExceptionRecord->ExceptionInformation[0] == 1); - - s_in_exception_handler = true; - - const bool handled = PageFaultHandler::HandlePageFault(exception_pc, exception_addr, is_write); - - s_in_exception_handler = false; - - return handled ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH; -} - -bool PageFaultHandler::Install(Error* error) -{ - std::unique_lock lock(s_exception_handler_mutex); - pxAssertRel(!s_exception_handler_installed, "Page fault handler has already been installed."); - - PVOID handle = AddVectoredExceptionHandler(1, SysPageFaultExceptionFilter); - if (!handle) - { - Error::SetWin32(error, "AddVectoredExceptionHandler() failed: ", GetLastError()); - return false; - } - - s_exception_handler_installed = true; - return true; -} - static DWORD ConvertToWinApi(const PageProtectionMode& mode) { DWORD winmode = PAGE_NOACCESS; @@ -309,7 +256,7 @@ bool SharedMemoryMappingArea::Unmap(void* map_base, size_t map_size) // combine placeholders before and the range we're unmapping, i.e. to the left if (!VirtualFreeEx(GetCurrentProcess(), OffsetPointer(left_it->first), - left_it->second - left_it->first, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS)) + left_it->second - left_it->first, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS)) { pxFail("Failed to coalesce placeholders left for unmap"); } @@ -341,4 +288,60 @@ bool SharedMemoryMappingArea::Unmap(void* map_base, size_t map_size) return true; } +namespace PageFaultHandler +{ + static LONG ExceptionHandler(PEXCEPTION_POINTERS exi); + + static std::recursive_mutex s_exception_handler_mutex; + static bool s_in_exception_handler = false; + static bool s_installed = false; +} // namespace PageFaultHandler + +LONG PageFaultHandler::ExceptionHandler(PEXCEPTION_POINTERS exi) +{ + // Executing the handler concurrently from multiple threads wouldn't go down well. + std::unique_lock lock(s_exception_handler_mutex); + + // Prevent recursive exception filtering. + if (s_in_exception_handler) + return EXCEPTION_CONTINUE_SEARCH; + + // Only interested in page faults. + if (exi->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION) + return EXCEPTION_CONTINUE_SEARCH; + +#if defined(_M_X86) + void* const exception_pc = reinterpret_cast(exi->ContextRecord->Rip); +#elif defined(_M_ARM64) + void* const exception_pc = reinterpret_cast(exi->ContextRecord->Pc); +#else + void* const exception_pc = nullptr; #endif + + void* const exception_address = reinterpret_cast(exi->ExceptionRecord->ExceptionInformation[1]); + const bool is_write = exi->ExceptionRecord->ExceptionInformation[0] == 1; + + s_in_exception_handler = true; + + const HandlerResult handled = HandlePageFault(exception_pc, exception_address, is_write); + + s_in_exception_handler = false; + + return (handled == HandlerResult::ContinueExecution) ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH; +} + +bool PageFaultHandler::Install(Error* error) +{ + std::unique_lock lock(s_exception_handler_mutex); + pxAssertRel(!s_installed, "Page fault handler has already been installed."); + + PVOID handle = AddVectoredExceptionHandler(1, ExceptionHandler); + if (!handle) + { + Error::SetWin32(error, "AddVectoredExceptionHandler() failed: ", GetLastError()); + return false; + } + + s_installed = true; + return true; +} diff --git a/common/Windows/WinMisc.cpp b/common/Windows/WinMisc.cpp index 3abb505e85..c2e5434073 100644 --- a/common/Windows/WinMisc.cpp +++ b/common/Windows/WinMisc.cpp @@ -1,8 +1,6 @@ -// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team +// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team // SPDX-License-Identifier: LGPL-3.0+ -#if defined(_WIN32) - #include "common/FileSystem.h" #include "common/HostSys.h" #include "common/RedtapeWindows.h" @@ -126,4 +124,3 @@ void Threading::SleepUntil(u64 ticks) } } -#endif diff --git a/common/Windows/WinThreads.cpp b/common/Windows/WinThreads.cpp index b4b02f9526..2e87794792 100644 --- a/common/Windows/WinThreads.cpp +++ b/common/Windows/WinThreads.cpp @@ -1,8 +1,6 @@ // SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team // SPDX-License-Identifier: LGPL-3.0+ -#if defined(_WIN32) - #include "common/Threading.h" #include "common/Assertions.h" #include "common/RedtapeWindows.h" @@ -265,5 +263,3 @@ void Threading::SetNameOfCurrentThread(const char* name) } #endif } - -#endif diff --git a/common/common.vcxproj b/common/common.vcxproj index 655ae626f2..0523a89d2a 100644 --- a/common/common.vcxproj +++ b/common/common.vcxproj @@ -74,9 +74,6 @@ Create - - - diff --git a/common/common.vcxproj.filters b/common/common.vcxproj.filters index 42869b1c19..4b04b516c0 100644 --- a/common/common.vcxproj.filters +++ b/common/common.vcxproj.filters @@ -28,15 +28,6 @@ Source Files - - Source Files - - - Source Files - - - Source Files - Source Files diff --git a/pcsx2/vtlb.cpp b/pcsx2/vtlb.cpp index 82def73c52..32569ff8b2 100644 --- a/pcsx2/vtlb.cpp +++ b/pcsx2/vtlb.cpp @@ -1454,12 +1454,12 @@ static __fi void mmap_ClearCpuBlock(uint offset) Cpu->Clear(m_PageProtectInfo[rampage].ReverseRamMap, __pagesize); } -bool PageFaultHandler::HandlePageFault(uptr pc, uptr addr, bool is_write) +PageFaultHandler::HandlerResult PageFaultHandler::HandlePageFault(void* exception_pc, void* fault_address, bool is_write) { pxAssert(eeMem); u32 vaddr; - if (CHECK_FASTMEM && vtlb_GetGuestAddress(addr, &vaddr)) + if (CHECK_FASTMEM && vtlb_GetGuestAddress(reinterpret_cast(fault_address), &vaddr)) { // this was inside the fastmem area. check if it's a code page // fprintf(stderr, "Fault on fastmem %p vaddr %08X\n", info.addr, vaddr); @@ -1470,23 +1470,26 @@ bool PageFaultHandler::HandlePageFault(uptr pc, uptr addr, bool is_write) { // fprintf(stderr, "Not backpatching code write at %08X\n", vaddr); mmap_ClearCpuBlock(offset); - return true; + return HandlerResult::ContinueExecution; } else { // fprintf(stderr, "Trying backpatching vaddr %08X\n", vaddr); - return vtlb_BackpatchLoadStore(pc, addr); + return vtlb_BackpatchLoadStore(reinterpret_cast(exception_pc), + reinterpret_cast(fault_address)) ? + HandlerResult::ContinueExecution : + HandlerResult::ExecuteNextHandler; } } else { // get bad virtual address - uptr offset = addr - (uptr)eeMem->Main; + uptr offset = reinterpret_cast(fault_address) - reinterpret_cast(eeMem->Main); if (offset >= Ps2MemSize::ExposedRam) - return false; + return HandlerResult::ExecuteNextHandler; mmap_ClearCpuBlock(offset); - return true; + return HandlerResult::ContinueExecution; } }