From: Frode Solheim Date: Thu, 10 Sep 2015 19:25:00 +0000 (+0200) Subject: JIT: Fix and enable exception handler for x86-64 + cleaned up code a bit X-Git-Tag: 3200~70^2~11 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=f53857f0b6865dbc6bd9dbdaa91b4a327d2a689b;p=francis%2Fwinuae.git JIT: Fix and enable exception handler for x86-64 + cleaned up code a bit --- diff --git a/jit/compemu.h b/jit/compemu.h index 19f478f4..c8b95fa1 100644 --- a/jit/compemu.h +++ b/jit/compemu.h @@ -451,9 +451,7 @@ typedef struct { uae_u32 next; } regacc; -#ifndef CPU_x86_64 #define JIT_EXCEPTION_HANDLER -#endif /* ARAnyM uses fpu_register name, used in scratch_t */ /* FIXME: check that no ARAnyM code assumes different floating point type */ diff --git a/jit/compemu_support.cpp b/jit/compemu_support.cpp index 9bcef980..5053e187 100644 --- a/jit/compemu_support.cpp +++ b/jit/compemu_support.cpp @@ -3796,7 +3796,9 @@ void build_comp(void) #endif raw_init_cpu(); #ifdef NATMEM_OFFSET +#ifdef JIT_EXCEPTION_HANDLER install_exception_handler(); +#endif #endif jit_log("Building compiler function tables"); diff --git a/jit/exception_handler.cpp b/jit/exception_handler.cpp index f5c11d95..d30ecc9d 100644 --- a/jit/exception_handler.cpp +++ b/jit/exception_handler.cpp @@ -16,24 +16,19 @@ #define SIG_READ 1 #define SIG_WRITE 2 -static int in_handler=0; +static int in_handler = 0; static uae_u8 *veccode; -#ifdef _WIN32 +#if defined(JIT_DEBUG) +#define DEBUG_ACCESS +#elif defined(CPU_x86_64) +#define DEBUG_ACCESS +#endif + +#if defined(_WIN32) && defined(CPU_x86_64) typedef LPEXCEPTION_POINTERS CONTEXT_T; #define HAVE_CONTEXT_T 1 - -#define CONTEXT_EIP(context) (context->ContextRecord->Eip) -#define CONTEXT_EAX(context) (context->ContextRecord->Eax) -#define CONTEXT_ECX(context) (context->ContextRecord->Ecx) -#define CONTEXT_EDX(context) (context->ContextRecord->Edx) -#define CONTEXT_EBX(context) (context->ContextRecord->Ebx) -#define CONTEXT_ESP(context) (context->ContextRecord->Esp) -#define CONTEXT_EBP(context) (context->ContextRecord->Ebp) -#define CONTEXT_ESI(context) (context->ContextRecord->Esi) -#define CONTEXT_EDI(context) (context->ContextRecord->Edi) - #define CONTEXT_RIP(context) (context->ContextRecord->Rip) #define CONTEXT_RAX(context) (context->ContextRecord->Rax) #define CONTEXT_RCX(context) (context->ContextRecord->Rcx) @@ -44,11 +39,24 @@ typedef LPEXCEPTION_POINTERS CONTEXT_T; #define CONTEXT_RSI(context) (context->ContextRecord->Rsi) #define CONTEXT_RDI(context) (context->ContextRecord->Rdi) -#define CONTEXT_CR2(context) ((uae_u32)(context->ExceptionRecord->ExceptionInformation[1])) +#elif defined(_WIN32) && defined(CPU_i386) -#elif HAVE_STRUCT_UCONTEXT_UC_MCONTEXT_GREGS -#ifdef CPU_x86_64 +typedef LPEXCEPTION_POINTERS CONTEXT_T; +#define HAVE_CONTEXT_T 1 +#define CONTEXT_EIP(context) (context->ContextRecord->Eip) +#define CONTEXT_EAX(context) (context->ContextRecord->Eax) +#define CONTEXT_ECX(context) (context->ContextRecord->Ecx) +#define CONTEXT_EDX(context) (context->ContextRecord->Edx) +#define CONTEXT_EBX(context) (context->ContextRecord->Ebx) +#define CONTEXT_ESP(context) (context->ContextRecord->Esp) +#define CONTEXT_EBP(context) (context->ContextRecord->Ebp) +#define CONTEXT_ESI(context) (context->ContextRecord->Esi) +#define CONTEXT_EDI(context) (context->ContextRecord->Edi) +#elif defined(HAVE_STRUCT_UCONTEXT_UC_MCONTEXT_GREGS) && defined(CPU_x86_64) + +typedef void *CONTEXT_T; +#define HAVE_CONTEXT_T 1 #define CONTEXT_RIP(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_RIP]) #define CONTEXT_RAX(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_RAX]) #define CONTEXT_RCX(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_RCX]) @@ -59,11 +67,10 @@ typedef LPEXCEPTION_POINTERS CONTEXT_T; #define CONTEXT_RSI(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_RSI]) #define CONTEXT_RDI(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_RDI]) -#else +#elif defined(HAVE_STRUCT_UCONTEXT_UC_MCONTEXT_GREGS) && defined(CPU_i386) typedef void *CONTEXT_T; #define HAVE_CONTEXT_T 1 - #define CONTEXT_EIP(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_EIP]) #define CONTEXT_EAX(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_EAX]) #define CONTEXT_ECX(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_ECX]) @@ -74,12 +81,9 @@ typedef void *CONTEXT_T; #define CONTEXT_ESI(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_ESI]) #define CONTEXT_EDI(context) (((struct ucontext *) context)->uc_mcontext.gregs[REG_EDI]) -#define CONTEXT_CR2(context) (((struct ucontext *) context)->uc_mcontext.cr2) - -#endif #endif -#if defined(CPU_64_BIT) +#if defined(CPU_x86_64) #ifdef CONTEXT_RIP #define CONTEXT_PC(context) CONTEXT_RIP(context) #endif @@ -89,14 +93,36 @@ typedef void *CONTEXT_T; #endif #endif +/* FIXME: replace usage with bswap16, move fallback defition to header */ static inline uae_u16 swap16(uae_u16 x) { - return ((x&0xff00)>>8)|((x&0x00ff)<<8); + return ((x & 0xff00) >> 8) | ((x & 0x00ff) << 8); } +/* FIXME: replace usage with bswap32, move fallback defition to header */ static inline uae_u32 swap32(uae_u32 x) { - return ((x&0xff00)<<8)|((x&0x00ff)<<24)|((x&0xff0000)>>8)|((x&0xff000000)>>24); + return ((x & 0x0000ff00) << 8) | ((x & 0x00ff0000) << 24) | + ((x & 0x00ff0000) >> 8) | ((x & 0xff000000) >> 24); +} + +static int delete_trigger(blockinfo *bi, void *pc) +{ + while (bi) { + if (bi->handler && (uae_u8*)bi->direct_handler <= pc && + (uae_u8*)bi->nexthandler > pc) { +#ifdef DEBUG_ACCESS + write_log(_T("JIT: Deleted trigger (%p < %p < %p) %p\n"), + bi->handler, pc, bi->nexthandler, bi->pc_p); +#endif + invalidate_block(bi); + raise_in_cl_list(bi); + set_special(0); + return 1; + } + bi = bi->next; + } + return 0; } #ifdef HAVE_CONTEXT_T @@ -105,18 +131,22 @@ static inline uae_u32 swap32(uae_u32 x) * * Returns 1 if handled, 0 otherwise */ -static int handle_access(CONTEXT_T context) +static int handle_access(uintptr_t fault_addr, CONTEXT_T context) { - uae_u8 *i = (uae_u8 *) CONTEXT_EIP(context); - uae_u32 addr = CONTEXT_CR2(context); + uae_u8 *fault_pc = (uae_u8 *) CONTEXT_PC(context); +#ifdef CPU_64_BIT + if (fault_addr > 0xffffffff) { + return 0; + } +#endif - int r=-1; - int size=4; - int dir=-1; - int len=0; + int r = -1; + int size = 4; + int dir = -1; + int len = 0; -#ifdef JIT_DEBUG - write_log (_T("JIT: fault address is 0x%x at 0x%x\n"),addr,i); +#ifdef DEBUG_ACCESS + write_log (_T("JIT: Fault address is 0x%lx at PC=%p\n"), fault_addr, fault_pc); #endif if (!canbang || !currprefs.cachesize) return 0; @@ -124,17 +154,25 @@ static int handle_access(CONTEXT_T context) if (in_handler) write_log (_T("JIT: Argh --- Am already in a handler. Shouldn't happen!\n")); - if (canbang && i>=compiled_code && i<=current_compile_p) { - if (*i==0x66) { - i++; - size=2; + if (canbang && fault_pc >= compiled_code && fault_pc <= current_compile_p) { + uae_u8 *pc = fault_pc; +#ifdef CPU_x86_64 + if (*pc == 0x67) { + /* Skip address-size override prefix */ + pc++; + len++; + } +#endif + if (*pc == 0x66) { + pc++; + size = 2; len++; } - switch(i[0]) { + switch (pc[0]) { case 0x8a: - if ((i[1]&0xc0)==0x80) { - r=(i[1]>>3)&7; + if ((pc[1]&0xc0)==0x80) { + r=(pc[1]>>3)&7; dir=SIG_READ; size=1; len+=6; @@ -142,8 +180,8 @@ static int handle_access(CONTEXT_T context) } break; case 0x88: - if ((i[1]&0xc0)==0x80) { - r=(i[1]>>3)&7; + if ((pc[1]&0xc0)==0x80) { + r=(pc[1]>>3)&7; dir=SIG_WRITE; size=1; len+=6; @@ -151,19 +189,19 @@ static int handle_access(CONTEXT_T context) } break; case 0x8b: - switch(i[1]&0xc0) { + switch (pc[1]&0xc0) { case 0x80: - r=(i[1]>>3)&7; + r=(pc[1]>>3)&7; dir=SIG_READ; len+=6; break; case 0x40: - r=(i[1]>>3)&7; + r=(pc[1]>>3)&7; dir=SIG_READ; len+=3; break; case 0x00: - r=(i[1]>>3)&7; + r=(pc[1]>>3)&7; dir=SIG_READ; len+=2; break; @@ -172,19 +210,19 @@ static int handle_access(CONTEXT_T context) } break; case 0x89: - switch(i[1]&0xc0) { + switch (pc[1]&0xc0) { case 0x80: - r=(i[1]>>3)&7; + r=(pc[1]>>3)&7; dir=SIG_WRITE; len+=6; break; case 0x40: - r=(i[1]>>3)&7; + r=(pc[1]>>3)&7; dir=SIG_WRITE; len+=3; break; case 0x00: - r=(i[1]>>3)&7; + r=(pc[1]>>3)&7; dir=SIG_WRITE; len+=2; break; @@ -194,13 +232,14 @@ static int handle_access(CONTEXT_T context) } if (r!=-1) { - void* pr=NULL; -#ifdef JIT_DEBUG - write_log (_T("JIT: register was %d, direction was %d, size was %d\n"),r,dir,size); + void *pr = NULL; +#ifdef DEBUG_ACCESS + write_log (_T("JIT: Register was %d, direction was %d, size was %d\n"), + r, dir, size); #endif switch(r) { -#if defined(CPU_64_BIT) +#if defined(CPU_x86_64) case 0: pr = &(CONTEXT_RAX(context)); break; case 1: pr = &(CONTEXT_RCX(context)); break; case 2: pr = &(CONTEXT_RDX(context)); break; @@ -239,15 +278,12 @@ static int handle_access(CONTEXT_T context) abort (); } if (pr) { - blockinfo* bi; - if (currprefs.comp_oldsegv) { - addr-=(uae_u32)NATMEM_OFFSET; - -#ifdef JIT_DEBUG - if ((addr>=0x10000000 && addr<0x40000000) || - (addr>=0x50000000)) { - write_log (_T("JIT: Suspicious address 0x%x in SEGV handler.\n"),addr); + uae_u32 addr = uae_p32(fault_addr) - uae_p32(NATMEM_OFFSET); +#ifdef DEBUG_ACCESS + if ((addr >= 0x10000000 && addr < 0x40000000) || + (addr >= 0x50000000)) { + write_log (_T("JIT: Suspicious address 0x%x in SEGV handler.\n"), addr); } #endif if (dir==SIG_READ) { @@ -266,7 +302,7 @@ static int handle_access(CONTEXT_T context) default: abort(); } } -#ifdef JIT_DEBUG +#ifdef DEBUG_ACCESS write_log (_T("JIT: Handled one access!\n")); #endif fflush(stdout); @@ -274,32 +310,30 @@ static int handle_access(CONTEXT_T context) CONTEXT_PC(context) += len; } else { - void* tmp=target; - int i; - uae_u8 vecbuf[5]; - - addr-=(uae_u32)NATMEM_OFFSET; - -#ifdef JIT_DEBUG - if ((addr>=0x10000000 && addr<0x40000000) || - (addr>=0x50000000)) { - write_log (_T("JIT: Suspicious address 0x%x in SEGV handler.\n"),addr); + uae_u32 addr = uae_p32(fault_addr) - uae_p32(NATMEM_OFFSET); +#ifdef DEBUG_ACCESS + if ((addr >= 0x10000000 && addr < 0x40000000) || + (addr >= 0x50000000)) { + write_log (_T("JIT: Suspicious address 0x%x in SEGV handler.\n"), addr); } #endif + uae_u8* original_target = target; target = (uae_u8*) CONTEXT_PC(context); - for (i=0;i<5;i++) - vecbuf[i]=target[i]; - emit_byte(0xe9); - emit_long((uae_u32)veccode-(uae_u32)target-4); -#ifdef JIT_DEBUG - write_log (_T("JIT: Create jump to %p\n"),veccode); + uae_u8 vecbuf[5]; + for (int i = 0; i < 5; i++) { + vecbuf[i] = target[i]; + } + raw_jmp(uae_p32(veccode)); + +#ifdef DEBUG_ACCESS + write_log (_T("JIT: Create jump to %p\n"), veccode); write_log (_T("JIT: Handled one access!\n")); #endif segvcount++; - target=veccode; + target = veccode; if (dir==SIG_READ) { switch(size) { @@ -317,74 +351,38 @@ static int handle_access(CONTEXT_T context) default: abort(); } } - for (i=0;i<5;i++) + for (int i = 0; i < 5; i++) { raw_mov_b_mi(CONTEXT_PC(context) + i, vecbuf[i]); - raw_mov_l_mi((uae_u32)&in_handler,0); - emit_byte(0xe9); - emit_long(CONTEXT_PC(context) + len - (uae_u32)target - 4); - in_handler=1; - target=(uae_u8*)tmp; - } - bi=active; - while (bi) { - if (bi->handler && - (uae_u8*)bi->direct_handler<=i && - (uae_u8*)bi->nexthandler>i) { -#ifdef JIT_DEBUG - write_log (_T("JIT: deleted trigger (%p<%p<%p) %p\n"), - bi->handler, - i, - bi->nexthandler, - bi->pc_p); -#endif - invalidate_block(bi); - raise_in_cl_list(bi); - set_special(0); - return 1; } - bi=bi->next; + raw_mov_l_mi(uae_p32(&in_handler), 0); + raw_jmp(uae_p32(CONTEXT_PC(context)) + len); + in_handler = 1; + target = original_target; + } + + if (delete_trigger(active, fault_pc)) { + return 1; } /* Not found in the active list. Might be a rom routine that - is in the dormant list */ - bi=dormant; - while (bi) { - if (bi->handler && - (uae_u8*)bi->direct_handler<=i && - (uae_u8*)bi->nexthandler>i) { -#ifdef JIT_DEBUG - write_log (_T("JIT: deleted trigger (%p<%p<%p) %p\n"), - bi->handler, - i, - bi->nexthandler, - bi->pc_p); -#endif - invalidate_block(bi); - raise_in_cl_list(bi); - set_special(0); - return 1; - } - bi=bi->next; + * is in the dormant list */ + if (delete_trigger(dormant, fault_pc)) { + return 1; } -#ifdef JIT_DEBUG +#ifdef DEBUG_ACCESS write_log (_T("JIT: Huh? Could not find trigger!\n")); #endif return 1; } } - write_log (_T("JIT: Can't handle access %08X!\n"), i); -#if 0 - if (i) - { - int j; - - for (j=0;j<10;j++) { - write_log (_T("JIT: instruction byte %2d is 0x%02x\n"),j,i[j]); + + write_log (_T("JIT: Can't handle access PC=%p!\n"), fault_pc); + if (fault_pc) { + write_log (_T("JIT: Instruction bytes")); + for (int j = 0; j < 10; j++) { + write_log (_T(" %02x"), fault_pc[j]); } + write_log (_T("\n")); } - write_log (_T("Please send the above info (starting at \"fault address\") to\n")); - write_log (_T("bmeyer@csse.monash.edu.au\n")); - write_log (_T("This shouldn't happen ;-)\n")); -#endif return 0; } #endif /* CONTEXT_T */ @@ -397,7 +395,8 @@ LONG WINAPI EvalException(LPEXCEPTION_POINTERS info) if (code != STATUS_ACCESS_VIOLATION || !canbang || currprefs.cachesize == 0) return EXCEPTION_CONTINUE_SEARCH; - if (handle_access(info)) { + uintptr_t address = info->ExceptionRecord->ExceptionInformation[1]; + if (handle_access(address, info)) { return EXCEPTION_CONTINUE_EXECUTION; } return EXCEPTION_CONTINUE_SEARCH; @@ -405,22 +404,17 @@ LONG WINAPI EvalException(LPEXCEPTION_POINTERS info) #elif defined(HAVE_CONTEXT_T) -static void sigsegv_handler(int signum, struct siginfo *info, void *context) +static void sigsegv_handler(int signum, siginfo_t *info, void *context) { - uae_u8 *i = (uae_u8 *) CONTEXT_EIP(context); - uae_u32 addr = CONTEXT_CR2(context); + uae_u8 *i = (uae_u8 *) CONTEXT_PC(context); + uintptr_t address = (uintptr_t) info->si_addr; if (i >= compiled_code) { - if (handle_access (context)) + if (handle_access(address, context)) { return; - else { - int j; - write_log ("JIT: can't handle access!\n"); - for (j = 0 ; j < 10; j++) - write_log ("JIT: instruction byte %2d is %02x\n", i, j[i]); } } else { - write_log ("Caught illegal access to %08x at eip=%08x\n", addr, i); + write_log ("Caught illegal access to %08lx at eip=%p\n", address, i); } exit (EXIT_FAILURE);