diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/libtools/signal32.c | 15 |
1 files changed, 11 insertions, 4 deletions
diff --git a/src/libtools/signal32.c b/src/libtools/signal32.c index 4e6c8e1e..9324e89f 100644 --- a/src/libtools/signal32.c +++ b/src/libtools/signal32.c @@ -592,6 +592,7 @@ void my_sigactionhandler_oldcode_32(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; @@ -637,7 +638,7 @@ void my_sigactionhandler_oldcode_32(x64emu_t* emu, int32_t sig, int simple, sigi info2->si_code = 128; info2->_sifields._sigfault.__si_addr = 0; sigcontext->uc_mcontext.gregs[I386_TRAPNO] = 13; - + skip = 3; // can resume in dynarec // some special cases... if(int_n==3) { info2->si_signo = X64_SIGTRAP; @@ -657,12 +658,14 @@ void my_sigactionhandler_oldcode_32(x64emu_t* emu, int32_t sig, int simple, sigi sigcontext->uc_mcontext.gregs[I386_ERR] = 0; sigcontext->uc_mcontext.gregs[I386_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[I386_TRAPNO] = 4; else sigcontext->uc_mcontext.gregs[I386_TRAPNO] = 19; + skip = 3; } else if(sig==X64_SIGILL) { info2->si_code = 2; sigcontext->uc_mcontext.gregs[I386_TRAPNO] = 6; @@ -674,6 +677,8 @@ void my_sigactionhandler_oldcode_32(x64emu_t* emu, int32_t sig, int simple, sigi info2->si_code = 128; sigcontext->uc_mcontext.gregs[I386_TRAPNO] = info->si_code; sigcontext->uc_mcontext.gregs[I386_ERR] = 0; + } else { + skip = 3; // other signal can resume in interpretor } //TODO: SIGABRT generate what? printf_log((sig==10)?LOG_DEBUG:log_minimum, "Signal32 %d: si_addr=%p, TRAPNO=%d, ERR=%d, RIP=%p, prot:%x, mmaped:%d\n", sig, from_ptrv(info2->_sifields._sigfault.__si_addr), sigcontext->uc_mcontext.gregs[I386_TRAPNO], sigcontext->uc_mcontext.gregs[I386_ERR],from_ptrv(sigcontext->uc_mcontext.gregs[I386_EIP]), prot, mmapped); @@ -725,6 +730,8 @@ void my_sigactionhandler_oldcode_32(x64emu_t* emu, int32_t sig, int simple, sigi GO(SP); GO(BX); #undef GO + if((skip==1) && (emu->ip.q[0]!=sigcontext->uc_mcontext.gregs[I386_EIP])) + skip = 3; // if it jumps elsewhere, it can resume with dynarec... emu->ip.q[0]=sigcontext->uc_mcontext.gregs[I386_EIP]; // flags emu->eflags.x64=sigcontext->uc_mcontext.gregs[I386_EFL]; @@ -739,7 +746,7 @@ void my_sigactionhandler_oldcode_32(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 @@ -751,9 +758,9 @@ void my_sigactionhandler_oldcode_32(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[I386_EIP]!=sigcontext_copy.uc_mcontext.gregs[I386_EIP])?" (EIP changed)":""); |