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.
This commit is contained in:
comex 2013-09-24 01:38:27 -04:00
parent 4cdce55615
commit 29dc253fde
5 changed files with 225 additions and 102 deletions

View File

@ -81,11 +81,9 @@ void sigsegv_handler(int signal, siginfo_t *info, void *raw_context)
u32 em_address = (u32)(bad_address - memspace_bottom); u32 em_address = (u32)(bad_address - memspace_bottom);
CONTEXT fake_ctx; const u8 *new_rip = jit->BackPatch(fault_instruction_ptr, em_address, ctx);
fake_ctx.reg_pc = ctx->arm_pc;
const u8 *new_rip = jit->BackPatch(fault_instruction_ptr, em_address, &fake_ctx);
if (new_rip) { if (new_rip) {
ctx->arm_pc = fake_ctx.reg_pc; ctx->arm_pc = (u32) new_rip;
} }
} }

View File

@ -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) const u8 *JitArm::BackPatch(u8 *codePtr, u32, void *ctx_void)
{ {
// TODO: This ctx needs to be filled with our information // 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 // We need to get the destination register before we start
u32 Value = *(u32*)codePtr; u32 Value = *(u32*)codePtr;
@ -90,7 +90,7 @@ const u8 *JitArm::BackPatch(u8 *codePtr, u32, void *ctx_void)
if (!DisamLoadStore(Value, rD, accessSize, Store)) 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); exit(0);
} }
@ -117,8 +117,8 @@ const u8 *JitArm::BackPatch(u8 *codePtr, u32, void *ctx_void)
emitter.MOV(R1, R10); // Addr- 5 emitter.MOV(R1, R10); // Addr- 5
emitter.BL(R14); // 6 emitter.BL(R14); // 6
emitter.POP(4, R0, R1, R2, R3); // 7 emitter.POP(4, R0, R1, R2, R3); // 7
u32 newPC = ctx->reg_pc - (ARMREGOFFSET + 4 * 4); u32 newPC = ctx->CTX_PC - (ARMREGOFFSET + 4 * 4);
ctx->reg_pc = newPC; ctx->CTX_PC = newPC;
emitter.FlushIcache(); emitter.FlushIcache();
return codePtr; return codePtr;
} }
@ -144,7 +144,7 @@ const u8 *JitArm::BackPatch(u8 *codePtr, u32, void *ctx_void)
emitter.MOV(R14, R0); // 6 emitter.MOV(R14, R0); // 6
emitter.POP(4, R0, R1, R2, R3); // 7 emitter.POP(4, R0, R1, R2, R3); // 7
emitter.MOV(rD, R14); // 8 emitter.MOV(rD, R14); // 8
ctx->reg_pc -= ARMREGOFFSET + (4 * 4); ctx->CTX_PC -= ARMREGOFFSET + (4 * 4);
emitter.FlushIcache(); emitter.FlushIcache();
return codePtr; return codePtr;
} }

View File

@ -163,7 +163,7 @@ const u8 *TrampolineCache::GetWriteTrampoline(const InstructionInfo &info)
const u8 *Jitx86Base::BackPatch(u8 *codePtr, u32 emAddress, void *ctx_void) const u8 *Jitx86Base::BackPatch(u8 *codePtr, u32 emAddress, void *ctx_void)
{ {
#ifdef _M_X64 #ifdef _M_X64
CONTEXT *ctx = (CONTEXT *)ctx_void; SContext *ctx = (SContext *)ctx_void;
if (!jit->IsInCodeSpace(codePtr)) if (!jit->IsInCodeSpace(codePtr))
return 0; // this will become a regular crash real soon after this 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) if (info.instructionSize < 3)
PanicAlert("Instruction too small"); PanicAlert("Instruction too small");
// We entered here with a BSWAP-ed EAX. We'll have to swap it back. // 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 codePtr - 2;
} }
return 0; return 0;

View File

@ -10,38 +10,220 @@
#include "x64Analyzer.h" #include "x64Analyzer.h"
#include "Thunk.h" #include "Thunk.h"
// Declarations and definitions // meh.
// ---------- #if defined(_WIN32)
#include <windows.h>
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
#error No context definition for OS
#endif
#elif defined(__APPLE__)
#include <mach/mach.h>
#include <mach/message.h>
#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 <signal.h>
#if defined(_M_X64)
#include <ucontext.h>
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 <ucontext.h>
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 <ucontext.h>
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 <ucontext.h>
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
// void Jit(u32 em_address); #if defined(_M_X64)
#define CTX_PC CTX_RIP
#ifndef _WIN32 #include <stddef.h>
static inline u64 *ContextRN(SContext* ctx, int n)
// 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 static const u8 offsets[] =
u32 reg_pc; {
#else offsetof(SContext, CTX_RAX),
#ifdef _M_X64 offsetof(SContext, CTX_RCX),
u64 Rip; offsetof(SContext, CTX_RDX),
u64 Rax; offsetof(SContext, CTX_RBX),
#else offsetof(SContext, CTX_RSP),
u32 Eip; offsetof(SContext, CTX_RBP),
u32 Eax; offsetof(SContext, CTX_RSI),
#endif offsetof(SContext, CTX_RDI),
#endif 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]);
#endif }
#elif defined(_M_IX86)
#if defined(_M_ARM) #define CTX_PC CTX_EIP
#define CONTEXT_PC(ctx) ((ctx)->reg_pc)
#elif defined(_M_X64)
#define CONTEXT_PC(ctx) ((ctx)->Rip)
#else
#define CONTEXT_PC(ctx) ((ctx)->Eip)
#endif #endif
class TrampolineCache : public Gen::XCodeBlock class TrampolineCache : public Gen::XCodeBlock

View File

@ -2,44 +2,11 @@
// Licensed under GPLv2 // Licensed under GPLv2
// Refer to the license.txt file included. // Refer to the license.txt file included.
#ifdef _WIN32
#include <windows.h>
#else
#include <stdio.h> #include <stdio.h>
#include <signal.h>
#ifndef ANDROID
#include <sys/ucontext.h> // Look in here for the context definition.
#endif
#endif
#ifdef __APPLE__ #ifdef __APPLE__
#include <mach/mach.h>
#include <mach/message.h>
#include "Thread.h" #include "Thread.h"
#endif #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 <vector> #include <vector>
#include "Common.h" #include "Common.h"
@ -73,9 +40,9 @@ void print_trace(const char * msg)
} }
#endif #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. // Let's not prevent debugging.
return false; return false;
@ -93,10 +60,10 @@ bool DoFault(u64 bad_address, CONTEXT *ctx)
return false; return false;
} }
u32 em_address = (u32)(bad_address - memspace_bottom); 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) if (new_pc)
{ {
CONTEXT_PC(ctx) = (u64) new_pc; ctx->CTX_PC = (u64) new_pc;
} }
return true; 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; 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); bool ok = DoFault(msg_in.code[1], state);
state->__rax = fake_ctx.Rax;
state->__rip = fake_ctx.Rip;
// Set up the reply. // Set up the reply.
msg_out.Head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(msg_in.Head.msgh_bits), 0); 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. // Get all the information we can out of the context.
mcontext_t *ctx = &context->uc_mcontext; 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 // assume it's not a write
if (DoFault(bad_address, &fake_ctx)) if (!DoFault(bad_address, 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
{ {
// retry and crash // retry and crash
signal(SIGSEGV, SIG_DFL); signal(SIGSEGV, SIG_DFL);