about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2025-09-01 11:00:34 +0200
committerptitSeb <sebastien.chev@gmail.com>2025-09-01 11:00:34 +0200
commit1edd0eb47d207b21af0586db36abfc3625d1a849 (patch)
tree9f8b104579156c27f56bc78d7eac4fa57060c3d7
parentf46987b6af1459046a9fbc590e6814a9e8800125 (diff)
downloadbox64-1edd0eb47d207b21af0586db36abfc3625d1a849.tar.gz
box64-1edd0eb47d207b21af0586db36abfc3625d1a849.zip
Allow resuming signal directly on dynarec instead of interpretor when possible
-rw-r--r--src/libtools/signals.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/src/libtools/signals.c b/src/libtools/signals.c
index 7fa41e7b..7f99c182 100644
--- a/src/libtools/signals.c
+++ b/src/libtools/signals.c
@@ -986,6 +986,7 @@ void my_sigactionhandler_oldcode_64(x64emu_t* emu, int32_t sig, int simple, sigi
     uint32_t mmapped = memExist((uintptr_t)info->si_addr);
     uint32_t sysmapped = (info->si_addr<(void*)box64_pagesize)?1:mmapped;
     uint32_t real_prot = 0;
+    int skip = 1;   // in case sigjump is used to restore exectuion, 1 will switch to interpreter, 3 will switch to dynarec
     if(prot&PROT_READ) real_prot|=PROT_READ;
     if(prot&PROT_WRITE) real_prot|=PROT_WRITE;
     if(prot&PROT_EXEC) real_prot|=PROT_WRITE;
@@ -1010,6 +1011,7 @@ void my_sigactionhandler_oldcode_64(x64emu_t* emu, int32_t sig, int simple, sigi
                 if(!mmapped) info2->si_code = 1;
                 info2->si_errno = 0;
             } else if (info->si_errno==0xb09d) {
+                // bound exception
                 sigcontext->uc_mcontext.gregs[X64_ERR] = 0;
                 sigcontext->uc_mcontext.gregs[X64_TRAPNO] = 5;
                 info2->si_errno = 0;
@@ -1035,6 +1037,7 @@ void my_sigactionhandler_oldcode_64(x64emu_t* emu, int32_t sig, int simple, sigi
             info2->si_code = 128;
             info2->si_addr = NULL;
             sigcontext->uc_mcontext.gregs[X64_TRAPNO] = 13;
+            skip = 3;   // can resume in dynarec
             // some special cases...
             if(int_n==3) {
                 info2->si_signo = X64_SIGTRAP;
@@ -1054,12 +1057,14 @@ void my_sigactionhandler_oldcode_64(x64emu_t* emu, int32_t sig, int simple, sigi
             sigcontext->uc_mcontext.gregs[X64_ERR] = 0;
             sigcontext->uc_mcontext.gregs[X64_TRAPNO] = 0;
             info2->si_signo = X64_SIGFPE;
+            skip = 3; // can resume in dynarec
         }
     } else if(sig==X64_SIGFPE) {
         if (info->si_code == FPE_INTOVF)
             sigcontext->uc_mcontext.gregs[X64_TRAPNO] = 4;
         else
             sigcontext->uc_mcontext.gregs[X64_TRAPNO] = 19;
+        skip = 3;
     } else if(sig==X64_SIGILL) {
         info2->si_code = 2;
         sigcontext->uc_mcontext.gregs[X64_TRAPNO] = 6;
@@ -1071,6 +1076,8 @@ void my_sigactionhandler_oldcode_64(x64emu_t* emu, int32_t sig, int simple, sigi
             info2->si_code = 128;
         sigcontext->uc_mcontext.gregs[X64_TRAPNO] = info->si_code;
         sigcontext->uc_mcontext.gregs[X64_ERR] = 0;
+    } else {
+        skip = 3;   // other signal can resume in interpretor
     }
     //TODO: SIGABRT generate what?
     printf_log((sig==10)?LOG_DEBUG:log_minimum, "Signal %d: si_addr=%p, TRAPNO=%d, ERR=%d, RIP=%p, prot=%x, mmapped:%d\n", sig, (void*)info2->si_addr, sigcontext->uc_mcontext.gregs[X64_TRAPNO], sigcontext->uc_mcontext.gregs[X64_ERR],sigcontext->uc_mcontext.gregs[X64_RIP], prot, mmapped);
@@ -1140,6 +1147,8 @@ void my_sigactionhandler_oldcode_64(x64emu_t* emu, int32_t sig, int simple, sigi
             GO(R14);
             GO(R15);
             #undef GO
+            if((skip==1) && (emu->ip.q[0]!=sigcontext->uc_mcontext.gregs[X64_RIP]))
+                skip = 3;   // if it jumps elsewhere, it can resume with dynarec...
             emu->ip.q[0]=sigcontext->uc_mcontext.gregs[X64_RIP];
             // flags
             emu->eflags.x64=sigcontext->uc_mcontext.gregs[X64_EFL];
@@ -1155,7 +1164,7 @@ void my_sigactionhandler_oldcode_64(x64emu_t* emu, int32_t sig, int simple, sigi
             #undef GO
             for(int i=0; i<6; ++i)
                 emu->segs_serial[i] = 0;
-            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);
+            printf_log((sig==10)?LOG_DEBUG:log_minimum, "Context has been changed in Sigactionhanlder, doing siglongjmp to resume emu at %p, RSP=%p (resume with %s)\n", (void*)R_RIP, (void*)R_RSP, (skip==3)?"Dynarec":"Interp");
             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
@@ -1167,9 +1176,9 @@ void my_sigactionhandler_oldcode_64(x64emu_t* emu, int32_t sig, int simple, sigi
             emu->xSPSave = emu->old_savedsp;
             #endif
             #ifdef ANDROID
-            siglongjmp(*emu->jmpbuf, 1);
+            siglongjmp(*emu->jmpbuf, skip);
             #else
-            siglongjmp(emu->jmpbuf, 1);
+            siglongjmp(emu->jmpbuf, skip);
             #endif
         }
         printf_log(LOG_INFO, "Warning, context has been changed in Sigactionhanlder%s\n", (sigcontext->uc_mcontext.gregs[X64_RIP]!=sigcontext_copy.uc_mcontext.gregs[X64_RIP])?" (EIP changed)":"");