commit
4af98d63bc
|
@ -36,7 +36,7 @@
|
||||||
#else
|
#else
|
||||||
#error No context definition for OS
|
#error No context definition for OS
|
||||||
#endif
|
#endif
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__) && !defined(USE_SIGACTION_ON_APPLE)
|
||||||
#include <mach/mach.h>
|
#include <mach/mach.h>
|
||||||
#include <mach/message.h>
|
#include <mach/message.h>
|
||||||
#if _M_X86_64
|
#if _M_X86_64
|
||||||
|
@ -61,6 +61,26 @@
|
||||||
#else
|
#else
|
||||||
#error No context definition for OS
|
#error No context definition for OS
|
||||||
#endif
|
#endif
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
#include <signal.h>
|
||||||
|
typedef _STRUCT_MCONTEXT64 SContext;
|
||||||
|
#define CTX_RAX __ss.__rax
|
||||||
|
#define CTX_RBX __ss.__rbx
|
||||||
|
#define CTX_RCX __ss.__rcx
|
||||||
|
#define CTX_RDX __ss.__rdx
|
||||||
|
#define CTX_RDI __ss.__rdi
|
||||||
|
#define CTX_RSI __ss.__rsi
|
||||||
|
#define CTX_RBP __ss.__rbp
|
||||||
|
#define CTX_RSP __ss.__rsp
|
||||||
|
#define CTX_R8 __ss.__r8
|
||||||
|
#define CTX_R9 __ss.__r9
|
||||||
|
#define CTX_R10 __ss.__r10
|
||||||
|
#define CTX_R11 __ss.__r11
|
||||||
|
#define CTX_R12 __ss.__r12
|
||||||
|
#define CTX_R13 __ss.__r13
|
||||||
|
#define CTX_R14 __ss.__r14
|
||||||
|
#define CTX_R15 __ss.__r15
|
||||||
|
#define CTX_RIP __ss.__rip
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#if _M_X86_64
|
#if _M_X86_64
|
||||||
|
|
|
@ -5,12 +5,9 @@
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
#include "Common/Thread.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "Common/CommonFuncs.h"
|
#include "Common/CommonFuncs.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Thread.h"
|
||||||
#include "Common/x64Analyzer.h"
|
#include "Common/x64Analyzer.h"
|
||||||
|
|
||||||
#include "Core/MemTools.h"
|
#include "Core/MemTools.h"
|
||||||
|
@ -92,7 +89,7 @@ void InstallExceptionHandler()
|
||||||
|
|
||||||
void UninstallExceptionHandler() {}
|
void UninstallExceptionHandler() {}
|
||||||
|
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__) && !defined(USE_SIGACTION_ON_APPLE)
|
||||||
|
|
||||||
void CheckKR(const char* name, kern_return_t kr)
|
void CheckKR(const char* name, kern_return_t kr)
|
||||||
{
|
{
|
||||||
|
@ -216,7 +213,7 @@ void UninstallExceptionHandler() {}
|
||||||
|
|
||||||
static void sigsegv_handler(int sig, siginfo_t *info, void *raw_context)
|
static void sigsegv_handler(int sig, siginfo_t *info, void *raw_context)
|
||||||
{
|
{
|
||||||
if (sig != SIGSEGV)
|
if (sig != SIGSEGV && sig != SIGBUS)
|
||||||
{
|
{
|
||||||
// We are not interested in other signals - handle it as usual.
|
// We are not interested in other signals - handle it as usual.
|
||||||
return;
|
return;
|
||||||
|
@ -233,10 +230,19 @@ static void sigsegv_handler(int sig, siginfo_t *info, void *raw_context)
|
||||||
// Get all the information we can out of the context.
|
// Get all the information we can out of the context.
|
||||||
mcontext_t *ctx = &context->uc_mcontext;
|
mcontext_t *ctx = &context->uc_mcontext;
|
||||||
// assume it's not a write
|
// assume it's not a write
|
||||||
if (!JitInterface::HandleFault(bad_address, ctx))
|
if (!JitInterface::HandleFault(bad_address,
|
||||||
|
#ifdef __APPLE__
|
||||||
|
*ctx
|
||||||
|
#else
|
||||||
|
ctx
|
||||||
|
#endif
|
||||||
|
))
|
||||||
{
|
{
|
||||||
// retry and crash
|
// retry and crash
|
||||||
signal(SIGSEGV, SIG_DFL);
|
signal(SIGSEGV, SIG_DFL);
|
||||||
|
#ifdef __APPLE__
|
||||||
|
signal(SIGBUS, SIG_DFL);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,6 +260,9 @@ void InstallExceptionHandler()
|
||||||
sa.sa_flags = SA_SIGINFO;
|
sa.sa_flags = SA_SIGINFO;
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
sigaction(SIGSEGV, &sa, nullptr);
|
sigaction(SIGSEGV, &sa, nullptr);
|
||||||
|
#ifdef __APPLE__
|
||||||
|
sigaction(SIGBUS, &sa, nullptr);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void UninstallExceptionHandler()
|
void UninstallExceptionHandler()
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
add_dolphin_test(MMIOTest MMIOTest.cpp)
|
add_dolphin_test(MMIOTest MMIOTest.cpp)
|
||||||
|
add_dolphin_test(PageFaultTest PageFaultTest.cpp)
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Timer.h"
|
||||||
|
#include "Core/MemTools.h"
|
||||||
|
#include "Core/PowerPC/JitCommon/JitBase.h"
|
||||||
|
|
||||||
|
// include order is important
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#if _M_X86_64 || _M_ARM_32
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
PAGE_GRAN = 0x10000
|
||||||
|
#else
|
||||||
|
PAGE_GRAN = 0x1000
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
class PageFaultFakeJit : public JitBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// CPUCoreBase methods
|
||||||
|
void Init() override {}
|
||||||
|
void Shutdown() override {}
|
||||||
|
void ClearCache() override {}
|
||||||
|
void Run() override {}
|
||||||
|
void SingleStep() override {}
|
||||||
|
const char *GetName() override { return nullptr; }
|
||||||
|
|
||||||
|
// JitBase methods
|
||||||
|
JitBaseBlockCache *GetBlockCache() override { return nullptr; }
|
||||||
|
void Jit(u32 em_address) override {}
|
||||||
|
const CommonAsmRoutinesBase *GetAsmRoutines() override { return nullptr; }
|
||||||
|
|
||||||
|
virtual bool HandleFault(uintptr_t access_address, SContext* ctx) override
|
||||||
|
{
|
||||||
|
m_pre_unprotect_time = std::chrono::high_resolution_clock::now();
|
||||||
|
UnWriteProtectMemory(m_data, PAGE_GRAN, /*allowExecute*/ false);
|
||||||
|
m_post_unprotect_time = std::chrono::high_resolution_clock::now();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* m_data;
|
||||||
|
std::chrono::time_point<std::chrono::high_resolution_clock>
|
||||||
|
m_pre_unprotect_time, m_post_unprotect_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TEST(PageFault, PageFault)
|
||||||
|
{
|
||||||
|
EMM::InstallExceptionHandler();
|
||||||
|
void* data = AllocateMemoryPages(PAGE_GRAN);
|
||||||
|
EXPECT_NE(data, nullptr);
|
||||||
|
WriteProtectMemory(data, PAGE_GRAN, false);
|
||||||
|
|
||||||
|
PageFaultFakeJit pfjit;
|
||||||
|
jit = &pfjit;
|
||||||
|
pfjit.m_data = data;
|
||||||
|
|
||||||
|
auto start = std::chrono::high_resolution_clock::now();
|
||||||
|
*(volatile int*) data = 5;
|
||||||
|
auto end = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
#define AS_NS(diff) ((unsigned long long)std::chrono::duration_cast<std::chrono::nanoseconds>(diff).count())
|
||||||
|
|
||||||
|
EMM::UninstallExceptionHandler();
|
||||||
|
jit = nullptr;
|
||||||
|
|
||||||
|
printf("page fault timing:\n");
|
||||||
|
printf("start->HandleFault %llu ns\n", AS_NS(pfjit.m_pre_unprotect_time - start));
|
||||||
|
printf("UnWriteProtectMemory %llu ns\n", AS_NS(pfjit.m_post_unprotect_time - pfjit.m_pre_unprotect_time));
|
||||||
|
printf("HandleFault->end %llu ns\n", AS_NS(end - pfjit.m_post_unprotect_time));
|
||||||
|
printf("total %llu ns\n", AS_NS(end - start));
|
||||||
|
}
|
||||||
|
#endif
|
Loading…
Reference in New Issue