diff options
| author | ptitSeb <sebastien.chev@gmail.com> | 2021-03-07 11:44:09 +0100 |
|---|---|---|
| committer | ptitSeb <sebastien.chev@gmail.com> | 2021-03-07 11:44:09 +0100 |
| commit | 2a514f14c13c93c32b5ba01a5a3cae811e9f3e0e (patch) | |
| tree | dd0e0f51100d8144fda9bb832bde9e8ff633e108 /src | |
| parent | 395d9eb6224841edf72d5494bf306cf1ff79915e (diff) | |
| download | box64-2a514f14c13c93c32b5ba01a5a3cae811e9f3e0e.tar.gz box64-2a514f14c13c93c32b5ba01a5a3cae811e9f3e0e.zip | |
Reworked FPU/MMX regs, added Context and Signal handling (and test13 works)
Diffstat (limited to 'src')
| -rwxr-xr-x | src/box64context.c | 5 | ||||
| -rwxr-xr-x | src/emu/x64emu.c | 7 | ||||
| -rwxr-xr-x | src/emu/x64emu_private.h | 16 | ||||
| -rwxr-xr-x | src/emu/x64run.c | 13 | ||||
| -rwxr-xr-x | src/emu/x64run_private.c | 10 | ||||
| -rwxr-xr-x | src/emu/x64run_private.h | 4 | ||||
| -rw-r--r-- | src/emu/x64rund9.c | 10 | ||||
| -rw-r--r-- | src/emu/x64rundb.c | 12 | ||||
| -rwxr-xr-x | src/emu/x87emu_private.c | 149 | ||||
| -rwxr-xr-x | src/emu/x87emu_private.h | 16 | ||||
| -rwxr-xr-x | src/include/regs.h | 17 | ||||
| -rwxr-xr-x | src/include/signals.h | 41 | ||||
| -rwxr-xr-x | src/libtools/signals.c | 1156 | ||||
| -rw-r--r-- | src/wrapped/generated/functions_list.txt | 2 | ||||
| -rw-r--r-- | src/wrapped/generated/wrapper.c | 4 | ||||
| -rw-r--r-- | src/wrapped/generated/wrapper.h | 2 | ||||
| -rwxr-xr-x | src/wrapped/wrappedlibc.c | 3 | ||||
| -rwxr-xr-x | src/wrapped/wrappedlibc_private.h | 12 |
18 files changed, 1355 insertions, 124 deletions
diff --git a/src/box64context.c b/src/box64context.c index 75fb5028..3a5e0c25 100755 --- a/src/box64context.c +++ b/src/box64context.c @@ -17,6 +17,7 @@ #include "library.h" #include "wrapper.h" #include "x64emu.h" +#include "signals.h" EXPORTDYN void initAllHelpers(box64context_t* context) @@ -26,7 +27,7 @@ void initAllHelpers(box64context_t* context) return; my_context = context; init_pthread_helper(); - //init_signal_helper(context); + init_signal_helper(context); inited = 1; } @@ -37,7 +38,7 @@ void finiAllHelpers(box64context_t* context) if(finied) return; fini_pthread_helper(context); - //fini_signal_helper(); + fini_signal_helper(); cleanAlternate(); fini_custommem_helper(context); finied = 1; diff --git a/src/emu/x64emu.c b/src/emu/x64emu.c index 80752a0a..60cceacb 100755 --- a/src/emu/x64emu.c +++ b/src/emu/x64emu.c @@ -205,7 +205,7 @@ void CloneEmu(x64emu_t *newemu, const x64emu_t* emu) newemu->old_ip = emu->old_ip; memcpy(newemu->segs, emu->segs, sizeof(emu->segs)); memset(newemu->segs_serial, 0, sizeof(newemu->segs_serial)); - memcpy(newemu->fpu, emu->fpu, sizeof(emu->fpu)); + memcpy(newemu->mmx87, emu->mmx87, sizeof(emu->mmx87)); memcpy(newemu->fpu_ld, emu->fpu_ld, sizeof(emu->fpu_ld)); memcpy(newemu->fpu_ll, emu->fpu_ll, sizeof(emu->fpu_ll)); memcpy(newemu->p_regs, emu->p_regs, sizeof(emu->p_regs)); @@ -215,7 +215,6 @@ void CloneEmu(x64emu_t *newemu, const x64emu_t* emu) newemu->top = emu->top; newemu->fpu_stack = emu->fpu_stack; memcpy(&newemu->round, &emu->round, sizeof(emu->round)); - memcpy(newemu->mmx, emu->mmx, sizeof(emu->mmx)); memcpy(newemu->xmm, emu->xmm, sizeof(emu->xmm)); newemu->mxcsr = emu->mxcsr; newemu->quit = emu->quit; @@ -336,7 +335,7 @@ const char* DumpCPURegs(x64emu_t* emu, uintptr_t ip) if(trace_emm) { // do emm reg is needed for(int i=0; i<8; ++i) { - sprintf(tmp, "mm%d:%016lx", i, emu->mmx[i].q); + sprintf(tmp, "mm%d:%016lx", i, emu->mmx87[i].q); strcat(buff, tmp); if ((i&3)==3) strcat(buff, "\n"); else strcat(buff, " "); } @@ -352,7 +351,7 @@ const char* DumpCPURegs(x64emu_t* emu, uintptr_t ip) // start with FPU regs... if(emu->fpu_stack) { for (int i=0; i<emu->fpu_stack; i++) { - sprintf(tmp, "ST%d=%f", i, emu->fpu[(emu->top+i)&7].d); + sprintf(tmp, "ST%d=%f", i, emu->mmx87[(emu->top+i)&7].d); strcat(buff, tmp); int c = 10-strlen(tmp); if(c<1) c=1; diff --git a/src/emu/x64emu_private.h b/src/emu/x64emu_private.h index 8e804981..113b722d 100755 --- a/src/emu/x64emu_private.h +++ b/src/emu/x64emu_private.h @@ -4,7 +4,7 @@ #include "regs.h" typedef struct box64context_s box64context_t; -//typedef struct i386_ucontext_s i386_ucontext_t; +typedef struct x64_ucontext_s x64_ucontext_t; #define ERR_UNIMPL 1 #define ERR_DIVBY0 2 @@ -29,18 +29,16 @@ typedef struct x64emu_s { x86flags_t eflags; reg64_t ip; uintptr_t old_ip; - // fpu - fpu_reg_t fpu[9]; + // fpu / mmx + mmx87_regs_t mmx87[8]; uint16_t cw,cw_mask_all; x87flags_t sw; uint32_t top; // top is part of sw, but it's faster to have it separatly int fpu_stack; fpu_round_t round; - fpu_ld_t fpu_ld[9]; // for long double emulation / 80bits fld fst - fpu_ll_t fpu_ll[9]; // for 64bits fild / fist sequence - fpu_p_reg_t p_regs[9]; - // mmx - mmx_regs_t mmx[8]; + fpu_ld_t fpu_ld[8]; // for long double emulation / 80bits fld fst + fpu_ll_t fpu_ll[8]; // for 64bits fild / fist sequence + fpu_p_reg_t p_regs[8]; // sse sse_regs_t xmm[16]; uint32_t mxcsr; @@ -77,7 +75,7 @@ typedef struct x64emu_s { void* init_stack; // initial stack (owned or not) uint32_t size_stack; // stack size (owned or not) - //i386_ucontext_t *uc_link; // to handle setcontext + x64_ucontext_t *uc_link; // to handle setcontext int type; // EMUTYPE_xxx define diff --git a/src/emu/x64run.c b/src/emu/x64run.c index 0795cdb9..9c465d54 100755 --- a/src/emu/x64run.c +++ b/src/emu/x64run.c @@ -18,9 +18,8 @@ #include "x64trace.h" #include "x87emu_private.h" #include "box64context.h" -//#include "my_cpuid.h" #include "bridge.h" -//#include "signals.h" +#include "signals.h" #ifdef DYNAREC #include "../dynarec/arm_lock_helper.h" #endif @@ -844,10 +843,10 @@ fini: goto x64emurun; } // setcontext handling -// else if(emu->uc_link) { -// emu->quit = 0; -// my_setcontext(emu, emu->uc_link); -// goto x64emurun; -// } + else if(emu->uc_link) { + emu->quit = 0; + my_setcontext(emu, emu->uc_link); + goto x64emurun; + } return 0; } diff --git a/src/emu/x64run_private.c b/src/emu/x64run_private.c index a6b900fb..737225e3 100755 --- a/src/emu/x64run_private.c +++ b/src/emu/x64run_private.c @@ -1147,12 +1147,12 @@ reg64_t* GetEw16off(x64emu_t *emu, rex_t rex, uint8_t v, uintptr_t offset) } } -mmx_regs_t* GetEm(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta) +mmx87_regs_t* GetEm(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta) { uint8_t m = v&0xC7; // filter Ed if(m>=0xC0) { - return &emu->mmx[m&0x07]; - } else return (mmx_regs_t*)GetECommon(emu, rex, m, delta); + return &emu->mmx87[m&0x07]; + } else return (mmx87_regs_t*)GetECommon(emu, rex, m, delta); } sse_regs_t* GetEx(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta) @@ -1178,10 +1178,10 @@ reg64_t* GetGb(x64emu_t *emu, rex_t rex, uint8_t v) return (reg64_t*)&emu->regs[m&3].byte[m>>2]; } -mmx_regs_t* GetGm(x64emu_t *emu, rex_t rex, uint8_t v) +mmx87_regs_t* GetGm(x64emu_t *emu, rex_t rex, uint8_t v) { uint8_t m = (v&0x38)>>3; - return &emu->mmx[m&7]; + return &emu->mmx87[m&7]; } sse_regs_t* GetGx(x64emu_t *emu, rex_t rex, uint8_t v) diff --git a/src/emu/x64run_private.h b/src/emu/x64run_private.h index e85dcfce..f9d3012e 100755 --- a/src/emu/x64run_private.h +++ b/src/emu/x64run_private.h @@ -82,12 +82,12 @@ reg64_t* GetEdO(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta, uintptr_t of #define GetEw GetEd reg64_t* GetEw16(x64emu_t *emu, rex_t rex, uint8_t v); reg64_t* GetEw16off(x64emu_t *emu, rex_t rex, uint8_t v, uintptr_t offset); -mmx_regs_t* GetEm(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta); +mmx87_regs_t* GetEm(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta); sse_regs_t* GetEx(x64emu_t *emu, rex_t rex, uint8_t v, uint8_t delta); reg64_t* GetGd(x64emu_t *emu, rex_t rex, uint8_t v); #define GetGw GetGd reg64_t* GetGb(x64emu_t *emu, rex_t rex, uint8_t v); -mmx_regs_t* GetGm(x64emu_t *emu, rex_t rex, uint8_t v); +mmx87_regs_t* GetGm(x64emu_t *emu, rex_t rex, uint8_t v); sse_regs_t* GetGx(x64emu_t *emu, rex_t rex, uint8_t v); void UpdateFlags(x64emu_t *emu); diff --git a/src/emu/x64rund9.c b/src/emu/x64rund9.c index 00314c97..113e5d42 100644 --- a/src/emu/x64rund9.c +++ b/src/emu/x64rund9.c @@ -45,9 +45,9 @@ int RunD9(x64emu_t *emu, rex_t rex) case 0xC5: case 0xC6: case 0xC7: /* FLD STx */ - ll = ST(nextop&7).ll; + ll = ST(nextop&7).q; fpu_do_push(emu); - ST0.ll = ll; + ST0.q = ll; break; case 0xC8: case 0xC9: @@ -57,9 +57,9 @@ int RunD9(x64emu_t *emu, rex_t rex) case 0xCD: case 0xCE: case 0xCF: /* FXCH STx */ - ll = ST(nextop&7).ll; - ST(nextop&7).ll = ST0.ll; - ST0.ll = ll; + ll = ST(nextop&7).q; + ST(nextop&7).q = ST0.q; + ST0.q = ll; break; case 0xD0: /* FNOP */ diff --git a/src/emu/x64rundb.c b/src/emu/x64rundb.c index ae29f362..772748a6 100644 --- a/src/emu/x64rundb.c +++ b/src/emu/x64rundb.c @@ -45,7 +45,7 @@ int RunDB(x64emu_t *emu, rex_t rex) case 0xC7: CHECK_FLAGS(emu); if(!ACCESS_FLAG(F_CF)) - ST0.ll = ST(nextop&7).ll; + ST0.q = ST(nextop&7).q; break; case 0xC8: /* FCMOVNE ST(0), ST(i) */ case 0xC9: @@ -57,7 +57,7 @@ int RunDB(x64emu_t *emu, rex_t rex) case 0xCF: CHECK_FLAGS(emu); if(!ACCESS_FLAG(F_ZF)) - ST0.ll = ST(nextop&7).ll; + ST0.q = ST(nextop&7).q; break; case 0xD0: /* FCMOVNBE ST(0), ST(i) */ case 0xD1: @@ -69,7 +69,7 @@ int RunDB(x64emu_t *emu, rex_t rex) case 0xD7: CHECK_FLAGS(emu); if(!(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF))) - ST0.ll = ST(nextop&7).ll; + ST0.q = ST(nextop&7).q; break; case 0xD8: /* FCMOVNU ST(0), ST(i) */ case 0xD9: @@ -81,7 +81,7 @@ int RunDB(x64emu_t *emu, rex_t rex) case 0xDF: CHECK_FLAGS(emu); if(!ACCESS_FLAG(F_PF)) - ST0.ll = ST(nextop&7).ll; + ST0.q = ST(nextop&7).q; break; case 0xE1: /* FDISI8087_NOP */ @@ -168,11 +168,11 @@ int RunDB(x64emu_t *emu, rex_t rex) fpu_do_push(emu); memcpy(&STld(0).ld, ED, 10); LD2D(&STld(0), &ST(0).d); - STld(0).ref = ST0.ll; + STld(0).ref = ST0.q; break; case 7: /* FSTP tbyte */ GETED(0); - if(ST0.ll!=STld(0).ref) + if(ST0.q!=STld(0).ref) D2LD(&ST0.d, ED); else memcpy(ED, &STld(0).ld, 10); diff --git a/src/emu/x87emu_private.c b/src/emu/x87emu_private.c index 3e0c0458..5f638bfb 100755 --- a/src/emu/x87emu_private.c +++ b/src/emu/x87emu_private.c @@ -11,13 +11,13 @@ void reset_fpu(x64emu_t* emu) { - memset(emu->fpu, 0, sizeof(emu->fpu)); + memset(emu->mmx87, 0, sizeof(emu->mmx87)); memset(emu->fpu_ld, 0, sizeof(emu->fpu_ld)); emu->cw = 0x37F; emu->sw.x16 = 0x0000; emu->top = 0; emu->fpu_stack = 0; - for(int i=0; i<9; ++i) + for(int i=0; i<8; ++i) emu->p_regs[i].tag = 0b11; // STx is empty } @@ -67,7 +67,7 @@ void fpu_fbld(x64emu_t* emu, uint8_t* s) { } -#define FPU_t fpu_reg_t +#define FPU_t mmx87_regs_t #define BIAS80 16383 #define BIAS64 1023 // long double (80bits) -> double (64bits) @@ -83,8 +83,8 @@ void LD2D(void* ld, void* d) #if 1 memcpy(&val, ld, 10); #else - val.f.l.lower = *(uint32_t*)ld; - val.f.l.upper = *(uint32_t*)(char*)(ld+4); + val.f.ud[0] = *(uint32_t*)ld; + val.f.ud[1] = *(uint32_t*)(char*)(ld+4); val.b = *(int16_t*)((char*)ld+8); #endif int32_t exp64 = (((uint32_t)(val.b&0x7fff) - BIAS80) + BIAS64); @@ -95,31 +95,31 @@ void LD2D(void* ld, void* d) if((uint32_t)(val.b&0x7fff)==0x7fff) { // infinity and nans int t = 0; //nan - switch((val.f.l.upper>>30)) { - case 0: if((val.f.l.upper&(1<<29))==0) t = 1; + switch((val.f.ud[1]>>30)) { + case 0: if((val.f.ud[1]&(1<<29))==0) t = 1; break; - case 2: if((val.f.l.upper&(1<<29))==0) t = 1; + case 2: if((val.f.ud[1]&(1<<29))==0) t = 1; break; } if(t) { // infinite result.d = HUGE_VAL; } else { // NaN - result.l.upper = 0x7ff << 20; - result.l.lower = 0; + result.ud[1] = 0x7ff << 20; + result.ud[0] = 0; } if(val.b&0x8000) - result.l.upper |= 0x80000000; - *(uint64_t*)d = result.ll; + result.ud[1] |= 0x80000000; + *(uint64_t*)d = result.q; return; } if(((uint32_t)(val.b&0x7fff)==0) || (exp64<=0)) { - //if(val.f.ll==0) + //if(val.f.q==0) // zero - //if(val.f.ll!=0) + //if(val.f.q!=0) // denormal, but that's to small value for double uint64_t r = 0; if(val.b&0x8000) - r |= 0x8000000000000000LL; + r |= 0x8000000000000000L; *(uint64_t*)d = r; return; } @@ -128,17 +128,17 @@ void LD2D(void* ld, void* d) // to big value... result.d = HUGE_VAL; if(val.b&0x8000) - result.l.upper |= 0x80000000; - *(uint64_t*)d = result.ll; + result.ud[1] |= 0x80000000; + *(uint64_t*)d = result.q; return; } - uint64_t mant64 = (val.f.ll >> 11) & 0xfffffffffffffLL; + uint64_t mant64 = (val.f.q >> 11) & 0xfffffffffffffL; uint32_t sign = (val.b&0x8000)?1:0; - result.ll = mant64; - result.l.upper |= (sign <<31)|((exp64final&0x7ff) << 20); + result.q = mant64; + result.ud[1] |= (sign <<31)|((exp64final&0x7ff) << 20); - *(uint64_t*)d = result.ll; + *(uint64_t*)d = result.q; } // double (64bits) -> long double (80bits) @@ -151,12 +151,12 @@ void D2LD(void* d, void* ld) } val; #pragma pack(pop) FPU_t s; - s.ll = *(uint64_t*)d; // use memcpy to avoid risk of Bus Error? + s.q = *(uint64_t*)d; // use memcpy to avoid risk of Bus Error? // do special value first - if((s.ll&0x7fffffffffffffffLL)==0) { + if((s.q&0x7fffffffffffffffL)==0) { // zero... - val.f.ll = 0; - if(s.l.upper&0x8000) + val.f.q = 0; + if(s.ud[1]&0x8000) val.b = 0x8000; else val.b = 0; @@ -164,26 +164,26 @@ void D2LD(void* d, void* ld) return; } - int32_t sign80 = (s.l.upper&0x80000000)?1:0; - int32_t exp80 = s.l.upper&0x7ff00000; + int32_t sign80 = (s.ud[1]&0x80000000)?1:0; + int32_t exp80 = s.ud[1]&0x7ff00000; int32_t exp80final = (exp80>>20); - int64_t mant80 = s.ll&0x000fffffffffffffLL; + int64_t mant80 = s.q&0x000fffffffffffffL; int64_t mant80final = (mant80 << 11); if(exp80final==0x7ff) { // NaN and Infinite exp80final = 0x7fff; if(mant80==0x0) - mant80final = 0x8000000000000000LL; //infinity + mant80final = 0x8000000000000000L; //infinity else - mant80final = 0xc000000000000000LL; //(quiet)NaN + mant80final = 0xc000000000000000L; //(quiet)NaN } else { if(exp80!=0){ - mant80final |= 0x8000000000000000LL; + mant80final |= 0x8000000000000000L; exp80final += (BIAS80 - BIAS64); } } val.b = ((int16_t)(sign80)<<15)| (int16_t)(exp80final); - val.f.ll = mant80final; + val.f.q = mant80final; memcpy(ld, &val, 10); /*memcpy(ld, &f.ll, 8); memcpy((char*)ld + 8, &val.b, 2);*/ @@ -231,7 +231,8 @@ void fpu_savenv(x64emu_t* emu, char* p, int b16) // other stuff are not pushed.... } -typedef struct xsave_s { +// this is the 64bits version (slightly different than the 32bits!) +typedef struct xsave32_s { uint16_t ControlWord; /* 000 */ uint16_t StatusWord; /* 002 */ uint8_t TagWord; /* 004 */ @@ -248,11 +249,25 @@ typedef struct xsave_s { sse_regs_t FloatRegisters[8];/* 020 */ // fpu/mmx are store in 128bits here sse_regs_t XmmRegisters[16]; /* 0a0 */ uint8_t Reserved4[96]; /* 1a0 */ -} xsave_t; +} xsave32_t; +typedef struct xsave64_s { + uint16_t ControlWord; /* 000 */ + uint16_t StatusWord; /* 002 */ + uint8_t TagWord; /* 004 */ + uint8_t Reserved1; /* 005 */ + uint16_t ErrorOpcode; /* 006 */ + uint64_t ErrorOffset; /* 008 */ + uint64_t DataOffset; /* 010 */ + uint32_t MxCsr; /* 018 */ + uint32_t MxCsr_Mask; /* 01c */ + sse_regs_t FloatRegisters[8];/* 020 */ // fpu/mmx are store in 128bits here + sse_regs_t XmmRegisters[16]; /* 0a0 */ + uint8_t Reserved4[96]; /* 1a0 */ +} xsave64_t; -void fpu_fxsave(x64emu_t* emu, void* ed) +void fpu_fxsave32(x64emu_t* emu, void* ed) { - xsave_t *p = (xsave_t*)ed; + xsave32_t *p = (xsave32_t*)ed; // should save flags & all emu->sw.f.F87_TOP = emu->top&7; p->ControlWord = emu->cw; @@ -268,21 +283,55 @@ void fpu_fxsave(x64emu_t* emu, void* ed) p->DataSelector = 0; p->MxCsr = 0; p->MxCsr_Mask = 0; - // copy MMX regs... + // copy FPU/MMX regs... + for(int i=0; i<8; ++i) + memcpy(&p->FloatRegisters[i].q[0], &emu->mmx87[0], sizeof(emu->mmx87[0])); + // copy SSE regs + memcpy(&p->XmmRegisters[0], &emu->xmm[0], sizeof(emu->xmm)); +} + +void fpu_fxsave64(x64emu_t* emu, void* ed) +{ + xsave64_t *p = (xsave64_t*)ed; + // should save flags & all + emu->sw.f.F87_TOP = emu->top&7; + p->ControlWord = emu->cw; + p->StatusWord = emu->sw.x16; + uint8_t tags = 0; + for (int i=0; i<8; ++i) + tags |= ((emu->p_regs[i].tag)<<(i*2)==0b11)?0:1; + p->TagWord = tags; + p->ErrorOpcode = 0; + p->ErrorOffset = 0; + p->DataOffset = 0; + p->MxCsr = 0; + p->MxCsr_Mask = 0; + // copy FPU/MMX regs... for(int i=0; i<8; ++i) - memcpy(&p->FloatRegisters[i].q[0], &emu->mmx[0], sizeof(emu->mmx[0])); + memcpy(&p->FloatRegisters[i].q[0], &emu->mmx87[0], sizeof(emu->mmx87[0])); // copy SSE regs memcpy(&p->XmmRegisters[0], &emu->xmm[0], sizeof(emu->xmm)); - // put also FPU regs in a reserved area... on XMM 8-15 +} + +void fpu_fxrstor32(x64emu_t* emu, void* ed) +{ + xsave32_t *p = (xsave32_t*)ed; + emu->cw = p->ControlWord; + emu->sw.x16 = p->StatusWord; + emu->top = emu->sw.f.F87_TOP; + uint8_t tags = p->TagWord; for(int i=0; i<8; ++i) - memcpy(&p->XmmRegisters[8+i].q[0], &emu->fpu[0], sizeof(emu->fpu[0])); - // put a magic sign in reserved area, box86 specific - ((unsigned int *)p->Reserved4)[11] = 0x50515253; + emu->p_regs[i].tag = (tags>>(i*2))?0:0b11; + // copy back MMX regs... + for(int i=0; i<8; ++i) + memcpy(&emu->mmx87[i], &p->FloatRegisters[i].q[0], sizeof(emu->mmx87[0])); + // copy SSE regs + memcpy(&emu->xmm[0], &p->XmmRegisters[0], sizeof(emu->xmm)); } -void fpu_fxrstor(x64emu_t* emu, void* ed) +void fpu_fxrstor64(x64emu_t* emu, void* ed) { - xsave_t *p = (xsave_t*)ed; + xsave64_t *p = (xsave64_t*)ed; emu->cw = p->ControlWord; emu->sw.x16 = p->StatusWord; emu->top = emu->sw.f.F87_TOP; @@ -291,17 +340,7 @@ void fpu_fxrstor(x64emu_t* emu, void* ed) emu->p_regs[i].tag = (tags>>(i*2))?0:0b11; // copy back MMX regs... for(int i=0; i<8; ++i) - memcpy(&emu->mmx[i], &p->FloatRegisters[i].q[0], sizeof(emu->mmx[0])); + memcpy(&emu->mmx87[i], &p->FloatRegisters[i].q[0], sizeof(emu->mmx87[0])); // copy SSE regs memcpy(&emu->xmm[0], &p->XmmRegisters[0], sizeof(emu->xmm)); - // check the box86 magic sign in reserved area - if(((unsigned int *)p->Reserved4)[11] == 0x50515253) { - // also FPU regs where a reserved area... on XMM 8-15? - for(int i=0; i<8; ++i) - memcpy(&emu->fpu[0], &p->XmmRegisters[8+i].q[0], sizeof(emu->fpu[0])); - } else { - // copy the mmx to fpu... - for(int i=0; i<8; ++i) - memcpy(&emu->fpu[0], &emu->mmx[i], sizeof(emu->mmx[0])); - } } diff --git a/src/emu/x87emu_private.h b/src/emu/x87emu_private.h index b8fcf9ad..f188187a 100755 --- a/src/emu/x87emu_private.h +++ b/src/emu/x87emu_private.h @@ -18,9 +18,9 @@ typedef struct x64emu_s x64emu_t; //void Run66DD(x64emu_t *emu); //void RunDF(x64emu_t *emu); -#define ST0 emu->fpu[emu->top] -#define ST1 emu->fpu[(emu->top+1)&7] -#define ST(a) emu->fpu[(emu->top+(a))&7] +#define ST0 emu->mmx87[emu->top] +#define ST1 emu->mmx87[(emu->top+1)&7] +#define ST(a) emu->mmx87[(emu->top+(a))&7] #define STld(a) emu->fpu_ld[(emu->top+(a))&7] #define STll(a) emu->fpu_ll[(emu->top+(a))&7] @@ -133,7 +133,7 @@ static inline double fpu_round(x64emu_t* emu, double d) { } static inline void fpu_fxam(x64emu_t* emu) { - emu->sw.f.F87_C1 = (ST0.l.upper&0x80000000)?1:0; + emu->sw.f.F87_C1 = (ST0.ud[1]&0x80000000)?1:0; if(!emu->fpu_stack) { emu->sw.f.F87_C3 = 1; emu->sw.f.F87_C2 = 0; @@ -187,7 +187,7 @@ static inline void fpu_ftst(x64emu_t* emu) { // normal... emu->sw.f.F87_C3 = 0; emu->sw.f.F87_C2 = 0; - emu->sw.f.F87_C0 = (ST0.l.upper&0x80000000)?1:0; + emu->sw.f.F87_C0 = (ST0.ud[1]&0x80000000)?1:0; } void fpu_fbst(x64emu_t* emu, uint8_t* d); @@ -195,7 +195,9 @@ void fpu_fbld(x64emu_t* emu, uint8_t* s); void fpu_loadenv(x64emu_t* emu, char* p, int b16); void fpu_savenv(x64emu_t* emu, char* p, int b16); -void fpu_fxsave(x64emu_t* emu, void* ed); -void fpu_fxrstor(x64emu_t* emu, void* ed); +void fpu_fxsave32(x64emu_t* emu, void* ed); +void fpu_fxrstor32(x64emu_t* emu, void* ed); +void fpu_fxsave64(x64emu_t* emu, void* ed); +void fpu_fxrstor64(x64emu_t* emu, void* ed); #endif //__X87RUN_PRIVATE_H_ diff --git a/src/include/regs.h b/src/include/regs.h index 84159d2b..f75624a0 100755 --- a/src/include/regs.h +++ b/src/include/regs.h @@ -127,19 +127,6 @@ typedef enum { #pragma pack(push, 1) typedef union { - double d; - struct { - uint32_t lower; - uint32_t upper; - } l; - struct { - float lower; - float upper; - } f; - int64_t ll; -} fpu_reg_t; - -typedef union { //long double ld; // works only if 80bits! struct { uint64_t lower; @@ -237,13 +224,15 @@ typedef union { typedef union { uint64_t q; int64_t sq; + double d; + float f[2]; uint32_t ud[2]; int32_t sd[2]; uint16_t uw[4]; int16_t sw[4]; uint8_t ub[8]; int8_t sb[8]; -} mmx_regs_t; +} mmx87_regs_t; typedef union { uint64_t q[2]; diff --git a/src/include/signals.h b/src/include/signals.h new file mode 100755 index 00000000..513e5812 --- /dev/null +++ b/src/include/signals.h @@ -0,0 +1,41 @@ +#ifndef __SIGNALS_H__ +#define __SIGNALS_H__ +#include <signal.h> + +typedef void (*sighandler_t)(int); + +typedef struct x64_sigaction_s { + union { + __sighandler_t _sa_handler; + void (*_sa_sigaction)(int, siginfo_t *, void *); + } _u; + sigset_t sa_mask; + uint32_t sa_flags; + void (*sa_restorer)(void); +} x64_sigaction_t; + +typedef struct x64_sigaction_restorer_s { + union { + __sighandler_t _sa_handler; + void (*_sa_sigaction)(int, siginfo_t *, void *); + } _u; + uint32_t sa_flags; + void (*sa_restorer)(void); + sigset_t sa_mask; +} x64_sigaction_restorer_t; + +sighandler_t my_signal(x64emu_t* emu, int signum, sighandler_t handler); +sighandler_t my___sysv_signal(x64emu_t* emu, int signum, sighandler_t handler); +sighandler_t my_sysv_signal(x64emu_t* emu, int signum, sighandler_t handler); + +int my_sigaction(x64emu_t* emu, int signum, const x64_sigaction_t *act, x64_sigaction_t *oldact); +int my___sigaction(x64emu_t* emu, int signum, const x64_sigaction_t *act, x64_sigaction_t *oldact); + +int my_syscall_rt_sigaction(x64emu_t* emu, int signum, const x64_sigaction_restorer_t *act, x64_sigaction_restorer_t *oldact, int sigsetsize); + +void init_signal_helper(box64context_t* context); +void fini_signal_helper(); + +void emit_signal(x64emu_t* emu, int sig, void* addr, int code); + +#endif //__SIGNALS_H__ \ No newline at end of file diff --git a/src/libtools/signals.c b/src/libtools/signals.c new file mode 100755 index 00000000..1ff13887 --- /dev/null +++ b/src/libtools/signals.c @@ -0,0 +1,1156 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <signal.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <syscall.h> +#include <stddef.h> +#include <stdarg.h> +#include <ucontext.h> +#include <setjmp.h> +#include <sys/mman.h> + +#include "box64context.h" +#include "debug.h" +#include "x64emu.h" +#include "emu/x64emu_private.h" +#include "emu/x64run_private.h" +#include "signals.h" +#include "box64stack.h" +#include "dynarec.h" +#include "callback.h" +#include "x64run.h" +#include "elfloader.h" +#include "threads.h" +#include "emu/x87emu_private.h" +#include "custommem.h" +#ifdef DYNAREC +#include "dynablock.h" +#include "../dynarec/dynablock_private.h" +#endif + + +typedef uint64_t x64_gregset_t[23]; +enum +{ + X64_R8 = 0, +# define X64_R8 X64_R8 + X64_R9, +# define X64_R9 X64_R9 + X64_R10, +# define X64_R10 X64_R10 + X64_R11, +# define X64_R11 X64_R11 + X64_R12, +# define X64_R12 X64_R12 + X64_R13, +# define X64_R13 X64_R13 + X64_R14, +# define X64_R14 X64_R14 + X64_R15, +# define X64_R15 X64_R15 + X64_RDI, +# define X64_RDI X64_RDI + X64_RSI, +# define X64_RSI X64_RSI + X64_RBP, +# define X64_RBP X64_RBP + X64_RBX, +# define X64_RBX X64_RBX + X64_RDX, +# define X64_RDX X64_RDX + X64_RAX, +# define X64_RAX X64_RAX + X64_RCX, +# define X64_RCX X64_RCX + X64_RSP, +# define X64_RSP X64_RSP + X64_RIP, +# define X64_RIP X64_RIP + X64_EFL, +# define X64_EFL X64_EFL + X64_CSGSFS, /* Actually short cs, gs, fs, __pad0. */ +# define X64_CSGSFS X64_CSGSFS + X64_ERR, +# define X64_ERR X64_ERR + X64_TRAPNO, +# define X64_TRAPNO X64_TRAPNO + X64_OLDMASK, +# define X64_OLDMASK X64_OLDMASK + X64_CR2 +# define X64_CR2 X64_CR2 +}; + +struct x64_fpreg +{ + uint64_t value; +}__attribute__((packed)); + +struct x64_fpxreg +{ + unsigned short significand[4]; + unsigned short exponent; + unsigned short padding[3]; +}__attribute__((packed)); + +struct x64_xmmreg +{ + uint32_t element[4]; +}__attribute__((packed)); + +struct x64_fpstate +{ + /* Regular FPU environment. */ + uint16_t cw; + uint16_t sw; + uint16_t tw; + uint16_t fop; + uint64_t rip; + uint64_t rdp; + uint32_t mxcsr; + uint32_t mxcsr_mask; + struct x64_fpreg _st[8]; + struct x64_xmmreg _xmm[16]; + uint32_t res[12]; + uint32_t res2[12]; +}__attribute__((packed)); + +typedef struct x64_fpstate *x64_fpregset_t; + +typedef struct +{ + void *ss_sp; + int ss_flags; + size_t ss_size; +} x64_stack_t; + +struct sigcontext_x64 +{ + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t di; + uint64_t si; + uint64_t bp; + uint64_t bx; + uint64_t dx; + uint64_t ax; + uint64_t cx; + uint64_t sp; + uint64_t ip; + uint64_t flags; + uint64_t cs; + uint64_t gs; + uint64_t fs; + uint64_t ss; + uint64_t err; + uint64_t trapno; + uint64_t oldmask; + uint64_t cr2; + uint64_t fpstate; /* Zero when no FPU/extended context */ + uint64_t reserved1[8]; +}; + +struct x64_sigcontext +{ + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t rdi; + uint64_t rsi; + uint64_t rbp; + uint64_t rbx; + uint64_t rdx; + uint64_t rax; + uint64_t rcx; + uint64_t rsp; + uint64_t rip; + uint64_t eflags; /* RFLAGS */ + uint16_t cs; + uint16_t gs; + uint16_t fs; + union { + uint16_t ss; /* If UC_SIGCONTEXT_SS */ + uint16_t __pad0; /* Alias name for old (!UC_SIGCONTEXT_SS) user-space */ + }; + uint64_t err; + uint64_t trapno; + uint64_t oldmask; + uint64_t cr2; + struct x64_fpstate *fpstate; /* Zero when no FPU context */ + uint64_t reserved1[8]; +}; + +struct x64_libc_fpstate +{ + /* 64-bit FXSAVE format. */ + uint16_t cwd; + uint16_t swd; + uint16_t ftw; + uint16_t fop; + uint64_t rip; + uint64_t rdp; + uint32_t mxcsr; + uint32_t mxcr_mask; + struct x64_fpxreg st[8]; + struct x64_xmmreg xmm[16]; + uint32_t res1[24]; +}; + +typedef struct x64_mcontext_s +{ + x64_gregset_t gregs; + struct x64_libc_fpstate *fpregs; + uint64_t res[8]; +} x64_mcontext_t; + +// /!\ signal sig_set is different than glibc __sig_set +#define _NSIG_WORDS (128 / sizeof(unsigned long int)) + +typedef struct { + unsigned long int sig[_NSIG_WORDS]; +} x64_sigset_t; + +typedef struct x64_ucontext_s +{ + uint64_t uc_flags; + struct x64_ucontext_s* uc_link; + x64_stack_t uc_stack; + x64_mcontext_t uc_mcontext; + x64_sigset_t uc_sigmask; + struct x64_libc_fpstate xstate; + uint64_t ssp[4]; +} x64_ucontext_t; + +typedef struct x64_sigframe_s { + uintptr_t pretcode; // pointer to retcode + int sig; + x64_mcontext_t cpustate; + struct x64_libc_fpstate xstate; + uintptr_t extramask[64-1]; + char retcode[8]; +} x64_sigframe_t; + +struct kernel_sigaction { + void (*k_sa_handler) (int); + unsigned long sa_flags; + void (*sa_restorer) (void); + unsigned long sa_mask; + unsigned long sa_mask2; +}; + +static void sigstack_destroy(void* p) +{ + x64_stack_t *ss = (x64_stack_t*)p; + free(ss); +} + +static void free_signal_emu(void* p) +{ + if(p) + FreeX64Emu((x64emu_t**)&p); +} + +static pthread_key_t sigstack_key; +static pthread_once_t sigstack_key_once = PTHREAD_ONCE_INIT; + +static void sigstack_key_alloc() { + pthread_key_create(&sigstack_key, sigstack_destroy); +} + +static pthread_key_t sigemu_key; +static pthread_once_t sigemu_key_once = PTHREAD_ONCE_INIT; + +static void sigemu_key_alloc() { + pthread_key_create(&sigemu_key, free_signal_emu); +} + +static x64emu_t* get_signal_emu() +{ + x64emu_t *emu = (x64emu_t*)pthread_getspecific(sigemu_key); + if(!emu) { + const int stsize = 8*1024; // small stack for signal handler + void* stack = calloc(1, stsize); + emu = NewX64Emu(my_context, 0, (uintptr_t)stack, stsize, 1); + emu->type = EMUTYPE_SIGNAL; + pthread_setspecific(sigemu_key, emu); + } + return emu; +} + + +uint64_t RunFunctionHandler(int* exit, uintptr_t fnc, int nargs, ...) +{ + if(fnc==0 || fnc==1) { + printf_log(LOG_NONE, "BOX86: Warning, calling Signal function handler %s\n", fnc?"SIG_DFL":"SIG_IGN"); + return 0; + } + uintptr_t old_start = trace_start, old_end = trace_end; +// trace_start = 0; trace_end = 1; // disabling trace, globably for now... + + x64emu_t *emu = get_signal_emu(); + printf_log(LOG_DEBUG, "%04d|signal function handler %p called, ESP=%p\n", GetTID(), (void*)fnc, (void*)R_RSP); + + /*SetFS(emu, default_fs);*/ + for (int i=0; i<6; ++i) + emu->segs_serial[i] = 0; + + if(nargs>6) + R_RSP -= (nargs-6)*4; // need to push in reverse order + + uint64_t *p = (uint64_t*)R_RSP; + + va_list va; + va_start (va, nargs); + for (int i=0; i<nargs; ++i) { + if(i<6) { + int nn[] = {_DI, _SI, _DX, _CX, _R8, _R9}; + emu->regs[nn[i]].q[0] = va_arg(va, uint64_t); + } else { + *p = va_arg(va, uint64_t); + p++; + } + } + va_end (va); + + EmuCall(emu, fnc); // avoid DynaCall for now + if(nargs>6) + R_RSP+=((nargs-6)*4); + + if(exit) + *exit = emu->exit; + + uint64_t ret = R_RAX; + + trace_start = old_start; trace_end = old_end; + + return ret; +} + +EXPORT int my_sigaltstack(x64emu_t* emu, const x64_stack_t* ss, x64_stack_t* oss) +{ + if(!ss && !oss) { // this is not true, ss can be NULL to retreive oss info only + errno = EFAULT; + return -1; + } + x64emu_t *sigemu = get_signal_emu(); + x64_stack_t *new_ss = (x64_stack_t*)pthread_getspecific(sigstack_key); + if(!ss) { + if(!new_ss) { + oss->ss_flags = SS_DISABLE; + oss->ss_sp = sigemu->init_stack; + oss->ss_size = sigemu->size_stack; + } else { + oss->ss_flags = new_ss->ss_flags; + oss->ss_sp = new_ss->ss_sp; + oss->ss_size = new_ss->ss_size; + } + return 0; + } + printf_log(LOG_DEBUG, "%04d|sigaltstack called ss=%p[flags=0x%x, sp=%p, ss=0x%lx], oss=%p\n", GetTID(), ss, ss->ss_flags, ss->ss_sp, ss->ss_size, oss); + if(ss->ss_flags && ss->ss_flags!=SS_DISABLE && ss->ss_flags!=SS_ONSTACK) { + errno = EINVAL; + return -1; + } + + if(ss->ss_flags==SS_DISABLE) { + if(new_ss) + free(new_ss); + pthread_setspecific(sigstack_key, NULL); + + sigemu->regs[_SP].dword[0] = ((uintptr_t)sigemu->init_stack + sigemu->size_stack) & ~7; + + return 0; + } + if(oss) { + if(!new_ss) { + oss->ss_flags = SS_DISABLE; + oss->ss_sp = sigemu->init_stack; + oss->ss_size = sigemu->size_stack; + } else { + oss->ss_flags = new_ss->ss_flags; + oss->ss_sp = new_ss->ss_sp; + oss->ss_size = new_ss->ss_size; + } + } + if(!new_ss) + new_ss = (x64_stack_t*)calloc(1, sizeof(x64_stack_t)); + new_ss->ss_sp = ss->ss_sp; + new_ss->ss_size = ss->ss_size; + + pthread_setspecific(sigstack_key, new_ss); + + sigemu->regs[_SP].dword[0] = ((uintptr_t)new_ss->ss_sp + new_ss->ss_size - 16) & ~0x0f; + + return 0; +} + + +void my_sighandler(int32_t sig) +{ + pthread_mutex_unlock(&my_context->mutex_trace); // just in case + printf_log(LOG_DEBUG, "Sighanlder for signal #%d called (jump to %p)\n", sig, (void*)my_context->signals[sig]); + uintptr_t restorer = my_context->restorer[sig]; + int exits = 0; + int ret = RunFunctionHandler(&exits, my_context->signals[sig], 1, sig); + if(exits) + exit(ret); + if(restorer) + RunFunctionHandler(&exits, restorer, 0); +} + +#ifdef DYNAREC +uintptr_t getX64Address(dynablock_t* db, uintptr_t arm_addr) +{ + uintptr_t x64addr = (uintptr_t)db->x64_addr; + uintptr_t armaddr = (uintptr_t)db->block; + int i = 0; + do { + int x64sz = 0; + int armsz = 0; + do { + x64sz+=db->instsize[i].x64; + armsz+=db->instsize[i].nat*4; + } + while(!db->instsize[++i].x64); + if(arm_addr>=armaddr && arm_addr<(armaddr+armsz)) + return x64addr; + armaddr+=armsz; + x64addr+=x64sz; + if(arm_addr==armaddr) + return x64addr; + } while(db->instsize[i].x64 || db->instsize[i].nat); + return x64addr; +} +#endif + +void my_sigactionhandler_oldcode(int32_t sig, siginfo_t* info, void * ucntx, int* old_code, void* cur_db) +{ + // need to create some x64_ucontext???? + pthread_mutex_unlock(&my_context->mutex_trace); // just in case + 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(); + uint64_t *frame = (uint64_t*)R_RSP; +#if defined(DYNAREC) && defined(__arm__) + ucontext_t *p = (ucontext_t *)ucntx; + void * pc = (void*)p->uc_mcontext.arm_pc; + dynablock_t* db = (dynablock_t*)cur_db;//FindDynablockFromNativeAddress(pc); + if(db) { + frame = (uint32_t*)p->uc_mcontext.arm_r8; + } +#endif + // stack tracking + x64emu_t *sigemu = get_signal_emu(); + x64_stack_t *new_ss = my_context->onstack[sig]?(x64_stack_t*)pthread_getspecific(sigstack_key):NULL; + int used_stack = 0; + if(new_ss) { + if(new_ss->ss_flags == SS_ONSTACK) { // already using it! + frame = (uint64_t*)sigemu->regs[_SP].q[0]; + } else { + frame = (uint64_t*)(((uintptr_t)new_ss->ss_sp + new_ss->ss_size - 16) & ~0x0f); + used_stack = 1; + new_ss->ss_flags = SS_ONSTACK; + } + } + + // TODO: do I need to really setup 2 stack frame? That doesn't seems right! + // setup stack frame + // try to fill some sigcontext.... + frame -= sizeof(x64_ucontext_t); + x64_ucontext_t *sigcontext = (x64_ucontext_t*)frame; + // get general register + sigcontext->uc_mcontext.gregs[X64_R8] = R_R8; + sigcontext->uc_mcontext.gregs[X64_R9] = R_R9; + sigcontext->uc_mcontext.gregs[X64_R10] = R_R10; + sigcontext->uc_mcontext.gregs[X64_R11] = R_R11; + sigcontext->uc_mcontext.gregs[X64_R12] = R_R12; + sigcontext->uc_mcontext.gregs[X64_R13] = R_R13; + sigcontext->uc_mcontext.gregs[X64_R14] = R_R14; + sigcontext->uc_mcontext.gregs[X64_R15] = R_R15; + sigcontext->uc_mcontext.gregs[X64_RAX] = R_RAX; + sigcontext->uc_mcontext.gregs[X64_RCX] = R_RCX; + sigcontext->uc_mcontext.gregs[X64_RDX] = R_RDX; + sigcontext->uc_mcontext.gregs[X64_RDI] = R_RDI; + sigcontext->uc_mcontext.gregs[X64_RSI] = R_RSI; + sigcontext->uc_mcontext.gregs[X64_RBP] = R_RBP; + sigcontext->uc_mcontext.gregs[X64_RIP] = R_RIP; + sigcontext->uc_mcontext.gregs[X64_RSP] = R_RSP; + sigcontext->uc_mcontext.gregs[X64_RBX] = R_RBX; + // flags + sigcontext->uc_mcontext.gregs[X64_EFL] = emu->eflags.x32; + // get segments + sigcontext->uc_mcontext.gregs[X64_CSGSFS] = ((uint64_t)(R_CS)) | (((uint64_t)(R_GS))<<16) | (((uint64_t)(R_FS))<<32); +#if defined(DYNAREC) && defined(__arm__) + if(db) { + sigcontext->uc_mcontext.gregs[X64_RAX] = p->uc_mcontext.arm_r4; + sigcontext->uc_mcontext.gregs[X64_RCX] = p->uc_mcontext.arm_r5; + sigcontext->uc_mcontext.gregs[X64_RDX] = p->uc_mcontext.arm_r6; + sigcontext->uc_mcontext.gregs[X64_RBX] = p->uc_mcontext.arm_r7; + sigcontext->uc_mcontext.gregs[X64_RSP] = p->uc_mcontext.arm_r8; + sigcontext->uc_mcontext.gregs[X64_RBP] = p->uc_mcontext.arm_r9; + sigcontext->uc_mcontext.gregs[X64_RSI] = p->uc_mcontext.arm_r10; + sigcontext->uc_mcontext.gregs[X64_RDI] = p->uc_mcontext.arm_fp; + sigcontext->uc_mcontext.gregs[X64_RIP] = getX86Address(db, (uintptr_t)pc); + } +#endif + // get FloatPoint status + sigcontext->uc_mcontext.fpregs = (struct x64_libc_fpstate*)&sigcontext->xstate; + fpu_fxsave64(emu, &sigcontext->xstate); + // add custom SIGN in reserved area + //((unsigned int *)(&sigcontext.xstate.fpstate.padding))[8*4+12] = 0x46505853; // not yet, when XSAVE / XRSTR will be ready + // get signal mask + + if(!new_ss) { + sigcontext->uc_stack.ss_sp = sigemu->init_stack; + sigcontext->uc_stack.ss_size = sigemu->size_stack; + sigcontext->uc_stack.ss_flags = SS_DISABLE; + } else { + sigcontext->uc_stack.ss_sp = new_ss->ss_sp; + sigcontext->uc_stack.ss_size = new_ss->ss_size; + sigcontext->uc_stack.ss_flags = new_ss->ss_flags; + } + // Try to guess some X64_TRAPNO + /* + TRAP_x86_DIVIDE = 0, // Division by zero exception + TRAP_x86_TRCTRAP = 1, // Single-step exception + TRAP_x86_NMI = 2, // NMI interrupt + TRAP_x86_BPTFLT = 3, // Breakpoint exception + TRAP_x86_OFLOW = 4, // Overflow exception + TRAP_x86_BOUND = 5, // Bound range exception + TRAP_x86_PRIVINFLT = 6, // Invalid opcode exception + TRAP_x86_DNA = 7, // Device not available exception + TRAP_x86_DOUBLEFLT = 8, // Double fault exception + TRAP_x86_FPOPFLT = 9, // Coprocessor segment overrun + TRAP_x86_TSSFLT = 10, // Invalid TSS exception + TRAP_x86_SEGNPFLT = 11, // Segment not present exception + TRAP_x86_STKFLT = 12, // Stack fault + TRAP_x86_PROTFLT = 13, // General protection fault + TRAP_x86_PAGEFLT = 14, // Page fault + TRAP_x86_ARITHTRAP = 16, // Floating point exception + TRAP_x86_ALIGNFLT = 17, // Alignment check exception + TRAP_x86_MCHK = 18, // Machine check exception + 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); + 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] = 0x0010; // execution flag issue (probably) + sigcontext->uc_mcontext.gregs[X64_TRAPNO] = (info->si_code == SEGV_ACCERR)?13:14; + } else if(info->si_code==SEGV_ACCERR && !(prot&PROT_WRITE)) { + sigcontext->uc_mcontext.gregs[X64_ERR] = 0x0002; // write flag issue + if(abs((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] = 14; // PAGE_FAULT + } else { + sigcontext->uc_mcontext.gregs[X64_TRAPNO] = (info->si_code == SEGV_ACCERR)?13:14; + //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 box86 anyway + } + if(info->si_code == SEGV_ACCERR && old_code) + *old_code = -1; + } else if(sig==SIGFPE) + sigcontext->uc_mcontext.gregs[X64_TRAPNO] = 19; + else if(sig==SIGILL) + sigcontext->uc_mcontext.gregs[X64_TRAPNO] = 6; + // call the signal handler + x64_ucontext_t sigcontext_copy = *sigcontext; + + // set stack pointer + sigemu->regs[_SP].dword[0] = (uintptr_t)frame; + + // set segments + memcpy(sigemu->segs, emu->segs, sizeof(sigemu->segs)); + + int exits = 0; + int ret = RunFunctionHandler(&exits, my_context->signals[sig], 3, sig, info, sigcontext); + + if(memcmp(sigcontext, &sigcontext_copy, sizeof(x64_ucontext_t))) { + emu_jmpbuf_t* ejb = GetJmpBuf(); + if(ejb->jmpbuf_ok) { + #define GO(R) if(sigcontext->uc_mcontext.gregs[X64_R##R]!=sigcontext_copy.uc_mcontext.gregs[X64_R##R]) ejb->emu->regs[_##R].dword[0]=sigcontext->uc_mcontext.gregs[X64_R##R] + GO(AX); + GO(CX); + GO(DX); + GO(DI); + GO(SI); + GO(BP); + GO(SP); + GO(BX); + #undef GO + #define GO(R) if(sigcontext->uc_mcontext.gregs[X64_##R]!=sigcontext_copy.uc_mcontext.gregs[X64_##R]) ejb->emu->regs[_##R].dword[0]=sigcontext->uc_mcontext.gregs[X64_##R] + GO(R8); + GO(R9); + GO(R10); + GO(R11); + GO(R12); + GO(R13); + GO(R14); + GO(R15); + #undef GO + if(sigcontext->uc_mcontext.gregs[X64_RIP]!=sigcontext_copy.uc_mcontext.gregs[X64_RIP]) ejb->emu->ip.dword[0]=sigcontext->uc_mcontext.gregs[X64_RIP]; + sigcontext->uc_mcontext.gregs[X64_RIP] = R_RIP; + // flags + if(sigcontext->uc_mcontext.gregs[X64_EFL]!=sigcontext_copy.uc_mcontext.gregs[X64_EFL]) ejb->emu->eflags.x32=sigcontext->uc_mcontext.gregs[X64_EFL]; + // get segments + uint16_t seg; + seg = (sigcontext->uc_mcontext.gregs[X64_CSGSFS] >> 0)&0xffff; + #define GO(S) if(ejb->emu->segs[_##S]!=seg) {ejb->emu->segs[_##S]=seg; ejb->emu->segs_serial[_##S] = 0;} + GO(CS); + seg = (sigcontext->uc_mcontext.gregs[X64_CSGSFS] >> 16)&0xffff; + GO(GS); + seg = (sigcontext->uc_mcontext.gregs[X64_CSGSFS] >> 32)&0xffff; + GO(FS); + #undef GO + printf_log(LOG_DEBUG, "Context has been changed in Sigactionhanlder, doing longjmp to resume emu\n"); + if(old_code) + *old_code = -1; // re-init the value to allow another segfault at the same place + if(used_stack) // release stack + new_ss->ss_flags = 0; + longjmp(ejb->jmpbuf, 1); + } + 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)":""); + } + printf_log(LOG_DEBUG, "Sigactionhanlder main function returned (exit=%d, restorer=%p)\n", exits, (void*)restorer); + if(exits) + exit(ret); + if(restorer) + RunFunctionHandler(&exits, restorer, 0); + if(used_stack) // release stack + new_ss->ss_flags = 0; +} + +void my_box86signalhandler(int32_t sig, siginfo_t* info, void * ucntx) +{ + // sig==SIGSEGV || sig==SIGBUS || sig==SIGILL here! + int log_minimum = (my_context->is_sigaction[sig] && sig==SIGSEGV)?LOG_INFO:LOG_NONE; + ucontext_t *p = (ucontext_t *)ucntx; + void* addr = (void*)info->si_addr; // address that triggered the issue + void* rsp = NULL; +#ifdef __aarch64__ + void * pc = (void*)p->uc_mcontext.arm_pc; +#elif defined __x86_64__ + void * pc = (void*)p->uc_mcontext.gregs[X64_RIP]; +#elif defined __powerpc64__ + void * pc = (void*)p->uc_mcontext.uc_regs->gregs[PT_NIP]; +#else + void * pc = NULL; // unknow arch... + #warning Unhandled architecture +#endif +#ifdef DYNAREC + uint32_t prot = getProtection((uintptr_t)addr); + dynablock_t* db = NULL; + int db_searched = 0; + if ((sig==SIGSEGV) && (addr) && (info->si_code == SEGV_ACCERR) && (prot&PROT_DYNAREC)) { + if(box86_dynarec_smc) { + dynablock_t* db_pc = NULL; + db_pc = FindDynablockFromNativeAddress(pc); + if(db_pc) { + db = FindDynablockFromNativeAddress(addr); + db_searched = 1; + } + if(db_pc && db) { + if (db_pc == db) { + dynarec_log(LOG_NONE, "Warning: Access to protected %p from %p, inside same dynablock\n", addr, pc); + } + } + if(db && db->x86_addr>= addr && (db->x86_addr+db->x86_size)<addr) { + dynarec_log(LOG_INFO, "Warning, addr inside current dynablock!\n"); + } + } + dynarec_log(LOG_DEBUG, "Access to protected %p from %p, unprotecting memory (prot=%x)\n", addr, pc, prot); + // access error, unprotect the block (and mark them dirty) + if(prot&PROT_DYNAREC) // on heavy multi-thread program, the protection can already be gone... + unprotectDB((uintptr_t)addr, 1); // unprotect 1 byte... But then, the whole page will be unprotected + // done + if(prot&PROT_WRITE) return; // if there is no write permission, don't return and continue to program signal handling + } else if ((sig==SIGSEGV) && (addr) && (info->si_code == SEGV_ACCERR) && (prot&(PROT_READ|PROT_WRITE))) { + db = FindDynablockFromNativeAddress(pc); + db_searched = 1; + if(db && db->x86_addr>= addr && (db->x86_addr+db->x86_size)<addr) { + dynarec_log(LOG_INFO, "Warning, addr inside current dynablock!\n"); + } + if(addr && pc && db) { + // probably a glitch due to intensive multitask... + dynarec_log(/*LOG_DEBUG*/LOG_INFO, "SIGSEGV with Access error on %p for %p , db=%p, retrying\n", pc, addr, db); + return; // try again + } + } +#else + void* db = NULL; +#endif + static int old_code = -1; + static void* old_pc = 0; + static void* old_addr = 0; + const char* signame = (sig==SIGSEGV)?"SIGSEGV":((sig==SIGBUS)?"SIGBUS":"SIGILL"); + if(old_code==info->si_code && old_pc==pc && old_addr==addr) { + printf_log(log_minimum, "%04d|Double %s (code=%d, pc=%p, addr=%p)!\n", GetTID(), signame, old_code, old_pc, old_addr); +exit(-1); + } else { +#ifdef DYNAREC + if(!db_searched) + db = FindDynablockFromNativeAddress(pc); +#endif + old_code = info->si_code; + old_pc = pc; + old_addr = addr; + const char* name = GetNativeName(pc); + uintptr_t x64pc = (uintptr_t)-1; + const char* x64name = NULL; + const char* elfname = NULL; + x64emu_t* emu = thread_get_emu(); + x64pc = R_RIP; + rsp = (void*)R_RSP; +#if defined(__arm__) && defined(DYNAREC) + if(db && p->uc_mcontext.arm_r0>0x10000) { + emu = (x64emu_t*)p->uc_mcontext.arm_r0; + } + if(db) { + x64pc = getX64Address(db, (uintptr_t)pc); + rsp = (void*)p->uc_mcontext.arm_r8; + } +#endif + x64name = getAddrFunctionName(x64pc); + elfheader_t* elf = FindElfAddress(my_context, x64pc); + if(elf) + elfname = ElfName(elf); + if(jit_gdb) { + pid_t pid = getpid(); + int v = fork(); // is this ok in a signal handler??? + if(v) { + // parent process, the one that have the segfault + volatile int waiting = 1; + printf("Waiting for %s (pid %d)...\n", (jit_gdb==2)?"gdbserver":"gdb", pid); + while(waiting) { + // using gdb, use "set waiting=0" to stop waiting... + usleep(1000); + } + } else { + char myarg[50] = {0}; + sprintf(myarg, "%d", pid); + if(jit_gdb==2) + execlp("gdbserver", "gdbserver", "127.0.0.1:1234", "--attach", myarg, (char*)NULL); + else + execlp("gdb", "gdb", "-pid", myarg, (char*)NULL); + exit(-1); + } + } +#ifdef DYNAREC + uint32_t hash = 0; + if(db) + hash = X31_hash_code(db->x86_addr, db->x86_size); + printf_log(log_minimum, "%04d|%s @%p (%s) (x64pc=%p/%s:\"%s\", rsp=%p), for accessing %p (code=%d/prot=%x), db=%p(%p:%p/%p:%p/%s:%s, hash:%x/%x)", + GetTID(), signame, pc, name, (void*)x64pc, elfname?elfname:"???", x64name?x64name:"???", rsp, addr, info->si_code, + prot, db, db?db->block:0, db?(db->block+db->size):0, + db?db->x86_addr:0, db?(db->x86_addr+db->x86_size):0, + getAddrFunctionName((uintptr_t)(db?db->x86_addr:0)), (db?db->need_test:0)?"need_stest":"clean", db?db->hash:0, hash); +#else + printf_log(log_minimum, "%04d|%s @%p (%s) (x64pc=%p/%s:\"%s\", rsp=%p), for accessing %p (code=%d)", GetTID(), signame, pc, name, (void*)x64pc, elfname?elfname:"???", x64name?x64name:"???", rsp, addr, info->si_code); +#endif + if(sig==SIGILL) + printf_log(log_minimum, " opcode=%02X %02X %02X %02X %02X %02X %02X %02X\n", ((uint8_t*)pc)[0], ((uint8_t*)pc)[1], ((uint8_t*)pc)[2], ((uint8_t*)pc)[3], ((uint8_t*)pc)[4], ((uint8_t*)pc)[5], ((uint8_t*)pc)[6], ((uint8_t*)pc)[7]); + else if(sig==SIGBUS) + printf_log(log_minimum, " x86opcode=%02X %02X %02X %02X %02X %02X %02X %02X\n", ((uint8_t*)x64pc)[0], ((uint8_t*)x64pc)[1], ((uint8_t*)x64pc)[2], ((uint8_t*)x64pc)[3], ((uint8_t*)x64pc)[4], ((uint8_t*)x64pc)[5], ((uint8_t*)x64pc)[6], ((uint8_t*)x64pc)[7]); + else + printf_log(log_minimum, "\n"); + } + if(my_context->signals[sig] && my_context->signals[sig]!=1) { + if(my_context->is_sigaction[sig]) + my_sigactionhandler_oldcode(sig, info, ucntx, &old_code, db); + else + my_sighandler(sig); + return; + } + // no handler (or double identical segfault) + // set default and that's it, instruction will restart and default segfault handler will be called... + if(my_context->signals[sig]!=1) + signal(sig, SIG_DFL); +} + +void my_sigactionhandler(int32_t sig, siginfo_t* info, void * ucntx) +{ + #ifdef DYNAREC + ucontext_t *p = (ucontext_t *)ucntx; + void * pc = (void*)p->uc_mcontext.arm_pc; + dynablock_t* db = FindDynablockFromNativeAddress(pc); + #else + void* db = NULL; + #endif + + my_sigactionhandler_oldcode(sig, info, ucntx, NULL, db); +} + +void emit_signal(x64emu_t* emu, int sig, void* addr, int code) +{ + ucontext_t ctx = {0}; + void* db = NULL; + siginfo_t info = {0}; + info.si_signo = sig; + info.si_errno = 0; + info.si_code = code; + info.si_addr = addr; + printf_log(LOG_INFO, "Emit Signal %d at IP=%p / addr=%p, code=%d\n", sig, (void*)R_RIP, addr, code); + my_sigactionhandler_oldcode(sig, &info, &ctx, NULL, db); +} + +EXPORT sighandler_t my_signal(x64emu_t* emu, int signum, sighandler_t handler) +{ + if(signum<0 || signum>=MAX_SIGNAL) + return SIG_ERR; + + if(signum==SIGSEGV && emu->context->no_sigsegv) + return 0; + + // create a new handler + my_context->signals[signum] = (uintptr_t)handler; + my_context->is_sigaction[signum] = 0; + my_context->restorer[signum] = 0; + if(handler!=NULL && handler!=(sighandler_t)1) { + handler = my_sighandler; + } + + if(signum==SIGSEGV || signum==SIGBUS || signum==SIGILL) + return 0; + + return signal(signum, handler); +} +EXPORT sighandler_t my___sysv_signal(x64emu_t* emu, int signum, sighandler_t handler) __attribute__((alias("my_signal"))); +EXPORT sighandler_t my_sysv_signal(x64emu_t* emu, int signum, sighandler_t handler) __attribute__((alias("my_signal"))); // not completly exact + +int EXPORT my_sigaction(x64emu_t* emu, int signum, const x64_sigaction_t *act, x64_sigaction_t *oldact) +{ + if(signum<0 || signum>=MAX_SIGNAL) + return -1; + + if(signum==SIGSEGV && emu->context->no_sigsegv) + return 0; + + if(signum==SIGILL && emu->context->no_sigill) + return 0; + struct sigaction newact = {0}; + struct sigaction old = {0}; + if(act) { + newact.sa_mask = act->sa_mask; + newact.sa_flags = act->sa_flags&~0x04000000; // No sa_restorer... + if(act->sa_flags&0x04) { + my_context->signals[signum] = (uintptr_t)act->_u._sa_sigaction; + my_context->is_sigaction[signum] = 1; + if(act->_u._sa_handler!=NULL && act->_u._sa_handler!=(sighandler_t)1) { + newact.sa_sigaction = my_sigactionhandler; + } else + newact.sa_sigaction = act->_u._sa_sigaction; + } else { + my_context->signals[signum] = (uintptr_t)act->_u._sa_handler; + my_context->is_sigaction[signum] = 0; + if(act->_u._sa_handler!=NULL && act->_u._sa_handler!=(sighandler_t)1) { + newact.sa_handler = my_sighandler; + } else + newact.sa_handler = act->_u._sa_handler; + } + my_context->restorer[signum] = (act->sa_flags&0x04000000)?(uintptr_t)act->sa_restorer:0; + my_context->onstack[signum] = (act->sa_flags&SA_ONSTACK)?1:0; + } + int ret = 0; + if(signum!=SIGSEGV && signum!=SIGBUS && signum!=SIGILL) + sigaction(signum, act?&newact:NULL, oldact?&old:NULL); + if(oldact) { + oldact->sa_flags = old.sa_flags; + oldact->sa_mask = old.sa_mask; + if(old.sa_flags & 0x04) + oldact->_u._sa_sigaction = old.sa_sigaction; //TODO should wrap... + else + oldact->_u._sa_handler = old.sa_handler; //TODO should wrap... + oldact->sa_restorer = NULL; // no handling for now... + } + return ret; +} +int EXPORT my___sigaction(x64emu_t* emu, int signum, const x64_sigaction_t *act, x64_sigaction_t *oldact) +__attribute__((alias("my_sigaction"))); + +int EXPORT my_syscall_rt_sigaction(x64emu_t* emu, int signum, const x64_sigaction_restorer_t *act, x64_sigaction_restorer_t *oldact, int sigsetsize) +{ + printf_log(LOG_DEBUG, "Syscall/Sigaction(signum=%d, act=%p, old=%p, size=%d)\n", signum, act, oldact, sigsetsize); + if(signum<0 || signum>=MAX_SIGNAL) + return -1; + + if(signum==SIGSEGV && emu->context->no_sigsegv) + return 0; + // TODO, how to handle sigsetsize>4?! + if(signum==32 || signum==33) { + // cannot use libc sigaction, need to use syscall! + struct kernel_sigaction newact = {0}; + struct kernel_sigaction old = {0}; + if(act) { + printf_log(LOG_DEBUG, " New (kernel) action flags=0x%x mask=0x%x\n", act->sa_flags, *(uint32_t*)&act->sa_mask); + memcpy(&newact.sa_mask, &act->sa_mask, (sigsetsize>16)?16:sigsetsize); + newact.sa_flags = act->sa_flags&~0x04000000; // No sa_restorer... + if(act->sa_flags&0x04) { + my_context->signals[signum] = (uintptr_t)act->_u._sa_sigaction; + my_context->is_sigaction[signum] = 1; + if(act->_u._sa_handler!=NULL && act->_u._sa_handler!=(sighandler_t)1) { + newact.k_sa_handler = (void*)my_sigactionhandler; + } else { + newact.k_sa_handler = (void*)act->_u._sa_sigaction; + } + } else { + my_context->signals[signum] = (uintptr_t)act->_u._sa_handler; + my_context->is_sigaction[signum] = 0; + if(act->_u._sa_handler!=NULL && act->_u._sa_handler!=(sighandler_t)1) { + newact.k_sa_handler = my_sighandler; + } else { + newact.k_sa_handler = act->_u._sa_handler; + } + } + my_context->restorer[signum] = (act->sa_flags&0x04000000)?(uintptr_t)act->sa_restorer:0; + } + + if(oldact) { + old.sa_flags = oldact->sa_flags; + memcpy(&old.sa_mask, &oldact->sa_mask, (sigsetsize>16)?16:sigsetsize); + } + + int ret = syscall(__NR_rt_sigaction, signum, act?&newact:NULL, oldact?&old:NULL, (sigsetsize>16)?16:sigsetsize); + if(oldact && ret==0) { + oldact->sa_flags = old.sa_flags; + memcpy(&oldact->sa_mask, &old.sa_mask, (sigsetsize>16)?16:sigsetsize); + if(old.sa_flags & 0x04) + oldact->_u._sa_sigaction = (void*)old.k_sa_handler; //TODO should wrap... + else + oldact->_u._sa_handler = old.k_sa_handler; //TODO should wrap... + } + return ret; + } else { + // using libc sigaction + struct sigaction newact = {0}; + struct sigaction old = {0}; + if(act) { + printf_log(LOG_DEBUG, " New action flags=0x%x mask=0x%lx\n", act->sa_flags, *(uint64_t*)&act->sa_mask); + newact.sa_mask = act->sa_mask; + newact.sa_flags = act->sa_flags&~0x04000000; // No sa_restorer... + if(act->sa_flags&0x04) { + if(act->_u._sa_handler!=NULL && act->_u._sa_handler!=(sighandler_t)1) { + my_context->signals[signum] = (uintptr_t)act->_u._sa_sigaction; + newact.sa_sigaction = my_sigactionhandler; + } else { + newact.sa_sigaction = act->_u._sa_sigaction; + } + } else { + if(act->_u._sa_handler!=NULL && act->_u._sa_handler!=(sighandler_t)1) { + my_context->signals[signum] = (uintptr_t)act->_u._sa_handler; + my_context->is_sigaction[signum] = 0; + newact.sa_handler = my_sighandler; + } else { + newact.sa_handler = act->_u._sa_handler; + } + } + my_context->restorer[signum] = (act->sa_flags&0x04000000)?(uintptr_t)act->sa_restorer:0; + } + + if(oldact) { + old.sa_flags = oldact->sa_flags; + old.sa_mask = oldact->sa_mask; + } + int ret = 0; + + if(signum!=SIGSEGV && signum!=SIGBUS && signum!=SIGILL) + ret = sigaction(signum, act?&newact:NULL, oldact?&old:NULL); + if(oldact && ret==0) { + oldact->sa_flags = old.sa_flags; + oldact->sa_mask = old.sa_mask; + if(old.sa_flags & 0x04) + oldact->_u._sa_sigaction = old.sa_sigaction; //TODO should wrap... + else + oldact->_u._sa_handler = old.sa_handler; //TODO should wrap... + } + return ret; + } +} + +EXPORT sighandler_t my_sigset(x64emu_t* emu, int signum, sighandler_t handler) +{ + // emulated SIG_HOLD + if(handler == (sighandler_t)2) { + x64_sigaction_t oact; + sigset_t nset; + sigset_t oset; + if (sigemptyset (&nset) < 0) + return (sighandler_t)-1; + if (sigaddset (&nset, signum) < 0) + return (sighandler_t)-1; + if (sigprocmask (SIG_BLOCK, &nset, &oset) < 0) + return (sighandler_t)-1; + if (sigismember (&oset, signum)) + return (sighandler_t)2; + if (my_sigaction (emu, signum, NULL, &oact) < 0) + return (sighandler_t)-1; + return oact._u._sa_handler; + } + return my_signal(emu, signum, handler); +} + +EXPORT int my_getcontext(x64emu_t* emu, void* ucp) +{ +// printf_log(LOG_NONE, "Warning: call to partially implemented getcontext\n"); + x64_ucontext_t *u = (x64_ucontext_t*)ucp; + // stack traking + u->uc_stack.ss_sp = NULL; + u->uc_stack.ss_size = 0; // this need to filled + // get general register + u->uc_mcontext.gregs[X64_RAX] = R_RAX; + u->uc_mcontext.gregs[X64_RCX] = R_RCX; + u->uc_mcontext.gregs[X64_RDX] = R_RDX; + u->uc_mcontext.gregs[X64_RDI] = R_RDI; + u->uc_mcontext.gregs[X64_RSI] = R_RSI; + u->uc_mcontext.gregs[X64_RBP] = R_RBP; + u->uc_mcontext.gregs[X64_RIP] = *(uint64_t*)R_RSP; + u->uc_mcontext.gregs[X64_RSP] = R_RSP+sizeof(uintptr_t); + u->uc_mcontext.gregs[X64_RBX] = R_RBX; + u->uc_mcontext.gregs[X64_R8] = R_R8; + u->uc_mcontext.gregs[X64_R9] = R_R9; + u->uc_mcontext.gregs[X64_R10] = R_R10; + u->uc_mcontext.gregs[X64_R11] = R_R11; + u->uc_mcontext.gregs[X64_R12] = R_R12; + u->uc_mcontext.gregs[X64_R13] = R_R13; + u->uc_mcontext.gregs[X64_R14] = R_R14; + u->uc_mcontext.gregs[X64_R15] = R_R15; + // get segments + u->uc_mcontext.gregs[X64_CSGSFS] = ((uint64_t)(R_CS)) | (((uint64_t)(R_GS))<<16) | (((uint64_t)(R_FS))<<32); + // get FloatPoint status + // get signal mask + sigprocmask(SIG_SETMASK, NULL, (sigset_t*)&u->uc_sigmask); + + return 0; +} + +EXPORT int my_setcontext(x64emu_t* emu, void* ucp) +{ +// printf_log(LOG_NONE, "Warning: call to partially implemented setcontext\n"); + x64_ucontext_t *u = (x64_ucontext_t*)ucp; + // stack tracking + emu->init_stack = u->uc_stack.ss_sp; + emu->size_stack = u->uc_stack.ss_size; + // set general register + R_RAX = u->uc_mcontext.gregs[X64_RAX]; + R_RCX = u->uc_mcontext.gregs[X64_RCX]; + R_RDX = u->uc_mcontext.gregs[X64_RDX]; + R_RDI = u->uc_mcontext.gregs[X64_RDI]; + R_RSI = u->uc_mcontext.gregs[X64_RSI]; + R_RBP = u->uc_mcontext.gregs[X64_RBP]; + R_RIP = u->uc_mcontext.gregs[X64_RIP]; + R_RSP = u->uc_mcontext.gregs[X64_RSP]; + R_RBX = u->uc_mcontext.gregs[X64_RBX]; + R_R8 = u->uc_mcontext.gregs[X64_R8]; + R_R9 = u->uc_mcontext.gregs[X64_R9]; + R_R10 = u->uc_mcontext.gregs[X64_R10]; + R_R11 = u->uc_mcontext.gregs[X64_R11]; + R_R12 = u->uc_mcontext.gregs[X64_R12]; + R_R13 = u->uc_mcontext.gregs[X64_R13]; + R_R14 = u->uc_mcontext.gregs[X64_R14]; + R_R15 = u->uc_mcontext.gregs[X64_R15]; + // get segments + R_CS = (u->uc_mcontext.gregs[X64_CSGSFS]>> 0)&0xffff; + R_GS = (u->uc_mcontext.gregs[X64_CSGSFS]>>16)&0xffff; + R_FS = (u->uc_mcontext.gregs[X64_CSGSFS]>>32)&0xffff; + // set FloatPoint status + // set signal mask + //sigprocmask(SIG_SETMASK, NULL, (sigset_t*)&u->uc_sigmask); + // set uc_link + emu->uc_link = u->uc_link; + + return R_EAX; +} + +EXPORT int my_makecontext(x64emu_t* emu, void* ucp, void* fnc, int32_t argc, int64_t* argv) +{ +// printf_log(LOG_NONE, "Warning: call to unimplemented makecontext\n"); + x64_ucontext_t *u = (x64_ucontext_t*)ucp; + // setup stack + uintptr_t* rsp = (uintptr_t*)(u->uc_stack.ss_sp + u->uc_stack.ss_size - sizeof(uintptr_t)); + // setup the function + u->uc_mcontext.gregs[X64_RIP] = (intptr_t)fnc; + // setup args + int n = 3; + int j = 0; + int regs_abi[] = {_DI, _SI, _DX, _CX, _R8, _R9}; + for (int i=0; i<argc; ++i) { + // get value first + uint64_t v; + if(n<6) + v = emu->regs[regs_abi[n++]].q[0]; + else + v = argv[j++]; + // push value + switch(i) { + case 0: u->uc_mcontext.gregs[X64_RDI] = v; break; + case 1: u->uc_mcontext.gregs[X64_RSI] = v; break; + case 2: u->uc_mcontext.gregs[X64_RDX] = v; break; + case 3: u->uc_mcontext.gregs[X64_RCX] = v; break; + case 4: u->uc_mcontext.gregs[X64_R8] = v; break; + case 5: u->uc_mcontext.gregs[X64_R9] = v; break; + default: + --rsp; + *rsp = argv[(argc-1)-i]; + } + } + // push the return value + --rsp; + *rsp = (uintptr_t)GetExit(); + u->uc_mcontext.gregs[X64_RSP] = (uintptr_t)rsp; + + return 0; +} + +EXPORT int my_swapcontext(x64emu_t* emu, void* ucp1, void* ucp2) +{ +// printf_log(LOG_NONE, "Warning: call to unimplemented swapcontext\n"); + // grab current context in ucp1 + my_getcontext(emu, ucp1); + // activate ucp2 + my_setcontext(emu, ucp2); + return 0; +} + +void init_signal_helper(box64context_t* context) +{ + // setup signal handling + for(int i=0; i<MAX_SIGNAL; ++i) { + context->signals[i] = 1; // SIG_DFL + } + struct sigaction action; + action.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER; + action.sa_sigaction = my_box86signalhandler; + sigaction(SIGSEGV, &action, NULL); + action.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER; + action.sa_sigaction = my_box86signalhandler; + sigaction(SIGBUS, &action, NULL); + action.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER; + action.sa_sigaction = my_box86signalhandler; + sigaction(SIGILL, &action, NULL); + + pthread_once(&sigstack_key_once, sigstack_key_alloc); + pthread_once(&sigemu_key_once, sigemu_key_alloc); +} + +void fini_signal_helper() +{ + signal(SIGSEGV, SIG_DFL); + signal(SIGBUS, SIG_DFL); + signal(SIGILL, SIG_DFL); +} diff --git a/src/wrapped/generated/functions_list.txt b/src/wrapped/generated/functions_list.txt index 6c6f56d3..2a7ddd9e 100644 --- a/src/wrapped/generated/functions_list.txt +++ b/src/wrapped/generated/functions_list.txt @@ -1,5 +1,6 @@ #() vFE #() vFv +#() vFi #() vFp #() iFE #() iFv @@ -72,6 +73,7 @@ #() pFEppp #() pFppiL #() pFppuL +#() iFEppiV #() iFEpppp #() iFipppi #() iFEpippppp diff --git a/src/wrapped/generated/wrapper.c b/src/wrapped/generated/wrapper.c index 370cdac8..872238a6 100644 --- a/src/wrapped/generated/wrapper.c +++ b/src/wrapped/generated/wrapper.c @@ -71,6 +71,7 @@ void VulkanTox86(void* src, void* save); int of_convert(int); typedef void (*vFE_t)(x64emu_t*); typedef void (*vFv_t)(void); +typedef void (*vFi_t)(int32_t); typedef void (*vFp_t)(void*); typedef int32_t (*iFE_t)(x64emu_t*); typedef int32_t (*iFv_t)(void); @@ -143,6 +144,7 @@ typedef void* (*pFEppi_t)(x64emu_t*, void*, void*, int32_t); typedef void* (*pFEppp_t)(x64emu_t*, void*, void*, void*); typedef void* (*pFppiL_t)(void*, void*, int32_t, uintptr_t); typedef void* (*pFppuL_t)(void*, void*, uint32_t, uintptr_t); +typedef int32_t (*iFEppiV_t)(x64emu_t*, void*, void*, int32_t, void*); typedef int32_t (*iFEpppp_t)(x64emu_t*, void*, void*, void*, void*); typedef int32_t (*iFipppi_t)(int32_t, void*, void*, void*, int32_t); typedef int32_t (*iFEpippppp_t)(x64emu_t*, void*, int32_t, void*, void*, void*, void*, void*); @@ -161,6 +163,7 @@ typedef double (*KFKp_t)(double, void*); void vFE(x64emu_t *emu, uintptr_t fcn) { vFE_t fn = (vFE_t)fcn; fn(emu); } void vFv(x64emu_t *emu, uintptr_t fcn) { vFv_t fn = (vFv_t)fcn; fn(); } +void vFi(x64emu_t *emu, uintptr_t fcn) { vFi_t fn = (vFi_t)fcn; fn((int32_t)R_RDI); } void vFp(x64emu_t *emu, uintptr_t fcn) { vFp_t fn = (vFp_t)fcn; fn((void*)R_RDI); } void iFE(x64emu_t *emu, uintptr_t fcn) { iFE_t fn = (iFE_t)fcn; R_RAX=fn(emu); } void iFv(x64emu_t *emu, uintptr_t fcn) { iFv_t fn = (iFv_t)fcn; R_RAX=fn(); } @@ -233,6 +236,7 @@ void pFEppi(x64emu_t *emu, uintptr_t fcn) { pFEppi_t fn = (pFEppi_t)fcn; R_RAX=( void pFEppp(x64emu_t *emu, uintptr_t fcn) { pFEppp_t fn = (pFEppp_t)fcn; R_RAX=(uintptr_t)fn(emu, (void*)R_RDI, (void*)R_RSI, (void*)R_RDX); } void pFppiL(x64emu_t *emu, uintptr_t fcn) { pFppiL_t fn = (pFppiL_t)fcn; R_RAX=(uintptr_t)fn((void*)R_RDI, (void*)R_RSI, (int32_t)R_RDX, (uintptr_t)R_RCX); } void pFppuL(x64emu_t *emu, uintptr_t fcn) { pFppuL_t fn = (pFppuL_t)fcn; R_RAX=(uintptr_t)fn((void*)R_RDI, (void*)R_RSI, (uint32_t)R_RDX, (uintptr_t)R_RCX); } +void iFEppiV(x64emu_t *emu, uintptr_t fcn) { iFEppiV_t fn = (iFEppiV_t)fcn; R_RAX=fn(emu, (void*)R_RDI, (void*)R_RSI, (int32_t)R_RDX, (void*)(R_RSP + 8)); } void iFEpppp(x64emu_t *emu, uintptr_t fcn) { iFEpppp_t fn = (iFEpppp_t)fcn; R_RAX=fn(emu, (void*)R_RDI, (void*)R_RSI, (void*)R_RDX, (void*)R_RCX); } void iFipppi(x64emu_t *emu, uintptr_t fcn) { iFipppi_t fn = (iFipppi_t)fcn; R_RAX=fn((int32_t)R_RDI, (void*)R_RSI, (void*)R_RDX, (void*)R_RCX, (int32_t)R_R8); } void iFEpippppp(x64emu_t *emu, uintptr_t fcn) { iFEpippppp_t fn = (iFEpippppp_t)fcn; R_RAX=fn(emu, (void*)R_RDI, (int32_t)R_RSI, (void*)R_RDX, (void*)R_RCX, (void*)R_R8, (void*)R_R9, *(void**)(R_RSP + 8)); } diff --git a/src/wrapped/generated/wrapper.h b/src/wrapped/generated/wrapper.h index 7c053833..b134b8fb 100644 --- a/src/wrapped/generated/wrapper.h +++ b/src/wrapped/generated/wrapper.h @@ -32,6 +32,7 @@ typedef void (*wrapper_t)(x64emu_t* emu, uintptr_t fnc); void vFE(x64emu_t *emu, uintptr_t fnc); void vFv(x64emu_t *emu, uintptr_t fnc); +void vFi(x64emu_t *emu, uintptr_t fnc); void vFp(x64emu_t *emu, uintptr_t fnc); void iFE(x64emu_t *emu, uintptr_t fnc); void iFv(x64emu_t *emu, uintptr_t fnc); @@ -104,6 +105,7 @@ void pFEppi(x64emu_t *emu, uintptr_t fnc); void pFEppp(x64emu_t *emu, uintptr_t fnc); void pFppiL(x64emu_t *emu, uintptr_t fnc); void pFppuL(x64emu_t *emu, uintptr_t fnc); +void iFEppiV(x64emu_t *emu, uintptr_t fnc); void iFEpppp(x64emu_t *emu, uintptr_t fnc); void iFipppi(x64emu_t *emu, uintptr_t fnc); void iFEpippppp(x64emu_t *emu, uintptr_t fnc); diff --git a/src/wrapped/wrappedlibc.c b/src/wrapped/wrappedlibc.c index e7ac5156..b86980e7 100755 --- a/src/wrapped/wrappedlibc.c +++ b/src/wrapped/wrappedlibc.c @@ -413,7 +413,7 @@ int EXPORT my_atexit(x64emu_t* emu, void *p) AddCleanup(emu, p); return 0; } -#if 0 + int my_getcontext(x64emu_t* emu, void* ucp); int my_setcontext(x64emu_t* emu, void* ucp); int my_makecontext(x64emu_t* emu, void* ucp, void* fnc, int32_t argc, void* argv); @@ -429,7 +429,6 @@ int my_swapcontext(x64emu_t* emu, void* ucp1, void* ucp2); // this one is defined in elfloader.c int my_dl_iterate_phdr(x64emu_t *emu, void* F, void *data); -#endif pid_t EXPORT my_fork(x64emu_t* emu) { // execute atforks prepare functions, in reverse order diff --git a/src/wrapped/wrappedlibc_private.h b/src/wrapped/wrappedlibc_private.h index b199f408..1451abbb 100755 --- a/src/wrapped/wrappedlibc_private.h +++ b/src/wrapped/wrappedlibc_private.h @@ -283,9 +283,9 @@ GOM(__cxa_finalize, vFEp) //GOW(execve, //GO(execvp, //GOW(execvpe, -//GO(_exit, -//GO(exit, -//GOW(_Exit, +GO(_exit, vFi) +GO(exit, vFi) +GOW(_Exit, vFi) //GO(explicit_bzero, //GO(__explicit_bzero_chk, //GO(faccessat, @@ -472,7 +472,7 @@ GOW(fwrite, LFpLLp) //GOW(getc, //GO(getchar, //GO(getchar_unlocked, -//GOW(getcontext, +GOM(getcontext, iFEp) //Weak //GOW(getc_unlocked, //GO(get_current_dir_name, //GOW(getcwd, @@ -1086,7 +1086,7 @@ GOM(__libc_start_main, iFEpippppp) //GO(__lxstat64, //GO(__madvise, //GOW(madvise, -//GOW(makecontext, +GOM(makecontext, iFEppiV) //weak //GOW(mallinfo, GO(malloc, pFL) // need to wrap to clear allocated memory? //GO(malloc_get_state, @@ -1869,7 +1869,7 @@ GO(strlen, LFp) //GO(svcunixfd_create, //GO(svc_unregister, //GO(swab, -//GOW(swapcontext, +GOM(swapcontext, iFEpp) //Weak //GOW(swapoff, //GOW(swapon, //GO(swprintf, |