about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2024-12-03 11:43:38 +0100
committerptitSeb <sebastien.chev@gmail.com>2024-12-03 11:43:46 +0100
commit794f2104bcee9a2aff192804d9c07b2163e79a51 (patch)
tree6d96d0493dc84d3ad10ffc6b598fce976b46a903
parent036af9f55fa5b8542872c14b801bce5512c31583 (diff)
downloadbox64-794f2104bcee9a2aff192804d9c07b2163e79a51.tar.gz
box64-794f2104bcee9a2aff192804d9c07b2163e79a51.zip
Improved signal handling ([BOX32] Too)
-rw-r--r--CMakeLists.txt1
-rw-r--r--src/dynarec/dynarec.c8
-rw-r--r--src/libtools/decopcode.c381
-rw-r--r--src/libtools/signal32.c27
-rw-r--r--src/libtools/signals.c37
-rw-r--r--tests/ref21.txt48
-rwxr-xr-xtests/test21bin23696 -> 23624 bytes
-rw-r--r--tests/test21.c195
8 files changed, 644 insertions, 53 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a4608510..fb308689 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -374,6 +374,7 @@ set(ELFLOADER_SRC
     "${BOX64_ROOT}/src/libtools/auxval.c"
     "${BOX64_ROOT}/src/libtools/myalign.c"
     "${BOX64_ROOT}/src/libtools/signals.c"
+    "${BOX64_ROOT}/src/libtools/decopcode.c"
     "${BOX64_ROOT}/src/libtools/threads.c"
     "${BOX64_ROOT}/src/tools/bitutils.c"
     "${BOX64_ROOT}/src/tools/box64stack.c"
diff --git a/src/dynarec/dynarec.c b/src/dynarec/dynarec.c
index 265b23f7..106b447a 100644
--- a/src/dynarec/dynarec.c
+++ b/src/dynarec/dynarec.c
@@ -34,17 +34,17 @@ void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
     #ifdef HAVE_TRACE
     if(!addr) {
         dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
-        printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x64addr=%p/%s)\n", x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
+        printf_log(LOG_INFO, "Warning, jumping to NULL address from %p (db=%p, x64addr=%p/%s)\n", x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
     } else if(addr<0x10000) {
         dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
-        printf_log(LOG_NONE, "Warning, jumping to low address %p from %p (db=%p, x64addr=%p/%s)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
+        printf_log(LOG_INFO, "Warning, jumping to low address %p from %p (db=%p, x64addr=%p/%s)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
     #ifdef BOX32
     } else if(emu->segs[_CS]==0x23 && addr>0x100000000LL) {
         dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
-        printf_log(LOG_NONE, "Warning, jumping to high address %p from %p (db=%p, x64addr=%p/%s)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
+        printf_log(LOG_INFO, "Warning, jumping to high address %p from %p (db=%p, x64addr=%p/%s)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
     } else if(!memExist(addr)) {
         dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
-        printf_log(LOG_NONE, "Warning, jumping to an unmapped address %p from %p (db=%p, x64addr=%p/%s)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
+        printf_log(LOG_INFO, "Warning, jumping to an unmapped address %p from %p (db=%p, x64addr=%p/%s)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
     #endif
     }
     #endif
diff --git a/src/libtools/decopcode.c b/src/libtools/decopcode.c
new file mode 100644
index 00000000..5bc84657
--- /dev/null
+++ b/src/libtools/decopcode.c
@@ -0,0 +1,381 @@
+#include <stdint.h>
+#include <sys/mman.h>
+
+#include "debug.h"
+#include "x64emu.h"
+#include "emu/x64run_private.h"
+#include "custommem.h"
+
+#define OPCODE_READ  (1<<0)
+#define OPCODE_WRITE (1<<1)
+#define OPCODE_STACK (1<<2)
+
+#define MODREG  ((nextop&0xC0)==0xC0)
+
+int decode_avx(uint8_t* addr, int idx, vex_t vex)
+{
+    return 0;
+}
+
+int decode_0f(uint8_t* addr, int idx, rex_t rex)
+{
+    uint8_t nextop;
+    switch(addr[idx++]) {
+        case 0x00:
+            return OPCODE_READ;
+        case 0x01:
+            return OPCODE_WRITE;
+        case 0x10:
+        case 0x12:
+        case 0x14:
+        case 0x15:
+        case 0x16:
+        case 0x28:
+        case 0x2A:
+        case 0x2C:
+        case 0x2D:
+        case 0x2E:
+        case 0x2F:
+        case 0x50 ... 0x6B:
+        case 0x6E:
+        case 0x6F:
+        case 0x70:
+        case 0x74:
+        case 0x75:
+        case 0x76:
+        case 0xA3:
+        case 0xAF:
+        case 0xB6:
+        case 0xB7:
+        case 0xBC:
+        case 0xBD:
+        case 0xBE:
+        case 0xBF:
+        case 0xC2:
+        case 0xC4 ... 0xC6:
+        case 0xD1 ... 0xD5:
+        case 0xD7 ... 0xE5:
+        case 0xE8 ... 0xEF:
+        case 0xF1 ... 0xFE:
+            nextop = addr[idx++];
+            return (MODREG)?0:OPCODE_READ;
+        case 0x11:
+        case 0x13:
+        case 0x17:
+        case 0x29:
+        case 0x2B:
+        case 0x7E:
+        case 0x7F:
+        case 0x90 ... 0x9F:
+        case 0xAE:
+        case 0xC3:
+        case 0xE7:
+            nextop = addr[idx++];
+            return (MODREG)?0:OPCODE_WRITE;
+        case 0x71:
+        case 0x72:
+        case 0x73:
+        case 0xA4:
+        case 0xA5:
+        case 0xAB:
+        case 0xAC:
+        case 0xAD:
+        case 0xB0:
+        case 0xB1:
+        case 0xB3:
+        case 0xBA:
+        case 0xBB:
+        case 0xC0:
+        case 0xC1:
+        case 0xC7:
+            return (MODREG)?0:(OPCODE_READ|OPCODE_WRITE);
+        case 0xA0:
+        case 0xA8:
+            return OPCODE_WRITE|OPCODE_STACK;
+        case 0xA1:
+        case 0xA9:
+            return OPCODE_READ|OPCODE_STACK;
+        case 0x38:  //todo
+            return 0;
+        case 0x3A:  //todo
+            return 0;
+    }
+    return 0;
+}
+int decode_660f(uint8_t* addr, int idx, rex_t rex)
+{
+    return 0;
+}
+int decode_f20f(uint8_t* addr, int idx, rex_t rex)
+{
+    return 0;
+}
+int decode_f30f(uint8_t* addr, int idx, rex_t rex)
+{
+    return 0;
+}
+
+int decode_opcode(uintptr_t rip, int is32bits)
+{
+    if(!(getProtection(rip)&PROT_READ))
+        return 0;
+    // check if opcode is one that write to memory... pretty crude for now.
+    uint8_t* addr = (uint8_t*)rip;
+    int idx = 0;
+    rex_t rex = {0};
+    int is66 = 0, is67 = 0, rep = 0;
+    int lock = 0;
+    vex_t vex = {0};
+    uint8_t nextop;
+    if(is32bits) {
+        rex.is32bits = 1;
+        while(addr[idx]==0x66 || addr[idx]==0xF2 || addr[idx]==0xF3 || (addr[idx]==0x2E)|| (addr[idx]==0x3E) || (addr[idx]==0x26)|| (addr[idx]==0x36) || (addr[idx]==0xf0) || (addr[idx]==0x64)|| (addr[idx]==0x65)) {
+            switch(addr[idx++]) {
+                case 0x66: is66=1; break;
+                case 0xF0: lock=1; break;
+                case 0xF2: rep=1; break;
+                case 0xF3: rep=2; break;
+            }
+        }
+    } else {
+        while((addr[idx]>=0x40 && addr[idx]<0x4f) || (addr[idx]==0x66 || addr[idx]==0xF2 || addr[idx]==0xF3 || (addr[idx]==0x3E) || (addr[idx]==0x26) || (addr[idx]==0xf0)) || (addr[idx]==0x64)|| (addr[idx]==0x65)) {
+            switch(addr[idx++]) {
+                case 0x66: is66=1; break;
+                case 0xF0: lock=1; break;
+                case 0xF2: rep=1; break;
+                case 0xF3: rep=2; break;
+                case 0x40 ... 0x4f: rex.rex = addr[idx-1]; break;
+            }
+        }
+    }
+    if((addr[idx]==0xC4 || addr[idx]==0xC5) && (!is32bits || (addr[idx+1]&0xc0!=0xc0))) {
+        uint8_t tmp8u;
+        switch(addr[idx++]) {
+            case 0xC4:
+                vex.rex = rex;
+                tmp8u = nextop;
+                vex.m = tmp8u&0b00011111;
+                vex.rex.b = (tmp8u&0b00100000)?0:1;
+                vex.rex.x = (tmp8u&0b01000000)?0:1;
+                vex.rex.r = (tmp8u&0b10000000)?0:1;
+                tmp8u = addr[idx++];
+                vex.p = tmp8u&0b00000011;
+                vex.l = (tmp8u>>2)&1;
+                vex.v = ((~tmp8u)>>3)&0b1111;
+                vex.rex.w = (tmp8u>>7)&1;
+                break;
+            case 0xC5:
+                vex.rex = rex;
+                tmp8u = nextop;
+                vex.p = tmp8u&0b00000011;
+                vex.l = (tmp8u>>2)&1;
+                vex.v = ((~tmp8u)>>3)&0b1111;
+                vex.rex.r = (tmp8u&0b10000000)?0:1;
+                vex.rex.b = 0;
+                vex.rex.x = 0;
+                vex.rex.w = 0;
+                vex.m = VEX_M_0F;
+                break;
+        }
+        return decode_avx(addr, idx, vex);
+    }
+    switch(addr[idx++]) {
+        case 0x00:
+        case 0x01:
+        case 0x08:
+        case 0x09:
+        case 0x10:
+        case 0x11:
+        case 0x18:
+        case 0x19:
+        case 0x20:
+        case 0x21:
+        case 0x28:
+        case 0x29:
+        case 0x30:
+        case 0x31:
+        case 0x86:
+        case 0x87:
+        case 0x88:
+        case 0x89:
+        case 0x8C:
+        case 0xC0:
+        case 0xC1:
+        case 0xC6:
+        case 0xC7:
+        case 0xD0:
+        case 0xD1:
+        case 0xD2:
+        case 0xD3:
+            nextop = addr[idx++];
+            return (MODREG)?0:(OPCODE_WRITE|OPCODE_READ);
+        case 0x02:
+        case 0x03:
+        case 0x0a:
+        case 0x0b:
+        case 0x12:
+        case 0x13:
+        case 0x1a:
+        case 0x1b:
+        case 0x22:
+        case 0x23:
+        case 0x2a:
+        case 0x2b:
+        case 0x32:
+        case 0x33:
+        case 0x38:
+        case 0x39:
+        case 0x3a:
+        case 0x3b:
+        case 0x63:
+        case 0x69:
+        case 0x6B:
+        case 0x84:
+        case 0x85:
+        case 0x8A:
+        case 0x8B:
+        case 0x8E:
+            nextop = addr[idx++];
+            return (MODREG)?0:(OPCODE_READ);
+        case 0x06: 
+        case 0x0E: 
+        case 0x16: 
+        case 0x1E: 
+        case 0x60:
+            return is32bits?(OPCODE_WRITE|OPCODE_STACK):0;
+        case 0x07: 
+        case 0x17: 
+        case 0x1F:
+        case 0x61: 
+            return is32bits?(OPCODE_READ|OPCODE_STACK):0;
+        case 0x50 ... 0x57:
+        case 0x68:
+        case 0x6A:
+        case 0x9C:
+        case 0xC8:
+        case 0xE8:
+            return OPCODE_WRITE|OPCODE_STACK;
+        case 0x58 ... 0x5F:
+        case 0x9D:
+        case 0xC2:
+        case 0xC3:
+        case 0xC9:
+        case 0xCA:
+        case 0xCB:
+        case 0xCF:
+            return OPCODE_READ|OPCODE_STACK;
+        case 0x80 ... 0x83:
+            nextop = addr[idx++];
+            return (MODREG)?0:((((nextop>>3)&7!=7)?OPCODE_WRITE:0)|OPCODE_READ);
+        case 0x8F:
+            nextop = addr[idx++];
+            return ((MODREG)?0:(OPCODE_WRITE))|OPCODE_READ|OPCODE_STACK;
+        case 0xA0:
+        case 0xA1:
+        case 0xA6:
+        case 0xA7:
+        case 0xAC:
+        case 0xAD:
+        case 0xAE:
+        case 0xAF:
+        case 0xD7:
+            return OPCODE_READ;
+        case 0xA2:
+        case 0xA3:
+        case 0xA4:
+        case 0xA5:
+        case 0xAA:
+        case 0xAB:
+            return OPCODE_WRITE;
+        case 0xF6:
+        case 0xF7:
+            nextop = addr[idx++];
+            if(MODREG) return 0;
+            switch((nextop>>3)&7) {
+                case 2:
+                case 3:
+                    return OPCODE_WRITE;
+                default:
+                    return OPCODE_READ;
+            }
+        case 0xFE:
+        case 0xFF:
+            nextop = addr[idx++];
+            if(MODREG) return 0;
+            switch((nextop>>3)&7) {
+                case 0:
+                case 1:
+                    return OPCODE_WRITE;
+                case 2:
+                case 3:
+                case 6:
+                    return OPCODE_READ|OPCODE_WRITE|OPCODE_STACK;
+                default:
+                    return OPCODE_READ;
+            }
+
+        case 0x0F: 
+            if(is66) return decode_660f(addr, idx, rex);
+            if(rep==1) return decode_f20f(addr, idx, rex);
+            if(rep==2) return decode_f30f(addr, idx, rex);
+            return decode_0f(addr, idx, rex);
+        case 0xD8 ... 0xDF:
+            nextop = addr[idx++];
+            if(nextop<0xC0) {
+                switch(addr[idx-2]) {
+                    case 0xD8: 
+                    case 0xDA: 
+                    case 0xDC:
+                    case 0xDE:
+                        return OPCODE_READ;
+                    case 0xD9: 
+                        switch((nextop>>3)&7) {
+                            case 0:
+                            case 4:
+                            case 5:
+                                return OPCODE_READ;
+                            case 2:
+                            case 3:
+                            case 6:
+                            case 7:
+                                return OPCODE_WRITE;
+                        }
+                        return 0;
+                    case 0xDB:
+                        switch((nextop>>3)&7) {
+                            case 0:
+                            case 1:
+                            case 2:
+                            case 3:
+                            case 7:
+                                return OPCODE_WRITE;
+                            case 5:
+                                return OPCODE_READ;
+                        }
+                        return 0;
+                    case 0xDF: 
+                        switch((nextop>>3)&7) {
+                            case 0:
+                            case 4:
+                            case 5:
+                                return OPCODE_READ;
+                            case 1:
+                            case 2:
+                            case 3:
+                            case 6:
+                            case 7:
+                                return OPCODE_WRITE;
+                        }
+                }
+            }
+            return 0;
+
+    }
+    return 0;
+}
+
+int write_opcode(uintptr_t rip, uintptr_t native_ip, int is32bits)
+{
+    // TODO, on ARM64, RiSCV and LoongArch, it would be easier to analyse the opcode at the native IP instead, as opcode that write to memory are more limited in quantity
+    return (decode_opcode(rip, is32bits)&OPCODE_WRITE)?1:0;
+}
\ No newline at end of file
diff --git a/src/libtools/signal32.c b/src/libtools/signal32.c
index 0cf9e440..e55c88f2 100644
--- a/src/libtools/signal32.c
+++ b/src/libtools/signal32.c
@@ -447,7 +447,7 @@ uint32_t RunFunctionHandler32(int* exit, int dynarec, i386_ucontext_t* sigcontex
 
     return ret;
 }
-
+int write_opcode(uintptr_t rip, uintptr_t native_ip, int is32bits);
 #define is_memprot_locked (1<<1)
 #define is_dyndump_locked (1<<8)
 void my_sigactionhandler_oldcode_32(int32_t sig, int simple, siginfo_t* info, void * ucntx, int* old_code, void* cur_db)
@@ -622,6 +622,7 @@ void my_sigactionhandler_oldcode_32(int32_t sig, int simple, siginfo_t* info, vo
     */
     uint32_t prot = getProtection((uintptr_t)info->si_addr);
     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;
     if(prot&PROT_READ) real_prot|=PROT_READ;
     if(prot&PROT_WRITE) real_prot|=PROT_WRITE;
@@ -642,28 +643,24 @@ void my_sigactionhandler_oldcode_32(int32_t sig, int simple, siginfo_t* info, vo
                 info2->_sifields._sigfault.__si_addr = 0;
             } else if (info->si_errno==0xecec) {
                 // no excute bit on segment
-                sigcontext->uc_mcontext.gregs[I386_ERR] = 16;//(real_prot&PROT_READ)?16:1; // EXECUTE_FAULT & READ_FAULT
+                sigcontext->uc_mcontext.gregs[I386_ERR] = 0x14|((sysmapped && !(real_prot&PROT_READ))?0:1);
                 sigcontext->uc_mcontext.gregs[I386_TRAPNO] = 14;
+                if(!mmapped) info2->si_code = 1;
                 info2->si_errno = 0;
             }else {
-                sigcontext->uc_mcontext.gregs[I386_ERR] = mmapped?16:1;//(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[I386_TRAPNO] = (mmapped)?14:13;
-                //sigcontext->uc_mcontext.gregs[I386_TRAPNO] = ((info->si_code==SEGV_ACCERR) || (info->si_errno==0x1234) || (info->si_errno==0xdead) || ((uintptr_t)info->si_addr==0))?13:14;
+                sigcontext->uc_mcontext.gregs[I386_ERR] = 0x14|((sysmapped && !(real_prot&PROT_READ))?0:1);
+                sigcontext->uc_mcontext.gregs[I386_TRAPNO] = 14;
             }
-        } else if(info->si_code==SEGV_ACCERR && !(prot&PROT_WRITE)) {
-            sigcontext->uc_mcontext.gregs[I386_ERR] = (real_prot&PROT_READ)?2:1;//0x0002;    // write flag issue
-            sigcontext->uc_mcontext.gregs[I386_TRAPNO] = 14;
         } else {
-            if((info->si_code!=SEGV_ACCERR) && labs((intptr_t)info->si_addr-(intptr_t)sigcontext->uc_mcontext.gregs[I386_ESP])<16)
-                sigcontext->uc_mcontext.gregs[I386_TRAPNO] = 12; // stack overflow probably
-            else
-                sigcontext->uc_mcontext.gregs[I386_TRAPNO] = (mmapped || ((uintptr_t)info->si_addr<0x10000))?14:13;
-            //I386_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[I386_ERR] = 0x0001;    // read error?
+            sigcontext->uc_mcontext.gregs[I386_TRAPNO] = 14;
+            sigcontext->uc_mcontext.gregs[I386_ERR] = 4|((sysmapped && !(real_prot&PROT_READ))?0:1);
+            if(write_opcode(sigcontext->uc_mcontext.gregs[I386_EIP], (uintptr_t)pc, 1))
+                sigcontext->uc_mcontext.gregs[I386_ERR] |= 2;
         }
         if(info->si_code == SEGV_ACCERR && old_code)
             *old_code = -1;
         if(info->si_errno==0x1234) {
+            sigcontext->uc_mcontext.gregs[I386_TRAPNO] = 13;
             info2->si_errno = 0;
         } else if(info->si_errno==0xdead) {
             // INT x
@@ -671,6 +668,8 @@ void my_sigactionhandler_oldcode_32(int32_t sig, int simple, siginfo_t* info, vo
             info2->si_errno = 0;
             info2->si_code = 128;
             info2->_sifields._sigfault.__si_addr = 0;
+            sigcontext->uc_mcontext.gregs[I386_TRAPNO] = 13;
+
             // some special cases...
             if(int_n==3) {
                 info2->si_signo = SIGTRAP;
diff --git a/src/libtools/signals.c b/src/libtools/signals.c
index 3bf37f50..d760ecf1 100644
--- a/src/libtools/signals.c
+++ b/src/libtools/signals.c
@@ -466,12 +466,13 @@ EXPORT int my_sigaltstack(x64emu_t* emu, const x64_stack_t* ss, x64_stack_t* oss
     return 0;
 }
 
-
 #ifdef DYNAREC
-uintptr_t getX64Address(dynablock_t* db, uintptr_t arm_addr)
+uintptr_t getX64Address(dynablock_t* db, uintptr_t native_addr)
 {
     uintptr_t x64addr = (uintptr_t)db->x64_addr;
     uintptr_t armaddr = (uintptr_t)db->block;
+    if(native_addr<(uintptr_t)db->block || native_addr>(uintptr_t)db->block+db->size)
+        return 0;
     int i = 0;
     do {
         int x64sz = 0;
@@ -482,7 +483,7 @@ uintptr_t getX64Address(dynablock_t* db, uintptr_t arm_addr)
             ++i;
         } while((db->instsize[i-1].x64==15) || (db->instsize[i-1].nat==15));
         // if the opcode is a NOP on ARM side (so armsz==0), it cannot be an address to find
-        if((arm_addr>=armaddr) && (arm_addr<(armaddr+armsz)))
+        if((native_addr>=armaddr) && (native_addr<(armaddr+armsz)))
             return x64addr;
         armaddr+=armsz;
         x64addr+=x64sz;
@@ -509,7 +510,7 @@ x64emu_t* getEmuSignal(x64emu_t* emu, ucontext_t* p, dynablock_t* db)
     return emu;
 }
 #endif
-
+int write_opcode(uintptr_t rip, uintptr_t native_ip, int is32bits);
 void adjustregs(x64emu_t* emu) {
 // tests some special cases
     uint8_t* mem = (uint8_t*)R_RIP;
@@ -1146,6 +1147,7 @@ void my_sigactionhandler_oldcode(x64emu_t* emu, int32_t sig, int simple, siginfo
     */
     uint32_t prot = getProtection((uintptr_t)info->si_addr);
     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;
     if(prot&PROT_READ) real_prot|=PROT_READ;
     if(prot&PROT_WRITE) real_prot|=PROT_WRITE;
@@ -1166,28 +1168,24 @@ void my_sigactionhandler_oldcode(x64emu_t* emu, int32_t sig, int simple, siginfo
                 info2->si_addr = NULL;
             } 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] = mmapped?14:13;
+                sigcontext->uc_mcontext.gregs[X64_ERR] = 0x14|((sysmapped && !(real_prot&PROT_READ))?0:1);
+                sigcontext->uc_mcontext.gregs[X64_TRAPNO] = 14;
+                if(!mmapped) info2->si_code = 1;
                 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] = mmapped?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;
+                sigcontext->uc_mcontext.gregs[X64_ERR] = 0x14|((sysmapped && !(real_prot&PROT_READ))?0:1);
+                sigcontext->uc_mcontext.gregs[X64_TRAPNO] = 14;
             }
-        } else if(info->si_code==SEGV_ACCERR && !(prot&PROT_WRITE)) {
-            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] = mmapped?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] = 0x0001;    // read error?
+            sigcontext->uc_mcontext.gregs[X64_TRAPNO] = 14;
+            sigcontext->uc_mcontext.gregs[X64_ERR] = 4|((sysmapped && !(real_prot&PROT_READ))?0:1);
+            if(write_opcode(sigcontext->uc_mcontext.gregs[X64_RIP], (uintptr_t)pc, (R_CS==0x23)))
+                sigcontext->uc_mcontext.gregs[X64_ERR] |= 2;
         }
         if(info->si_code == SEGV_ACCERR && old_code)
             *old_code = -1;
         if(info->si_errno==0x1234) {
+            sigcontext->uc_mcontext.gregs[X64_TRAPNO] = 13;
             info2->si_errno = 0;
         } else if(info->si_errno==0xdead) {
             // INT x
@@ -1195,6 +1193,7 @@ void my_sigactionhandler_oldcode(x64emu_t* emu, int32_t sig, int simple, siginfo
             info2->si_errno = 0;
             info2->si_code = 128;
             info2->si_addr = NULL;
+            sigcontext->uc_mcontext.gregs[X64_TRAPNO] = 13;
             // some special cases...
             if(int_n==3) {
                 info2->si_signo = SIGTRAP;
@@ -1461,7 +1460,7 @@ void my_box64signalhandler(int32_t sig, siginfo_t* info, void * ucntx)
     #ifdef BAD_SIGNAL
     // try to see if the si_code makes sense
     // the RK3588 tend to need a special Kernel that seems to have a weird behaviour sometimes
-    if((sig==SIGSEGV) && (addr) && (info->si_code == 1) && prot&(PROT_READ|PROT_WRITE|PROT_EXEC)) {
+    if((sig==SIGSEGV) && (addr) && (info->si_code == 1) && getMmapped((uintptr_t)addr)) {
         printf_log(LOG_DEBUG, "Workaround for suspicious si_code for %p / prot=0x%hhx\n", addr, prot);
         info->si_code = 2;
     }
diff --git a/tests/ref21.txt b/tests/ref21.txt
index 8fc221a0..14aada64 100644
--- a/tests/ref21.txt
+++ b/tests/ref21.txt
@@ -1,6 +1,50 @@
 sig = 11
 got bad_ptr
 sig = 5
-si_addr: 0, si_code: 128, si_errno: 0, RIP offset: 1, TRAPERR=0 TRAPNO=3
+si_addr: 0, si_code: 128, si_errno: 0, RIP offset: 1, TRAPERR=0x0 TRAPNO=3
 sig = 5
-si_addr: 0, si_code: 128, si_errno: 0, RIP offset: 2, TRAPERR=0 TRAPNO=3
+si_addr: 0, si_code: 128, si_errno: 0, RIP offset: 2, TRAPERR=0x0 TRAPNO=3
+sig = 11
+si_addr: 0, si_code: 128, si_errno: 0, RIP offset: 0, TRAPERR=0x16a TRAPNO=13
+from non-existant memory
+sig = 11
+si_addr: ffffffffdeadbeef, si_code: 1, si_errno: 0, TRAPERR=0x7 TRAPNO=14
+segfault, good
+sig = 11
+si_addr: ffffffffdeadbeef, si_code: 1, si_errno: 0, TRAPERR=0x5 TRAPNO=14
+segfault, good
+sig = 11
+si_addr: ffffffffdeadbeef, si_code: 1, si_errno: 0, TRAPERR=0x15 TRAPNO=14
+segfault, good
+from NULL memory
+sig = 11
+si_addr: 0, si_code: 1, si_errno: 0, TRAPERR=0x6 TRAPNO=14
+segfault, good
+sig = 11
+si_addr: 0, si_code: 1, si_errno: 0, TRAPERR=0x4 TRAPNO=14
+segfault, good
+sig = 11
+si_addr: 0, si_code: 1, si_errno: 0, TRAPERR=0x14 TRAPNO=14
+segfault, good
+from existant memory
+exec_p prot = 0
+sig = 11
+si_addr: exec_p+0, si_code: 2, si_errno: 0, TRAPERR=0x6 TRAPNO=14
+segfault, good
+sig = 11
+si_addr: exec_p+0, si_code: 2, si_errno: 0, TRAPERR=0x4 TRAPNO=14
+segfault, good
+exec_p prot = PROT_READ
+sig = 11
+si_addr: exec_p+0, si_code: 2, si_errno: 0, TRAPERR=0x7 TRAPNO=14
+segfault, good
+exec_p prot = PROT_READ|PROT_WRITE
+sig = 11
+si_addr: exec_p+0, si_code: 2, si_errno: 0, RIP offset: 0, TRAPERR=0x15 TRAPNO=14
+Cannot run, good
+exec_p prot = PROT_READ|PROT_WRITE|PROT_EXEC
+exec_p prot = PROT_READ|PROT_WRITE
+sig = 11
+si_addr: exec_p+0, si_code: 2, si_errno: 0, RIP offset: 0, TRAPERR=0x15 TRAPNO=14
+Cannot run, good!
+exec_p prot = PROT_READ|PROT_WRITE|PROT_EXEC
diff --git a/tests/test21 b/tests/test21
index 934ebcb7..7696b453 100755
--- a/tests/test21
+++ b/tests/test21
Binary files differdiff --git a/tests/test21.c b/tests/test21.c
index 09bae72a..74865023 100644
--- a/tests/test21.c
+++ b/tests/test21.c
@@ -7,6 +7,7 @@
 #include <errno.h>
 #include <string.h>
 #include <unistd.h>
+#include <stdint.h>
 
 static jmp_buf context_buf;
 
@@ -33,12 +34,20 @@ typedef void(*vFv_t)(void);
 #define X_ERR		19
 static void segv_action(int sig, siginfo_t* info, ucontext_t* ucntx)
 {
+	if(!exec_p) {
+		segv_handler(sig);
+		return;
+	}
 	printf("sig = %d\n", sig);
-	printf("si_addr: %zx, si_code: %d, si_errno: %d, RIP offset: %zd, TRAPERR=%d TRAPNO=%d\n", 
-		info->si_addr,
-		info->si_code,
-		info->si_errno,
-		((intptr_t)ucntx->uc_mcontext.gregs[X_IP])-((intptr_t)exec_p),
+	uintptr_t rip = (intptr_t)ucntx->uc_mcontext.gregs[X_IP];
+	if(info->si_addr>=exec_p && info->si_addr<(exec_p+10))
+		printf("si_addr: exec_p+%zx, ", (uintptr_t)info->si_addr-(uintptr_t)exec_p);
+	else
+		printf("si_addr: %zx, ", info->si_addr);
+	printf("si_code: %d, si_errno: %d, ", info->si_code, info->si_errno);
+	if(rip>=((intptr_t)exec_p) && rip<((intptr_t)exec_p+5))
+		printf("RIP offset: %zd, ", rip-((intptr_t)exec_p));
+	printf("TRAPERR=0x%x TRAPNO=%d\n", 
 		ucntx->uc_mcontext.gregs[X_ERR],
 		ucntx->uc_mcontext.gregs[X_TRAPNO]
 	);
@@ -48,6 +57,7 @@ static void segv_action(int sig, siginfo_t* info, ucontext_t* ucntx)
 static unsigned char buff_cc[] = { 0xcc, 0xc3 };
 static unsigned char buff_cd03[] = { 0xcd, 0x03, 0xc3 };
 static unsigned char buff_cd2d[] = { 0xcd, 0x2d, 0xc3 };
+static uint8_t buff_simplef[] = { 0xb8, 1, 0, 0, 0, 0xc3 };
 void test_cc()
 {
 	memcpy(exec_p, buff_cc, sizeof(buff_cc));
@@ -60,24 +70,178 @@ void test_cc()
 		vFv_t f = (vFv_t)exec_p;
 		f();
 	}
-	/*memcpy(exec_p, buff_cd2d, sizeof(buff_cd2d));
+	memcpy(exec_p, buff_cd2d, sizeof(buff_cd2d));
 	if(!setjmp(context_buf)) {
 		vFv_t f = (vFv_t)exec_p;
 		f();
-	}*/
+	}
 }
 
-int main()
+void test_segfault()
 {
-	if(signal(SIGSEGV, segv_handler) == SIG_ERR) {
-		printf("signal: Err = %d\n", errno);
-		return -1;
+	printf("from non-existant memory\n");
+	// writing to existing protected memory
+	if(!setjmp(context_buf)) {
+		int *bad_ptr = (int*)0xffffffffdeadbeef;
+		*(uint8_t*)bad_ptr = 0xc3;
+	} else {
+		printf("segfault, good\n");
 	}
-	//printf("handler = %p\n", segv_handler);
-	test();
+	// writing to existing protected memory
+	if(!setjmp(context_buf)) {
+		int *bad_ptr = (int*)0xffffffffdeadbeef;
+		if(*(uint8_t*)bad_ptr == 0xc3)
+			printf("should not be readable or writeable!\n");
+		else
+			printf("should not be readable!\n");
+		printf("aborting test\n");
+		return;
+	} else {
+		printf("segfault, good\n");
+	}
+	// writing to existing protected memory
+	if(!setjmp(context_buf)) {
+		void* bad_ptr = (int*)0xffffffffdeadbeef;
+		void(*f)() = bad_ptr;
+		f();
+		printf("should not work!!! aboting test\n");
+		return;
+	} else {
+		printf("segfault, good\n");
+	}
+	printf("from NULL memory\n");
+	// writing to existing protected memory
+	if(!setjmp(context_buf)) {
+		int *bad_ptr = (int*)NULL;
+		*(uint8_t*)bad_ptr = 0xc3;
+	} else {
+		printf("segfault, good\n");
+	}
+	// writing to existing protected memory
+	if(!setjmp(context_buf)) {
+		int *bad_ptr = (int*)NULL;
+		if(*(uint8_t*)bad_ptr == 0xc3)
+			printf("should not be readable or writeable!\n");
+		else
+			printf("should not be readable!\n");
+		printf("aborting test\n");
+		return;
+	} else {
+		printf("segfault, good\n");
+	}
+	// writing to existing protected memory
+	if(!setjmp(context_buf)) {
+		void* bad_ptr = (int*)NULL;
+		void(*f)() = bad_ptr;
+		f();
+		printf("should not work!!! aboting test\n");
+		return;
+	} else {
+		printf("segfault, good\n");
+	}
+	printf("from existant memory\n");
+	printf("exec_p prot = 0\n");
+	mprotect(exec_p, 65536, 0);
+	// writing to existing protected memory
+	if(!setjmp(context_buf)) {
+		*(uint8_t*)exec_p = 0xc3;
+	} else {
+		printf("segfault, good\n");
+	}
+	// reading for exising protected memory
+	if(!setjmp(context_buf)) {
+		if(*(uint8_t*)exec_p == 0xc3)
+			printf("Error, this value should not be 0xc3\n");
+	} else {
+		printf("segfault, good\n");
+	}
+	printf("exec_p prot = PROT_READ\n");
+	mprotect(exec_p, 65536, PROT_READ);
+	// writing to existing protected memory
+	if(!setjmp(context_buf)) {
+		*(uint8_t*)exec_p = 0xc3;
+	} else {
+		printf("segfault, good\n");
+	}
+	// reading should work
+	if(!setjmp(context_buf)) {
+		if(*(uint8_t*)exec_p == 0xc3)
+			printf("Error, this value should not be 0xc3\n");
+	} else {
+		printf("segfault, not good....\n");
+	}
+	// reading should work
+	if(!setjmp(context_buf)) {
+		if(*(uint8_t*)exec_p == 0xc3)
+			printf("Error, this value should not be 0xc3\n");
+	} else {
+		printf("segfault, good\n");
+	}
+	printf("exec_p prot = PROT_READ|PROT_WRITE\n");
+	mprotect(exec_p, 65536, PROT_READ|PROT_WRITE);
+	// writing should
+	if(!setjmp(context_buf)) {
+		*(uint8_t*)exec_p = 0xc3;
+	} else {
+		printf("segfault, not good, aborting test\n");
+		return;
+	}
+	// reading should work
+	if(!setjmp(context_buf)) {
+		if(*(uint8_t*)exec_p != 0xc3) {
+			printf("Error, this value should be 0xc3, aborting test\n");
+			return;
+		}
+	} else {
+		printf("segfault, not good....\n");
+	}
+	// should not be able to run
+	if(!setjmp(context_buf)) {
+		vFv_t f = (vFv_t)exec_p;
+		f();
+	} else {
+		printf("Cannot run, good\n");
+	}
+	printf("exec_p prot = PROT_READ|PROT_WRITE|PROT_EXEC\n");
+	mprotect(exec_p, 65536, PROT_READ|PROT_WRITE|PROT_EXEC);
+	if(!setjmp(context_buf)) {
+		vFv_t f = (vFv_t)exec_p;
+		f();
+	} else {
+		printf("Cannot run, not good!\n");
+	}
+	printf("exec_p prot = PROT_READ|PROT_WRITE\n");
+	mprotect(exec_p, 65536, PROT_READ|PROT_WRITE);
+	memcpy(exec_p, buff_simplef, sizeof(buff_simplef));
+	if(!setjmp(context_buf)) {
+		int(*f)() = exec_p;
+		if(f()!=1) {
+			printf("function return should be 1\n");
+		}
+	} else {
+		printf("Cannot run, good!\n");
+	}
+	printf("exec_p prot = PROT_READ|PROT_WRITE|PROT_EXEC\n");
+	mprotect(exec_p, 65536, PROT_READ|PROT_WRITE|PROT_EXEC);
+	if(!setjmp(context_buf)) {
+		int(*f)() = exec_p;
+		if(f()!=1) {
+			printf("function return should be 1\n");
+		}
+		((uint8_t*)exec_p)[1] = 2;
+		if(f()!=2) {
+			printf("function return should be 2\n");
+		}
+	} else {
+		printf("Cannot run, not good, aborting test!\n");
+	}
+}
+
+int main()
+{
     struct sigaction action = {0};
     action.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER;
-    action.sa_sigaction = segv_action;
+    action.sa_sigaction = (void*)segv_action;
     if(sigaction(SIGSEGV, &action, NULL)) {
 		printf("sigaction: Err = %d\n", errno);
 		return -2;
@@ -86,11 +250,14 @@ int main()
 		printf("sigaction 2: Err = %d\n", errno);
 		return -2;
 	}
+	exec_p = NULL;
+	test();
 	exec_p = mmap(NULL, 65536, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
 	if(exec_p==MAP_FAILED) {
 		printf("mmap: Err = %d\n", errno);
 		return -3;
 	}
 	test_cc();
+	test_segfault();
 	return 0;
 }