diff options
| author | ptitSeb <sebastien.chev@gmail.com> | 2021-03-03 16:43:42 +0100 |
|---|---|---|
| committer | ptitSeb <sebastien.chev@gmail.com> | 2021-03-03 16:43:42 +0100 |
| commit | f4829a8ce42b1abbcc8621802d6c6fad3a56cd5d (patch) | |
| tree | 211276c3587721126ded00be46487bf23b605591 /src/emu | |
| parent | f73fbd3cee38b4c0086c934d73972375c9c8c7d6 (diff) | |
| download | box64-f4829a8ce42b1abbcc8621802d6c6fad3a56cd5d.tar.gz box64-f4829a8ce42b1abbcc8621802d6c6fad3a56cd5d.zip | |
More infrastructure added to elf and x64 emu
Diffstat (limited to 'src/emu')
| -rwxr-xr-x | src/emu/x64emu.c | 72 | ||||
| -rwxr-xr-x | src/emu/x64run.c | 118 | ||||
| -rwxr-xr-x | src/emu/x64run_private.c | 787 | ||||
| -rwxr-xr-x | src/emu/x64syscall.c | 186 | ||||
| -rwxr-xr-x | src/emu/x64tls.c | 213 |
5 files changed, 1340 insertions, 36 deletions
diff --git a/src/emu/x64emu.c b/src/emu/x64emu.c index 3ce6b63e..ea3cc138 100755 --- a/src/emu/x64emu.c +++ b/src/emu/x64emu.c @@ -14,8 +14,8 @@ #include "box64context.h" #include "x64run.h" #include "x64run_private.h" -//#include "callback.h" -//#include "bridge.h" +#include "callback.h" +#include "bridge.h" #ifdef DYNAREC #include "custommem.h" #endif @@ -43,16 +43,16 @@ uint32_t* GetParityTab() return x86emu_parity_tab; } -//void PushExit(x64emu_t* emu) -//{ -// uintptr_t endMarker = AddCheckBridge(my_context->system, NULL, NULL, 0); -// Push(emu, endMarker); -//} +void PushExit(x64emu_t* emu) +{ + uintptr_t endMarker = AddCheckBridge(my_context->system, NULL, NULL, 0); + Push(emu, endMarker); +} -//void* GetExit() -//{ -// return (void*)AddCheckBridge(my_context->system, NULL, NULL, 0); -//} +void* GetExit() +{ + return (void*)AddCheckBridge(my_context->system, NULL, NULL, 0); +} static void internalX64Setup(x64emu_t* emu, box64context_t *context, uintptr_t start, uintptr_t stack, int stacksize, int ownstack) { @@ -403,31 +403,31 @@ void UnimpOpcode(x64emu_t* emu) emu->error |= ERR_UNIMPL; } -//void EmuCall(x64emu_t* emu, uintptr_t addr) -//{ -// uint64_t old_rsp = R_RSP; -// uint64_t old_rbx = R_RBX; -// uint64_t old_rdi = R_RDI; -// uint64_t old_rsi = R_RSI; -// uint64_t old_rbp = R_RBP; -// uint64_t old_rip = R_RIP; -// PushExit(emu); -// R_RIP = addr; -// emu->df = d_none; -// Run(emu, 0); -// emu->quit = 0; // reset Quit flags... -// emu->df = d_none; -// if(emu->quitonlongjmp && emu->longjmp) { -// emu->longjmp = 0; // don't change anything because of the longjmp -// } else { -// R_RBX = old_ebx; -// R_RDI = old_edi; -// R_RSI = old_esi; -// R_RBP = old_ebp; -// R_RSP = old_esp; -// R_RIP = old_eip; // and set back instruction pointer -// } -//} +void EmuCall(x64emu_t* emu, uintptr_t addr) +{ + uint64_t old_rsp = R_RSP; + uint64_t old_rbx = R_RBX; + uint64_t old_rdi = R_RDI; + uint64_t old_rsi = R_RSI; + uint64_t old_rbp = R_RBP; + uint64_t old_rip = R_RIP; + PushExit(emu); + R_RIP = addr; + emu->df = d_none; + Run(emu, 0); + emu->quit = 0; // reset Quit flags... + emu->df = d_none; + if(emu->quitonlongjmp && emu->longjmp) { + emu->longjmp = 0; // don't change anything because of the longjmp + } else { + R_RBX = old_rbx; + R_RDI = old_rdi; + R_RSI = old_rsi; + R_RBP = old_rbp; + R_RSP = old_rsp; + R_RIP = old_rip; // and set back instruction pointer + } +} uint64_t ReadTSC(x64emu_t* emu) { diff --git a/src/emu/x64run.c b/src/emu/x64run.c new file mode 100755 index 00000000..39533d8b --- /dev/null +++ b/src/emu/x64run.c @@ -0,0 +1,118 @@ +#define _GNU_SOURCE +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <string.h> +#include <signal.h> +#include <sys/types.h> +#include <unistd.h> + +#include "debug.h" +#include "box64stack.h" +#include "x64emu.h" +#include "x64run.h" +#include "x64emu_private.h" +#include "x64run_private.h" +//#include "x64primop.h" +#include "x64trace.h" +#include "x87emu_private.h" +#include "box64context.h" +//#include "my_cpuid.h" +#include "bridge.h" +//#include "signals.h" +#ifdef DYNAREC +#include "../dynarec/arm_lock_helper.h" +#endif + +int my_setcontext(x64emu_t* emu, void* ucp); + +int Run(x64emu_t *emu, int step) +{ + uint8_t opcode; + uint8_t nextop; + reg64_t *oped; + uint8_t tmp8u, tmp8u2; + int8_t tmp8s; + uint16_t tmp16u, tmp16u2; + int16_t tmp16s; + uint32_t tmp32u, tmp32u2, tmp32u3; + uint64_t tmp64u, tmp64u2, tmp64u3; + int32_t tmp32s, tmp32s2; + int64_t tmp64s, tmp64s2; + uintptr_t ip; + double d; + float f; + int64_t ll; + sse_regs_t *opex, eax1; + mmx_regs_t *opem, eam1; + + if(emu->quit) + return 0; + + //ref opcode: http://ref.x64asm.net/geek32.html#xA1 + printf_log(LOG_DEBUG, "Run X86 (%p), RIP=%p, Stack=%p\n", emu, (void*)R_RIP, emu->context->stack); +#define F8 *(uint8_t*)(ip++) +#define F8S *(int8_t*)(ip++) +#define F16 *(uint16_t*)(ip+=2, ip-2) +#define F32 *(uint32_t*)(ip+=4, ip-4) +#define F32S *(int32_t*)(ip+=4, ip-4) +#define PK(a) *(uint8_t*)(ip+a) +#ifdef DYNAREC +#define STEP if(step) goto stepout; +#else +#define STEP +#endif + +x64emurun: + ip = R_RIP; + +//#include "modrm.h" + while(1) { +#ifdef HAVE_TRACE + __builtin_prefetch((void*)ip, 0, 0); + emu->prev2_ip = emu->prev_ip; + emu->prev_ip = R_RIP; + R_RIP=ip; + if(my_context->dec && ( + (trace_end == 0) + || ((ip >= trace_start) && (ip < trace_end))) ) + PrintTrace(emu, ip, 0); +#endif + + opcode = F8; + switch(opcode) { + + default: + emu->old_ip = R_RIP; + R_RIP = ip; + UnimpOpcode(emu); + goto fini; + } + } +#ifdef DYNAREC +stepout: + emu->old_ip = R_RIP; + R_RIP = ip; + return 0; +#endif + +fini: + // fork handling +// if(emu->fork) { +// if(step) +// return 0; +// int forktype = emu->fork; +// emu->quit = 0; +// emu->fork = 0; +// emu = x64emu_fork(emu, forktype); +// goto x64emurun; +// } + // setcontext handling +// 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 new file mode 100755 index 00000000..5ceae0a3 --- /dev/null +++ b/src/emu/x64run_private.c @@ -0,0 +1,787 @@ +#define _GNU_SOURCE /* See feature_test_macros(7) */ +#include <dlfcn.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifdef HAVE_TRACE +#include <unistd.h> +#include <sys/syscall.h> +#endif + +#include "debug.h" +#include "box64stack.h" +#include "x64emu.h" +#include "x64run.h" +#include "x64run_private.h" +#include "x64emu_private.h" +#include "box64context.h" +#include "x64run.h" +#include "librarian.h" +#include "elfloader.h" +#ifdef HAVE_TRACE +#include "x64trace.h" +#endif +#include "x64tls.h" + +#define PARITY2(x) (((emu->x64emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0) +#define PARITY(x) (PARITY2((x)>>32)^PARITY2((x)&0xffffffff)) +#define XOR2(x) (((x) ^ ((x)>>1)) & 0x1) + +int32_t EXPORT my___libc_start_main(x64emu_t* emu, int *(main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end)) +{ + //TODO: register rtld_fini + //TODO: register fini + // let's cheat and set all args... + Push(emu, (uint64_t)my_context->envv); + Push(emu, (uint64_t)my_context->argv); + Push(emu, (uint64_t)my_context->argc); + if(init) { + PushExit(emu); + R_RIP=(uint64_t)*init; + printf_log(LOG_DEBUG, "Calling init(%p) from __libc_start_main\n", *init); + DynaRun(emu); + if(emu->error) // any error, don't bother with more + return 0; + emu->quit = 0; + } + printf_log(LOG_DEBUG, "Transfert to main(%d, %p, %p)=>%p from __libc_start_main\n", my_context->argc, my_context->argv, my_context->envv, main); + // call main and finish + PushExit(emu); + R_RIP=(uint64_t)main; +#ifdef DYNAREC + DynaRun(emu); +#endif + return 0; +} + +const char* GetNativeName(void* p) +{ + static char buff[500] = {0}; + Dl_info info; + if(dladdr(p, &info)==0) { + const char *ret = GetNameOffset(my_context->maplib, p); + if(ret) + return ret; + sprintf(buff, "%s(%p)", "???", p); + return buff; + } else { + if(info.dli_sname) { + strcpy(buff, info.dli_sname); + if(info.dli_fname) { + strcat(buff, " ("); strcat(buff, info.dli_fname); strcat(buff, ")"); + } + } else { + sprintf(buff, "%s(%s/%p)", "???", info.dli_fname, p); + return buff; + } + } + return buff; +} +#if 0 +void UpdateFlags(x64emu_t *emu) +{ + uint32_t cc; + uint32_t lo, hi; + uint32_t bc; + uint32_t cnt; + + switch(emu->df) { + case d_none: + return; + case d_add8: + CONDITIONAL_SET_FLAG(emu->res & 0x100, F_CF); + CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + + cc = (emu->op1 & emu->op2) | ((~emu->res) & (emu->op1 | emu->op2)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + break; + case d_add16: + CONDITIONAL_SET_FLAG(emu->res & 0x10000, F_CF); + CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + cc = (emu->op1 & emu->op2) | ((~emu->res) & (emu->op1 | emu->op2)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + break; + case d_add32: + lo = (emu->op2 & 0xFFFF) + (emu->op1 & 0xFFFF); + hi = (lo >> 16) + (emu->op2 >> 16) + (emu->op1 >> 16); + CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF); + CONDITIONAL_SET_FLAG(!emu->res, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + cc = (emu->op1 & emu->op2) | ((~emu->res) & (emu->op1 | emu->op2)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + break; + case d_and8: + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + break; + case d_and16: + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + break; + case d_and32: + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + break; + case d_dec8: + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = (emu->res & (~emu->op1 | 1)) | (~emu->op1 & 1); + CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_dec16: + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = (emu->res & (~emu->op1 | 1)) | (~emu->op1 & 1); + CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_dec32: + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(!emu->res, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = (emu->res & (~emu->op1 | 1)) | (~emu->op1 & 1); + CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_inc8: + CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + cc = ((1 & emu->op1) | (~emu->res)) & (1 | emu->op1); + CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + break; + case d_inc16: + CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + cc = (1 & emu->op1) | ((~emu->res) & (1 | emu->op1)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + break; + case d_inc32: + CONDITIONAL_SET_FLAG(!emu->res, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + cc = (1 & emu->op1) | ((~emu->res) & (1 | emu->op1)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + break; + case d_imul8: + lo = emu->res & 0xff; + hi = (emu->res>>8)&0xff; + if (((lo & 0x80) == 0 && hi == 0x00) || + ((lo & 0x80) != 0 && hi == 0xFF)) { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } else { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } + CONDITIONAL_SET_FLAG(PARITY(lo & 0xff), F_PF); + break; + case d_imul16: + lo = (uint16_t)emu->res; + hi = (uint16_t)(emu->res >> 16); + if (((lo & 0x8000) == 0 && hi == 0x00) || + ((lo & 0x8000) != 0 && hi == 0xFFFF)) { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } else { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } + CONDITIONAL_SET_FLAG(PARITY(lo & 0xff), F_PF); + break; + case d_imul32: + if (((emu->res & 0x80000000) == 0 && emu->op1 == 0x00) || + ((emu->res & 0x80000000) != 0 && emu->op1 == 0xFFFFFFFF)) { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } else { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + break; + case d_mul8: + lo = emu->res & 0xff; + hi = (emu->res>>8)&0xff; + if (hi == 0) { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } else { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } + CONDITIONAL_SET_FLAG(PARITY(lo & 0xff), F_PF); + break; + case d_mul16: + lo = (uint16_t)emu->res; + hi = (uint16_t)(emu->res >> 16); + if (hi == 0) { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } else { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } + CONDITIONAL_SET_FLAG(PARITY(lo & 0xff), F_PF); + break; + case d_mul32: + if (emu->op1 == 0) { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } else { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + break; + case d_or8: + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + break; + case d_or16: + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + break; + case d_or32: + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + break; + case d_neg8: + CONDITIONAL_SET_FLAG(emu->op1 != 0, F_CF); + CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = emu->res | emu->op1; + CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_neg16: + CONDITIONAL_SET_FLAG(emu->op1 != 0, F_CF); + CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = emu->res | emu->op1; + CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_neg32: + CONDITIONAL_SET_FLAG(emu->op1 != 0, F_CF); + CONDITIONAL_SET_FLAG(!emu->res, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = emu->res | emu->op1; + CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_shl8: + if (emu->op2 < 8) { + cnt = emu->op2 % 8; + if (cnt > 0) { + cc = emu->op1 & (1 << (8 - cnt)); + CONDITIONAL_SET_FLAG(cc, F_CF); + CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + } + if (cnt == 1) { + CONDITIONAL_SET_FLAG((((emu->res & 0x80) == 0x80) ^(ACCESS_FLAG(F_CF) != 0)), F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + CONDITIONAL_SET_FLAG((emu->op1 << (emu->op2-1)) & 0x80, F_CF); + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + SET_FLAG(F_ZF); + } + break; + case d_shl16: + if (emu->op2 < 16) { + cnt = emu->op2 % 16; + if (cnt > 0) { + cc = emu->op1 & (1 << (16 - cnt)); + CONDITIONAL_SET_FLAG(cc, F_CF); + CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + } + if (cnt == 1) { + CONDITIONAL_SET_FLAG(((!!(emu->res & 0x8000)) ^(ACCESS_FLAG(F_CF) != 0)), F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + CONDITIONAL_SET_FLAG((emu->op1 << (emu->op2-1)) & 0x8000, F_CF); + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + SET_FLAG(F_ZF); + } + break; + case d_shl32: + if (emu->op2 > 0) { + cc = emu->op1 & (1 << (32 - emu->op2)); + CONDITIONAL_SET_FLAG(cc, F_CF); + CONDITIONAL_SET_FLAG(!emu->res, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + } + if (emu->op2 == 1) { + CONDITIONAL_SET_FLAG(((!!(emu->res & 0x80000000)) ^ + (ACCESS_FLAG(F_CF) != 0)), F_OF); + } else { + CLEAR_FLAG(F_OF); + } + break; + case d_sar8: + if (emu->op2 < 8) { + if(emu->op2) { + cc = emu->op1 & (1 << (emu->op2 - 1)); + CONDITIONAL_SET_FLAG(cc, F_CF); + CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + } + } else { + if (emu->op1&0x80) { + SET_FLAG(F_CF); + CLEAR_FLAG(F_ZF); + SET_FLAG(F_SF); + SET_FLAG(F_PF); + } else { + CLEAR_FLAG(F_CF); + SET_FLAG(F_ZF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + } + } + break; + case d_sar16: + if (emu->op2 < 16) { + if(emu->op2) { + cc = emu->op1 & (1 << (emu->op2 - 1)); + CONDITIONAL_SET_FLAG(cc, F_CF); + CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + } + } else { + if (emu->op1&0x8000) { + SET_FLAG(F_CF); + CLEAR_FLAG(F_ZF); + SET_FLAG(F_SF); + SET_FLAG(F_PF); + } else { + CLEAR_FLAG(F_CF); + SET_FLAG(F_ZF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + } + } + break; + case d_sar32: + if(emu->op2) { + cc = emu->op1 & (1 << (emu->op2 - 1)); + CONDITIONAL_SET_FLAG(cc, F_CF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + } + break; + case d_shr8: + if (emu->op2 < 8) { + cnt = emu->op2 % 8; + if (cnt > 0) { + cc = emu->op1 & (1 << (cnt - 1)); + CONDITIONAL_SET_FLAG(cc, F_CF); + CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + } + if (cnt == 1) { + CONDITIONAL_SET_FLAG(XOR2(emu->res >> 6), F_OF); + } + } else { + CONDITIONAL_SET_FLAG((emu->op1 >> (emu->op2-1)) & 0x1, F_CF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + SET_FLAG(F_ZF); + } + break; + case d_shr16: + if (emu->op2 < 16) { + cnt = emu->op2 % 16; + if (cnt > 0) { + cc = emu->op1 & (1 << (cnt - 1)); + CONDITIONAL_SET_FLAG(cc, F_CF); + CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + } + if (cnt == 1) { + CONDITIONAL_SET_FLAG(XOR2(emu->res >> 14), F_OF); + } + } else { + CLEAR_FLAG(F_CF); + SET_FLAG(F_ZF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + } + break; + case d_shr32: + cnt = emu->op2; + if (cnt > 0) { + cc = emu->op1 & (1 << (cnt - 1)); + CONDITIONAL_SET_FLAG(cc, F_CF); + CONDITIONAL_SET_FLAG(!emu->res, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + } + if (cnt == 1) { + CONDITIONAL_SET_FLAG(XOR2(emu->res >> 30), F_OF); + } + break; + case d_sub8: + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2); + CONDITIONAL_SET_FLAG(bc & 0x80, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_sub16: + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2); + CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_sub32: + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(!emu->res, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2); + CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_xor8: + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + break; + case d_xor16: + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + break; + case d_xor32: + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + break; + case d_cmp8: + CLEAR_FLAG(F_CF); + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2); + CONDITIONAL_SET_FLAG(bc & 0x80, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_cmp16: + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2); + CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_cmp32: + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(!emu->res, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2); + CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_tst8: + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + CLEAR_FLAG(F_CF); + break; + case d_tst16: + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + CLEAR_FLAG(F_CF); + break; + case d_tst32: + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + CLEAR_FLAG(F_CF); + break; + case d_adc8: + CONDITIONAL_SET_FLAG(emu->res & 0x100, F_CF); + CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + cc = (emu->op1 & emu->op2) | ((~emu->res) & (emu->op1 | emu->op2)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + break; + case d_adc16: + CONDITIONAL_SET_FLAG(emu->res & 0x10000, F_CF); + CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + cc = (emu->op1 & emu->op2) | ((~emu->res) & (emu->op1 | emu->op2)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + break; + case d_adc32: + if(emu->res == (emu->op1+emu->op2)) { + lo = (emu->op1 & 0xFFFF) + (emu->op2 & 0xFFFF); + } else { + lo = 1 + (emu->op1 & 0xFFFF) + (emu->op2 & 0xFFFF); + } + hi = (lo >> 16) + (emu->op1 >> 16) + (emu->op2 >> 16); + CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF); + CONDITIONAL_SET_FLAG(!emu->res, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + cc = (emu->op2 & emu->op1) | ((~emu->res) & (emu->op2 | emu->op1)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + break; + case d_sbb8: + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2); + CONDITIONAL_SET_FLAG(bc & 0x80, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_sbb16: + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2); + CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_sbb32: + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(!emu->res, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2); + CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_rol8: + if(emu->op2 == 1) { + CONDITIONAL_SET_FLAG((emu->res + (emu->res >> 7)) & 1, F_OF); + } + CONDITIONAL_SET_FLAG(emu->res & 0x1, F_CF); + break; + case d_rol16: + if(emu->op2 == 1) { + CONDITIONAL_SET_FLAG((emu->res + (emu->res >> 15)) & 1, F_OF); + } + CONDITIONAL_SET_FLAG(emu->res & 0x1, F_CF); + break; + case d_rol32: + if(emu->op2 == 1) { + CONDITIONAL_SET_FLAG((emu->res + (emu->res >> 31)) & 1, F_OF); + } + CONDITIONAL_SET_FLAG(emu->res & 0x1, F_CF); + break; + case d_ror8: + if(emu->op2 == 1) { + CONDITIONAL_SET_FLAG(XOR2(emu->res >> 6), F_OF); + } + CONDITIONAL_SET_FLAG(emu->res & (1 << 7), F_CF); + break; + case d_ror16: + if(emu->op2 == 1) { + CONDITIONAL_SET_FLAG(XOR2(emu->res >> 14), F_OF); + } + CONDITIONAL_SET_FLAG(emu->res & (1 << 15), F_CF); + break; + case d_ror32: + if(emu->op2 == 1) { + CONDITIONAL_SET_FLAG(XOR2(emu->res >> 30), F_OF); + } + CONDITIONAL_SET_FLAG(emu->res & (1 << 31), F_CF); + break; + + case d_unknown: + printf_log(LOG_NONE, "Box86: %p trying to evaluate Unknown defered Flags\n", (void*)R_RIP); + break; + } + RESET_FLAGS(emu); +} +#endif + +uintptr_t GetSegmentBaseEmu(x64emu_t* emu, int seg) +{ + if(emu->segs_serial[seg] != emu->context->sel_serial) { + emu->segs_offs[seg] = (uintptr_t)GetSegmentBase(emu->segs[seg]); + emu->segs_serial[seg] = emu->context->sel_serial; + } + return emu->segs_offs[seg]; +} + + +const char* getAddrFunctionName(uintptr_t addr) +{ + static char ret[1000]; + uint32_t sz = 0; + uintptr_t start = 0; + const char* symbname = FindNearestSymbolName(FindElfAddress(my_context, addr), (void*)addr, &start, &sz); + if(symbname && addr>=start && (addr<(start+sz) || !sz)) { + if(addr==start) + sprintf(ret, "%s/%s", ElfName(FindElfAddress(my_context, addr)), symbname); + else + sprintf(ret, "%s/%s + %ld", ElfName(FindElfAddress(my_context, addr)), symbname, addr - start); + } else + sprintf(ret, "???"); + return ret; +} + +void printFunctionAddr(uintptr_t nextaddr, const char* text) +{ + uint32_t sz = 0; + uintptr_t start = 0; + const char* symbname = FindNearestSymbolName(FindElfAddress(my_context, nextaddr), (void*)nextaddr, &start, &sz); + if(symbname && nextaddr>=start && (nextaddr<(start+sz) || !sz)) { + if(nextaddr==start) + printf_log(LOG_NONE, " (%s%s/%s)", text, ElfName(FindElfAddress(my_context, nextaddr)), symbname); + else + printf_log(LOG_NONE, " (%s%s/%s + %ld)", text, ElfName(FindElfAddress(my_context, nextaddr)), symbname, nextaddr - start); + } +} + +#ifdef HAVE_TRACE +extern uint64_t start_cnt; +#define PK(a) (*(uint8_t*)(ip+a)) +#define PK32(a) (*(int32_t*)((uint8_t*)(ip+a))) +#define PK64(a) (*(int64_t*)((uint8_t*)(ip+a))) + +void PrintTrace(x64emu_t* emu, uintptr_t ip, int dynarec) +{ + if(start_cnt) --start_cnt; + if(!start_cnt && my_context->dec && ( + (trace_end == 0) + || ((ip >= trace_start) && (ip < trace_end))) ) { + int tid = syscall(SYS_gettid); + pthread_mutex_lock(&my_context->mutex_trace); +#ifdef DYNAREC + if((my_context->trace_tid != tid) || (my_context->trace_dynarec!=dynarec)) { + printf_log(LOG_NONE, "Thread %04d| (%s) |\n", tid, dynarec?"dyn":"int"); + my_context->trace_tid = tid; + my_context->trace_dynarec = dynarec; + } +#else + if(my_context->trace_tid != tid) { + printf_log(LOG_NONE, "Thread %04d|\n", tid); + my_context->trace_tid = tid; + } +#endif + printf_log(LOG_NONE, "%s", DumpCPURegs(emu, ip)); + if(PK(0)==0xcc && PK(1)=='S' && PK(2)=='C') { + uint64_t a = *(uint64_t*)(ip+3); + if(a==0) { + printf_log(LOG_NONE, "%p: Exit x86emu\n", (void*)ip); + } else { + printf_log(LOG_NONE, "%p: Native call to %p => %s\n", (void*)ip, (void*)a, GetNativeName(*(void**)(ip+7))); + } + } else { + printf_log(LOG_NONE, "%s", DecodeX64Trace(my_context->dec, ip)); + uint8_t peek = PK(0); + if(peek==0xC3 || peek==0xC2) { + printf_log(LOG_NONE, " => %p", *(void**)(R_RSP)); + printFunctionAddr(*(uintptr_t*)(R_RSP), "=> "); + } else if(peek==0x55) { + printf_log(LOG_NONE, " => STACK_TOP: %p", *(void**)(R_RSP)); + printFunctionAddr(ip, "here: "); + } else if(peek==0xE8) { // Call + uintptr_t nextaddr = ip + 5 + PK64(1); + printFunctionAddr(nextaddr, "=> "); + } else if(peek==0xFF) { + if(PK(1)==0x25) { + uintptr_t nextaddr = ip + 6 + PK64(2); + printFunctionAddr(nextaddr, "=> "); + } + } + printf_log(LOG_NONE, "\n"); + } + pthread_mutex_unlock(&my_context->mutex_trace); + } +} + +#endif diff --git a/src/emu/x64syscall.c b/src/emu/x64syscall.c new file mode 100755 index 00000000..5359939c --- /dev/null +++ b/src/emu/x64syscall.c @@ -0,0 +1,186 @@ +#define _GNU_SOURCE /* See feature_test_macros(7) */ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <sys/syscall.h> /* For SYS_xxx definitions */ +#include <unistd.h> +#include <time.h> +#include <sys/mman.h> +#include <sys/select.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <asm/stat.h> +#include <errno.h> +#include <sched.h> +#include <sys/wait.h> +#include <sys/utsname.h> +#include <sys/resource.h> +#include <poll.h> + +#include "debug.h" +#include "box64stack.h" +#include "x64emu.h" +#include "x64run.h" +#include "x64emu_private.h" +#include "x64run_private.h" +//#include "x64primop.h" +#include "x64trace.h" +//#include "myalign.h" +#include "box64context.h" +//#include "callback.h" +//#include "signals.h" +//#include "x64tls.h" + +typedef struct x64_sigaction_s x64_sigaction_t; + + +//int32_t my_getrandom(x64emu_t* emu, void* buf, uint32_t buflen, uint32_t flags); +//int of_convert(int flag); +//int32_t my_open(x64emu_t* emu, void* pathname, int32_t flags, uint32_t mode); + +//int my_sigaction(x64emu_t* emu, int signum, const x86_sigaction_t *act, x86_sigaction_t *oldact); +//int32_t my_execve(x64emu_t* emu, const char* path, char* const argv[], char* const envp[]); +//void* my_mmap(x64emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, int offset); +//void* my_mmap64(x64emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, int64_t offset); +//int my_munmap(x64emu_t* emu, void* addr, unsigned long length); +//int my_mprotect(x64emu_t* emu, void *addr, unsigned long len, int prot); + +// cannot include <fcntl.h>, it conflict with some asm includes... +#ifndef O_NONBLOCK +#define O_NONBLOCK 04000 +#endif +#undef fcntl +int fcntl(int fd, int cmd, ... /* arg */ ); + +// Syscall table for x86_64 can be found +typedef struct scwrap_s { + int x64s; + int nats; + int nbpars; +} scwrap_t; + +scwrap_t syscallwrap[] = { + { 0, __NR_read, 3 }, // wrapped so SA_RESTART can be handled by libc + { 1, __NR_write, 3 }, // same + { 2, __NR_open, 3 }, // flags need transformation + { 3, __NR_close, 1 }, // wrapped so SA_RESTART can be handled by libc + { 4, __NR_stat, 2 }, + { 5, __NR_fstat, 2}, +}; + +struct mmap_arg_struct { + unsigned long addr; + unsigned long len; + unsigned long prot; + unsigned long flags; + unsigned long fd; + unsigned long offset; +}; + +//struct x86_pt_regs { +// long ebx; +// long ecx; +// long edx; +// long esi; +// long edi; +// long ebp; +// long eax; +// int xds; +// int xes; +// int xfs; +// int xgs; +// long orig_eax; +// long eip; +// int xcs; +// long eflags; +// long esp; +// int xss; +//}; + +//int clone_fn(void* arg) +//{ +// x64emu_t *emu = (x64emu_t*)arg; +// R_RAX = 0; +// DynaRun(emu); +// int ret = R_EAX; +// FreeX64Emu(&emu); +// return ret; +//} + +void EXPORT x64Syscall(x64emu_t *emu) +{ + RESET_FLAGS(emu); + uint32_t s = R_EAX; + printf_log(LOG_DEBUG, "%p: Calling syscall 0x%02X (%d) %p %p %p %p %p %p", (void*)R_RIP, s, s, (void*)R_RDI, (void*)R_RSI, (void*)R_RDX, (void*)R_R10, (void*)R_R8, (void*)R_R9); + // check wrapper first + int cnt = sizeof(syscallwrap) / sizeof(scwrap_t); + for (int i=0; i<cnt; i++) { + if(syscallwrap[i].x64s == s) { + int sc = syscallwrap[i].nats; + switch(syscallwrap[i].nbpars) { + case 0: *(int64_t*)&R_RAX = syscall(sc); break; + case 1: *(int64_t*)&R_RAX = syscall(sc, R_RDI); break; + case 2: if(s==33) {printf_log(LOG_DUMP, " => sys_access(\"%s\", %ld)\n", (char*)R_RDI, R_RSI);}; *(int64_t*)&R_RAX = syscall(sc, R_RDI, R_RSI); break; + case 3: *(int64_t*)&R_RAX = syscall(sc, R_RDI, R_RSI, R_RDX); break; + case 4: *(int64_t*)&R_RAX = syscall(sc, R_RDI, R_RSI, R_RDX, R_R10); break; + case 5: *(int64_t*)&R_RAX = syscall(sc, R_RDI, R_RSI, R_RDX, R_R10, R_R8); break; + case 6: *(int64_t*)&R_RAX = syscall(sc, R_RDI, R_RSI, R_RDX, R_R10, R_R8, R_R9); break; + default: + printf_log(LOG_NONE, "ERROR, Unimplemented syscall wrapper (%d, %d)\n", s, syscallwrap[i].nbpars); + emu->quit = 1; + return; + } + printf_log(LOG_DEBUG, " => 0x%x\n", R_EAX); + return; + } + } + switch (s) { + default: + printf_log(LOG_INFO, "Error: Unsupported Syscall 0x%02Xh (%d)\n", s, s); + emu->quit = 1; + emu->error |= ERR_UNIMPL; + return; + } + printf_log(LOG_DEBUG, " => 0x%x\n", R_EAX); +} + +#define stack(n) (R_RSP+8+n) +#define i32(n) *(int32_t*)stack(n) +#define u32(n) *(uint32_t*)stack(n) +#define u64(n) *(uint64_t*)stack(n) +#define p(n) *(void**)stack(n) + +uint32_t EXPORT my_syscall(x64emu_t *emu) +{ + uint32_t s = R_EDI;; + printf_log(LOG_DUMP, "%p: Calling libc syscall 0x%02X (%d) %p %p %p %p %p\n", (void*)R_RIP, s, s, (void*)R_RSI, (void*)R_RDX, (void*)R_RCX, (void*)R_R8, (void*)R_R9); + // check wrapper first + int cnt = sizeof(syscallwrap) / sizeof(scwrap_t); + for (int i=0; i<cnt; i++) { + if(syscallwrap[i].x64s == s) { + int sc = syscallwrap[i].nats; + switch(syscallwrap[i].nbpars) { + case 0: return syscall(sc); + case 1: return syscall(sc, R_RSI); + case 2: return syscall(sc, R_RSI, R_RDX); + case 3: return syscall(sc, R_RSI, R_RDX, R_RCX); + case 4: return syscall(sc, R_RSI, R_RDX, R_RCX, R_R8); + case 5: return syscall(sc, R_RSI, R_RDX, R_RCX, R_R8, R_R9); + case 6: return syscall(sc, R_RSI, R_RDX, R_RCX, R_R8, R_R9, u64(0)); + default: + printf_log(LOG_NONE, "ERROR, Unimplemented syscall wrapper (%d, %d)\n", s, syscallwrap[i].nbpars); + emu->quit = 1; + return 0; + } + } + } + switch (s) { + default: + printf_log(LOG_INFO, "Error: Unsupported libc Syscall 0x%02X (%d)\n", s, s); + emu->quit = 1; + emu->error |= ERR_UNIMPL; + } + return 0; +} diff --git a/src/emu/x64tls.c b/src/emu/x64tls.c new file mode 100755 index 00000000..b76646b5 --- /dev/null +++ b/src/emu/x64tls.c @@ -0,0 +1,213 @@ +// Handling of TLS calls, include x86 specifi set_thread_area +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> + +#include "debug.h" +#include "box64context.h" +#include "x64emu.h" +#include "x64tls.h" +#include "elfloader.h" + +typedef struct thread_area_s +{ + int entry_number; + uintptr_t base_addr; + unsigned int limit; + unsigned int seg_32bit:1; + unsigned int contents:2; + unsigned int read_exec_only:1; + unsigned int limit_in_pages:1; + unsigned int seg_not_present:1; + unsigned int useable:1; +} thread_area_t; + +static pthread_once_t thread_key_once0 = PTHREAD_ONCE_INIT; +static pthread_once_t thread_key_once1 = PTHREAD_ONCE_INIT; +static pthread_once_t thread_key_once2 = PTHREAD_ONCE_INIT; + +static void thread_key_alloc0() { + pthread_key_create(&my_context->segtls[0].key, NULL); +} +static void thread_key_alloc1() { + pthread_key_create(&my_context->segtls[1].key, NULL); +} +static void thread_key_alloc2() { + pthread_key_create(&my_context->segtls[2].key, NULL); +} + +uint32_t my_set_thread_area(thread_area_t* td) +{ + printf_log(LOG_DEBUG, "set_thread_area(%p[%d/base=%p/limit=%u/32bits:%u/%u/%u...])\n", td, td->entry_number, (void*)td->base_addr, td->limit_in_pages, td->seg_32bit, td->contents, td->read_exec_only); + + int isempty = 0; + // first, check if the "user_desc", here td, is "empty" + if(td->read_exec_only==1 && td->seg_not_present==1) + if( !td->base_addr + && !td->limit + && !td->seg_32bit + && !td->contents + && !td->limit_in_pages + && !td->useable) + isempty = 1; + int idx = td->entry_number; + if(idx==-1) { + // find a free one + for (int i=0; i<3 && idx==-1; ++i) + if(!my_context->segtls[i].present) + idx=i; + if(idx==-1) { + errno = ESRCH; + return (uint32_t)-1; + } + idx+=7; + td->entry_number = idx; + } + if(isempty && (td->entry_number<7 || td->entry_number>7+2)) { + errno = EINVAL; + return (uint32_t)-1; + } + if(isempty) { + memset(&my_context->segtls[td->entry_number-7], 0, sizeof(base_segment_t)); + return 0; + } + if((idx<7 || idx>7+2)) { + errno = EINVAL; + return (uint32_t)-1; + } + + my_context->segtls[idx-7].base = td->base_addr; + my_context->segtls[idx-7].limit = td->limit; + my_context->segtls[idx-7].present = 1; + switch (idx-7) { + case 0: pthread_once(&thread_key_once0, thread_key_alloc0); break; + case 1: pthread_once(&thread_key_once1, thread_key_alloc1); break; + case 2: pthread_once(&thread_key_once2, thread_key_alloc2); break; + } + + pthread_setspecific(my_context->segtls[idx-7].key, (void*)my_context->segtls[idx-7].base); + + ResetSegmentsCache(thread_get_emu()); + + return 0; +} + +uint32_t my_modify_ldt(x64emu_t* emu, int op, thread_area_t* td, int size) +{ + printf_log(/*LOG_DEBUG*/LOG_INFO, "modify_ldt(0x%x, %p[0x%x/base=%p/limit=%u/32bits:%u/%u/%u...], %d)\n", op, td, td->entry_number, (void*)td->base_addr, td->limit_in_pages, td->seg_32bit, td->contents, td->read_exec_only, size); + if(!td) { + errno = EFAULT; + return (uint32_t)-1; + } + if(op!=0x11) { + errno = ENOSYS; + return (uint32_t)-1; + } + if(!td->seg_32bit) { + // not handling 16bits segments for now + errno = EINVAL; + return (uint32_t)-1; + } + + int idx = td->entry_number - 7; + if(idx<0 || idx>2) { + errno = EINVAL; + return (uint32_t)-1; + } + + /* + my_context->segtls[idx].base = td->base_addr; + my_context->segtls[idx].limit = td->limit; + pthread_setspecific(my_context->segtls[idx].key, (void*)my_context->segtls[idx].base); + */ + + ResetSegmentsCache(thread_get_emu()); + + return 0; +} + +#define POS_TLS 0x50 + +static tlsdatasize_t* setupTLSData(box64context_t* context) +{ + // Setup the GS segment: + int dtsize = context->elfsize*8; + void *ptr = (char*)malloc(context->tlssize+4+POS_TLS+dtsize); + memcpy(ptr, context->tlsdata, context->tlssize); + tlsdatasize_t *data = (tlsdatasize_t*)calloc(1, sizeof(tlsdatasize_t)); + data->tlsdata = ptr; + data->tlssize = context->tlssize; + pthread_setspecific(context->tlskey, data); + // copy canary... + memset((void*)((uintptr_t)ptr+context->tlssize), 0, POS_TLS+dtsize); // set to 0 remining bytes + memcpy((void*)((uintptr_t)ptr+context->tlssize+0x14), context->canary, 4); // put canary in place + uintptr_t tlsptr = (uintptr_t)ptr+context->tlssize; + memcpy((void*)((uintptr_t)ptr+context->tlssize+0x0), &tlsptr, 4); + uintptr_t dtp = (uintptr_t)ptr+context->tlssize+POS_TLS; + memcpy((void*)(tlsptr+0x4), &dtp, 4); + if(dtsize) { + for (int i=0; i<context->elfsize; ++i) { + // set pointer + dtp = (uintptr_t)ptr + (context->tlssize + GetTLSBase(context->elfs[i])); + memcpy((void*)((uintptr_t)ptr+context->tlssize+POS_TLS+i*8), &dtp, 4); + memcpy((void*)((uintptr_t)ptr+context->tlssize+POS_TLS+i*8+4), &i, 4); // index + } + } + memcpy((void*)((uintptr_t)ptr+context->tlssize+0x10), &context->vsyscall, 4); // address of vsyscall + return data; +} + +void* fillTLSData(box64context_t *context) +{ + pthread_mutex_lock(&context->mutex_tls); + tlsdatasize_t *data = setupTLSData(context); + pthread_mutex_unlock(&context->mutex_tls); + return data; +} + +void* resizeTLSData(box64context_t *context, void* oldptr) +{ + pthread_mutex_lock(&context->mutex_tls); + tlsdatasize_t* oldata = (tlsdatasize_t*)oldptr; + tlsdatasize_t *data = setupTLSData(context); + // copy the relevent old part, in case something changed + memcpy((void*)((uintptr_t)data->tlsdata+(context->tlssize-oldata->tlssize)), oldata->tlsdata, oldata->tlssize); + // all done, update new size, free old pointer and exit + pthread_mutex_unlock(&context->mutex_tls); + free_tlsdatasize(oldptr); + return data; +} + +static void* GetSeg33Base() +{ + tlsdatasize_t* ptr; + if ((ptr = (tlsdatasize_t*)pthread_getspecific(my_context->tlskey)) == NULL) { + ptr = (tlsdatasize_t*)fillTLSData(my_context); + } + if(ptr->tlssize != my_context->tlssize) + ptr = (tlsdatasize_t*)resizeTLSData(my_context, ptr); + return ptr->tlsdata+ptr->tlssize; +} + +void* GetSegmentBase(uint32_t desc) +{ + if(!desc) { + printf_log(LOG_NONE, "Warning, accessing segment NULL\n"); + return NULL; + } + int base = desc>>3; + if(base==0xe || base==0xf) + return NULL; // regular value... + if(base==0x6) + return GetSeg33Base(); + + if(base>6 && base<10 && my_context->segtls[base-7].present) { + void* ptr = pthread_getspecific(my_context->segtls[base-7].key); + return ptr; + } + + printf_log(LOG_NONE, "Warning, accessing segment unknown 0x%x or unset\n", desc); + return NULL; +} |