#define _LARGEFILE_SOURCE 1 #define _FILE_OFFSET_BITS 64 #define _GNU_SOURCE /* See feature_test_macros(7) */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef LOG_INFO #undef LOG_DEBUG #include "wrappedlibs.h" #include "box64stack.h" #include "x64emu.h" #include "debug.h" #include "wrapper.h" #include "bridge.h" #include "callback.h" #include "librarian.h" #include "librarian/library_private.h" #include "emu/x64emu_private.h" #include "box64context.h" #include "myalign.h" #include "signals.h" #include "fileutils.h" #include "auxval.h" #include "elfloader.h" #include "bridge.h" #include "globalsymbols.h" #define LIBNAME libc const char* libcName = "libc.so.6"; typedef int (*iFi_t)(int); typedef int (*iFL_t)(unsigned long); typedef void (*vFpp_t)(void*, void*); typedef void (*vFipp_t)(int32_t, void*, void*); typedef int32_t (*iFpi_t)(void*, int32_t); typedef int32_t (*iFpp_t)(void*, void*); typedef int32_t (*iFpL_t)(void*, size_t); typedef int32_t (*iFiip_t)(int32_t, int32_t, void*); typedef int32_t (*iFipp_t)(int32_t, void*, void*); typedef int32_t (*iFppi_t)(void*, void*, int32_t); typedef int32_t (*iFpup_t)(void*, uint32_t, void*); typedef int32_t (*iFpuu_t)(void*, uint32_t, uint32_t); typedef int32_t (*iFiiII_t)(int, int, int64_t, int64_t); typedef int32_t (*iFiiiV_t)(int, int, int, ...); typedef int32_t (*iFippi_t)(int32_t, void*, void*, int32_t); typedef int32_t (*iFpppp_t)(void*, void*, void*, void*); typedef int32_t (*iFpipp_t)(void*, int32_t, void*, void*); typedef int32_t (*iFppii_t)(void*, void*, int32_t, int32_t); typedef int32_t (*iFipuu_t)(int32_t, void*, uint32_t, uint32_t); typedef int32_t (*iFipiI_t)(int32_t, void*, int32_t, int64_t); typedef int32_t (*iFipuup_t)(int32_t, void*, uint32_t, uint32_t, void*); typedef int32_t (*iFiiV_t)(int32_t, int32_t, ...); typedef void* (*pFp_t)(void*); #define SUPER() \ GO(_ITM_addUserCommitAction, iFpup_t) \ GO(_IO_file_stat, iFpp_t) #include "wrappercallback.h" static int regs_abi[] = {_DI, _SI, _DX, _CX, _R8, _R9}; void* getVargN(x64emu_t *emu, int n) { if(n<6) return (void*)emu->regs[regs_abi[n]].q[0]; return ((void**)R_RSP)[1+n-6]; } // utility functions #define SUPER() \ GO(0) \ GO(1) \ GO(2) \ GO(3) \ GO(4) \ GO(5) \ GO(6) \ GO(7) \ GO(8) \ GO(9) \ GO(10) \ GO(11) \ GO(12) \ GO(13) \ GO(14) \ GO(15) // compare #define GO(A) \ static uintptr_t my_compare_fct_##A = 0; \ static int my_compare_##A(void* a, void* b) \ { \ return (int)RunFunction(my_context, my_compare_fct_##A, 2, a, b);\ } SUPER() #undef GO static void* findcompareFct(void* fct) { if(!fct) return NULL; void* p; if((p = GetNativeFnc((uintptr_t)fct))) return p; #define GO(A) if(my_compare_fct_##A == (uintptr_t)fct) return my_compare_##A; SUPER() #undef GO #define GO(A) if(my_compare_fct_##A == 0) {my_compare_fct_##A = (uintptr_t)fct; return my_compare_##A; } SUPER() #undef GO printf_log(LOG_NONE, "Warning, no more slot for libc compare callback\n"); return NULL; } // ftw64 #define GO(A) \ static uintptr_t my_ftw64_fct_##A = 0; \ static int my_ftw64_##A(void* fpath, void* sb, int flag) \ { \ struct x64_stat64 x64st; \ UnalignStat64(sb, &x64st); \ return (int)RunFunction(my_context, my_ftw64_fct_##A, 3, fpath, &x64st, flag); \ } SUPER() #undef GO static void* findftw64Fct(void* fct) { if(!fct) return NULL; #define GO(A) if(my_ftw64_fct_##A == (uintptr_t)fct) return my_ftw64_##A; SUPER() #undef GO #define GO(A) if(my_ftw64_fct_##A == 0) {my_ftw64_fct_##A = (uintptr_t)fct; return my_ftw64_##A; } SUPER() #undef GO printf_log(LOG_NONE, "Warning, no more slot for libc ftw64 callback\n"); return NULL; } // nftw64 #define GO(A) \ static uintptr_t my_nftw64_fct_##A = 0; \ static int my_nftw64_##A(void* fpath, void* sb, int flag, void* ftwbuff) \ { \ struct x64_stat64 x64st; \ UnalignStat64(sb, &x64st); \ return (int)RunFunction(my_context, my_nftw64_fct_##A, 4, fpath, &x64st, flag, ftwbuff); \ } SUPER() #undef GO static void* findnftw64Fct(void* fct) { if(!fct) return NULL; #define GO(A) if(my_nftw64_fct_##A == (uintptr_t)fct) return my_nftw64_##A; SUPER() #undef GO #define GO(A) if(my_nftw64_fct_##A == 0) {my_nftw64_fct_##A = (uintptr_t)fct; return my_nftw64_##A; } SUPER() #undef GO printf_log(LOG_NONE, "Warning, no more slot for libc nftw64 callback\n"); return NULL; } // globerr #define GO(A) \ static uintptr_t my_globerr_fct_##A = 0; \ static int my_globerr_##A(void* epath, int eerrno) \ { \ return (int)RunFunction(my_context, my_globerr_fct_##A, 2, epath, eerrno); \ } SUPER() #undef GO static void* findgloberrFct(void* fct) { if(!fct) return NULL; void* p; if((p = GetNativeFnc((uintptr_t)fct))) return p; #define GO(A) if(my_globerr_fct_##A == (uintptr_t)fct) return my_globerr_##A; SUPER() #undef GO #define GO(A) if(my_globerr_fct_##A == 0) {my_globerr_fct_##A = (uintptr_t)fct; return my_globerr_##A; } SUPER() #undef GO printf_log(LOG_NONE, "Warning, no more slot for libc globerr callback\n"); return NULL; } // free #define GO(A) \ static uintptr_t my_free_fct_##A = 0; \ static void my_free_##A(void* p) \ { \ RunFunction(my_context, my_free_fct_##A, 1, p); \ } SUPER() #undef GO static void* findfreeFct(void* fct) { if(!fct) return NULL; void* p; if((p = GetNativeFnc((uintptr_t)fct))) return p; #define GO(A) if(my_free_fct_##A == (uintptr_t)fct) return my_free_##A; SUPER() #undef GO #define GO(A) if(my_free_fct_##A == 0) {my_free_fct_##A = (uintptr_t)fct; return my_free_##A; } SUPER() #undef GO printf_log(LOG_NONE, "Warning, no more slot for libc free callback\n"); return NULL; } #if 0 #undef dirent // filter_dir #define GO(A) \ static uintptr_t my_filter_dir_fct_##A = 0; \ static int my_filter_dir_##A(const struct dirent* a) \ { \ return (int)RunFunction(my_context, my_filter_dir_fct_##A, 1, a); \ } SUPER() #undef GO static void* findfilter_dirFct(void* fct) { if(!fct) return NULL; void* p; if((p = GetNativeFnc((uintptr_t)fct))) return p; #define GO(A) if(my_filter_dir_fct_##A == (uintptr_t)fct) return my_filter_dir_##A; SUPER() #undef GO #define GO(A) if(my_filter_dir_fct_##A == 0) {my_filter_dir_fct_##A = (uintptr_t)fct; return my_filter_dir_##A; } SUPER() #undef GO printf_log(LOG_NONE, "Warning, no more slot for libc filter_dir callback\n"); return NULL; } // compare_dir #define GO(A) \ static uintptr_t my_compare_dir_fct_##A = 0; \ static int my_compare_dir_##A(const struct dirent* a, const struct dirent* b) \ { \ return (int)RunFunction(my_context, my_compare_dir_fct_##A, 2, a, b); \ } SUPER() #undef GO static void* findcompare_dirFct(void* fct) { if(!fct) return NULL; void* p; if((p = GetNativeFnc((uintptr_t)fct))) return p; #define GO(A) if(my_compare_dir_fct_##A == (uintptr_t)fct) return my_compare_dir_##A; SUPER() #undef GO #define GO(A) if(my_compare_dir_fct_##A == 0) {my_compare_dir_fct_##A = (uintptr_t)fct; return my_compare_dir_##A; } SUPER() #undef GO printf_log(LOG_NONE, "Warning, no more slot for libc compare_dir callback\n"); return NULL; } #endif // filter64 #define GO(A) \ static uintptr_t my_filter64_fct_##A = 0; \ static int my_filter64_##A(const struct dirent64* a) \ { \ return (int)RunFunction(my_context, my_filter64_fct_##A, 1, a); \ } SUPER() #undef GO static void* findfilter64Fct(void* fct) { if(!fct) return NULL; void* p; if((p = GetNativeFnc((uintptr_t)fct))) return p; #define GO(A) if(my_filter64_fct_##A == (uintptr_t)fct) return my_filter64_##A; SUPER() #undef GO #define GO(A) if(my_filter64_fct_##A == 0) {my_filter64_fct_##A = (uintptr_t)fct; return my_filter64_##A; } SUPER() #undef GO printf_log(LOG_NONE, "Warning, no more slot for libc filter64 callback\n"); return NULL; } // compare64 #define GO(A) \ static uintptr_t my_compare64_fct_##A = 0; \ static int my_compare64_##A(const struct dirent64* a, const struct dirent64* b) \ { \ return (int)RunFunction(my_context, my_compare64_fct_##A, 2, a, b); \ } SUPER() #undef GO static void* findcompare64Fct(void* fct) { if(!fct) return NULL; void* p; if((p = GetNativeFnc((uintptr_t)fct))) return p; #define GO(A) if(my_compare64_fct_##A == (uintptr_t)fct) return my_compare64_##A; SUPER() #undef GO #define GO(A) if(my_compare64_fct_##A == 0) {my_compare64_fct_##A = (uintptr_t)fct; return my_compare64_##A; } SUPER() #undef GO printf_log(LOG_NONE, "Warning, no more slot for libc compare64 callback\n"); return NULL; } #undef SUPER // some my_XXX declare and defines int32_t 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)); // implemented in x64run_private.c EXPORT void my___libc_init_first(x64emu_t* emu, int argc, char* arg0, char** b) { // do nothing specific for now (void)emu; (void)argc; (void)arg0; (void)b; return; } uintptr_t my_syscall(x64emu_t *emu); // implemented in x64syscall.c void EXPORT my___stack_chk_fail(x64emu_t* emu) { char buff[200]; #ifdef HAVE_TRACE sprintf(buff, "%p: Stack is corrupted, aborting (prev IP=%p)\n", (void*)emu->old_ip, (void*)emu->prev2_ip); #else sprintf(buff, "%p: Stack is corrupted, aborting\n", (void*)emu->old_ip); #endif StopEmu(emu, buff); } void EXPORT my___gmon_start__(x64emu_t *emu) { (void)emu; printf_log(LOG_DEBUG, "__gmon_start__ called (dummy call)\n"); } int EXPORT my___cxa_atexit(x64emu_t* emu, void* p, void* a, void* dso_handle) { (void)dso_handle; AddCleanup1Arg(emu, p, a); return 0; } void EXPORT my___cxa_finalize(x64emu_t* emu, void* p) { if(!p) { // p is null, call (and remove) all Cleanup functions CallAllCleanup(emu); return; } CallCleanup(emu, p); } int EXPORT my_atexit(x64emu_t* emu, void *p) { AddCleanup(emu, p); return 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); int my_swapcontext(x64emu_t* emu, void* ucp1, void* ucp2); // All signal and context functions defined in signals.c // All fts function defined in myfts.c // getauxval implemented in auxval.c // this one is defined in elfloader.c int my_dl_iterate_phdr(x64emu_t *emu, void* F, void *data); pid_t EXPORT my_fork(x64emu_t* emu) { // execute atforks prepare functions, in reverse order for (int i=my_context->atfork_sz-1; i>=0; --i) if(my_context->atforks[i].prepare) RunFunctionWithEmu(emu, 0, my_context->atforks[i].prepare, 0); int type = emu->type; pid_t v; v = fork(); if(type == EMUTYPE_MAIN) thread_set_emu(emu); if(v<0) { printf_log(LOG_NONE, "BOX64: Warning, fork errored... (%d)\n", v); // error... } else if(v>0) { // execute atforks parent functions for (int i=0; iatfork_sz; --i) if(my_context->atforks[i].parent) RunFunctionWithEmu(emu, 0, my_context->atforks[i].parent, 0); } else /*if(v==0)*/ { // execute atforks child functions for (int i=0; iatfork_sz; --i) if(my_context->atforks[i].child) RunFunctionWithEmu(emu, 0, my_context->atforks[i].child, 0); } return v; } pid_t EXPORT my___fork(x64emu_t* emu) __attribute__((alias("my_fork"))); pid_t EXPORT my_vfork(x64emu_t* emu) { #if 1 emu->quit = 1; emu->fork = 1; // use regular fork... return 0; #else return 0; #endif } int EXPORT my_uname(struct utsname *buf) { //TODO: check sizeof(struct utsname) == 390 int ret = uname(buf); strcpy(buf->machine, "x86_64"); return ret; } // X86_O_RDONLY 0x00 #define X86_O_WRONLY 0x01 // octal 01 #define X86_O_RDWR 0x02 // octal 02 #define X86_O_CREAT 0x40 // octal 0100 #define X86_O_EXCL 0x80 // octal 0200 #define X86_O_NOCTTY 0x100 // octal 0400 #define X86_O_TRUNC 0x200 // octal 01000 #define X86_O_APPEND 0x400 // octal 02000 #define X86_O_NONBLOCK 0x800 // octal 04000 #define X86_O_SYNC 0x101000 // octal 04010000 #define X86_O_DSYNC 0x1000 // octal 010000 #define X86_O_RSYNC O_SYNC #define X86_FASYNC 020000 #define X86_O_DIRECT 040000 #define X86_O_LARGEFILE 0100000 #define X86_O_DIRECTORY 0200000 #define X86_O_NOFOLLOW 0400000 #define X86_O_NOATIME 01000000 #define X86_O_CLOEXEC 02000000 #define X86_O_PATH 010000000 #define X86_O_TMPFILE 020200000 #ifndef O_TMPFILE #define O_TMPFILE (020000000 | O_DIRECTORY) #endif #define SUPER() \ GO(O_WRONLY) \ GO(O_RDWR) \ GO(O_CREAT) \ GO(O_EXCL) \ GO(O_NOCTTY) \ GO(O_TRUNC) \ GO(O_APPEND) \ GO(O_NONBLOCK) \ GO(O_SYNC) \ GO(O_DSYNC) \ GO(O_RSYNC) \ GO(FASYNC) \ GO(O_DIRECT) \ GO(O_LARGEFILE) \ GO(O_TMPFILE) \ GO(O_DIRECTORY) \ GO(O_NOFOLLOW) \ GO(O_NOATIME) \ GO(O_CLOEXEC) \ GO(O_PATH) \ // x86->arm int of_convert(int a) { if(!a || a==-1) return a; int b=0; #define GO(A) if((a&(X86_##A))==(X86_##A)) {a&=~(X86_##A); b|=(A);} SUPER(); #undef GO if(a) { printf_log(LOG_NONE, "Warning, of_convert(...) left over 0x%x, converted 0x%x\n", a, b); } return a|b; } // arm->x86 int of_unconvert(int a) { if(!a || a==-1) return a; int b=0; #define GO(A) if((a&(A))==(A)) {a&=~(A); b|=(X86_##A);} SUPER(); #undef GO // flags 0x20000 unknown?! if(a && (a&~0x20000)) { printf_log(LOG_NONE, "Warning, of_unconvert(...) left over 0x%x, converted 0x%x\n", a, b); } return a|b; } #undef SUPER EXPORT void* my__ZGTtnaX (size_t a) { (void)a; printf("warning _ZGTtnaX called\n"); return NULL; } EXPORT void my__ZGTtdlPv (void* a) { (void)a; printf("warning _ZGTtdlPv called\n"); } EXPORT uint8_t my__ITM_RU1(const uint8_t * a) { (void)a; printf("warning _ITM_RU1 called\n"); return 0; } EXPORT uint32_t my__ITM_RU4(const uint32_t * a) { (void)a; printf("warning _ITM_RU4 called\n"); return 0; } EXPORT uint64_t my__ITM_RU8(const uint64_t * a) { (void)a; printf("warning _ITM_RU8 called\n"); return 0; } EXPORT void my__ITM_memcpyRtWn(void * a, const void * b, size_t c) { (void)a; (void)b; (void)c; printf("warning _ITM_memcpyRtWn called\n"); } EXPORT void my__ITM_memcpyRnWt(void * a, const void * b, size_t c) { (void)a; (void)b; (void)c; printf("warning _ITM_memcpyRnWt called\n"); } EXPORT void my_longjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p, int32_t __val); EXPORT void my__longjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p, int32_t __val) __attribute__((alias("my_longjmp"))); EXPORT void my_siglongjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p, int32_t __val) __attribute__((alias("my_longjmp"))); EXPORT void my___longjmp_chk(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p, int32_t __val) __attribute__((alias("my_longjmp"))); //EXPORT int32_t my_setjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p); //EXPORT int32_t my__setjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p) __attribute__((alias("my_setjmp"))); //EXPORT int32_t my___sigsetjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p) __attribute__((alias("my_setjmp"))); EXPORT int my_printf(x64emu_t *emu, void* fmt, void* b) { myStackAlign(emu, (const char*)fmt, b, emu->scratch, R_EAX, 1); PREPARE_VALIST; return vprintf((const char*)fmt, VARARGS); } EXPORT int my___printf_chk(x64emu_t *emu, int chk, void* fmt, void* b) { (void)chk; myStackAlign(emu, (const char*)fmt, b, emu->scratch, R_EAX, 2); PREPARE_VALIST; return vprintf((const char*)fmt, VARARGS); } EXPORT int my_vprintf(x64emu_t *emu, void* fmt, x64_va_list_t b) { (void)emu; #ifdef CONVERT_VALIST CONVERT_VALIST(b); #else myStackAlignValist(emu, (const char*)fmt, emu->scratch, b); PREPARE_VALIST; #endif return vprintf(fmt, VARARGS); } EXPORT int my___vprintf_chk(x64emu_t *emu, void* fmt, x64_va_list_t b) __attribute__((alias("my_vprintf"))); EXPORT int my_vfprintf(x64emu_t *emu, void* F, void* fmt, x64_va_list_t b) { (void)emu; #ifdef CONVERT_VALIST CONVERT_VALIST(b); #else myStackAlignValist(emu, (const char*)fmt, emu->scratch, b); PREPARE_VALIST; #endif return vfprintf(F, fmt, VARARGS); } EXPORT int my___vfprintf_chk(x64emu_t *emu, void* F, void* fmt, x64_va_list_t b) __attribute__((alias("my_vfprintf"))); EXPORT int my__IO_vfprintf(x64emu_t *emu, void* F, void* fmt, x64_va_list_t b) __attribute__((alias("my_vfprintf"))); EXPORT int my_fprintf(x64emu_t *emu, void* F, void* fmt, void* b) { myStackAlign(emu, (const char*)fmt, b, emu->scratch, R_EAX, 2); PREPARE_VALIST; return vfprintf(F, fmt, VARARGS); } EXPORT int my___fprintf_chk(x64emu_t *emu, void* F, int flag, void* fmt, void* b) { (void)flag; myStackAlign(emu, (const char*)fmt, b, emu->scratch, R_EAX, 3); PREPARE_VALIST; return vfprintf(F, fmt, VARARGS); } #if 0 EXPORT int my_wprintf(x64emu_t *emu, void* fmt, void* b, va_list V) { #ifndef NOALIGN // need to align on arm myStackAlignW((const char*)fmt, b, emu->scratch); PREPARE_VALIST; void* f = vwprintf; return ((iFpp_t)f)(fmt, VARARGS); #else // other platform don't need that return vwprintf((const wchar_t*)fmt, V); #endif } EXPORT int my___wprintf_chk(x64emu_t *emu, int flag, void* fmt, void* b, va_list V) { #ifndef NOALIGN // need to align on arm myStackAlignW((const char*)fmt, b, emu->scratch); PREPARE_VALIST; void* f = vwprintf; return ((iFpp_t)f)(fmt, VARARGS); #else // other platform don't need that return vwprintf((const wchar_t*)fmt, V); #endif } #endif EXPORT int my_fwprintf(x64emu_t *emu, void* F, void* fmt, void* b) { myStackAlignW(emu, (const char*)fmt, b, emu->scratch, R_EAX, 2); PREPARE_VALIST; return vfwprintf(F, fmt, VARARGS); } #if 0 EXPORT int my___fwprintf_chk(x64emu_t *emu, void* F, void* fmt, void* b, va_list V) __attribute__((alias("my_fwprintf"))); EXPORT int my_vfwprintf(x64emu_t *emu, void* F, void* fmt, void* b) { #ifndef NOALIGN myStackAlignW((const char*)fmt, b, emu->scratch); PREPARE_VALIST; void* f = vfwprintf; return ((iFppp_t)f)(F, fmt, VARARGS); #else void* f = vfwprintf; return ((iFppp_t)f)(F, fmt, b); #endif } EXPORT int my_vwprintf(x64emu_t *emu, void* fmt, void* b) { #ifndef NOALIGN myStackAlignW((const char*)fmt, b, emu->scratch); PREPARE_VALIST; void* f = vwprintf; return ((iFpp_t)f)(fmt, VARARGS); #else void* f = vwprintf; return ((iFpp_t)f)(fmt, b); #endif } EXPORT void *my_div(void *result, int numerator, int denominator) { *(div_t *)result = div(numerator, denominator); return result; } #endif EXPORT int my_snprintf(x64emu_t* emu, void* buff, size_t s, void * fmt, uint64_t * b) { myStackAlign(emu, (const char*)fmt, b, emu->scratch, R_EAX, 3); PREPARE_VALIST; int r = vsnprintf(buff, s, fmt, VARARGS); return r; } EXPORT int my___snprintf(x64emu_t* emu, void* buff, size_t s, void * fmt, uint64_t * b) __attribute__((alias("my_snprintf"))); EXPORT int my___snprintf_chk(x64emu_t* emu, void* buff, size_t s, int flags, size_t maxlen, void * fmt, uint64_t * b) { (void)flags; (void)maxlen; myStackAlign(emu, (const char*)fmt, b, emu->scratch, R_EAX, 5); PREPARE_VALIST; int r = vsnprintf(buff, s, fmt, VARARGS); return r; } EXPORT int my_sprintf(x64emu_t* emu, void* buff, void * fmt, void * b) { myStackAlign(emu, (const char*)fmt, b, emu->scratch, R_EAX, 2); PREPARE_VALIST; return vsprintf(buff, (const char*)fmt, VARARGS); } EXPORT int my___sprintf_chk(x64emu_t* emu, void* buff, int flag, size_t l, void * fmt, void * b) { (void)flag; (void)l; myStackAlign(emu, (const char*)fmt, b, emu->scratch, R_EAX, 4); PREPARE_VALIST; return vsprintf(buff, (const char*)fmt, VARARGS); } EXPORT int my_asprintf(x64emu_t* emu, void** buff, void * fmt, uint64_t * b) { myStackAlign(emu, (const char*)fmt, b, emu->scratch, R_EAX, 2); PREPARE_VALIST; return vasprintf((char**)buff, (char*)fmt, VARARGS); } EXPORT int my___asprintf(x64emu_t* emu, void** buff, void * fmt, uint64_t * b) __attribute__((alias("my_asprintf"))); EXPORT int my_vasprintf(x64emu_t* emu, char** buff, void* fmt, x64_va_list_t b) { (void)emu; #ifdef CONVERT_VALIST CONVERT_VALIST(b); #else myStackAlignValist(emu, (const char*)fmt, emu->scratch, b); PREPARE_VALIST; #endif return vasprintf(buff, fmt, VARARGS); } EXPORT int my_vsprintf(x64emu_t* emu, void* buff, void * fmt, x64_va_list_t b) { (void)emu; #ifdef CONVERT_VALIST CONVERT_VALIST(b); #else myStackAlignValist(emu, (const char*)fmt, emu->scratch, b); PREPARE_VALIST; #endif return vsprintf(buff, fmt, VARARGS); } EXPORT int my___vsprintf_chk(x64emu_t* emu, void* buff, void * fmt, x64_va_list_t b) __attribute__((alias("my_vsprintf"))); EXPORT int my_vfscanf(x64emu_t* emu, void* stream, void* fmt, x64_va_list_t b) { (void)emu; #ifdef CONVERT_VALIST CONVERT_VALIST(b); #else myStackAlignScanfValist(emu, (const char*)fmt, emu->scratch, b); PREPARE_VALIST; #endif return vfscanf(stream, fmt, VARARGS); } EXPORT int my_vsscanf(x64emu_t* emu, void* stream, void* fmt, x64_va_list_t b) { (void)emu; #ifdef CONVERT_VALIST CONVERT_VALIST(b); #else myStackAlignScanfValist(emu, (const char*)fmt, emu->scratch, b); PREPARE_VALIST; #endif return vsscanf(stream, fmt, VARARGS); } EXPORT int my__vsscanf(x64emu_t* emu, void* stream, void* fmt, void* b) __attribute__((alias("my_vsscanf"))); EXPORT int my_vswscanf(x64emu_t* emu, void* stream, void* fmt, x64_va_list_t b) { (void)emu; #ifdef CONVERT_VALIST CONVERT_VALIST(b); #else myStackAlignScanfWValist(emu, (const char*)fmt, emu->scratch, b); PREPARE_VALIST; #endif return vswscanf(stream, fmt, VARARGS); } EXPORT int my_sscanf(x64emu_t* emu, void* stream, void* fmt, uint64_t* b) { myStackAlignScanf(emu, (const char*)fmt, b, emu->scratch, 2); PREPARE_VALIST; return vsscanf(stream, fmt, VARARGS); } EXPORT int my__IO_vfscanf(x64emu_t* emu, void* stream, void* fmt, void* b) __attribute__((alias("my_vfscanf"))); EXPORT int my___isoc99_vsscanf(x64emu_t* emu, void* stream, void* fmt, void* b) __attribute__((alias("my_vsscanf"))); EXPORT int my___isoc99_vfscanf(x64emu_t* emu, void* stream, void* fmt, void* b) __attribute__((alias("my_vfscanf"))); EXPORT int my___isoc99_fscanf(x64emu_t* emu, void* stream, void* fmt, uint64_t* b) { myStackAlignScanf(emu, (const char*)fmt, b, emu->scratch, 2); PREPARE_VALIST; return vfscanf(stream, fmt, VARARGS); } EXPORT int my_fscanf(x64emu_t* emu, void* stream, void* fmt, uint64_t* b) __attribute__((alias("my___isoc99_fscanf"))); EXPORT int my___isoc99_scanf(x64emu_t* emu, void* fmt, uint64_t* b) { myStackAlignScanf(emu, (const char*)fmt, b, emu->scratch, 1); PREPARE_VALIST; return vscanf(fmt, VARARGS); } EXPORT int my___isoc99_sscanf(x64emu_t* emu, void* stream, void* fmt, uint64_t* b) { myStackAlignScanf(emu, (const char*)fmt, b, emu->scratch, 2); PREPARE_VALIST; return vsscanf(stream, fmt, VARARGS); } EXPORT int my_vsnprintf(x64emu_t* emu, void* buff, size_t s, void * fmt, x64_va_list_t b) { (void)emu; #ifdef CONVERT_VALIST CONVERT_VALIST(b); #else myStackAlignValist(emu, (const char*)fmt, emu->scratch, b); PREPARE_VALIST; #endif int r = vsnprintf(buff, s, fmt, VARARGS); return r; } EXPORT int my___vsnprintf(x64emu_t* emu, void* buff, size_t s, void * fmt, x64_va_list_t b) __attribute__((alias("my_vsnprintf"))); EXPORT int my___vsnprintf_chk(x64emu_t* emu, void* buff, size_t s, void * fmt, x64_va_list_t b) __attribute__((alias("my_vsnprintf"))); #if 0 EXPORT int my_vasprintf(x64emu_t* emu, void* strp, void* fmt, void* b, va_list V) { #ifndef NOALIGN // need to align on arm myStackAlign((const char*)fmt, (uint32_t*)b, emu->scratch); PREPARE_VALIST; void* f = vasprintf; int r = ((iFppp_t)f)(strp, fmt, VARARGS); return r; #else void* f = vasprintf; int r = ((iFppp_t)f)(strp, fmt, (uint32_t*)b); return r; #endif } #endif EXPORT int my___vasprintf_chk(x64emu_t* emu, void* buff, int flags, void* fmt, x64_va_list_t b) { (void)emu; (void)flags; #ifdef CONVERT_VALIST CONVERT_VALIST(b); #else myStackAlignValist(emu, (const char*)fmt, emu->scratch, b); PREPARE_VALIST; #endif int r = vasprintf(buff, fmt, VARARGS); return r; } EXPORT int my___asprintf_chk(x64emu_t* emu, void* result_ptr, int flags, void* fmt, void* b) { myStackAlign(emu, (const char*)fmt, b, emu->scratch, R_EAX, 3); PREPARE_VALIST; return vasprintf((char**)result_ptr, (char*)fmt, VARARGS); } EXPORT int my_vswprintf(x64emu_t* emu, void* buff, size_t s, void * fmt, x64_va_list_t b) { (void)emu; #ifdef CONVERT_VALIST CONVERT_VALIST(b); #else myStackAlignWValist(emu, (const char*)fmt, emu->scratch, b); PREPARE_VALIST; #endif int r = vswprintf(buff, s, fmt, VARARGS); return r; } EXPORT int my___vswprintf(x64emu_t* emu, void* buff, size_t s, void * fmt, x64_va_list_t b) __attribute__((alias("my_vswprintf"))); EXPORT int my___vswprintf_chk(x64emu_t* emu, void* buff, size_t s, void * fmt, x64_va_list_t b) __attribute__((alias("my_vswprintf"))); EXPORT int my_swscanf(x64emu_t* emu, void* stream, void* fmt, uint64_t* b) { myStackAlignScanfW(emu, (const char*)fmt, b, emu->scratch, 2); PREPARE_VALIST; return vswscanf(stream, fmt, VARARGS); } #if 0 EXPORT void my_verr(x64emu_t* emu, int eval, void* fmt, void* b) { #ifndef NOALIGN myStackAlignW((const char*)fmt, (uint32_t*)b, emu->scratch); PREPARE_VALIST; void* f = verr; ((vFipp_t)f)(eval, fmt, VARARGS); #else void* f = verr; ((vFipp_t)f)(eval, fmt, (uint32_t*)b); #endif } EXPORT void my_vwarn(x64emu_t* emu, void* fmt, void* b) { #ifndef NOALIGN myStackAlignW((const char*)fmt, (uint32_t*)b, emu->scratch); PREPARE_VALIST; void* f = vwarn; ((vFpp_t)f)(fmt, VARARGS); #else void* f = vwarn; ((vFpp_t)f)(fmt, (uint32_t*)b); #endif } #endif EXPORT void my_err(x64emu_t *emu, int eval, void* fmt, void* b) { myStackAlign(emu, (const char*)fmt, b, emu->scratch, R_EAX, 2); PREPARE_VALIST; verr(eval, (const char*)fmt, VARARGS); } EXPORT void my_errx(x64emu_t *emu, int eval, void* fmt, void* b) { myStackAlign(emu, (const char*)fmt, b, emu->scratch, R_EAX, 2); PREPARE_VALIST; verrx(eval, (const char*)fmt, VARARGS); } EXPORT void my_warn(x64emu_t *emu, void* fmt, void* b) { myStackAlign(emu, (const char*)fmt, b, emu->scratch, R_EAX, 1); PREPARE_VALIST; vwarn((const char*)fmt, VARARGS); } EXPORT void my_warnx(x64emu_t *emu, void* fmt, void* b) { myStackAlign(emu, (const char*)fmt, b, emu->scratch, R_EAX, 1); PREPARE_VALIST; vwarnx((const char*)fmt, VARARGS); } EXPORT void my_syslog(x64emu_t* emu, int priority, const char* fmt, uint64_t* b) { myStackAlign(emu, fmt, b, emu->scratch, R_EAX, 2); PREPARE_VALIST; return vsyslog(priority, fmt, VARARGS); } EXPORT void my___syslog_chk(x64emu_t* emu, int priority, int flags, const char* fmt, uint64_t* b) { (void)flags; myStackAlign(emu, fmt, b, emu->scratch, R_EAX, 3); PREPARE_VALIST; return vsyslog(priority, fmt, VARARGS); } EXPORT void my_vsyslog(x64emu_t* emu, int priority, const char* fmt, x64_va_list_t b) { (void)emu; #ifdef CONVERT_VALIST CONVERT_VALIST(b); #else myStackAlignValist(emu, (const char*)fmt, emu->scratch, b); PREPARE_VALIST; #endif return vsyslog(priority, fmt, VARARGS); } EXPORT void my___vsyslog_chk(x64emu_t* emu, int priority, int flag, const char* fmt, x64_va_list_t b) { (void)emu; #ifdef CONVERT_VALIST CONVERT_VALIST(b); #else myStackAlignValist(emu, (const char*)fmt, emu->scratch, b); PREPARE_VALIST; #endif return vsyslog(priority, fmt, VARARGS); } EXPORT int my___swprintf_chk(x64emu_t* emu, void* s, size_t n, int32_t flag, size_t slen, void* fmt, uint64_t* b) { (void)flag; (void)slen; myStackAlignW(emu, (const char*)fmt, b, emu->scratch, R_EAX, 5); PREPARE_VALIST; return vswprintf(s, n, (const wchar_t*)fmt, VARARGS); } EXPORT int my_swprintf(x64emu_t* emu, void* s, size_t n, void* fmt, uint64_t* b) { myStackAlignW(emu, (const char*)fmt, b, emu->scratch, R_EAX, 3); PREPARE_VALIST; return vswprintf(s, n, (const wchar_t*)fmt, VARARGS); } EXPORT void my__ITM_addUserCommitAction(x64emu_t* emu, void* cb, uint32_t b, void* c) { // disabled for now... Are all this _ITM_ stuff really mendatory? #if 0 // quick and dirty... Should store the callback to be removed later.... libc_my_t *my = (libc_my_t *)emu->context->libclib->priv.w.p2; x64emu_t *cbemu = AddCallback(emu, (uintptr_t)cb, 1, c, NULL, NULL, NULL); my->_ITM_addUserCommitAction(libc1ArgCallback, b, cbemu); // should keep track of cbemu to remove at some point... #else (void)emu; (void)cb; (void)b; (void)c; printf("warning _ITM_addUserCommitAction called\n"); #endif } EXPORT void my__ITM_registerTMCloneTable(x64emu_t* emu, void* p, uint32_t s) { (void)emu; (void)p; (void)s; } EXPORT void my__ITM_deregisterTMCloneTable(x64emu_t* emu, void* p) { (void)emu; (void)p; } EXPORT int my___fxstat(x64emu_t *emu, int vers, int fd, void* buf) { (void)emu; (void)vers; struct stat64 st; int r = fstat64(fd, &st); UnalignStat64(&st, buf); return r; } EXPORT int my___fxstat64(x64emu_t *emu, int vers, int fd, void* buf) { (void)emu; (void)vers; struct stat64 st; int r = fstat64(fd, &st); //int r = syscall(__NR_stat64, fd, &st); UnalignStat64(&st, buf); return r; } EXPORT int my___xstat(x64emu_t* emu, int v, void* path, void* buf) { (void)emu; (void)v; struct stat64 st; int r = stat64((const char*)path, &st); UnalignStat64(&st, buf); return r; } EXPORT int my___xstat64(x64emu_t* emu, int v, void* path, void* buf) { (void)emu; (void)v; struct stat64 st; int r = stat64((const char*)path, &st); UnalignStat64(&st, buf); return r; } EXPORT int my___lxstat(x64emu_t* emu, int v, void* name, void* buf) { (void)emu; (void)v; struct stat64 st; int r = lstat64((const char*)name, &st); UnalignStat64(&st, buf); return r; } EXPORT int my___lxstat64(x64emu_t* emu, int v, void* name, void* buf) { (void)emu; (void)v; struct stat64 st; int r = lstat64((const char*)name, &st); UnalignStat64(&st, buf); return r; } EXPORT int my___fxstatat(x64emu_t* emu, int v, int d, void* path, void* buf, int flags) { (void)emu; (void)v; struct stat64 st; int r = fstatat64(d, path, &st, flags); UnalignStat64(&st, buf); return r; } EXPORT int my___fxstatat64(x64emu_t* emu, int v, int d, void* path, void* buf, int flags) { (void)emu; (void)v; struct stat64 st; int r = fstatat64(d, path, &st, flags); UnalignStat64(&st, buf); return r; } EXPORT int my_stat(x64emu_t *emu, void* filename, void* buf) { (void)emu; struct stat64 st; int r = stat(filename, (struct stat*)&st); UnalignStat64(&st, buf); return r; } EXPORT int my_lstat(x64emu_t *emu, void* filename, void* buf) { (void)emu; struct stat64 st; int r = lstat(filename, (struct stat*)&st); UnalignStat64(&st, buf); return r; } EXPORT int my_fstat(x64emu_t *emu, int fd, void* buf) { (void)emu; struct stat64 st; int r = fstat(fd, (struct stat*)&st); UnalignStat64(&st, buf); return r; } EXPORT int my_fstatat(x64emu_t *emu, int fd, const char* path, void* buf, int flags) { (void)emu; struct stat64 st; int r = fstatat(fd, path, (struct stat*)&st, flags); UnalignStat64(&st, buf); return r; } EXPORT int my__IO_file_stat(x64emu_t* emu, void* f, void* buf) { struct stat64 st; int r = my->_IO_file_stat(f, &st); UnalignStat64(&st, buf); return r; } #if 0 EXPORT int my_fstatfs64(int fd, void* buf) { struct statfs64 st; int r = fstatfs64(fd, &st); UnalignStatFS64(&st, buf); return r; } EXPORT int my_statfs64(const char* path, void* buf) { struct statfs64 st; int r = statfs64(path, &st); UnalignStatFS64(&st, buf); return r; } #endif typedef struct compare_r_s { x64emu_t* emu; uintptr_t f; void* data; int r; } compare_r_t; static int my_compare_r_cb(void* a, void* b, compare_r_t* arg) { return (int)RunFunctionWithEmu(arg->emu, 0, arg->f, 2+arg->r, a, b, arg->data); } EXPORT void my_qsort(x64emu_t* emu, void* base, size_t nmemb, size_t size, void* fnc) { compare_r_t args; args.emu = emu; args.f = (uintptr_t)fnc; args.r = 0; args.data = NULL; qsort_r(base, nmemb, size, (__compar_d_fn_t)my_compare_r_cb, &args); } EXPORT void my_qsort_r(x64emu_t* emu, void* base, size_t nmemb, size_t size, void* fnc, void* data) { compare_r_t args; args.emu = emu; args.f = (uintptr_t)fnc; args.r = 1; args.data = data; qsort_r(base, nmemb, size, (__compar_d_fn_t)my_compare_r_cb, &args); } EXPORT void* my_bsearch(x64emu_t* emu, void* key, void* base, size_t nmemb, size_t size, void* fnc) { (void)emu; return bsearch(key, base, nmemb, size, findcompareFct(fnc)); } EXPORT void* my_lsearch(x64emu_t* emu, void* key, void* base, size_t* nmemb, size_t size, void* fnc) { (void)emu; return lsearch(key, base, nmemb, size, findcompareFct(fnc)); } EXPORT void* my_tsearch(x64emu_t* emu, void* key, void* root, void* fnc) { (void)emu; return tsearch(key, root, findcompareFct(fnc)); } EXPORT void my_tdestroy(x64emu_t* emu, void* root, void* fnc) { (void)emu; return tdestroy(root, findfreeFct(fnc)); } EXPORT void* my_lfind(x64emu_t* emu, void* key, void* base, size_t* nmemb, size_t size, void* fnc) { (void)emu; return lfind(key, base, nmemb, size, findcompareFct(fnc)); } EXPORT void* my_fts_open(x64emu_t* emu, void* path, int options, void* c) { (void)emu; return fts_open(path, options, findcompareFct(c)); } #if 0 struct i386_dirent { uint32_t d_ino; int32_t d_off; uint16_t d_reclen; uint8_t d_type; char d_name[256]; }; EXPORT void* my_readdir(x64emu_t* emu, void* dirp) { if (fix_64bit_inodes) { struct dirent64 *dp64 = readdir64((DIR *)dirp); if (!dp64) return NULL; uint32_t ino32 = dp64->d_ino ^ (dp64->d_ino >> 32); int32_t off32 = dp64->d_off; struct i386_dirent *dp32 = (struct i386_dirent *)&(dp64->d_off); dp32->d_ino = ino32; dp32->d_off = off32; dp32->d_reclen -= 8; return dp32; } else { static pFp_t f = NULL; if(!f) { library_t* lib = my_lib; if(!lib) return NULL; f = (pFp_t)dlsym(lib->priv.w.lib, "readdir"); } return f(dirp); } } EXPORT int32_t my_readdir_r(x64emu_t* emu, void* dirp, void* entry, void** result) { struct dirent64 d64, *dp64; if (fix_64bit_inodes && (sizeof(d64.d_name) > 1)) { static iFppp_t f = NULL; if(!f) { library_t* lib = my_lib; if(!lib) { *result = NULL; return 0; } f = (iFppp_t)dlsym(lib->priv.w.lib, "readdir64_r"); } int r = f(dirp, &d64, &dp64); if (r || !dp64 || !entry) { *result = NULL; return r; } struct i386_dirent *dp32 = (struct i386_dirent *)entry; int namelen = dp64->d_reclen - offsetof(struct dirent64, d_name); if (namelen > sizeof(dp32->d_name)) { *result = NULL; return ENAMETOOLONG; } dp32->d_ino = dp64->d_ino ^ (dp64->d_ino >> 32); dp32->d_off = dp64->d_off; dp32->d_reclen = namelen + offsetof(struct i386_dirent, d_name); dp32->d_type = dp64->d_type; memcpy(dp32->d_name, dp64->d_name, namelen); *result = dp32; return 0; } else { static iFppp_t f = NULL; if(!f) { library_t* lib = my_lib; if(!lib) { *result = NULL; return 0; } f = (iFppp_t)dlsym(lib->priv.w.lib, "readdir_r"); } return f(dirp, entry, result); } } #endif static int isProcSelf(const char *path, const char* w) { if(strncmp(path, "/proc/", 6)==0) { char tmp[64]; // check if self .... sprintf(tmp, "/proc/self/%s", w); if(strcmp((const char*)path, tmp)==0) return 1; // check if self PID .... pid_t pid = getpid(); sprintf(tmp, "/proc/%d/%s", pid, w); if(strcmp((const char*)path, tmp)==0) return 1; } return 0; } EXPORT ssize_t my_readlink(x64emu_t* emu, void* path, void* buf, size_t sz) { if(isProcSelf((const char*)path, "exe")) { // special case for self... return strlen(strncpy((char*)buf, emu->context->fullpath, sz)); } return readlink((const char*)path, (char*)buf, sz); } static int nCPU = 0; static double bogoMips = 100.; void grabNCpu() { nCPU = 1; // default number of CPU to 1 FILE *f = fopen("/proc/cpuinfo", "r"); size_t dummy; if(f) { nCPU = 0; size_t len = 0; char* line = NULL; while ((dummy = getline(&line, &len, f)) != -1) { if(!strncmp(line, "processor\t", strlen("processor\t"))) ++nCPU; if(!nCPU && !strncmp(line, "BogoMIPS\t", strlen("BogoMIPS\t"))) { // grab 1st BogoMIPS float tmp; if(sscanf(line, "BogoMIPS\t: %g", &tmp)==1) bogoMips = tmp; } } if(line) free(line); fclose(f); if(!nCPU) nCPU=1; } } int getNCpu() { if(!nCPU) grabNCpu(); return nCPU; } #ifndef NOALIGN void CreateCPUInfoFile(int fd) { size_t dummy; char buff[600]; double freq = 600.0; // default to 600 MHz // try to get actual ARM max speed: FILE *f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", "r"); if(f) { int r; if(1==fscanf(f, "%d", &r)) freq = r/1000.; fclose(f); } int n = getNCpu(); // generate fake CPUINFO int gigahertz=(freq>=1000.); #define P \ dummy = write(fd, buff, strlen(buff)) for (int i=0; icontext->fullpath, strlen(emu->context->fullpath)+1); for (int i=1; icontext->argc; ++i) dummy = write(tmp, emu->context->argv[i], strlen(emu->context->argv[i])+1); lseek(tmp, 0, SEEK_SET); #else int tmp = shm_open(TMP_CMDLINE, O_RDWR | O_CREAT, S_IRWXU); if(tmp<0) return open(pathname, flags, mode); shm_unlink(TMP_CMDLINE); // remove the shm file, but it will still exist because it's currently in use int dummy = write(tmp, emu->context->fullpath, strlen(emu->context->fullpath)+1); (void)dummy; for (int i=1; icontext->argc; ++i) dummy = write(tmp, emu->context->argv[i], strlen(emu->context->argv[i])+1); lseek(tmp, 0, SEEK_SET); #endif return tmp; } if(isProcSelf((const char*)pathname, "exe")) { return open(emu->context->fullpath, flags, mode); } #ifndef NOALIGN if(strcmp((const char*)pathname, "/proc/cpuinfo")==0) { // special case for cpuinfo int tmp = shm_open(TMP_CPUINFO, O_RDWR | O_CREAT, S_IRWXU); if(tmp<0) return open(pathname, flags, mode); // error fallback shm_unlink(TMP_CPUINFO); // remove the shm file, but it will still exist because it's currently in use CreateCPUInfoFile(tmp); lseek(tmp, 0, SEEK_SET); return tmp; } #endif int ret = open(pathname, flags, mode); return ret; } EXPORT int32_t my___open(x64emu_t* emu, void* pathname, int32_t flags, uint32_t mode) __attribute__((alias("my_open"))); //#ifdef DYNAREC //static int hasDBFromAddress(uintptr_t addr) //{ // int idx = (addr>>DYNAMAP_SHIFT); // return getDB(idx)?1:0; //} //#endif //EXPORT int32_t my_read(int fd, void* buf, uint32_t count) //{ // int ret = read(fd, buf, count); //#ifdef DYNAREC // if(ret!=count && ret>0) { // // continue reading... // void* p = buf+ret; // if(hasDBFromAddress((uintptr_t)p)) { // // allow writing the whole block (this happens with HalfLife, libMiles load code directly from .mix and other file like that) // unprotectDB((uintptr_t)p, count-ret); // int l; // do { // l = read(fd, p, count-ret); // if(l>0) { // p+=l; ret+=l; // } // } while(l>0); // } // } //#endif // return ret; //} EXPORT int32_t my_open64(x64emu_t* emu, void* pathname, int32_t flags, uint32_t mode) { if(isProcSelf((const char*)pathname, "cmdline")) { // special case for self command line... #if 0 char tmpcmdline[200] = {0}; char tmpbuff[100] = {0}; sprintf(tmpbuff, "%s/cmdlineXXXXXX", getenv("TMP")?getenv("TMP"):"."); int tmp = mkstemp64(tmpbuff); int dummy; if(tmp<0) return open64(pathname, flags, mode); dummy = write(tmp, emu->context->fullpath, strlen(emu->context->fullpath)+1); for (int i=1; icontext->argc; ++i) dummy = write(tmp, emu->context->argv[i], strlen(emu->context->argv[i])+1); lseek64(tmp, 0, SEEK_SET); #else int tmp = shm_open(TMP_CMDLINE, O_RDWR | O_CREAT, S_IRWXU); if(tmp<0) return open64(pathname, flags, mode); shm_unlink(TMP_CMDLINE); // remove the shm file, but it will still exist because it's currently in use int dummy = write(tmp, emu->context->fullpath, strlen(emu->context->fullpath)+1); (void)dummy; for (int i=1; icontext->argc; ++i) dummy = write(tmp, emu->context->argv[i], strlen(emu->context->argv[i])+1); lseek(tmp, 0, SEEK_SET); #endif return tmp; } if(isProcSelf((const char*)pathname, "exe")) { return open64(emu->context->fullpath, flags, mode); } #ifndef NOALIGN if(strcmp((const char*)pathname, "/proc/cpuinfo")==0) { // special case for cpuinfo int tmp = shm_open(TMP_CPUINFO, O_RDWR | O_CREAT, S_IRWXU); if(tmp<0) return open64(pathname, flags, mode); // error fallback shm_unlink(TMP_CPUINFO); // remove the shm file, but it will still exist because it's currently in use CreateCPUInfoFile(tmp); lseek(tmp, 0, SEEK_SET); return tmp; } #endif return open64(pathname, flags, mode); } EXPORT FILE* my_fopen(x64emu_t* emu, const char* path, const char* mode) { if(isProcSelf(path, "maps")) { // special case for self memory map int tmp = shm_open(TMP_MEMMAP, O_RDWR | O_CREAT, S_IRWXU); if(tmp<0) return fopen(path, mode); // error fallback shm_unlink(TMP_MEMMAP); // remove the shm file, but it will still exist because it's currently in use CreateMemorymapFile(emu->context, tmp); lseek(tmp, 0, SEEK_SET); return fdopen(tmp, mode); } #ifndef NOALIGN if(strcmp(path, "/proc/cpuinfo")==0) { // special case for cpuinfo int tmp = shm_open(TMP_CPUINFO, O_RDWR | O_CREAT, S_IRWXU); if(tmp<0) return fopen(path, mode); // error fallback shm_unlink(TMP_CPUINFO); // remove the shm file, but it will still exist because it's currently in use CreateCPUInfoFile(tmp); lseek(tmp, 0, SEEK_SET); return fdopen(tmp, mode); } #endif if(isProcSelf(path, "exe")) { return fopen(emu->context->fullpath, mode); } return fopen(path, mode); } EXPORT FILE* my_fopen64(x64emu_t* emu, const char* path, const char* mode) { if(isProcSelf(path, "maps")) { // special case for self memory map int tmp = shm_open(TMP_MEMMAP, O_RDWR | O_CREAT, S_IRWXU); if(tmp<0) return fopen64(path, mode); // error fallback shm_unlink(TMP_MEMMAP); // remove the shm file, but it will still exist because it's currently in use CreateMemorymapFile(emu->context, tmp); lseek(tmp, 0, SEEK_SET); return fdopen(tmp, mode); } #ifndef NOALIGN if(strcmp(path, "/proc/cpuinfo")==0) { // special case for cpuinfo int tmp = shm_open(TMP_CPUINFO, O_RDWR | O_CREAT, S_IRWXU); if(tmp<0) return fopen64(path, mode); // error fallback shm_unlink(TMP_CPUINFO); // remove the shm file, but it will still exist because it's currently in use CreateCPUInfoFile(tmp); lseek(tmp, 0, SEEK_SET); return fdopen(tmp, mode); } #endif if(isProcSelf(path, "exe")) { return fopen64(emu->context->fullpath, mode); } return fopen64(path, mode); } #if 0 EXPORT int32_t my_ftw(x64emu_t* emu, void* pathname, void* B, int32_t nopenfd) { static iFppi_t f = NULL; if(!f) { library_t* lib = my_lib; if(!lib) return 0; f = (iFppi_t)dlsym(lib->priv.w.lib, "ftw"); } return f(pathname, findftwFct(B), nopenfd); } EXPORT int32_t my_nftw(x64emu_t* emu, void* pathname, void* B, int32_t nopenfd, int32_t flags) { static iFppii_t f = NULL; if(!f) { library_t* lib = my_lib; if(!lib) return 0; f = (iFppii_t)dlsym(lib->priv.w.lib, "nftw"); } return f(pathname, findnftwFct(B), nopenfd, flags); } EXPORT void* my_ldiv(x64emu_t* emu, void* p, int32_t num, int32_t den) { *((ldiv_t*)p) = ldiv(num, den); return p; } #endif #ifndef NOALIGN EXPORT int32_t my_epoll_ctl(x64emu_t* emu, int32_t epfd, int32_t op, int32_t fd, void* event) { struct epoll_event _event[1] = {0}; if(event && (op!=EPOLL_CTL_DEL)) AlignEpollEvent(_event, event, 1); return epoll_ctl(epfd, op, fd, event?_event:event); } EXPORT int32_t my_epoll_wait(x64emu_t* emu, int32_t epfd, void* events, int32_t maxevents, int32_t timeout) { struct epoll_event _events[maxevents]; //AlignEpollEvent(_events, events, maxevents); int32_t ret = epoll_wait(epfd, events?_events:NULL, maxevents, timeout); if(ret>0) UnalignEpollEvent(events, _events, ret); return ret; } EXPORT int32_t my_epoll_pwait(x64emu_t* emu, int32_t epfd, void* events, int32_t maxevents, int32_t timeout, const sigset_t *sigmask) { struct epoll_event _events[maxevents]; //AlignEpollEvent(_events, events, maxevents); int32_t ret = epoll_pwait(epfd, events?_events:NULL, maxevents, timeout, sigmask); if(ret>0) UnalignEpollEvent(events, _events, ret); return ret; } #endif EXPORT int32_t my_glob64(x64emu_t *emu, void* pat, int32_t flags, void* errfnc, void* pglob) { (void)emu; return glob64(pat, flags, findgloberrFct(errfnc), pglob); } EXPORT int32_t my_glob(x64emu_t *emu, void* pat, int32_t flags, void* errfnc, void* pglob) __attribute__((alias("my_glob64"))); EXPORT int my_scandir64(x64emu_t *emu, void* dir, void* namelist, void* sel, void* comp) { (void)emu; return scandir64(dir, namelist, findfilter64Fct(sel), findcompare64Fct(comp)); } EXPORT int my_scandir(x64emu_t *emu, void* dir, void* namelist, void* sel, void* comp) __attribute__((alias("my_scandir64"))); EXPORT int my_scandirat(x64emu_t *emu, int dirfd, void* dirp, void* namelist, void* sel, void* comp) { (void)emu; return scandirat(dirfd, dirp, namelist, findfilter64Fct(sel), findcompare64Fct(comp)); } EXPORT int my_ftw64(x64emu_t* emu, void* filename, void* func, int descriptors) { (void)emu; return ftw64(filename, findftw64Fct(func), descriptors); } EXPORT int my_ftw(x64emu_t* emu, void* filename, void* func, int descriptors) __attribute__((alias("my_ftw64"))); EXPORT int32_t my_nftw64(x64emu_t* emu, void* pathname, void* B, int32_t nopenfd, int32_t flags) { (void)emu; return nftw64(pathname, findnftw64Fct(B), nopenfd, flags); } EXPORT int32_t my_execv(x64emu_t* emu, const char* path, char* const argv[]) { int self = isProcSelf(path, "exe"); int x64 = FileIsX64ELF(path); int x86 = my_context->box86path?FileIsX86ELF(path):0; printf_log(LOG_DEBUG, "execv(\"%s\", %p) is x64=%d x86=%d\n", path, argv, x64, x86); #if 1 if (x64 || x86 || self) { int skip_first = 0; if(strlen(path)>=strlen("wine64-preloader") && strcmp(path+strlen(path)-strlen("wine64-preloader"), "wine64-preloader")==0) skip_first++; // count argv... int n=skip_first; while(argv[n]) ++n; const char** newargv = (const char**)calloc(n+2, sizeof(char*)); newargv[0] = x86?emu->context->box86path:emu->context->box64path; memcpy(newargv+1, argv+skip_first, sizeof(char*)*(n+1)); if(self) newargv[1] = emu->context->fullpath; printf_log(LOG_DEBUG, " => execv(\"%s\", %p [\"%s\", \"%s\", \"%s\"...:%d])\n", newargv[0], newargv, newargv[0], n?newargv[1]:"", (n>1)?newargv[2]:"",n); int ret = execv(newargv[0], (char* const*)newargv); free(newargv); return ret; } #endif return execv(path, argv); } EXPORT int32_t my_execve(x64emu_t* emu, const char* path, char* const argv[], char* const envp[]) { int self = isProcSelf(path, "exe"); int x64 = FileIsX64ELF(path); int x86 = my_context->box86path?FileIsX86ELF(path):0; // hack to update the environ var if needed if(envp == my_context->envv && environ) { envp = environ; } printf_log(LOG_DEBUG, "execve(\"%s\", %p, %p) is x64=%d x86=%d\n", path, argv, envp, x64, x86); #if 1 if (x64 || x86 || self) { int skip_first = 0; if(strlen(path)>=strlen("wine64-preloader") && strcmp(path+strlen(path)-strlen("wine64-preloader"), "wine64-preloader")==0) skip_first++; // count argv... int n=skip_first; while(argv[n]) ++n; const char** newargv = (const char**)calloc(n+2, sizeof(char*)); newargv[0] = x86?emu->context->box86path:emu->context->box64path; memcpy(newargv+1, argv+skip_first, sizeof(char*)*(n+1)); if(self) newargv[1] = emu->context->fullpath; printf_log(LOG_DEBUG, " => execve(\"%s\", %p [\"%s\", \"%s\", \"%s\"...:%d], %p)\n", newargv[0], newargv, newargv[0], n?newargv[1]:"", (n>1)?newargv[2]:"",n, envp); int ret = execve(newargv[0], (char* const*)newargv, envp); free(newargv); return ret; } #endif if(!strcmp(path + strlen(path) - strlen("/uname"), "/uname") && argv[1] && (!strcmp(argv[1], "-m") || !strcmp(argv[1], "-p") || !strcmp(argv[1], "-i")) && !argv[2]) { // uname -m is redirected to box64 -m path = my_context->box64path; char *argv2[3] = { my_context->box64path, argv[1], NULL }; return execve(path, argv2, envp); } return execve(path, argv, envp); } // execvp should use PATH to search for the program first EXPORT int32_t my_execvp(x64emu_t* emu, const char* path, char* const argv[]) { // need to use BOX64_PATH / PATH here... char* fullpath = ResolveFile(path, &my_context->box64_path); // use fullpath... int self = isProcSelf(fullpath, "exe"); int x64 = FileIsX64ELF(fullpath); int x86 = my_context->box86path?FileIsX86ELF(path):0; printf_log(LOG_DEBUG, "execvp(\"%s\", %p), IsX86=%d / fullpath=\"%s\"\n", path, argv, x64, fullpath); free(fullpath); if (x64 || x86 || self) { // count argv... int i=0; while(argv[i]) ++i; char** newargv = (char**)calloc(i+2, sizeof(char*)); newargv[0] = x86?emu->context->box86path:emu->context->box64path; for (int j=0; jcontext->fullpath; printf_log(LOG_DEBUG, " => execvp(\"%s\", %p [\"%s\", \"%s\"...:%d])\n", newargv[0], newargv, newargv[1], i?newargv[2]:"", i); int ret = execvp(newargv[0], newargv); free(newargv); return ret; } if((!strcmp(path + strlen(path) - strlen("/uname"), "/uname") || !strcmp(path, "uname")) && argv[1] && (!strcmp(argv[1], "-m") || !strcmp(argv[1], "-p") || !strcmp(argv[1], "-i")) && !argv[2]) { // uname -m is redirected to box64 -m path = my_context->box64path; char *argv2[3] = { my_context->box64path, argv[1], NULL }; return execvp(path, argv2); } // fullpath is gone, so the search will only be on PATH, not on BOX64_PATH (is that an issue?) return execvp(path, argv); } EXPORT int32_t my_execl(x64emu_t* emu, const char* path) { int self = isProcSelf(path, "exe"); int x64 = FileIsX64ELF(path); int x86 = my_context->box86path?FileIsX86ELF(path):0; printf_log(LOG_DEBUG, "execl(\"%s\", ...), IsX86=%d, self=%d\n", path, x64, self); // count argv... int i=0; while(getVargN(emu, i+1)) ++i; char** newargv = (char**)calloc(i+((x64 || self)?2:1), sizeof(char*)); int j=0; if ((x64 || x86 || self)) newargv[j++] = x86?emu->context->box86path:emu->context->box64path; for (int k=0; kcontext->fullpath; printf_log(LOG_DEBUG, " => execl(\"%s\", %p [\"%s\", \"%s\"...:%d])\n", newargv[0], newargv, newargv[1], i?newargv[2]:"", i); int ret = execv(newargv[0], newargv); free(newargv); return ret; } EXPORT int32_t my_execlp(x64emu_t* emu, const char* path) { // need to use BOX64_PATH / PATH here... char* fullpath = ResolveFile(path, &my_context->box64_path); // use fullpath... int self = isProcSelf(fullpath, "exe"); int x64 = FileIsX64ELF(fullpath); int x86 = my_context->box86path?FileIsX86ELF(path):0; printf_log(LOG_DEBUG, "execlp(\"%s\", ...), IsX86=%d / fullpath=\"%s\"\n", path, x64, fullpath); free(fullpath); // count argv... int i=0; while(getVargN(emu, i+1)) ++i; char** newargv = (char**)calloc(i+((x64 || self)?2:1), sizeof(char*)); int j=0; if ((x64 || x86 || self)) newargv[j++] = x86?emu->context->box86path:emu->context->box64path; for (int k=0; kcontext->fullpath; printf_log(LOG_DEBUG, " => execlp(\"%s\", %p [\"%s\", \"%s\"...:%d])\n", newargv[0], newargv, newargv[1], i?newargv[2]:"", i); int ret = execvp(newargv[0], newargv); free(newargv); return ret; } EXPORT int32_t my_posix_spawn(x64emu_t* emu, pid_t* pid, const char* fullpath, const posix_spawn_file_actions_t *actions, const posix_spawnattr_t* attrp, char* const argv[], char* const envp[]) { int self = isProcSelf(fullpath, "exe"); int x64 = FileIsX64ELF(fullpath); int x86 = my_context->box86path?FileIsX86ELF(fullpath):0; printf_log(/*LOG_DEBUG*/LOG_INFO, "posix_spawn(%p, \"%s\", %p, %p, %p, %p), IsX86=%d\n", pid, fullpath, actions, attrp, argv, envp, x64); if (x64 || x86 || self) { // count argv... int i=0; while(argv[i]) ++i; char** newargv = (char**)calloc(i+2, sizeof(char*)); newargv[0] = x86?emu->context->box86path:emu->context->box64path; for (int j=0; jcontext->fullpath; printf_log(/*LOG_DEBUG*/LOG_INFO, " => posix_spawn(%p, \"%s\", %p, %p, %p [\"%s\", \"%s\"...:%d], %p)\n", pid, newargv[0], actions, attrp, newargv, newargv[1], i?newargv[2]:"", i, envp); int ret = posix_spawn(pid, newargv[0], actions, attrp, newargv, envp); printf_log(/*LOG_DEBUG*/LOG_INFO, "posix_spawn returned %d\n", ret); //free(newargv); return ret; } // fullpath is gone, so the search will only be on PATH, not on BOX64_PATH (is that an issue?) return posix_spawn(pid, fullpath, actions, attrp, argv, envp); } // execvp should use PATH to search for the program first EXPORT int32_t my_posix_spawnp(x64emu_t* emu, pid_t* pid, const char* path, const posix_spawn_file_actions_t *actions, const posix_spawnattr_t* attrp, char* const argv[], char* const envp[]) { // need to use BOX64_PATH / PATH here... char* fullpath = ResolveFile(path, &my_context->box64_path); // use fullpath... int self = isProcSelf(fullpath, "exe"); int x64 = FileIsX64ELF(fullpath); int x86 = my_context->box86path?FileIsX86ELF(path):0; printf_log(/*LOG_DEBUG*/LOG_INFO, "posix_spawnp(%p, \"%s\", %p, %p, %p, %p), IsX86=%d / fullpath=\"%s\"\n", pid, path, actions, attrp, argv, envp, x64, fullpath); free(fullpath); if (x64 || x86 || self) { // count argv... int i=0; while(argv[i]) ++i; char** newargv = (char**)calloc(i+2, sizeof(char*)); newargv[0] = x86?emu->context->box86path:emu->context->box64path; for (int j=0; jcontext->fullpath; printf_log(/*LOG_DEBUG*/LOG_INFO, " => posix_spawnp(%p, \"%s\", %p, %p, %p [\"%s\", \"%s\"...:%d], %p)\n", pid, newargv[0], actions, attrp, newargv, newargv[1], i?newargv[2]:"", i, envp); int ret = posix_spawnp(pid, newargv[0], actions, attrp, newargv, envp); printf_log(/*LOG_DEBUG*/LOG_INFO, "posix_spawnp returned %d\n", ret); //free(newargv); return ret; } // fullpath is gone, so the search will only be on PATH, not on BOX64_PATH (is that an issue?) return posix_spawnp(pid, path, actions, attrp, argv, envp); } EXPORT void my__Jv_RegisterClasses() {} EXPORT int32_t my___cxa_thread_atexit_impl(x64emu_t* emu, void* dtor, void* obj, void* dso) { (void)emu; printf_log(LOG_INFO, "Warning, call to __cxa_thread_atexit_impl(%p, %p, %p) ignored\n", dtor, obj, dso); return 0; } EXPORT int32_t my___register_atfork(x64emu_t *emu, void* prepare, void* parent, void* child, void* handle) { (void)emu; // this is partly incorrect, because the emulated funcionts should be executed by actual fork and not by my_atfork... if(my_context->atfork_sz==my_context->atfork_cap) { my_context->atfork_cap += 4; my_context->atforks = (atfork_fnc_t*)realloc(my_context->atforks, my_context->atfork_cap*sizeof(atfork_fnc_t)); } my_context->atforks[my_context->atfork_sz].prepare = (uintptr_t)prepare; my_context->atforks[my_context->atfork_sz].parent = (uintptr_t)parent; my_context->atforks[my_context->atfork_sz].child = (uintptr_t)child; my_context->atforks[my_context->atfork_sz].handle = handle; return 0; } #if 0 EXPORT uint64_t my___umoddi3(uint64_t a, uint64_t b) { return a%b; } EXPORT uint64_t my___udivdi3(uint64_t a, uint64_t b) { return a/b; } EXPORT int64_t my___divdi3(int64_t a, int64_t b) { return a/b; } EXPORT int32_t my___poll_chk(void* a, uint32_t b, int c, int l) { return poll(a, b, c); // no check... } #endif EXPORT int32_t my_fcntl64(x64emu_t* emu, int32_t a, int32_t b, void* c) { (void)emu; if(b==F_SETFL) c = (void*)(uintptr_t)of_convert((intptr_t)c); #if 0 if(b==F_GETLK64 || b==F_SETLK64 || b==F_SETLKW64) { my_flock64_t fl; AlignFlock64(&fl, c); int ret = fcntl(a, b, &fl); UnalignFlock64(c, &fl); return ret; } #endif int ret = fcntl(a, b, c); if(b==F_GETFL && ret!=-1) ret = of_unconvert(ret); return ret; } EXPORT int32_t my_fcntl(x64emu_t* emu, int32_t a, int32_t b, void* c) { (void)emu; if(b==F_SETFL && (intptr_t)c==0xFFFFF7FF) { // special case for ~O_NONBLOCK... int flags = fcntl(a, F_GETFL); if(flags&O_NONBLOCK) { flags &= ~O_NONBLOCK; return fcntl(a, b, flags); } return 0; } if(b==F_SETFL) c = (void*)(uintptr_t)of_convert((intptr_t)c); #if 0 if(b==F_GETLK64 || b==F_SETLK64 || b==F_SETLKW64) { my_flock64_t fl; AlignFlock64(&fl, c); int ret = fcntl(a, b, &fl); UnalignFlock64(c, &fl); return ret; } #endif int ret = fcntl(a, b, c); if(b==F_GETFL && ret!=-1) ret = of_unconvert(ret); return ret; } EXPORT int32_t my___fcntl(x64emu_t* emu, int32_t a, int32_t b, void* c) __attribute__((alias("my_fcntl"))); #if 0 EXPORT int32_t my_preadv64(x64emu_t* emu, int32_t fd, void* v, int32_t c, int64_t o) { library_t* lib = my_lib; if(!lib) return 0; void* f = dlsym(lib->priv.w.lib, "preadv64"); if(f) return ((iFipiI_t)f)(fd, v, c, o); return syscall(__NR_preadv, fd, v, c,(uint32_t)(o&0xffffffff), (uint32_t)((o>>32)&0xffffffff)); } EXPORT int32_t my_pwritev64(x64emu_t* emu, int32_t fd, void* v, int32_t c, int64_t o) { library_t* lib = my_lib; if(!lib) return 0; void* f = dlsym(lib->priv.w.lib, "pwritev64"); if(f) return ((iFipiI_t)f)(fd, v, c, o); #ifdef __arm__ return syscall(__NR_pwritev, fd, v, c, 0, (uint32_t)(o&0xffffffff), (uint32_t)((o>>32)&0xffffffff)); // on arm, 64bits args needs to be on even/odd register, so need to put a 0 for aligment #else return syscall(__NR_pwritev, fd, v, c,(uint32_t)(o&0xffffffff), (uint32_t)((o>>32)&0xffffffff)); #endif } EXPORT int32_t my_accept4(x64emu_t* emu, int32_t fd, void* a, void* l, int32_t flags) { library_t* lib = my_lib; if(!lib) return 0; void* f = dlsym(lib->priv.w.lib, "accept4"); if(f) return ((iFippi_t)f)(fd, a, l, flags); if(!flags) return accept(fd, a, l); return syscall(__NR_accept4, fd, a, l, flags); } EXPORT int32_t my_fallocate64(int fd, int mode, int64_t offs, int64_t len) { iFiiII_t f = NULL; static int done = 0; if(!done) { library_t* lib = my_lib; f = (iFiiII_t)dlsym(lib->priv.w.lib, "fallocate64"); done = 1; } if(f) return f(fd, mode, offs, len); else return syscall(__NR_fallocate, fd, mode, (uint32_t)(offs&0xffffffff), (uint32_t)((offs>>32)&0xffffffff), (uint32_t)(len&0xffffffff), (uint32_t)((len>>32)&0xffffffff)); //return posix_fallocate64(fd, offs, len); } EXPORT struct __processor_model { unsigned int __cpu_vendor; unsigned int __cpu_type; unsigned int __cpu_subtype; unsigned int __cpu_features[1]; } my___cpu_model; #include "cpu_info.h" void InitCpuModel() { // some pseudo random cpu info... my___cpu_model.__cpu_vendor = VENDOR_INTEL; my___cpu_model.__cpu_type = INTEL_PENTIUM_M; my___cpu_model.__cpu_subtype = 0; // N/A my___cpu_model.__cpu_features[0] = (1<stack; // is this the end, or should I add stasz? } EXPORT void my___register_frame_info(void* a, void* b) { // nothing (void)a; (void)b; } EXPORT void* my___deregister_frame_info(void* a) { (void)a; return NULL; } EXPORT void* my____brk_addr = NULL; // longjmp / setjmp typedef struct jump_buff_x64_s { uint64_t save_rbx; uint64_t save_rbp; uint64_t save_r12; uint64_t save_r13; uint64_t save_r14; uint64_t save_r15; uint64_t save_rsp; uint64_t save_rip; } jump_buff_x64_t; typedef struct __jmp_buf_tag_s { jump_buff_x64_t __jmpbuf; int __mask_was_saved; __sigset_t __saved_mask; } __jmp_buf_tag_t; void EXPORT my_longjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p, int32_t __val) { jump_buff_x64_t *jpbuff = &((__jmp_buf_tag_t*)p)->__jmpbuf; //restore regs R_RBX = jpbuff->save_rbx; R_RBP = jpbuff->save_rbp; R_R12 = jpbuff->save_r12; R_R13 = jpbuff->save_r13; R_R14 = jpbuff->save_r14; R_R15 = jpbuff->save_r15; R_RSP = jpbuff->save_rsp; // jmp to saved location, plus restore val to rax R_RAX = __val; R_RIP = jpbuff->save_rip; if(((__jmp_buf_tag_t*)p)->__mask_was_saved) { sigprocmask(SIG_SETMASK, &((__jmp_buf_tag_t*)p)->__saved_mask, NULL); } if(emu->quitonlongjmp) { emu->longjmp = 1; emu->quit = 1; } } EXPORT int32_t my___sigsetjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p, int savesigs) { jump_buff_x64_t *jpbuff = &((__jmp_buf_tag_t*)p)->__jmpbuf; // save the buffer jpbuff->save_rbx = R_RBX; jpbuff->save_rbp = R_RBP; jpbuff->save_r12 = R_R12; jpbuff->save_r13 = R_R13; jpbuff->save_r14 = R_R14; jpbuff->save_r15 = R_R15; jpbuff->save_rsp = R_RSP+sizeof(uintptr_t); // include "return address" jpbuff->save_rip = *(uintptr_t*)(R_RSP); if(savesigs) { if(sigprocmask(SIG_SETMASK, NULL, &((__jmp_buf_tag_t*)p)->__saved_mask)) ((__jmp_buf_tag_t*)p)->__mask_was_saved = 0; else ((__jmp_buf_tag_t*)p)->__mask_was_saved = 1; } else ((__jmp_buf_tag_t*)p)->__mask_was_saved = 0; return 0; } EXPORT int32_t my__setjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p) { return my___sigsetjmp(emu, p, 0); } EXPORT int32_t my_setjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p) { return my___sigsetjmp(emu, p, 1); } EXPORT void my___explicit_bzero_chk(x64emu_t* emu, void* dst, uint32_t len, uint32_t dstlen) { (void)emu; (void)dstlen; memset(dst, 0, len); } EXPORT void* my_realpath(x64emu_t* emu, void* path, void* resolved_path) { if(isProcSelf(path, "exe")) { return realpath(emu->context->fullpath, resolved_path); } return realpath(path, resolved_path); } EXPORT int my_readlinkat(x64emu_t* emu, int fd, void* path, void* buf, size_t bufsize) { if(isProcSelf(path, "exe")) { strncpy(buf, emu->context->fullpath, bufsize); size_t l = strlen(emu->context->fullpath); return (l>bufsize)?bufsize:(l+1); } return readlinkat(fd, path, buf, bufsize); } EXPORT void* my_mmap64(x64emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, int64_t offset) { (void)emu; if(prot&PROT_WRITE) prot|=PROT_READ; // PROT_READ is implicit with PROT_WRITE on i386 if(box64_log ", addr, length, prot, flags, fd, offset);} #ifndef NOALIGN void* old_addr = addr; if(flags&0x40) { // 0x40 is MAP_32BIT, wich only exist on x86_64! //flags &= ~0x40; // let the flags in? addr = findBlockNearHint(addr, length); } else if (box64_wine) { if(!addr) addr = find47bitBlock(length); } #endif void* ret = mmap64(addr, length, prot, flags, fd, offset); #ifndef NOALIGN if((ret!=(void*)-1) && (flags&0x40) && (((uintptr_t)ret>0xffffffffLL) || (box64_wine && ((uintptr_t)ret&0xffff)))) { printf_log(LOG_DEBUG, "Warning, mmap on 32bits didn't worked, ask %p, got %p ", addr, ret); munmap(ret, length); loadProtectionFromMap(); // reload map, because something went wrong previously addr = findBlockNearHint(old_addr, length); // is this the best way? ret = mmap64(addr, length, prot, flags, fd, offset); printf_log(LOG_DEBUG, " tried again with %p, got %p\n", addr, ret); } else if((ret!=(void*)-1) && !(flags&MAP_FIXED) && (box64_wine) && (old_addr) && (addr!=ret) && (((uintptr_t)ret>0x7fffffffffffLL) || ((uintptr_t)ret&~0xffff))) { printf_log(LOG_DEBUG, "Warning, mmap on 47bits didn't worked, ask %p, got %p ", addr, ret); munmap(ret, length); loadProtectionFromMap(); // reload map, because something went wrong previously addr = find47bitBlockNearHint(old_addr, length); // is this the best way? ret = mmap64(addr, length, prot, flags, fd, offset); printf_log(LOG_DEBUG, " tried again with %p, got %p\n", addr, ret); } #endif if(box64_log", old_addr, old_size, new_size, flags, new_addr); void* ret = mremap(old_addr, old_size, new_size, flags, new_addr); dynarec_log(LOG_DEBUG, "%p\n", ret); if(ret==(void*)-1) return ret; // failed... uint32_t prot = getProtection((uintptr_t)old_addr)&~PROT_CUSTOM; if(ret==old_addr) { if(old_size && old_sizer, 3, cookie->cookie, buf, size); } static ssize_t my_cookie_write(void *p, const char *buf, size_t size) { my_cookie_t* cookie = (my_cookie_t*)p; return (ssize_t)RunFunction(my_context, cookie->w, 3, cookie->cookie, buf, size); } static int my_cookie_seek(void *p, off64_t *offset, int whence) { my_cookie_t* cookie = (my_cookie_t*)p; return RunFunction(my_context, cookie->s, 3, cookie->cookie, offset, whence); } static int my_cookie_close(void *p) { my_cookie_t* cookie = (my_cookie_t*)p; int ret = 0; if(cookie->c) ret = RunFunction(my_context, cookie->c, 1, cookie->cookie); free(cookie); return ret; } EXPORT void* my_fopencookie(x64emu_t* emu, void* cookie, void* mode, void* read, void* write, void* seek, void* close) { cookie_io_functions_t io_funcs = {read?my_cookie_read:NULL, write?my_cookie_write:NULL, seek?my_cookie_seek:NULL, my_cookie_close}; my_cookie_t *cb = (my_cookie_t*)calloc(1, sizeof(my_cookie_t)); cb->r = (uintptr_t)read; cb->w = (uintptr_t)write; cb->s = (uintptr_t)seek; cb->c = (uintptr_t)close; cb->cookie = cookie; return fopencookie(cb, mode, io_funcs); } EXPORT long my_prlimit64(void* pid, uint32_t res, void* new_rlim, void* old_rlim) { return syscall(__NR_prlimit64, pid, res, new_rlim, old_rlim); } EXPORT void* my_reallocarray(void* ptr, size_t nmemb, size_t size) { return realloc(ptr, nmemb*size); } #ifndef __OPEN_NEEDS_MODE # define __OPEN_NEEDS_MODE(oflag) \ (((oflag) & O_CREAT) != 0) // || ((oflag) & __O_TMPFILE) == __O_TMPFILE) #endif EXPORT int my___open_nocancel(x64emu_t* emu, void* file, int oflag, int* b) { int mode = 0; if (__OPEN_NEEDS_MODE (oflag)) mode = b[0]; return openat(AT_FDCWD, file, oflag, mode); } EXPORT int my___libc_alloca_cutoff(x64emu_t* emu, size_t size) { // not always implemented on old linux version... library_t* lib = my_lib; if(!lib) return 0; void* f = dlsym(lib->priv.w.lib, "__libc_alloca_cutoff"); if(f) return ((iFL_t)f)(size); // approximate version but it's better than nothing.... return (size<=(65536*4)); } // DL functions from wrappedlibdl.c void* my_dlopen(x64emu_t* emu, void *filename, int flag); int my_dlclose(x64emu_t* emu, void *handle); void* my_dlsym(x64emu_t* emu, void *handle, void *symbol); EXPORT int my___libc_dlclose(x64emu_t* emu, void* handle) { return my_dlclose(emu, handle); } EXPORT void* my___libc_dlopen_mode(x64emu_t* emu, void* name, int mode) { return my_dlopen(emu, name, mode); } EXPORT void* my___libc_dlsym(x64emu_t* emu, void* handle, void* name) { return my_dlsym(emu, handle, name); } // all obstack function defined in obstack.c file void obstackSetup(); EXPORT int my_nanosleep(const struct timespec *req, struct timespec *rem) { if(!req) return 0; // workaround for some strange calls return nanosleep(req, rem); } #endif EXPORT void* my_malloc(unsigned long size) { return calloc(1, size); } #if 0 #ifdef PANDORA #define RENAME_NOREPLACE (1 << 0) #define RENAME_EXCHANGE (1 << 1) #define RENAME_WHITEOUT (1 << 2) EXPORT int my_renameat2(int olddirfd, void* oldpath, int newdirfd, void* newpath, uint32_t flags) { // simulate that function, but if(flags&RENAME_NOREPLACE) { if(FileExist(newpath, -1)) { errno = EEXIST; return -1; } flags &= ~RENAME_NOREPLACE; } if(!flags) return renameat(olddirfd, oldpath, newdirfd, newpath); if(flags&RENAME_WHITEOUT) { errno = EINVAL; return -1; // not handling that } if((flags&RENAME_EXCHANGE) && (olddirfd==-1) && (newdirfd==-1)) { // cannot do atomically... char* tmp = (char*)malloc(strlen(oldpath)+10); // create a temp intermediary tmp = strcat(oldpath, ".tmp"); int ret = renameat(-1, oldpath, -1, tmp); if(ret==-1) return -1; ret = renameat(-1, newpath, -1, oldpath); if(ret==-1) return -1; ret = renameat(-1, tmp, -1, newpath); free(tmp); return ret; } return -1; // unknown flags } #endif #ifndef __NR_memfd_create #define MFD_CLOEXEC 0x0001U #define MFD_ALLOW_SEALING 0x0002U EXPORT int my_memfd_create(x64emu_t* emu, void* name, uint32_t flags) { // try to simulate that function uint32_t fl = O_RDWR | O_CREAT; if(flags&MFD_CLOEXEC) fl |= O_CLOEXEC; int tmp = shm_open(name, fl, S_IRWXU); if(tmp<0) return -1; shm_unlink(name); // remove the shm file, but it will still exist because it's currently in use return tmp; } #endif #ifndef GRND_RANDOM #define GRND_RANDOM 0x0002 #endif EXPORT int my_getentropy(x64emu_t* emu, void* buffer, size_t length) { library_t* lib = my_lib; if(!lib) return 0; void* f = dlsym(lib->priv.w.lib, "getentropy"); if(f) return ((iFpL_t)f)(buffer, length); // custom implementation if(length>256) { errno = EIO; return -1; } int ret = my_getrandom(emu, buffer, length, GRND_RANDOM); if(ret!=length) { errno = EIO; return -1; } return 0; } EXPORT void my_mcount(void* frompc, void* selfpc) { // stub doing nothing... return; } #endif union semun { int val; /* Value for SETVAL */ struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */ unsigned short *array; /* Array for GETALL, SETALL */ struct seminfo *__buf; /* Buffer for IPC_INFO (Linux-specific) */ }; #ifndef SEM_STAT_ANY #define SEM_STAT_ANY 20 #endif EXPORT int my_semctl(int semid, int semnum, int cmd, union semun b) { struct semid_ds semidds; void *backup = NULL; if ((cmd == IPC_STAT) || (cmd == IPC_SET) || (cmd == SEM_STAT) || (cmd == SEM_STAT_ANY)) { backup = b.buf; b.buf = &semidds; if (cmd == IPC_SET) { AlignSemidDs(&semidds, backup); } } int ret = semctl(semid, semnum, cmd, b); if ((cmd == IPC_STAT) || (cmd == IPC_SET) || (cmd == SEM_STAT) || (cmd == SEM_STAT_ANY)) { b.buf = backup; if (cmd == IPC_STAT) { UnalignSemidDs(backup, &semidds); } } return ret; } // Backtrace stuff #include "elfs/elfdwarf_private.h" EXPORT int my_backtrace(x64emu_t* emu, void** buffer, int size) { if (!size) return 0; dwarf_unwind_t *unwind = init_dwarf_unwind_registers(emu); int idx = 0; char success = 0; uintptr_t addr = *(uintptr_t*)R_RSP; buffer[0] = (void*)addr; while (++idx < size) { uintptr_t ret_addr = get_parent_registers(unwind, FindElfAddress(my_context, addr), addr, &success); if (ret_addr == (uintptr_t)GetExit()) { // TODO: do something to be able to get the function name buffer[idx] = (void*)ret_addr; success = 2; // See elfdwarf_private.c for the register mapping unwind->regs[6] = unwind->regs[7]; // mov rsp, rbp unwind->regs[7] = *(uint64_t*)unwind->regs[6]; // pop rbp unwind->regs[6] += 8; ret_addr = *(uint64_t*)unwind->regs[6]; // ret unwind->regs[6] += 8; if (++idx < size) buffer[idx] = (void*)ret_addr; } else if (!success) break; else buffer[idx] = (void*)ret_addr; addr = ret_addr; } free_dwarf_unwind_registers(&unwind); return idx; } EXPORT char** my_backtrace_symbols(x64emu_t* emu, uintptr_t* buffer, int size) { (void)emu; char** ret = (char**)calloc(1, size*sizeof(char*) + size*100); // capping each strings to 100 chars char* s = (char*)(ret+size); for (int i=0; i=start && (buffer[i]<(start+sz) || !sz)) { snprintf(s, 100, "%s(%s+%lx) [%p]", ElfName(hdr), symbname, buffer[i] - start, (void*)buffer[i]); } else if (hdr) { snprintf(s, 100, "%s+%lx [%p]", ElfName(hdr), buffer[i] - (uintptr_t)GetBaseAddress(hdr), (void*)buffer[i]); } else { snprintf(s, 100, "??? [%p]", (void*)buffer[i]); } ret[i] = s; s += 100; } return ret; } EXPORT void my_backtrace_symbols_fd(x64emu_t* emu, uintptr_t* buffer, int size, int fd) { (void)emu; char s[100]; for (int i=0; i=start && (buffer[i]<(start+sz) || !sz)) snprintf(s, 100, "%s+%ld [%p]\n", symbname, buffer[i] - start, (void*)buffer[i]); else snprintf(s, 100, "??? [%p]\n", (void*)buffer[i]); int dummy = write(fd, s, strlen(s)); (void)dummy; } } EXPORT int my_iopl(x64emu_t* emu, int level) { // Set I/O permission (so access IN/OUT opcodes) Default is 0. Can Set to 0..3 // set permission for all 65536 ports addresses // note ioperm can set individual permission /*static iFi_t real_iopl = NULL; static int searched = 0; if(!searched) { searched = 1; real_iopl = (iFi_t)dlsym(my_lib, "iopl"); } if(real_iopl) return real_iopl(level);*/ // For now, lets just return "unsupported" errno = ENOSYS; return -1; } EXPORT int my_stime(x64emu_t* emu, const time_t *t) { // TODO? errno = EPERM; return -1; } typedef struct clone_arg_s { x64emu_t* emu; uintptr_t fnc; void* args; int stack_clone_used; } clone_arg_t; static int clone_fn(void* p) { clone_arg_t* arg = (clone_arg_t*)p; x64emu_t *emu = arg->emu; thread_set_emu(emu); int ret = RunFunction(my_context, arg->fnc, 1, arg->args); FreeX64Emu(&emu); if(arg->stack_clone_used) my_context->stack_clone_used = 0; free(arg); return ret; } EXPORT int my_clone(x64emu_t* emu, void* fn, void* stack, int flags, void* args, void* parent, void* tls, void* child) { x64emu_t * newemu = NewX64Emu(emu->context, R_RIP, (uintptr_t)stack, 0, 0); SetupX64Emu(newemu); CloneEmu(newemu, emu); void* mystack = NULL; clone_arg_t* arg = (clone_arg_t*)calloc(1, sizeof(clone_arg_t)); if(my_context->stack_clone_used) { mystack = malloc(1024*1024); // stack for own process... memory leak, but no practical way to remove it } else { if(!my_context->stack_clone) my_context->stack_clone = malloc(1024*1024); mystack = my_context->stack_clone; my_context->stack_clone_used = 1; arg->stack_clone_used = 1; } arg->emu = newemu; arg->args = args; arg->fnc = (uintptr_t)fn; // x86_64 raw clone is long clone(unsigned long flags, void *stack, int *parent_tid, int *child_tid, unsigned long tls); int64_t ret = clone(clone_fn, (void*)((uintptr_t)mystack+1024*1024), flags, arg, parent, tls, child); return (uintptr_t)ret; } EXPORT char** my_environ = NULL; EXPORT char** my__environ = NULL; EXPORT char** my___environ = NULL; // all aliases EXPORT char* my___progname = NULL; EXPORT char* my___progname_full = NULL; EXPORT char* my_program_invocation_name = NULL; EXPORT char* my_program_invocation_short_name = NULL; // ignoring this for now EXPORT char my___libc_single_threaded = 0; #define PRE_INIT\ if(box64_tcmalloc_minimal) \ lib->priv.w.lib = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL); \ else #define CUSTOM_INIT \ box64->libclib = lib; \ /*InitCpuModel();*/ \ ctSetup(); \ stSetup(box64); \ /*obstackSetup();*/ \ my_environ = my__environ = my___environ = box64->envv; \ my___progname_full = my_program_invocation_name = box64->argv[0]; \ my___progname = my_program_invocation_short_name = \ strrchr(box64->argv[0], '/') + 1; \ getMy(lib); \ setNeededLibs(lib, 3, \ "ld-linux-x86-64.so.2", \ "libpthread.so.0", \ "librt.so.1"); #define CUSTOM_FINI \ freeMy(); #include "wrappedlib_init.h"