about summary refs log tree commit diff stats
path: root/src/libtools/signals.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libtools/signals.c')
-rw-r--r--src/libtools/signals.c93
1 files changed, 71 insertions, 22 deletions
diff --git a/src/libtools/signals.c b/src/libtools/signals.c
index e7280663..eebae427 100644
--- a/src/libtools/signals.c
+++ b/src/libtools/signals.c
@@ -286,7 +286,7 @@ static __thread int signal_jmpbuf_active = 0;
 //1<<1 is mutex_prot, 1<<8 is mutex_dyndump
 #define is_memprot_locked (1<<1)
 #define is_dyndump_locked (1<<8)
-uint64_t RunFunctionHandler(int* exit, int dynarec, x64_ucontext_t* sigcontext, uintptr_t fnc, int nargs, ...)
+uint64_t RunFunctionHandler(x64emu_t* emu, int* exit, int dynarec, x64_ucontext_t* sigcontext, uintptr_t fnc, int nargs, ...)
 {
     if(fnc==0 || fnc==1) {
         va_list va;
@@ -311,8 +311,8 @@ uint64_t RunFunctionHandler(int* exit, int dynarec, x64_ucontext_t* sigcontext,
     // Dynarec cannot be used in signal handling unless custom malloc is used
     dynarec = 0;
 #endif
-
-    x64emu_t *emu = thread_get_emu();
+    if(!emu)
+        emu = thread_get_emu();
     #ifdef DYNAREC
     if(box64_dynarec_test)
         emu->test.test = 0;
@@ -927,7 +927,7 @@ int sigbus_specialcases(siginfo_t* info, void * ucntx, void* pc, void* _fpsimd)
 #ifdef BOX32
 void my_sigactionhandler_oldcode_32(int32_t sig, int simple, siginfo_t* info, void * ucntx, int* old_code, void* cur_db);
 #endif
-void my_sigactionhandler_oldcode(int32_t sig, int simple, siginfo_t* info, void * ucntx, int* old_code, void* cur_db)
+void my_sigactionhandler_oldcode(x64emu_t* emu, int32_t sig, int simple, siginfo_t* info, void * ucntx, int* old_code, void* cur_db)
 {
     #ifdef BOX32
     if(box64_is32bits) {
@@ -936,12 +936,14 @@ void my_sigactionhandler_oldcode(int32_t sig, int simple, siginfo_t* info, void
     }
     #endif
     int Locks = unlockMutex();
+    int log_minimum = (box64_showsegv)?LOG_NONE:((sig==SIGSEGV && my_context->is_sigaction[sig])?LOG_DEBUG:LOG_INFO);
 
     printf_log(LOG_DEBUG, "Sigactionhanlder for signal #%d called (jump to %p/%s)\n", sig, (void*)my_context->signals[sig], GetNativeName((void*)my_context->signals[sig]));
 
     uintptr_t restorer = my_context->restorer[sig];
     // get that actual ESP first!
-    x64emu_t *emu = thread_get_emu();
+    if(!emu)
+        emu = thread_get_emu();
     uintptr_t frame = R_RSP;
 #if defined(DYNAREC)
 #if defined(ARM64)
@@ -1143,22 +1145,42 @@ void my_sigactionhandler_oldcode(int32_t sig, int simple, siginfo_t* info, void
     TRAP_x86_CACHEFLT   = 19   // SIMD exception (via SIGFPE) if CPU is SSE capable otherwise Cache flush exception (via SIGSEV)
     */
     uint32_t prot = getProtection((uintptr_t)info->si_addr);
+    uint32_t real_prot = 0;
+    if(prot&PROT_READ) real_prot|=PROT_READ;
+    if(prot&PROT_WRITE) real_prot|=PROT_WRITE;
+    if(prot&PROT_EXEC) real_prot|=PROT_WRITE;
+    if(prot&PROT_DYNAREC) real_prot|=PROT_WRITE;
+    sigcontext->uc_mcontext.gregs[X64_ERR] = 0;
+    sigcontext->uc_mcontext.gregs[X64_TRAPNO] = 0;
     if(sig==SIGBUS)
         sigcontext->uc_mcontext.gregs[X64_TRAPNO] = 17;
     else if(sig==SIGSEGV) {
         if((uintptr_t)info->si_addr == sigcontext->uc_mcontext.gregs[X64_RIP]) {
-            sigcontext->uc_mcontext.gregs[X64_ERR] = (info->si_errno==0x1234)?0:((info->si_errno==0xdead)?(0x2|(info->si_code<<3)):0x0010);    // execution flag issue (probably), unless it's a #GP(0)
-            sigcontext->uc_mcontext.gregs[X64_TRAPNO] = ((info->si_code==SEGV_ACCERR) || (info->si_errno==0x1234) || (info->si_errno==0xdead) || ((uintptr_t)info->si_addr==0))?13:14;
+            if(info->si_errno==0xbad0) {
+                //bad opcode
+                sigcontext->uc_mcontext.gregs[X64_ERR] = 0;
+                sigcontext->uc_mcontext.gregs[X64_TRAPNO] = 13;
+                info2->si_errno = 0;
+            } else if (info->si_errno==0xecec) {
+                // no excute bit on segment
+                sigcontext->uc_mcontext.gregs[X64_ERR] = (real_prot&PROT_READ)?16:1; // EXECUTE_FAULT & READ_FAULT
+                sigcontext->uc_mcontext.gregs[X64_TRAPNO] = (getMmapped((uintptr_t)info->si_addr))?14:13;
+                info2->si_errno = 0;
+            }else {
+                sigcontext->uc_mcontext.gregs[X64_ERR] = (real_prot&PROT_READ)?16:1;//(info->si_errno==0x1234)?0:((info->si_errno==0xdead)?(0x2|(info->si_code<<3)):0x0010);    // execution flag issue (probably), unless it's a #GP(0)
+                sigcontext->uc_mcontext.gregs[X64_TRAPNO] = (getMmapped((uintptr_t)info->si_addr))?14:13;
+                //sigcontext->uc_mcontext.gregs[X64_TRAPNO] = ((info->si_code==SEGV_ACCERR) || (info->si_errno==0x1234) || (info->si_errno==0xdead) || ((uintptr_t)info->si_addr==0))?13:14;
+            }
         } else if(info->si_code==SEGV_ACCERR && !(prot&PROT_WRITE)) {
-            sigcontext->uc_mcontext.gregs[X64_ERR] = 0x0002;    // write flag issue
+            sigcontext->uc_mcontext.gregs[X64_ERR] = (real_prot&PROT_READ)?2:1;//0x0002;    // write flag issue
             sigcontext->uc_mcontext.gregs[X64_TRAPNO] = 14;
         } else {
             if((info->si_code!=SEGV_ACCERR) && labs((intptr_t)info->si_addr-(intptr_t)sigcontext->uc_mcontext.gregs[X64_RSP])<16)
                 sigcontext->uc_mcontext.gregs[X64_TRAPNO] = 12; // stack overflow probably
             else
-                sigcontext->uc_mcontext.gregs[X64_TRAPNO] = (info->si_code == SEGV_ACCERR)?13:14;
+                sigcontext->uc_mcontext.gregs[X64_TRAPNO] = (info->si_code == SEGV_ACCERR)?14:13;
             //X64_ERR seems to be INT:8 CODE:8. So for write access segfault it's 0x0002 For a read it's 0x0004 (and 8 for exec). For an int 2d it could be 0x2D01 for example
-            sigcontext->uc_mcontext.gregs[X64_ERR] = 0x0004;    // read error? there is no execute control in box64 anyway
+            sigcontext->uc_mcontext.gregs[X64_ERR] = 0x0001;    // read error?
         }
         if(info->si_code == SEGV_ACCERR && old_code)
             *old_code = -1;
@@ -1166,7 +1188,7 @@ void my_sigactionhandler_oldcode(int32_t sig, int simple, siginfo_t* info, void
             info2->si_errno = 0;
         } else if(info->si_errno==0xdead) {
             // INT x
-            uint8_t int_n = info2->si_code;
+            uint8_t int_n = info->si_code;
             info2->si_errno = 0;
             info2->si_code = info->si_code;
             info2->si_addr = NULL;
@@ -1201,7 +1223,7 @@ void my_sigactionhandler_oldcode(int32_t sig, int simple, siginfo_t* info, void
         sigcontext->uc_mcontext.gregs[X64_ERR] = 0;
     }
     //TODO: SIGABRT generate what?
-    printf_log(LOG_DEBUG, "Signal %d: si_addr=%p, TRAPNO=%d, ERR=%d, RIP=%p\n", sig, (void*)info2->si_addr, sigcontext->uc_mcontext.gregs[X64_TRAPNO], sigcontext->uc_mcontext.gregs[X64_ERR],sigcontext->uc_mcontext.gregs[X64_RIP]);
+    printf_log((sig==10)?LOG_DEBUG:log_minimum, "Signal %d: si_addr=%p, TRAPNO=%d, ERR=%d, RIP=%p\n", sig, (void*)info2->si_addr, sigcontext->uc_mcontext.gregs[X64_TRAPNO], sigcontext->uc_mcontext.gregs[X64_ERR],sigcontext->uc_mcontext.gregs[X64_RIP]);
     // call the signal handler
     x64_ucontext_t sigcontext_copy = *sigcontext;
     // save old value from emu
@@ -1227,7 +1249,7 @@ void my_sigactionhandler_oldcode(int32_t sig, int simple, siginfo_t* info, void
     if(sig!=SIGSEGV && !(Locks&is_dyndump_locked) && !(Locks&is_memprot_locked))
         dynarec = 1;
     #endif
-    ret = RunFunctionHandler(&exits, dynarec, sigcontext, my_context->signals[info2->si_signo], 3, info2->si_signo, info2, sigcontext);
+    ret = RunFunctionHandler(emu, &exits, dynarec, sigcontext, my_context->signals[info2->si_signo], 3, info2->si_signo, info2, sigcontext);
     // restore old value from emu
     if(used_stack)  // release stack
         new_ss->ss_flags = 0;
@@ -1279,7 +1301,7 @@ void my_sigactionhandler_oldcode(int32_t sig, int simple, siginfo_t* info, void
             #undef GO
             for(int i=0; i<6; ++i)
                 emu->segs_serial[i] = 0;
-            printf_log(LOG_DEBUG, "Context has been changed in Sigactionhanlder, doing siglongjmp to resume emu at %p, RSP=%p\n", (void*)R_RIP, (void*)R_RSP);
+            printf_log((sig==10)?LOG_DEBUG:log_minimum, "Context has been changed in Sigactionhanlder, doing siglongjmp to resume emu at %p, RSP=%p\n", (void*)R_RIP, (void*)R_RSP);
             if(old_code)
                 *old_code = -1;    // re-init the value to allow another segfault at the same place
             //relockMutex(Locks);   // do not relock mutex, because of the siglongjmp, whatever was running is canceled
@@ -1339,7 +1361,7 @@ void my_sigactionhandler_oldcode(int32_t sig, int simple, siginfo_t* info, void
         exit(ret);
     }
     if(restorer)
-        RunFunctionHandler(&exits, 0, NULL, restorer, 0);
+        RunFunctionHandler(emu, &exits, 0, NULL, restorer, 0);
     relockMutex(Locks);
 }
 
@@ -1854,7 +1876,7 @@ dynarec_log(/*LOG_DEBUG*/LOG_INFO, "Repeated SIGSEGV with Access error on %p for
     }
     relockMutex(Locks);
     if(my_context->signals[sig] && my_context->signals[sig]!=1) {
-        my_sigactionhandler_oldcode(sig, my_context->is_sigaction[sig]?0:1, info, ucntx, &old_code, db);
+        my_sigactionhandler_oldcode(emu, sig, my_context->is_sigaction[sig]?0:1, info, ucntx, &old_code, db);
         return;
     }
     // no handler (or double identical segfault)
@@ -1882,7 +1904,7 @@ void my_sigactionhandler(int32_t sig, siginfo_t* info, void * ucntx)
     void* db = NULL;
     #endif
 
-    my_sigactionhandler_oldcode(sig, 0, info, ucntx, NULL, db);
+    my_sigactionhandler_oldcode(NULL, sig, 0, info, ucntx, NULL, db);
 }
 
 #ifndef DYNAREC
@@ -1895,6 +1917,13 @@ void emit_signal(x64emu_t* emu, int sig, void* addr, int code)
     info.si_signo = sig;
     info.si_errno = (sig==SIGSEGV)?0x1234:0;    // Mark as a sign this is a #GP(0) (like privileged instruction)
     info.si_code = code;
+    if(sig==SIGSEGV && code==0xbad0) {
+        info.si_errno = 0xbad0;
+        info.si_code = 0;
+    } else if(sig==SIGSEGV && code==0xecec) {
+        info.si_errno = 0xecec;
+        info.si_code = SEGV_ACCERR;
+    }
     info.si_addr = addr;
     const char* x64name = NULL;
     const char* elfname = NULL;
@@ -1903,13 +1932,33 @@ void emit_signal(x64emu_t* emu, int sig, void* addr, int code)
         elfheader_t* elf = FindElfAddress(my_context, R_RIP);
         if(elf)
             elfname = ElfName(elf);
-        printf_log(LOG_NONE, "Emit Signal %d at IP=%p(%s / %s) / addr=%p, code=%d\n", sig, (void*)R_RIP, x64name?x64name:"???", elfname?elfname:"?", addr, code);
+        printf_log(LOG_NONE, "Emit Signal %d at IP=%p(%s / %s) / addr=%p, code=0x%x\n", sig, (void*)R_RIP, x64name?x64name:"???", elfname?elfname:"?", addr, code);
+printf_log(LOG_NONE, DumpCPURegs(emu, R_RIP, emu->segs[_CS]==0x23));
+        //if(!elf) {
+        //    FILE* f = fopen("/proc/self/maps", "r");
+        //    if(f) {
+        //        char line[1024];
+        //        while(!feof(f)) {
+        //            char* ret = fgets(line, sizeof(line), f);
+        //            printf_log(LOG_NONE, "\t%s", ret);
+        //        }
+        //        fclose(f);
+        //    }
+        //}
         if(sig==SIGILL) {
             uint8_t* mem = (uint8_t*)R_RIP;
             printf_log(LOG_NONE, "SIGILL: Opcode at ip is %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n", mem[0], mem[1], mem[2], mem[3], mem[4], mem[5]);
         }
     }
-    my_sigactionhandler_oldcode(sig, 0, &info, NULL, NULL, NULL);
+    my_sigactionhandler_oldcode(emu, sig, 0, &info, NULL, NULL, NULL);
+}
+
+void check_exec(x64emu_t* emu, uintptr_t addr)
+{
+    while((getProtection(addr)&(PROT_EXEC|PROT_READ))!=(PROT_EXEC|PROT_READ)) {
+        R_RIP = addr;   // incase there is a slight difference
+        emit_signal(emu, SIGSEGV, (void*)addr, 0xecec);
+    }
 }
 
 void emit_interruption(x64emu_t* emu, int num, void* addr)
@@ -1918,7 +1967,7 @@ void emit_interruption(x64emu_t* emu, int num, void* addr)
     info.si_signo = SIGSEGV;
     info.si_errno = 0xdead;
     info.si_code = num;
-    info.si_addr = addr;
+    info.si_addr = NULL;//addr;
     const char* x64name = NULL;
     const char* elfname = NULL;
     if(box64_log>LOG_INFO || box64_dynarec_dump || box64_showsegv) {
@@ -1928,7 +1977,7 @@ void emit_interruption(x64emu_t* emu, int num, void* addr)
             elfname = ElfName(elf);
         printf_log(LOG_NONE, "Emit Interruption 0x%x at IP=%p(%s / %s) / addr=%p\n", num, (void*)R_RIP, x64name?x64name:"???", elfname?elfname:"?", addr);
     }
-    my_sigactionhandler_oldcode(SIGSEGV, 0, &info, NULL, NULL, NULL);
+    my_sigactionhandler_oldcode(emu, SIGSEGV, 0, &info, NULL, NULL, NULL);
 }
 
 void emit_div0(x64emu_t* emu, void* addr, int code)
@@ -1947,7 +1996,7 @@ void emit_div0(x64emu_t* emu, void* addr, int code)
             elfname = ElfName(elf);
         printf_log(LOG_NONE, "Emit Divide by 0 at IP=%p(%s / %s) / addr=%p\n", (void*)R_RIP, x64name?x64name:"???", elfname?elfname:"?", addr);
     }
-    my_sigactionhandler_oldcode(SIGSEGV, 0, &info, NULL, NULL, NULL);
+    my_sigactionhandler_oldcode(emu, SIGSEGV, 0, &info, NULL, NULL, NULL);
 }
 
 EXPORT sighandler_t my_signal(x64emu_t* emu, int signum, sighandler_t handler)