From 29dc253fde386b7d1186f85ca43569cc73795b6e Mon Sep 17 00:00:00 2001 From: comex Date: Tue, 24 Sep 2013 01:38:27 -0400 Subject: [PATCH] Improve context structure handling on non-Windows. Instead of copying data into and out of a fake CONTEXT structure with only a few entries, use the platform specific structure directly with a typedef and macros. This is needed because fastmem writes need to be able to access any register from BackPatch. It adds a fair number of repetitive defines, but it's better than the alternative. --- Source/Core/Core/Src/ArmMemTools.cpp | 6 +- .../Src/PowerPC/JitArm32/JitArm_BackPatch.cpp | 10 +- .../Src/PowerPC/JitCommon/JitBackpatch.cpp | 4 +- .../Core/Src/PowerPC/JitCommon/JitBackpatch.h | 238 +++++++++++++++--- Source/Core/Core/Src/x64MemTools.cpp | 69 +---- 5 files changed, 225 insertions(+), 102 deletions(-) diff --git a/Source/Core/Core/Src/ArmMemTools.cpp b/Source/Core/Core/Src/ArmMemTools.cpp index 01e63a6a42..d2c003060f 100644 --- a/Source/Core/Core/Src/ArmMemTools.cpp +++ b/Source/Core/Core/Src/ArmMemTools.cpp @@ -81,11 +81,9 @@ void sigsegv_handler(int signal, siginfo_t *info, void *raw_context) u32 em_address = (u32)(bad_address - memspace_bottom); - CONTEXT fake_ctx; - fake_ctx.reg_pc = ctx->arm_pc; - const u8 *new_rip = jit->BackPatch(fault_instruction_ptr, em_address, &fake_ctx); + const u8 *new_rip = jit->BackPatch(fault_instruction_ptr, em_address, ctx); if (new_rip) { - ctx->arm_pc = fake_ctx.reg_pc; + ctx->arm_pc = (u32) new_rip; } } diff --git a/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_BackPatch.cpp b/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_BackPatch.cpp index d051dae726..465e1fac1e 100644 --- a/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_BackPatch.cpp +++ b/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_BackPatch.cpp @@ -80,7 +80,7 @@ bool DisamLoadStore(const u32 inst, ARMReg &rD, u8 &accessSize, bool &Store) const u8 *JitArm::BackPatch(u8 *codePtr, u32, void *ctx_void) { // TODO: This ctx needs to be filled with our information - CONTEXT *ctx = (CONTEXT *)ctx_void; + SContext *ctx = (SContext *)ctx_void; // We need to get the destination register before we start u32 Value = *(u32*)codePtr; @@ -90,7 +90,7 @@ const u8 *JitArm::BackPatch(u8 *codePtr, u32, void *ctx_void) if (!DisamLoadStore(Value, rD, accessSize, Store)) { - printf("Invalid backpatch at location 0x%08x(0x%08x)\n", ctx->reg_pc, Value); + printf("Invalid backpatch at location 0x%08x(0x%08x)\n", ctx->CTX_PC, Value); exit(0); } @@ -117,8 +117,8 @@ const u8 *JitArm::BackPatch(u8 *codePtr, u32, void *ctx_void) emitter.MOV(R1, R10); // Addr- 5 emitter.BL(R14); // 6 emitter.POP(4, R0, R1, R2, R3); // 7 - u32 newPC = ctx->reg_pc - (ARMREGOFFSET + 4 * 4); - ctx->reg_pc = newPC; + u32 newPC = ctx->CTX_PC - (ARMREGOFFSET + 4 * 4); + ctx->CTX_PC = newPC; emitter.FlushIcache(); return codePtr; } @@ -144,7 +144,7 @@ const u8 *JitArm::BackPatch(u8 *codePtr, u32, void *ctx_void) emitter.MOV(R14, R0); // 6 emitter.POP(4, R0, R1, R2, R3); // 7 emitter.MOV(rD, R14); // 8 - ctx->reg_pc -= ARMREGOFFSET + (4 * 4); + ctx->CTX_PC -= ARMREGOFFSET + (4 * 4); emitter.FlushIcache(); return codePtr; } diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitBackpatch.cpp b/Source/Core/Core/Src/PowerPC/JitCommon/JitBackpatch.cpp index 506435284e..57a2f002ff 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/JitBackpatch.cpp +++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitBackpatch.cpp @@ -163,7 +163,7 @@ const u8 *TrampolineCache::GetWriteTrampoline(const InstructionInfo &info) const u8 *Jitx86Base::BackPatch(u8 *codePtr, u32 emAddress, void *ctx_void) { #ifdef _M_X64 - CONTEXT *ctx = (CONTEXT *)ctx_void; + SContext *ctx = (SContext *)ctx_void; if (!jit->IsInCodeSpace(codePtr)) return 0; // this will become a regular crash real soon after this @@ -206,7 +206,7 @@ const u8 *Jitx86Base::BackPatch(u8 *codePtr, u32 emAddress, void *ctx_void) if (info.instructionSize < 3) PanicAlert("Instruction too small"); // We entered here with a BSWAP-ed EAX. We'll have to swap it back. - ctx->Rax = Common::swap32((u32)ctx->Rax); + ctx->CTX_RAX = Common::swap32((u32)ctx->CTX_RAX); return codePtr - 2; } return 0; diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitBackpatch.h b/Source/Core/Core/Src/PowerPC/JitCommon/JitBackpatch.h index a8f204b1e1..5c44f844a9 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/JitBackpatch.h +++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitBackpatch.h @@ -10,38 +10,220 @@ #include "x64Analyzer.h" #include "Thunk.h" -// Declarations and definitions -// ---------- - -// void Jit(u32 em_address); - -#ifndef _WIN32 - - // A bit of a hack to get things building under linux. We manually fill in this structure as needed - // from the real context. - struct CONTEXT - { - #ifdef _M_ARM - u32 reg_pc; +// meh. +#if defined(_WIN32) + #include + typedef CONTEXT SContext; + #if defined(_M_X64) + #define CTX_RAX Rax + #define CTX_RBX Rbx + #define CTX_RCX Rcx + #define CTX_RDX Rdx + #define CTX_RDI Rdi + #define CTX_RSI Rsi + #define CTX_RBP Rbp + #define CTX_RSP Rsp + #define CTX_R8 R8 + #define CTX_R9 R9 + #define CTX_R10 R10 + #define CTX_R11 R11 + #define CTX_R12 R12 + #define CTX_R13 R13 + #define CTX_R14 R14 + #define CTX_R15 R15 + #define CTX_RIP Rip + #elif defined(_M_IX86) + #define CTX_EAX Eax + #define CTX_EBX Ebx + #define CTX_ECX Ecx + #define CTX_EDX Edx + #define CTX_EDI Edi + #define CTX_ESI Esi + #define CTX_EBP Ebp + #define CTX_ESP Esp + #define CTX_EIP Eip #else - #ifdef _M_X64 - u64 Rip; - u64 Rax; - #else - u32 Eip; - u32 Eax; - #endif + #error No context definition for OS + #endif +#elif defined(__APPLE__) + #include + #include + #if defined(_M_X64) + typedef x86_thread_state64_t SContext; + #define CTX_RAX __rax + #define CTX_RBX __rbx + #define CTX_RCX __rcx + #define CTX_RDX __rdx + #define CTX_RDI __rdi + #define CTX_RSI __rsi + #define CTX_RBP __rbp + #define CTX_RSP __rsp + #define CTX_R8 __r8 + #define CTX_R9 __r9 + #define CTX_R10 __r10 + #define CTX_R11 __r11 + #define CTX_R12 __r12 + #define CTX_R13 __r13 + #define CTX_R14 __r14 + #define CTX_R15 __r15 + #define CTX_RIP __rip + #elif defined(_M_IX86) + typedef x86_thread_state_t SContext; + #define CTX_EAX __eax + #define CTX_EBX __ebx + #define CTX_ECX __ecx + #define CTX_EDX __edx + #define CTX_EDI __edi + #define CTX_ESI __esi + #define CTX_EBP __ebp + #define CTX_ESP __esp + #define CTX_EIP __eip + #elif defined(_M_ARM) + typedef arm_thread_state_t SContext; + // Add others if required. + #define CTX_PC __pc + #else + #error No context definition for OS + #endif +#elif defined(__linux__) + #include + #if defined(_M_X64) + #include + typedef mcontext_t SContext; + #define CTX_RAX gregs[REG_RAX] + #define CTX_RBX gregs[REG_RBX] + #define CTX_RCX gregs[REG_RCX] + #define CTX_RDX gregs[REG_RDX] + #define CTX_RDI gregs[REG_RDI] + #define CTX_RSI gregs[REG_RSI] + #define CTX_RBP gregs[REG_RBP] + #define CTX_RSP gregs[REG_RSP] + #define CTX_R8 gregs[REG_R8] + #define CTX_R9 gregs[REG_R9] + #define CTX_R10 gregs[REG_R10] + #define CTX_R11 gregs[REG_R11] + #define CTX_R12 gregs[REG_R12] + #define CTX_R13 gregs[REG_R13] + #define CTX_R14 gregs[REG_R14] + #define CTX_R15 gregs[REG_R15] + #define CTX_RIP gregs[REG_RIP] + #elif defined(_M_IX86) + #include + typedef mcontext_t SContext; + #define CTX_EAX gregs[REG_EAX] + #define CTX_EBX gregs[REG_EBX] + #define CTX_ECX gregs[REG_ECX] + #define CTX_EDX gregs[REG_EDX] + #define CTX_EDI gregs[REG_EDI] + #define CTX_ESI gregs[REG_ESI] + #define CTX_EBP gregs[REG_EBP] + #define CTX_ESP gregs[REG_ESP] + #define CTX_EIP gregs[REG_EIP] + #elif defined(ANDROID) + // Add others if required. + typedef struct sigcontext SContext; + #define CTX_PC arm_pc + #else + #error No context definition for OS + #endif +#elif defined(__NetBSD__) + #include + typedef mcontext_t SContext; + #if defined(_M_X64) + #define CTX_RAX __gregs[_REG_RAX] + #define CTX_RBX __gregs[_REG_RBX] + #define CTX_RCX __gregs[_REG_RCX] + #define CTX_RDX __gregs[_REG_RDX] + #define CTX_RDI __gregs[_REG_RDI] + #define CTX_RSI __gregs[_REG_RSI] + #define CTX_RBP __gregs[_REG_RBP] + #define CTX_RSP __gregs[_REG_RSP] + #define CTX_R8 __gregs[_REG_R8] + #define CTX_R9 __gregs[_REG_R9] + #define CTX_R10 __gregs[_REG_R10] + #define CTX_R11 __gregs[_REG_R11] + #define CTX_R12 __gregs[_REG_R12] + #define CTX_R13 __gregs[_REG_R13] + #define CTX_R14 __gregs[_REG_R14] + #define CTX_R15 __gregs[_REG_R15] + #define CTX_RIP __gregs[_REG_RIP] + #elif defined(_M_IX86) + #define CTX_EAX __gregs[__REG_EAX] + #define CTX_EBX __gregs[__REG_EBX] + #define CTX_ECX __gregs[__REG_ECX] + #define CTX_EDX __gregs[__REG_EDX] + #define CTX_EDI __gregs[__REG_EDI] + #define CTX_ESI __gregs[__REG_ESI] + #define CTX_EBP __gregs[__REG_EBP] + #define CTX_ESP __gregs[__REG_ESP] + #define CTX_EIP __gregs[__REG_EIP] + #else + #error No context definition for OS + #endif +#elif defined(__FreeBSD__) + #include + typedef mcontext_t SContext; + #if defined(_M_X64) + #define CTX_RAX mc_rax + #define CTX_RBX mc_rbx + #define CTX_RCX mc_rcx + #define CTX_RDX mc_rdx + #define CTX_RDI mc_rdi + #define CTX_RSI mc_rsi + #define CTX_RBP mc_rbp + #define CTX_RSP mc_rsp + #define CTX_R8 mc_r8 + #define CTX_R9 mc_r9 + #define CTX_R10 mc_r10 + #define CTX_R11 mc_r11 + #define CTX_R12 mc_r12 + #define CTX_R13 mc_r13 + #define CTX_R14 mc_r14 + #define CTX_R15 mc_r15 + #define CTX_RIP mc_rip + #elif defined(_M_IX86) + #define CTX_EAX mc_eax + #define CTX_EBX mc_ebx + #define CTX_ECX mc_ecx + #define CTX_EDX mc_edx + #define CTX_EDI mc_edi + #define CTX_ESI mc_esi + #define CTX_EBP mc_ebp + #define CTX_ESP mc_esp + #define CTX_EIP mc_eip + #else + #error No context definition for OS #endif - }; - #endif -#if defined(_M_ARM) -#define CONTEXT_PC(ctx) ((ctx)->reg_pc) -#elif defined(_M_X64) -#define CONTEXT_PC(ctx) ((ctx)->Rip) -#else -#define CONTEXT_PC(ctx) ((ctx)->Eip) +#if defined(_M_X64) +#define CTX_PC CTX_RIP +#include +static inline u64 *ContextRN(SContext* ctx, int n) +{ + static const u8 offsets[] = + { + offsetof(SContext, CTX_RAX), + offsetof(SContext, CTX_RCX), + offsetof(SContext, CTX_RDX), + offsetof(SContext, CTX_RBX), + offsetof(SContext, CTX_RSP), + offsetof(SContext, CTX_RBP), + offsetof(SContext, CTX_RSI), + offsetof(SContext, CTX_RDI), + offsetof(SContext, CTX_R8), + offsetof(SContext, CTX_R9), + offsetof(SContext, CTX_R10), + offsetof(SContext, CTX_R11), + offsetof(SContext, CTX_R12), + offsetof(SContext, CTX_R13), + offsetof(SContext, CTX_R14), + offsetof(SContext, CTX_R15) + }; + return (u64 *) ((char *) ctx + offsets[n]); +} +#elif defined(_M_IX86) +#define CTX_PC CTX_EIP #endif class TrampolineCache : public Gen::XCodeBlock diff --git a/Source/Core/Core/Src/x64MemTools.cpp b/Source/Core/Core/Src/x64MemTools.cpp index 9d854238d5..a0c79aaed5 100644 --- a/Source/Core/Core/Src/x64MemTools.cpp +++ b/Source/Core/Core/Src/x64MemTools.cpp @@ -2,44 +2,11 @@ // Licensed under GPLv2 // Refer to the license.txt file included. -#ifdef _WIN32 -#include -#else #include -#include -#ifndef ANDROID -#include // Look in here for the context definition. -#endif -#endif - #ifdef __APPLE__ -#include -#include #include "Thread.h" #endif -#ifdef __APPLE__ -#define CREG_RAX(ctx) (*(ctx))->__ss.__rax -#define CREG_RIP(ctx) (*(ctx))->__ss.__rip -#define CREG_EAX(ctx) (*(ctx))->__ss.__eax -#define CREG_EIP(ctx) (*(ctx))->__ss.__eip -#elif defined __FreeBSD__ -#define CREG_RAX(ctx) (ctx)->mc_rax -#define CREG_RIP(ctx) (ctx)->mc_rip -#define CREG_EAX(ctx) (ctx)->mc_eax -#define CREG_EIP(ctx) (ctx)->mc_eip -#elif defined __linux__ -#define CREG_RAX(ctx) (ctx)->gregs[REG_RAX] -#define CREG_RIP(ctx) (ctx)->gregs[REG_RIP] -#define CREG_EAX(ctx) (ctx)->gregs[REG_EAX] -#define CREG_EIP(ctx) (ctx)->gregs[REG_EIP] -#elif defined __NetBSD__ -#define CREG_RAX(ctx) (ctx)->__gregs[_REG_RAX] -#define CREG_RIP(ctx) (ctx)->__gregs[_REG_RIP] -#define CREG_EAX(ctx) (ctx)->__gregs[_REG_EAX] -#define CREG_EIP(ctx) (ctx)->__gregs[_REG_EIP] -#endif - #include #include "Common.h" @@ -73,9 +40,9 @@ void print_trace(const char * msg) } #endif -bool DoFault(u64 bad_address, CONTEXT *ctx) +bool DoFault(u64 bad_address, SContext *ctx) { - if (!JitInterface::IsInCodeSpace((u8*) CONTEXT_PC(ctx))) + if (!JitInterface::IsInCodeSpace((u8*) ctx->CTX_PC)) { // Let's not prevent debugging. return false; @@ -93,10 +60,10 @@ bool DoFault(u64 bad_address, CONTEXT *ctx) return false; } u32 em_address = (u32)(bad_address - memspace_bottom); - const u8 *new_pc = jit->BackPatch((u8*) CONTEXT_PC(ctx), em_address, ctx); + const u8 *new_pc = jit->BackPatch((u8*) ctx->CTX_PC, em_address, ctx); if (new_pc) { - CONTEXT_PC(ctx) = (u64) new_pc; + ctx->CTX_PC = (u64) new_pc; } return true; @@ -244,14 +211,8 @@ void ExceptionThread(mach_port_t port) } x86_thread_state64_t *state = (x86_thread_state64_t *) msg_in.old_state; - CONTEXT fake_ctx; - fake_ctx.Rax = state->__rax; - fake_ctx.Rip = state->__rip; - bool ok = DoFault(msg_in.code[1], &fake_ctx); - - state->__rax = fake_ctx.Rax; - state->__rip = fake_ctx.Rip; + bool ok = DoFault(msg_in.code[1], state); // Set up the reply. msg_out.Head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(msg_in.Head.msgh_bits), 0); @@ -324,26 +285,8 @@ void sigsegv_handler(int sig, siginfo_t *info, void *raw_context) // Get all the information we can out of the context. mcontext_t *ctx = &context->uc_mcontext; - CONTEXT fake_ctx; -#ifdef _M_X64 - fake_ctx.Rax = CREG_RAX(ctx); - fake_ctx.Rip = CREG_RIP(ctx); -#else - fake_ctx.Eax = CREG_EAX(ctx); - fake_ctx.Eip = CREG_EIP(ctx); -#endif // assume it's not a write - if (DoFault(bad_address, &fake_ctx)) - { -#ifdef _M_X64 - CREG_RAX(ctx) = fake_ctx.Rax; - CREG_RIP(ctx) = fake_ctx.Rip; -#else - CREG_EAX(ctx) = fake_ctx.Eax; - CREG_EIP(ctx) = fake_ctx.Eip; -#endif - } - else + if (!DoFault(bad_address, ctx)) { // retry and crash signal(SIGSEGV, SIG_DFL);