]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
JIT: Fix and enable exception handler for x86-64 + cleaned up code a bit
authorFrode Solheim <frode@fs-uae.net>
Thu, 10 Sep 2015 19:25:00 +0000 (21:25 +0200)
committerFrode Solheim <frode@fs-uae.net>
Thu, 17 Sep 2015 17:18:09 +0000 (19:18 +0200)
jit/compemu.h
jit/compemu_support.cpp
jit/exception_handler.cpp

index 19f478f4cd2ebe26743b4d9ce3f56ae4f254741b..c8b95fa1441a1163bc542ab32e109fc493406574 100644 (file)
@@ -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 */
index 9bcef98002941caa95cb6be854be5be48becf419..5053e1873cee224ea9c1bd3053d81c62b732d406 100644 (file)
@@ -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");
index f5c11d95166a8ebc12dd74dc88e7db1556e1d203..d30ecc9d18b1a74286dfba4a55d0d787f4f864d8 100644 (file)
 #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);