diff options
| author | howard97 <837971940@qq.com> | 2024-03-26 00:42:01 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-03-25 17:42:01 +0100 |
| commit | 50caca8fdcb1316571849cfb2f293b929d1089bd (patch) | |
| tree | 8b20567ed267f372e85661af6ef91916cb0a8fd3 /src | |
| parent | 1dca97b4d3663af54e48057c63c7d4b17b75dd85 (diff) | |
| download | box64-50caca8fdcb1316571849cfb2f293b929d1089bd.tar.gz box64-50caca8fdcb1316571849cfb2f293b929d1089bd.zip | |
[REFACTOR] Refactor main.c (#1362)
Co-authored-by: howard <howardzz@foxmail.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/core.c | 2176 | ||||
| -rw-r--r-- | src/include/core.h | 13 | ||||
| -rw-r--r-- | src/main.c | 2161 |
3 files changed, 2194 insertions, 2156 deletions
diff --git a/src/core.c b/src/core.c new file mode 100644 index 00000000..7fc8bcdf --- /dev/null +++ b/src/core.c @@ -0,0 +1,2176 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <limits.h> +#include <errno.h> +#include <unistd.h> +#include <dirent.h> +#include <signal.h> +#include <sys/syscall.h> +#include <sys/mman.h> +#include <pthread.h> +#include <sys/prctl.h> +#include <stdarg.h> +#ifdef DYNAREC +#ifdef ARM64 +#include <linux/auxvec.h> +#include <asm/hwcap.h> +#endif +#endif + +#include "build_info.h" +#include "debug.h" +#include "fileutils.h" +#include "box64context.h" +#include "wine_tools.h" +#include "elfloader.h" +#include "custommem.h" +#include "box64stack.h" +#include "auxval.h" +#include "x64emu.h" +#include "threads.h" +#include "x64trace.h" +#include "librarian.h" +#include "x64run.h" +#include "symbols.h" +#include "rcfile.h" +#include "emu/x64run_private.h" +#include "elfs/elfloader_private.h" +#include "library.h" +#include "core.h" + +box64context_t *my_context = NULL; +int box64_quit = 0; +int box64_exit_code = 0; +int box64_log = LOG_INFO; //LOG_NONE; +int box64_dump = 0; +int box64_nobanner = 0; +int box64_dynarec_log = LOG_NONE; +uintptr_t box64_pagesize; +uintptr_t box64_load_addr = 0; +int box64_nosandbox = 0; +int box64_inprocessgpu = 0; +int box64_cefdisablegpu = 0; +int box64_cefdisablegpucompositor = 0; +int box64_malloc_hack = 0; +int box64_dynarec_test = 0; +int box64_maxcpu = 0; +int box64_maxcpu_immutable = 0; +#if defined(SD845) || defined(SD888) || defined(SD8G2) || defined(TEGRAX1) +int box64_mmap32 = 1; +#else +int box64_mmap32 = 0; +#endif +int box64_ignoreint3 = 0; +int box64_rdtsc = 0; +uint8_t box64_rdtsc_shift = 0; +#ifdef DYNAREC +int box64_dynarec = 1; +int box64_dynarec_dump = 0; +int box64_dynarec_forced = 0; +int box64_dynarec_bigblock = 1; +int box64_dynarec_forward = 128; +int box64_dynarec_strongmem = 0; +int box64_dynarec_x87double = 0; +int box64_dynarec_div0 = 0; +int box64_dynarec_fastnan = 1; +int box64_dynarec_fastround = 1; +int box64_dynarec_safeflags = 1; +int box64_dynarec_callret = 0; +int box64_dynarec_bleeding_edge = 1; +int box64_dynarec_jvm = 1; +int box64_dynarec_tbb = 1; +int box64_dynarec_wait = 1; +int box64_dynarec_missing = 0; +int box64_dynarec_aligned_atomics = 0; +uintptr_t box64_nodynarec_start = 0; +uintptr_t box64_nodynarec_end = 0; +#ifdef ARM64 +int arm64_asimd = 0; +int arm64_aes = 0; +int arm64_pmull = 0; +int arm64_crc32 = 0; +int arm64_atomics = 0; +int arm64_sha1 = 0; +int arm64_sha2 = 0; +int arm64_uscat = 0; +int arm64_flagm = 0; +int arm64_flagm2 = 0; +int arm64_frintts = 0; +int arm64_afp = 0; +#elif defined(RV64) +int rv64_zba = 0; +int rv64_zbb = 0; +int rv64_zbc = 0; +int rv64_zbs = 0; +int rv64_xtheadba = 0; +int rv64_xtheadbb = 0; +int rv64_xtheadbs = 0; +int rv64_xtheadcondmov = 0; +int rv64_xtheadmemidx = 0; +int rv64_xtheadmempair = 0; +int rv64_xtheadfmemidx = 0; +int rv64_xtheadmac = 0; +int rv64_xtheadfmv = 0; +#elif defined(LA64) +int la64_lbt = 0; +#endif +#else //DYNAREC +int box64_dynarec = 0; +#endif +int box64_libcef = 1; +int box64_sdl2_jguid = 0; +int dlsym_error = 0; +int cycle_log = 0; +#ifdef HAVE_TRACE +int trace_xmm = 0; +int trace_emm = 0; +int trace_regsdiff = 0; +uint64_t start_cnt = 0; +uintptr_t trace_start = 0, trace_end = 0; +char* trace_func = NULL; +char* trace_init = NULL; +char* box64_trace = NULL; +#ifdef DYNAREC +int box64_dynarec_trace = 0; +#endif +#endif +int box64_x11threads = 0; +int box64_x11glx = 1; +int allow_missing_libs = 0; +int box64_prefer_emulated = 0; +int box64_prefer_wrapped = 0; +int box64_sse_flushto0 = 0; +int box64_x87_no80bits = 0; +int box64_sync_rounding = 0; +int fix_64bit_inodes = 0; +int box64_dummy_crashhandler = 1; +int box64_mapclean = 0; +int box64_zoom = 0; +int box64_steam = 0; +int box64_wine = 0; +int box64_musl = 0; +int box64_nopulse = 0; +int box64_nogtk = 0; +int box64_novulkan = 0; +int box64_showsegv = 0; +int box64_showbt = 0; +int box64_isglibc234 = 0; +#ifdef BAD_SIGNAL +int box64_futex_waitv = 0; +#else +int box64_futex_waitv = 1; +#endif +char* box64_libGL = NULL; +char* box64_custom_gstreamer = NULL; +uintptr_t fmod_smc_start = 0; +uintptr_t fmod_smc_end = 0; +uint32_t default_gs = 0x53; +int jit_gdb = 0; +int box64_tcmalloc_minimal = 0; + +FILE* ftrace = NULL; +char* ftrace_name = NULL; +int ftrace_has_pid = 0; + +void openFTrace(const char* newtrace) +{ + const char* t = newtrace?newtrace:getenv("BOX64_TRACE_FILE"); + #ifndef MAX_PATH + #define MAX_PATH 4096 + #endif + char tmp[MAX_PATH]; + char tmp2[MAX_PATH]; + const char* p = t; + int append=0; + if(p && strlen(p) && p[strlen(p)-1]=='+') { + strncpy(tmp2, p, sizeof(tmp2)); + tmp2[strlen(p)-1]='\0'; + p = tmp2; + append=1; + } + if(p && strstr(p, "%pid")) { + int next = 0; + do { + strcpy(tmp, p); + char* c = strstr(tmp, "%pid"); + *c = 0; // cut + char pid[16]; + if(next) + sprintf(pid, "%d-%d", getpid(), next); + else + sprintf(pid, "%d", getpid()); + strcat(tmp, pid); + c = strstr(p, "%pid") + strlen("%pid"); + strcat(tmp, c); + ++next; + } while (FileExist(tmp, IS_FILE) && !append); + p = tmp; + ftrace_has_pid = 1; + } + if(ftrace_name) + free(ftrace_name); + ftrace_name = NULL; + if(p) { + if(!strcmp(p, "stderr")) + ftrace = stderr; + else { + if(append) + ftrace = fopen(p, "w+"); + else + ftrace = fopen(p, "w"); + if(!ftrace) { + ftrace = stdout; + printf_log(LOG_INFO, "Cannot open trace file \"%s\" for writing (error=%s)\n", p, strerror(errno)); + } else { + ftrace_name = strdup(p); + /*fclose(ftrace); + ftrace = NULL;*/ + if(!box64_nobanner) + printf("BOX64 Trace %s to \"%s\"\n", append?"appended":"redirected", p); + PrintBox64Version(); + } + } + } +} + +void printf_ftrace(const char* fmt, ...) +{ + if(ftrace_name) { + int fd = fileno(ftrace); + if(fd<0 || lseek(fd, 0, SEEK_CUR)==(off_t)-1) + ftrace=fopen(ftrace_name, "w+"); + } + + va_list args; + va_start(args, fmt); + vfprintf(ftrace, fmt, args); + + fflush(ftrace); + + va_end(args); +} + +void my_child_fork() +{ + if(ftrace_has_pid) { + // open a new ftrace... + if(!ftrace_name) + fclose(ftrace); + openFTrace(NULL); + printf_log(/*LOG_DEBUG*/LOG_INFO, "Forked child of %s\n", GetLastApplyName()); + } +} + +const char* getCpuName(); +int getNCpu(); +#ifdef DYNAREC +void GatherDynarecExtensions() +{ + if(box64_dynarec==0) // no need to check if no dynarec + return; +#ifdef ARM64 +/* +HWCAP_FP + Functionality implied by ID_AA64PFR0_EL1.FP == 0b0000. +HWCAP_ASIMD + Functionality implied by ID_AA64PFR0_EL1.AdvSIMD == 0b0000. +HWCAP_EVTSTRM + The generic timer is configured to generate events at a frequency of + approximately 10KHz. +HWCAP_AES + Functionality implied by ID_AA64ISAR0_EL1.AES == 0b0001. => AESE, AESD, AESMC, and AESIMC instructions are implemented +HWCAP_PMULL + Functionality implied by ID_AA64ISAR0_EL1.AES == 0b0010. => AESE, AESD, AESMC, and AESIMC instructions are implemented plus PMULL/PMULL2 instructions operating on 64-bit data quantities. +HWCAP_SHA1 + Functionality implied by ID_AA64ISAR0_EL1.SHA1 == 0b0001. => SHA1C, SHA1P, SHA1M, SHA1H, SHA1SU0, and SHA1SU1 instructions implemented. +HWCAP_SHA2 + Functionality implied by ID_AA64ISAR0_EL1.SHA2 == 0b0001. => SHA256H, SHA256H2, SHA256SU0 and SHA256SU1 instructions implemented. +HWCAP_CRC32 + Functionality implied by ID_AA64ISAR0_EL1.CRC32 == 0b0001. => CRC32B, CRC32H, CRC32W, CRC32X, CRC32CB, CRC32CH, CRC32CW, and CRC32CX instructions implemented. +HWCAP_ATOMICS + Functionality implied by ID_AA64ISAR0_EL1.Atomic == 0b0010. => LDADD, LDCLR, LDEOR, LDSET, LDSMAX, LDSMIN, LDUMAX, LDUMIN, CAS, CASP, and SWP instructions implemented. +HWCAP_FPHP + Functionality implied by ID_AA64PFR0_EL1.FP == 0b0001. +HWCAP_ASIMDHP + Functionality implied by ID_AA64PFR0_EL1.AdvSIMD == 0b0001. +HWCAP_CPUID + EL0 access to certain ID registers is available. + These ID registers may imply the availability of features. +HWCAP_ASIMDRDM + Functionality implied by ID_AA64ISAR0_EL1.RDM == 0b0001. => SQRDMLAH and SQRDMLSH instructions implemented. +HWCAP_JSCVT + Functionality implied by ID_AA64ISAR1_EL1.JSCVT == 0b0001. => The FJCVTZS instruction is implemented. +HWCAP_FCMA + Functionality implied by ID_AA64ISAR1_EL1.FCMA == 0b0001. => The FCMLA and FCADD instructions are implemented. +HWCAP_LRCPC + Functionality implied by ID_AA64ISAR1_EL1.LRCPC == 0b0001. => LDAPR and variants +HWCAP_DCPOP + Functionality implied by ID_AA64ISAR1_EL1.DPB == 0b0001. +HWCAP_SHA3 + Functionality implied by ID_AA64ISAR0_EL1.SHA3 == 0b0001. => EOR3, RAX1, XAR, and BCAX instructions implemented. +HWCAP_SM3 + Functionality implied by ID_AA64ISAR0_EL1.SM3 == 0b0001. => SM3SS1, SM3TT1A, SM3TT1B, SM3TT2A, SM3TT2B, SM3PARTW1, and SM3PARTW2 instructions implemented. +HWCAP_SM4 + Functionality implied by ID_AA64ISAR0_EL1.SM4 == 0b0001. => SM4E and SM4EKEY instructions implemented. +HWCAP_ASIMDDP + Functionality implied by ID_AA64ISAR0_EL1.DP == 0b0001. => UDOT and SDOT instructions implemented. +HWCAP_SHA512 + Functionality implied by ID_AA64ISAR0_EL1.SHA2 == 0b0010. => SHA512H, SHA512H2, SHA512SU0, and SHA512SU1 instructions implemented. +HWCAP_SVE + Functionality implied by ID_AA64PFR0_EL1.SVE == 0b0001. +HWCAP_ASIMDFHM + Functionality implied by ID_AA64ISAR0_EL1.FHM == 0b0001. => FMLAL and FMLSL instructions are implemented. +HWCAP_DIT + Functionality implied by ID_AA64PFR0_EL1.DIT == 0b0001. +HWCAP_USCAT + Functionality implied by ID_AA64MMFR2_EL1.AT == 0b0001. +HWCAP_ILRCPC + Functionality implied by ID_AA64ISAR1_EL1.LRCPC == 0b0010. => The LDAPUR*, STLUR*, and LDAPR* instructions are implemented. +HWCAP_FLAGM + Functionality implied by ID_AA64ISAR0_EL1.TS == 0b0001. +HWCAP_SSBS + Functionality implied by ID_AA64PFR1_EL1.SSBS == 0b0010. => AArch64 provides the PSTATE.SSBS mechanism to mark regions that are Speculative Store Bypassing Safe, and the MSR and MRS instructions to directly read and write the PSTATE.SSBS field. +HWCAP_SB + Functionality implied by ID_AA64ISAR1_EL1.SB == 0b0001. => SB instruction is implemented. +HWCAP_PACA + Functionality implied by ID_AA64ISAR1_EL1.APA == 0b0001 or + ID_AA64ISAR1_EL1.API == 0b0001. +HWCAP_PACG + Functionality implied by ID_AA64ISAR1_EL1.GPA == 0b0001 or => Generic Authentication using the QARMA algorithm is implemented. This includes the PACGA instruction. + ID_AA64ISAR1_EL1.GPI == 0b0001. +HWCAP2_DCPODP + Functionality implied by ID_AA64ISAR1_EL1.DPB == 0b0010. => DC CVAP and DC CVADP supported +HWCAP2_SVE2 + Functionality implied by ID_AA64ZFR0_EL1.SVEVer == 0b0001. +HWCAP2_SVEAES + Functionality implied by ID_AA64ZFR0_EL1.AES == 0b0001. +HWCAP2_SVEPMULL + Functionality implied by ID_AA64ZFR0_EL1.AES == 0b0010. +HWCAP2_SVEBITPERM + Functionality implied by ID_AA64ZFR0_EL1.BitPerm == 0b0001. +HWCAP2_SVESHA3 + Functionality implied by ID_AA64ZFR0_EL1.SHA3 == 0b0001. +HWCAP2_SVESM4 + Functionality implied by ID_AA64ZFR0_EL1.SM4 == 0b0001. +HWCAP2_FLAGM2 + Functionality implied by ID_AA64ISAR0_EL1.TS == 0b0010. => CFINV, RMIF, SETF16, SETF8, AXFLAG, and XAFLAG instructions are implemented. +HWCAP2_FRINT + Functionality implied by ID_AA64ISAR1_EL1.FRINTTS == 0b0001. => FRINT32Z, FRINT32X, FRINT64Z, and FRINT64X instructions are implemented. +HWCAP2_SVEI8MM + Functionality implied by ID_AA64ZFR0_EL1.I8MM == 0b0001. +HWCAP2_SVEF32MM + Functionality implied by ID_AA64ZFR0_EL1.F32MM == 0b0001. +HWCAP2_SVEF64MM + Functionality implied by ID_AA64ZFR0_EL1.F64MM == 0b0001. +HWCAP2_SVEBF16 + Functionality implied by ID_AA64ZFR0_EL1.BF16 == 0b0001 +HWCAP2_I8MM + Functionality implied by ID_AA64ISAR1_EL1.I8MM == 0b0001. => SMMLA, SUDOT, UMMLA, USMMLA, and USDOT instructions are implemented +HWCAP2_BF16 + Functionality implied by ID_AA64ISAR1_EL1.BF16 == 0b0001. => BFDOT, BFMLAL, BFMLAL2, BFMMLA, BFCVT, and BFCVT2 instructions are implemented. +HWCAP2_DGH + Functionality implied by ID_AA64ISAR1_EL1.DGH == 0b0001. => Data Gathering Hint is implemented. +HWCAP2_RNG + Functionality implied by ID_AA64ISAR0_EL1.RNDR == 0b0001. +HWCAP2_BTI + Functionality implied by ID_AA64PFR0_EL1.BT == 0b0001. +HWCAP2_MTE + Functionality implied by ID_AA64PFR1_EL1.MTE == 0b0010. => Full Memory Tagging Extension is implemented. +HWCAP2_ECV + Functionality implied by ID_AA64MMFR0_EL1.ECV == 0b0001. +*/ + unsigned long hwcap = real_getauxval(AT_HWCAP); + if(!hwcap) // no HWCap: provide a default... + hwcap = HWCAP_ASIMD; + // first, check all needed extensions, lif half, edsp and fastmult + if((hwcap&HWCAP_ASIMD) == 0) { + printf_log(LOG_INFO, "Missing ASMID cpu support, disabling Dynarec\n"); + box64_dynarec=0; + return; + } + if(hwcap&HWCAP_CRC32) + arm64_crc32 = 1; + if(hwcap&HWCAP_PMULL) + arm64_pmull = 1; + if(hwcap&HWCAP_AES) + arm64_aes = 1; + // ATOMIC use are disable for now. They crashes Batman Arkham Knight, bossibly other (also seems to make steamwebhelper unstable) + if(hwcap&HWCAP_ATOMICS) + arm64_atomics = 1; + #ifdef HWCAP_SHA1 + if(hwcap&HWCAP_SHA1) + arm64_sha1 = 1; + #endif + #ifdef HWCAP_SHA2 + if(hwcap&HWCAP_SHA2) + arm64_sha2 = 1; + #endif + #ifdef HWCAP_USCAT + if(hwcap&HWCAP_USCAT) + arm64_uscat = 1; + #endif + #ifdef HWCAP_FLAGM + if(hwcap&HWCAP_FLAGM) + arm64_flagm = 1; + #endif + unsigned long hwcap2 = real_getauxval(AT_HWCAP2); + #ifdef HWCAP2_FLAGM2 + if(hwcap2&HWCAP2_FLAGM2) + arm64_flagm2 = 1; + #endif + #ifdef HWCAP2_FRINT + if(hwcap2&HWCAP2_FRINT) + arm64_frintts = 1; + #endif + #ifdef HWCAP2_AFP + if(hwcap2&HWCAP2_AFP) + arm64_afp = 1; + #endif + printf_log(LOG_INFO, "Dynarec for ARM64, with extension: ASIMD"); + if(arm64_aes) + printf_log(LOG_INFO, " AES"); + if(arm64_crc32) + printf_log(LOG_INFO, " CRC32"); + if(arm64_pmull) + printf_log(LOG_INFO, " PMULL"); + if(arm64_atomics) + printf_log(LOG_INFO, " ATOMICS"); + if(arm64_sha1) + printf_log(LOG_INFO, " SHA1"); + if(arm64_sha2) + printf_log(LOG_INFO, " SHA2"); + if(arm64_uscat) + printf_log(LOG_INFO, " USCAT"); + if(arm64_flagm) + printf_log(LOG_INFO, " FLAGM"); + if(arm64_flagm2) + printf_log(LOG_INFO, " FLAGM2"); + if(arm64_frintts) + printf_log(LOG_INFO, " FRINT"); + if(arm64_afp) + printf_log(LOG_INFO, " AFP"); +#elif defined(LA64) + printf_log(LOG_INFO, "Dynarec for LoongArch "); + char* p = getenv("BOX64_DYNAREC_LA64NOEXT"); + if(p == NULL || p[0] == '0') { + uint32_t cpucfg2 = 0, idx = 2; + // there are other extensions, but we don't care. + asm volatile("cpucfg %0, %1" : "=r"(cpucfg2) : "r"(idx)); + if (la64_lbt = (cpucfg2 >> 18) & 0b1) + printf_log(LOG_INFO, "with extension LBT_X86"); + } +#elif defined(RV64) + void RV64_Detect_Function(); + char *p = getenv("BOX64_DYNAREC_RV64NOEXT"); + if(p == NULL || p[0] == '0') + RV64_Detect_Function(); + printf_log(LOG_INFO, "Dynarec for RISC-V "); + printf_log(LOG_INFO, "With extension: I M A F D C"); + if(rv64_zba) printf_log(LOG_INFO, " Zba"); + if(rv64_zbb) printf_log(LOG_INFO, " Zbb"); + if(rv64_zbc) printf_log(LOG_INFO, " Zbc"); + if(rv64_zbs) printf_log(LOG_INFO, " Zbs"); + if(rv64_xtheadba) printf_log(LOG_INFO, " XTheadBa"); + if(rv64_xtheadbb) printf_log(LOG_INFO, " XTheadBb"); + if(rv64_xtheadbs) printf_log(LOG_INFO, " XTheadBs"); + if(rv64_xtheadcondmov) printf_log(LOG_INFO, " XTheadCondMov"); + if(rv64_xtheadmemidx) printf_log(LOG_INFO, " XTheadMemIdx"); + if(rv64_xtheadmempair) printf_log(LOG_INFO, " XTheadMemPair"); + if(rv64_xtheadfmemidx) printf_log(LOG_INFO, " XTheadFMemIdx"); + if(rv64_xtheadmac) printf_log(LOG_INFO, " XTheadMac"); + if(rv64_xtheadfmv) printf_log(LOG_INFO, " XTheadFmv"); +#else +#error Unsupported architecture +#endif +} +#endif + + +EXPORTDYN +void LoadLogEnv() +{ + ftrace = stdout; + box64_nobanner = isatty(fileno(stdout))?0:1; + const char *p = getenv("BOX64_NOBANNER"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='1') + box64_nobanner = p[0]-'0'; + } + } + // grab BOX64_TRACE_FILE envvar, and change %pid to actual pid is present in the name + openFTrace(NULL); + box64_log = ftrace_name?LOG_INFO:(isatty(fileno(stdout))?LOG_INFO:LOG_NONE); //default LOG value different if stdout is redirected or not + p = getenv("BOX64_LOG"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0'+LOG_NONE && p[0]<='0'+LOG_NEVER) { + box64_log = p[0]-'0'; + if(box64_log == LOG_NEVER) { + --box64_log; + box64_dump = 1; + } + } + } else { + if(!strcasecmp(p, "NONE")) + box64_log = LOG_NONE; + else if(!strcasecmp(p, "INFO")) + box64_log = LOG_INFO; + else if(!strcasecmp(p, "DEBUG")) + box64_log = LOG_DEBUG; + else if(!strcasecmp(p, "DUMP")) { + box64_log = LOG_DEBUG; + box64_dump = 1; + } + } + if(!box64_nobanner) + printf_log(LOG_INFO, "Debug level is %d\n", box64_log); + } + +#if !defined(DYNAREC) && (defined(ARM64) || defined(RV64) || defined(LA64)) + printf_log(LOG_INFO, "Warning: DynaRec is available on this host architecture, an interpreter-only build is probably not intended.\n"); +#endif + + p = getenv("BOX64_ROLLING_LOG"); + if(p) { + int cycle = 0; + if(sscanf(p, "%d", &cycle)==1) + cycle_log = cycle; + if(cycle_log==1) + cycle_log = 16; + if(cycle_log<0) + cycle_log = 0; + if(cycle_log && box64_log>LOG_INFO) { + cycle_log = 0; + printf_log(LOG_NONE, "Incompatible Rolling log and Debug Log, disabling Rolling log\n"); + } + } + if(!box64_nobanner && cycle_log) + printf_log(LOG_INFO, "Rolling log, showing last %d function call on signals\n", cycle_log); + p = getenv("BOX64_DUMP"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='1') + box64_dump = p[0]-'0'; + } + } + if(!box64_nobanner && box64_dump) + printf_log(LOG_INFO, "Elf Dump if ON\n"); +#ifdef DYNAREC + #ifdef ARM64 + // unaligned atomic (with restriction) is supported in hardware + /*if(arm64_uscat) + box64_dynarec_aligned_atomics = 1;*/ // the unaligned support is not good enough for x86 emulation, so diabling + #endif + p = getenv("BOX64_DYNAREC_DUMP"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='2') + box64_dynarec_dump = p[0]-'0'; + } + if (box64_dynarec_dump) printf_log(LOG_INFO, "Dynarec blocks are dumped%s\n", (box64_dynarec_dump>1)?" in color":""); + } + p = getenv("BOX64_DYNAREC_LOG"); + if(p) { + if(strlen(p)==1) { + if((p[0]>='0'+LOG_NONE) && (p[0]<='0'+LOG_NEVER)) + box64_dynarec_log = p[0]-'0'; + } else { + if(!strcasecmp(p, "NONE")) + box64_dynarec_log = LOG_NONE; + else if(!strcasecmp(p, "INFO")) + box64_dynarec_log = LOG_INFO; + else if(!strcasecmp(p, "DEBUG")) + box64_dynarec_log = LOG_DEBUG; + else if(!strcasecmp(p, "VERBOSE")) + box64_dynarec_log = LOG_VERBOSE; + } + printf_log(LOG_INFO, "Dynarec log level is %d\n", box64_dynarec_log); + } + p = getenv("BOX64_DYNAREC"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='1') + box64_dynarec = p[0]-'0'; + } + printf_log(LOG_INFO, "Dynarec is %s\n", box64_dynarec?"on":"off"); + } + p = getenv("BOX64_DYNAREC_FORCED"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='1') + box64_dynarec_forced = p[0]-'0'; + } + if(box64_dynarec_forced) + printf_log(LOG_INFO, "Dynarec is forced on all addresses\n"); + } + p = getenv("BOX64_DYNAREC_BIGBLOCK"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='3') + box64_dynarec_bigblock = p[0]-'0'; + } + if(!box64_dynarec_bigblock) + printf_log(LOG_INFO, "Dynarec will not try to make big block\n"); + else if (box64_dynarec_bigblock>1) + printf_log(LOG_INFO, "Dynarec will try to make bigger blocks%s\n", (box64_dynarec_bigblock>2)?" even on non-elf memory":""); + + } + p = getenv("BOX64_DYNAREC_FORWARD"); + if(p) { + int val = -1; + if(sscanf(p, "%d", &val)==1) { + if(val>=0) + box64_dynarec_forward = val; + } + if(box64_dynarec_forward) + printf_log(LOG_INFO, "Dynarec will continue block for %d bytes on forward jump\n", box64_dynarec_forward); + else + printf_log(LOG_INFO, "Dynarec will not continue block on forward jump\n"); + } + p = getenv("BOX64_DYNAREC_STRONGMEM"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='4') + box64_dynarec_strongmem = p[0]-'0'; + } + if(box64_dynarec_strongmem) + printf_log(LOG_INFO, "Dynarec will try to emulate a strong memory model%s\n", (box64_dynarec_strongmem==1)?" with limited performance loss":((box64_dynarec_strongmem>1)?" with more performance loss":"")); + } + p = getenv("BOX64_DYNAREC_X87DOUBLE"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='1') + box64_dynarec_x87double = p[0]-'0'; + } + if(box64_dynarec_x87double) + printf_log(LOG_INFO, "Dynarec will use only double for x87 emulation\n"); + } + p = getenv("BOX64_DYNAREC_DIV0"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='1') + box64_dynarec_div0 = p[0]-'0'; + } + if(box64_dynarec_div0) + printf_log(LOG_INFO, "Dynarec will check for divide by 0\n"); + } + p = getenv("BOX64_DYNAREC_FASTNAN"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='1') + box64_dynarec_fastnan = p[0]-'0'; + } + if(!box64_dynarec_fastnan) + printf_log(LOG_INFO, "Dynarec will try to normalize generated NAN\n"); + } + p = getenv("BOX64_DYNAREC_FASTROUND"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='1') + box64_dynarec_fastround = p[0]-'0'; + } + if(!box64_dynarec_fastround) + printf_log(LOG_INFO, "Dynarec will try tp generate x86 precise IEEE->int rounding\n"); + } + p = getenv("BOX64_DYNAREC_SAFEFLAGS"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='2') + box64_dynarec_safeflags = p[0]-'0'; + } + if(!box64_dynarec_safeflags) + printf_log(LOG_INFO, "Dynarec will not play it safe with x64 flags\n"); + else + printf_log(LOG_INFO, "Dynarec will play %s safe with x64 flags\n", (box64_dynarec_safeflags==1)?"moderatly":"it"); + } + p = getenv("BOX64_DYNAREC_CALLRET"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='1') + box64_dynarec_callret = p[0]-'0'; + } + if(box64_dynarec_callret) + printf_log(LOG_INFO, "Dynarec will optimize CALL/RET\n"); + else + printf_log(LOG_INFO, "Dynarec will not optimize CALL/RET\n"); + } + p = getenv("BOX64_DYNAREC_BLEEDING_EDGE"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='1') + box64_dynarec_bleeding_edge = p[0]-'0'; + } + if(!box64_dynarec_bleeding_edge) + printf_log(LOG_INFO, "Dynarec will not detect MonoBleedingEdge\n"); + } + p = getenv("BOX64_DYNAREC_JVM"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='1') + box64_dynarec_jvm = p[0]-'0'; + } + if(!box64_dynarec_jvm) + printf_log(LOG_INFO, "Dynarec will not detect libjvm\n"); + } + p = getenv("BOX64_DYNAREC_TBB"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='1') + box64_dynarec_tbb = p[0]-'0'; + } + if(!box64_dynarec_tbb) + printf_log(LOG_INFO, "Dynarec will not detect libtbb\n"); + } + p = getenv("BOX64_DYNAREC_WAIT"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='1') + box64_dynarec_wait = p[0]-'0'; + } + if(!box64_dynarec_wait) + printf_log(LOG_INFO, "Dynarec will not wait for FillBlock to ready and use Interpreter instead\n"); + } + p = getenv("BOX64_DYNAREC_ALIGNED_ATOMICS"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='1') + box64_dynarec_aligned_atomics = p[0]-'0'; + } + if(box64_dynarec_aligned_atomics) + printf_log(LOG_INFO, "Dynarec will generate only aligned atomics code\n"); + } + p = getenv("BOX64_DYNAREC_MISSING"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='1') + box64_dynarec_missing = p[0]-'0'; + } + if(box64_dynarec_missing) + printf_log(LOG_INFO, "Dynarec will print missing opcodes\n"); + } + p = getenv("BOX64_NODYNAREC"); + if(p) { + if (strchr(p,'-')) { + if(sscanf(p, "%ld-%ld", &box64_nodynarec_start, &box64_nodynarec_end)!=2) { + if(sscanf(p, "0x%lX-0x%lX", &box64_nodynarec_start, &box64_nodynarec_end)!=2) + sscanf(p, "%lx-%lx", &box64_nodynarec_start, &box64_nodynarec_end); + } + printf_log(LOG_INFO, "No dynablock creation that start in the range %p - %p\n", (void*)box64_nodynarec_start, (void*)box64_nodynarec_end); + } + } + p = getenv("BOX64_DYNAREC_TEST"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='1') + box64_dynarec_test = p[0]-'0'; + } + if(box64_dynarec_test) { + box64_dynarec_fastnan = 0; + box64_dynarec_fastround = 0; + box64_dynarec_x87double = 1; + box64_dynarec_div0 = 1; + box64_dynarec_callret = 0; + printf_log(LOG_INFO, "Dynarec will compare it's execution with the interpreter (super slow, only for testing)\n"); + } + } + +#endif +#ifdef HAVE_TRACE + p = getenv("BOX64_TRACE_XMM"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='0'+1) + trace_xmm = p[0]-'0'; + } + } + p = getenv("BOX64_TRACE_EMM"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='0'+1) + trace_emm = p[0]-'0'; + } + } + p = getenv("BOX64_TRACE_COLOR"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='0'+1) + trace_regsdiff = p[0]-'0'; + } + } + p = getenv("BOX64_TRACE_START"); + if(p) { + char* p2; + start_cnt = strtoll(p, &p2, 10); + printf_log(LOG_INFO, "Will start trace only after %lu instructions\n", start_cnt); + } +#ifdef DYNAREC + p = getenv("BOX64_DYNAREC_TRACE"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='0'+1) + box64_dynarec_trace = p[0]-'0'; + if(box64_dynarec_trace) + printf_log(LOG_INFO, "Dynarec generated code will also print a trace\n"); + } + } +#endif +#endif + // Other BOX64 env. var. + p = getenv("BOX64_LIBCEF"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='1') + box64_libcef = p[0]-'0'; + } + if(!box64_libcef) + printf_log(LOG_INFO, "BOX64 will not detect libcef\n"); + } + p = getenv("BOX64_SDL2_JGUID"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='1') + box64_sdl2_jguid = p[0]-'0'; + } + if(!box64_sdl2_jguid) + printf_log(LOG_INFO, "BOX64 will workaround the use of SDL_GetJoystickGUIDInfo with 4 args instead of 5\n"); + } + p = getenv("BOX64_LOAD_ADDR"); + if(p) { + if(sscanf(p, "0x%zx", &box64_load_addr)!=1) + box64_load_addr = 0; + if(box64_load_addr) + printf_log(LOG_INFO, "Use a starting load address of %p\n", (void*)box64_load_addr); + } + p = getenv("BOX64_DLSYM_ERROR"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='0'+1) + dlsym_error = p[0]-'0'; + } + } + p = getenv("BOX64_X11THREADS"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='0'+1) + box64_x11threads = p[0]-'0'; + } + if(box64_x11threads) + printf_log(LOG_INFO, "Try to Call XInitThreads if libX11 is loaded\n"); + } + p = getenv("BOX64_X11GLX"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='0'+1) + box64_x11glx = p[0]-'0'; + } + if(box64_x11glx) + printf_log(LOG_INFO, "Hack to force libX11 GLX extension present\n"); + else + printf_log(LOG_INFO, "Disabled Hack to force libX11 GLX extension present\n"); + } + p = getenv("BOX64_LIBGL"); + if(p) + box64_libGL = box_strdup(p); + if(!box64_libGL) { + p = getenv("SDL_VIDEO_GL_DRIVER"); + if(p) + box64_libGL = box_strdup(p); + } + if(box64_libGL) { + printf_log(LOG_INFO, "BOX64 using \"%s\" as libGL.so.1\n", p); + } + p = getenv("BOX64_ALLOWMISSINGLIBS"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='0'+1) + allow_missing_libs = p[0]-'0'; + } + if(allow_missing_libs) + printf_log(LOG_INFO, "Allow missing needed libs\n"); + } + p = getenv("BOX64_CRASHHANDLER"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='0'+1) + box64_dummy_crashhandler = p[0]-'0'; + } + if(!box64_dummy_crashhandler) + printf_log(LOG_INFO, "Don't use dummy crashhandler lib\n"); + } + p = getenv("BOX64_MALLOC_HACK"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='0'+2) + box64_malloc_hack = p[0]-'0'; + } + if(!box64_malloc_hack) { + if(box64_malloc_hack==1) { + printf_log(LOG_INFO, "Malloc hook will not be redirected\n"); + } else + printf_log(LOG_INFO, "Malloc hook will check for mmap/free occurrences\n"); + } + } + p = getenv("BOX64_NOPULSE"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='0'+1) + box64_nopulse = p[0]-'0'; + } + if(box64_nopulse) + printf_log(LOG_INFO, "Disable the use of pulseaudio libs\n"); + } + p = getenv("BOX64_NOGTK"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='0'+1) + box64_nogtk = p[0]-'0'; + } + if(box64_nogtk) + printf_log(LOG_INFO, "Disable the use of wrapped gtk libs\n"); + } + p = getenv("BOX64_NOVULKAN"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='0'+1) + box64_novulkan = p[0]-'0'; + } + if(box64_novulkan) + printf_log(LOG_INFO, "Disable the use of wrapped vulkan libs\n"); + } + p = getenv("BOX64_FUTEX_WAITV"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='0'+1) + box64_futex_waitv = p[0]-'0'; + } + #ifdef BAD_SIGNAL + if(box64_futex_waitv) + printf_log(LOG_INFO, "Enable the use of futex waitv syscall (if available on the system\n"); + #else + if(!box64_futex_waitv) + printf_log(LOG_INFO, "Disable the use of futex waitv syscall\n"); + #endif + } + p = getenv("BOX64_FIX_64BIT_INODES"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='0'+1) + fix_64bit_inodes = p[0]-'0'; + } + if(fix_64bit_inodes) + printf_log(LOG_INFO, "Fix 64bit inodes\n"); + } + p = getenv("BOX64_JITGDB"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='0'+3) + jit_gdb = p[0]-'0'; + } + if(jit_gdb) + printf_log(LOG_INFO, "Launch %s on segfault\n", (jit_gdb==2)?"gdbserver":((jit_gdb==3)?"lldb":"gdb")); + } + p = getenv("BOX64_SHOWSEGV"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='0'+1) + box64_showsegv = p[0]-'0'; + } + if(box64_showsegv) + printf_log(LOG_INFO, "Show Segfault signal even if a signal handler is present\n"); + } + p = getenv("BOX64_SHOWBT"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='0'+1) + box64_showbt = p[0]-'0'; + } + if(box64_showbt) + printf_log(LOG_INFO, "Show a Backtrace when a Segfault signal is caught\n"); + } + p = getenv("BOX64_MAXCPU"); + if(p) { + int maxcpu = 0; + if(sscanf(p, "%d", &maxcpu)==1) + box64_maxcpu = maxcpu; + if(box64_maxcpu<0) + box64_maxcpu = 0; + if(box64_maxcpu) { + printf_log(LOG_NONE, "Will not expose more than %d cpu cores\n", box64_maxcpu); + } else { + printf_log(LOG_NONE, "Will not limit the number of cpu cores exposed\n"); + } + } + p = getenv("BOX64_MMAP32"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='0'+1) + box64_mmap32 = p[0]-'0'; + } + if(box64_mmap32) + printf_log(LOG_INFO, "Will use 32bits address in priority for external MMAP (when 32bits process are detected)\n"); + else + printf_log(LOG_INFO, "Will not use 32bits address in priority for external MMAP (when 32bits process are detected)\n"); + } + p = getenv("BOX64_IGNOREINT3"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='0'+1) + box64_ignoreint3 = p[0]-'0'; + } + if(box64_ignoreint3) + printf_log(LOG_INFO, "Will silently ignore INT3 in the code\n"); + } + // grab pagesize + box64_pagesize = sysconf(_SC_PAGESIZE); + if(!box64_pagesize) + box64_pagesize = 4096; +#ifdef DYNAREC + // grab cpu extensions for dynarec usage + GatherDynarecExtensions(); +#endif + // grab cpu name + int ncpu = getNCpu(); + const char* cpuname = getCpuName(); + printf_log(LOG_INFO, " PageSize:%zd Running on %s with %d Cores\n", box64_pagesize, cpuname, ncpu); + // grab and calibrate hardware counter + int hardware = 0; + #if defined(ARM64) || defined(RV64) + hardware = 1; + box64_rdtsc = 0; // allow hardxare counter + #else + box64_rdtsc = 1; + printf_log(LOG_INFO, "Will use time-based emulation for rdtsc, even if hardware counter are available\n"); + #endif + uint64_t freq = ReadTSCFrequency(NULL); + if(freq<1000000) { + box64_rdtsc = 1; + if(hardware) printf_log(LOG_INFO, "Hardware counter to slow (%d kHz), not using it\n", freq/1000); + hardware = 0; + freq = ReadTSCFrequency(NULL); + } + uint64_t efreq = freq; + while(efreq<500000000) { // minium 500MHz + ++box64_rdtsc_shift; + efreq = freq<<box64_rdtsc_shift; + } + printf_log(LOG_INFO, "Will use %s counter measured at ", box64_rdtsc?"Software":"Hardware"); + int ghz = freq>=1000000000LL; + if(ghz) freq/=100000000LL; else freq/=100000; + if(ghz) printf_log(LOG_INFO, "%d.%d GHz", freq/10, freq%10); + if(!ghz & freq>=1000) printf_log(LOG_INFO, "%d MHz", freq/10); + if(!ghz & freq<1000) printf_log(LOG_INFO, "%d.%d MHz", freq/10, freq%10); + if(box64_rdtsc_shift) { + printf_log(LOG_INFO, " emulating "); + ghz = efreq>=1000000000LL; + if(ghz) efreq/=100000000LL; else efreq/=100000; + if(ghz) printf_log(LOG_INFO, "%d.%d GHz", efreq/10, efreq%10); + if(!ghz & efreq>=1000) printf_log(LOG_INFO, "%d MHz", efreq/10); + if(!ghz & efreq<1000) printf_log(LOG_INFO, "%d.%d MHz", efreq/10, efreq%10); + } + printf_log(LOG_INFO, "\n"); +} + +EXPORTDYN +void LoadEnvPath(path_collection_t *col, const char* defpath, const char* env) +{ + const char* p = getenv(env); + if(p) { + ParseList(p, col, 1); + } else { + ParseList(defpath, col, 1); + } +} + +void PrintCollection(path_collection_t* col, const char* env) +{ + if(LOG_INFO<=box64_log) { + printf_log(LOG_INFO, "%s: ", env); + for(int i=0; i<col->size; i++) + printf_log(LOG_INFO, "%s%s", col->paths[i], (i==col->size-1)?"\n":":"); + } +} + +EXPORTDYN +int CountEnv(char** env) +{ + // count, but remove all BOX64_* environnement + // also remove PATH and LD_LIBRARY_PATH + // but add 2 for default BOX64_PATH and BOX64_LD_LIBRARY_PATH + char** p = env; + int c = 0; + while(*p) { + if(strncmp(*p, "BOX64_", 6)!=0) + //if(!(strncmp(*p, "PATH=", 5)==0 || strncmp(*p, "LD_LIBRARY_PATH=", 16)==0)) + ++c; + ++p; + } + return c+2; +} +EXPORTDYN +int GatherEnv(char*** dest, char** env, char* prog) +{ + // Add all but BOX64_* environnement + // but add 2 for default BOX64_PATH and BOX64_LD_LIBRARY_PATH + char** p = env; + int idx = 0; + int path = 0; + int ld_path = 0; + while(*p) { + if(strncmp(*p, "BOX64_PATH=", 11)==0) { + (*dest)[idx++] = box_strdup(*p+6); + path = 1; + } else if(strncmp(*p, "BOX64_LD_LIBRARY_PATH=", 22)==0) { + (*dest)[idx++] = box_strdup(*p+6); + ld_path = 1; + } else if(strncmp(*p, "_=", 2)==0) { + /*int l = strlen(prog); + char tmp[l+3]; + strcpy(tmp, "_="); + strcat(tmp, prog); + (*dest)[idx++] = box_strdup(tmp);*/ + } else if(strncmp(*p, "BOX64_", 6)!=0) { + (*dest)[idx++] = box_strdup(*p); + /*if(!(strncmp(*p, "PATH=", 5)==0 || strncmp(*p, "LD_LIBRARY_PATH=", 16)==0)) { + }*/ + } + ++p; + } + // update the calloc of envv when adding new variables here + if(!path) { + (*dest)[idx++] = box_strdup("BOX64_PATH=.:bin"); + } + if(!ld_path) { + (*dest)[idx++] = box_strdup("BOX64_LD_LIBRARY_PATH=.:lib:lib64:x86_64:bin64:libs64"); + } + // add "_=prog" at the end... + if(prog) { + int l = strlen(prog); + char tmp[l+3]; + strcpy(tmp, "_="); + strcat(tmp, prog); + (*dest)[idx++] = box_strdup(tmp); + } + // and a final NULL + (*dest)[idx++] = 0; + return 0; +} + +void PrintFlags() { + printf("Environment Variables:\n"); + printf(" BOX64_PATH is the box64 version of PATH (default is '.:bin')\n"); + printf(" BOX64_LD_LIBRARY_PATH is the box64 version LD_LIBRARY_PATH (default is '.:lib:lib64')\n"); + printf(" BOX64_LOG with 0/1/2/3 or NONE/INFO/DEBUG/DUMP to set the printed debug info (level 3 is level 2 + BOX64_DUMP)\n"); + printf(" BOX64_DUMP with 0/1 to dump elf infos\n"); + printf(" BOX64_NOBANNER with 0/1 to enable/disable the printing of box64 version and build at start\n"); +#ifdef DYNAREC + printf(" BOX64_DYNAREC_LOG with 0/1/2/3 or NONE/INFO/DEBUG/DUMP to set the printed dynarec info\n"); + printf(" BOX64_DYNAREC with 0/1 to disable or enable Dynarec (On by default)\n"); + printf(" BOX64_NODYNAREC with address interval (0x1234-0x4567) to forbid dynablock creation in the interval specified\n"); +#endif +#ifdef HAVE_TRACE + printf(" BOX64_TRACE with 1 to enable x86_64 execution trace\n"); + printf(" or with XXXXXX-YYYYYY to enable x86_64 execution trace only between address\n"); + printf(" or with FunctionName to enable x86_64 execution trace only in one specific function\n"); + printf(" use BOX64_TRACE_INIT instead of BOX64_TRACE to start trace before init of Libs and main program\n\t (function name will probably not work then)\n"); + printf(" BOX64_TRACE_EMM with 1 to enable dump of MMX registers along with regular registers\n"); + printf(" BOX64_TRACE_XMM with 1 to enable dump of SSE registers along with regular registers\n"); + printf(" BOX64_TRACE_COLOR with 1 to enable detection of changed general register values\n"); + printf(" BOX64_TRACE_START with N to enable trace after N instructions\n"); +#ifdef DYNAREC + printf(" BOX64_DYNAREC_TRACE with 0/1 to disable or enable Trace on generated code too\n"); +#endif +#endif + printf(" BOX64_TRACE_FILE with FileName to redirect logs in a file (or stderr to use stderr instead of stdout)\n"); + printf(" BOX64_DLSYM_ERROR with 1 to log dlsym errors\n"); + printf(" BOX64_LOAD_ADDR=0xXXXXXX try to load at 0xXXXXXX main binary (if binary is a PIE)\n"); + printf(" BOX64_NOSIGSEGV=1 to disable handling of SigSEGV\n"); + printf(" BOX64_NOSIGILL=1 to disable handling of SigILL\n"); + printf(" BOX64_SHOWSEGV=1 to show Segfault signal even if a signal handler is present\n"); + printf(" BOX64_X11THREADS=1 to call XInitThreads when loading X11 (for old Loki games with Loki_Compat lib)\n"); + printf(" BOX64_LIBGL=libXXXX set the name (and optionnally full path) for libGL.so.1\n"); + printf(" BOX64_LD_PRELOAD=XXXX[:YYYYY] force loading XXXX (and YYYY...) libraries with the binary\n"); + printf(" BOX64_ALLOWMISSINGLIBS with 1 to allow one to continue even if a lib is missing (unadvised, will probably crash later)\n"); + printf(" BOX64_PREFER_EMULATED=1 to prefer emulated libs first (execpt for glibc, alsa, pulse, GL, vulkan and X11)\n"); + printf(" BOX64_PREFER_WRAPPED if box64 will use wrapped libs even if the lib is specified with absolute path\n"); + printf(" BOX64_CRASHHANDLER=0 to not use a dummy crashhandler lib\n"); + printf(" BOX64_NOPULSE=1 to disable the loading of pulseaudio libs\n"); + printf(" BOX64_NOGTK=1 to disable the loading of wrapped gtk libs\n"); + printf(" BOX64_NOVULKAN=1 to disable the loading of wrapped vulkan libs\n"); + printf(" BOX64_ENV='XXX=yyyy' will add XXX=yyyy env. var.\n"); + printf(" BOX64_ENV1='XXX=yyyy' will add XXX=yyyy env. var. and continue with BOX86_ENV2 ... until var doesn't exist\n"); + printf(" BOX64_JITGDB with 1 to launch \"gdb\" when a segfault is trapped, attached to the offending process\n"); + printf(" BOX64_MMAP32=1 to use 32bits address space mmap in priority for external mmap as soon a 32bits process are detected (default for Snapdragon build)\n"); +} + +void PrintHelp() { + printf("This is Box64, The Linux x86_64 emulator with a twist\n"); + printf("\nUsage is 'box64 [options] path/to/software [args]' to launch x86_64 software.\n"); + printf(" options are:\n"); + printf(" '-v'|'--version' to print box64 version and quit\n"); + printf(" '-h'|'--help' to print this and quit\n"); + printf(" '-f'|'--flags' to print box64 flags and quit\n"); +} + +void addNewEnvVar(const char* s) +{ + if(!s) + return; + char* p = box_strdup(s); + char* e = strchr(p, '='); + if(!e) { + printf_log(LOG_INFO, "Invalid specific env. var. '%s'\n", s); + box_free(p); + return; + } + *e='\0'; + ++e; + setenv(p, e, 1); + box_free(p); +} + +EXPORTDYN +void LoadEnvVars(box64context_t *context) +{ + // Check custom env. var. and add them if needed + { + char* p = getenv("BOX64_ENV"); + if(p) + addNewEnvVar(p); + int i = 1; + char box64_env[50]; + do { + sprintf(box64_env, "BOX64_ENV%d", i); + p = getenv(box64_env); + if(p) { + addNewEnvVar(p); + ++i; + } + } while(p); + } + // check BOX64_LD_LIBRARY_PATH and load it + LoadEnvPath(&context->box64_ld_lib, ".:lib:lib64:x86_64:bin64:libs64", "BOX64_LD_LIBRARY_PATH"); + #ifndef TERMUX + if(FileExist("/lib/x86_64-linux-gnu", 0)) + AddPath("/lib/x86_64-linux-gnu", &context->box64_ld_lib, 1); + if(FileExist("/usr/lib/x86_64-linux-gnu", 0)) + AddPath("/usr/lib/x86_64-linux-gnu", &context->box64_ld_lib, 1); + if(FileExist("/usr/x86_64-linux-gnu/lib", 0)) + AddPath("/usr/x86_64-linux-gnu/lib", &context->box64_ld_lib, 1); + #else + //TODO: Add Termux Library Path - Lily + if(FileExist("/data/data/com.termux/files/usr/lib/x86_64-linux-gnu", 0)) + AddPath("/data/data/com.termux/files/usr/lib/x86_64-linux-gnu", &context->box64_ld_lib, 1); + #endif + if(getenv("LD_LIBRARY_PATH")) + PrependList(&context->box64_ld_lib, getenv("LD_LIBRARY_PATH"), 1); // in case some of the path are for x86 world + if(getenv("BOX64_EMULATED_LIBS")) { + char* p = getenv("BOX64_EMULATED_LIBS"); + ParseList(p, &context->box64_emulated_libs, 0); + if (my_context->box64_emulated_libs.size && box64_log) { + printf_log(LOG_INFO, "BOX64 will force the used of emulated libs for "); + for (int i=0; i<context->box64_emulated_libs.size; ++i) + printf_log(LOG_INFO, "%s ", context->box64_emulated_libs.paths[i]); + printf_log(LOG_INFO, "\n"); + } + } + // add libssl and libcrypto (and a few other) to prefer emulated version because of multiple version exist + AddPath("libssl.so.1", &context->box64_emulated_libs, 0); + AddPath("libssl.so.1.0.0", &context->box64_emulated_libs, 0); + AddPath("libcrypto.so.1", &context->box64_emulated_libs, 0); + AddPath("libcrypto.so.1.0.0", &context->box64_emulated_libs, 0); + AddPath("libunwind.so.8", &context->box64_emulated_libs, 0); + AddPath("libpng12.so.0", &context->box64_emulated_libs, 0); + AddPath("libcurl.so.4", &context->box64_emulated_libs, 0); + AddPath("libtbbmalloc.so.2", &context->box64_emulated_libs, 0); + AddPath("libtbbmalloc_proxy.so.2", &context->box64_emulated_libs, 0); + + if(getenv("BOX64_SSE_FLUSHTO0")) { + if (strcmp(getenv("BOX64_SSE_FLUSHTO0"), "1")==0) { + box64_sse_flushto0 = 1; + printf_log(LOG_INFO, "BOX64: Direct apply of SSE Flush to 0 flag\n"); + } + } + if(getenv("BOX64_X87_NO80BITS")) { + if (strcmp(getenv("BOX64_X87_NO80BITS"), "1")==0) { + box64_x87_no80bits = 1; + printf_log(LOG_INFO, "BOX64: All 80bits x87 long double will be handle as double\n"); + } + } + if(getenv("BOX64_SYNC_ROUNDING")) { + if (strcmp(getenv("BOX64_SYNC_ROUNDING"), "1")==0) { + box64_sync_rounding = 1; + printf_log(LOG_INFO, "BOX64: Rouding mode with be synced with fesetround/fegetround\n"); + } + } + if(getenv("BOX64_PREFER_WRAPPED")) { + if (strcmp(getenv("BOX64_PREFER_WRAPPED"), "1")==0) { + box64_prefer_wrapped = 1; + printf_log(LOG_INFO, "BOX64: Prefering Wrapped libs\n"); + } + } + if(getenv("BOX64_PREFER_EMULATED")) { + if (strcmp(getenv("BOX64_PREFER_EMULATED"), "1")==0) { + box64_prefer_emulated = 1; + printf_log(LOG_INFO, "BOX64: Prefering Emulated libs\n"); + } + } + + if(getenv("BOX64_NOSIGSEGV")) { + if (strcmp(getenv("BOX64_NOSIGSEGV"), "1")==0) { + context->no_sigsegv = 1; + printf_log(LOG_INFO, "BOX64: Disabling handling of SigSEGV\n"); + } + } + if(getenv("BOX64_NOSIGILL")) { + if (strcmp(getenv("BOX64_NOSIGILL"), "1")==0) { + context->no_sigill = 1; + printf_log(LOG_INFO, "BOX64: Disabling handling of SigILL\n"); + } + } + // check BOX64_PATH and load it + LoadEnvPath(&context->box64_path, ".:bin", "BOX64_PATH"); + if(getenv("PATH")) + AppendList(&context->box64_path, getenv("PATH"), 1); // in case some of the path are for x86 world +#ifdef HAVE_TRACE + char* p = getenv("BOX64_TRACE"); + if(p) { + if (strcmp(p, "0")) { + context->x64trace = 1; + box64_trace = p; + } + } + p = getenv("BOX64_TRACE_INIT"); + if(p) { + if (strcmp(p, "0")) { + context->x64trace = 1; + trace_init = p; + } + } + if(my_context->x64trace) { + printf_log(LOG_INFO, "Initializing Zydis lib\n"); + if(InitX64Trace(my_context)) { + printf_log(LOG_INFO, "Zydis init failed. No x86 trace activated\n"); + context->x64trace = 0; + } + } +#endif +} + +EXPORTDYN +void setupTraceInit() +{ +#ifdef HAVE_TRACE + char* p = trace_init; + if(p) { + setbuf(stdout, NULL); + uintptr_t s_trace_start=0, s_trace_end=0; + if (strcmp(p, "1")==0) + SetTraceEmu(0, 0); + else if (strchr(p,'-')) { + if(sscanf(p, "%ld-%ld", &s_trace_start, &s_trace_end)!=2) { + if(sscanf(p, "0x%lX-0x%lX", &s_trace_start, &s_trace_end)!=2) + sscanf(p, "%lx-%lx", &s_trace_start, &s_trace_end); + } + if(s_trace_start || s_trace_end) + SetTraceEmu(s_trace_start, s_trace_end); + } else { + if (GetGlobalSymbolStartEnd(my_context->maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL, 0, NULL)) { + SetTraceEmu(s_trace_start, s_trace_end); + printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end); + } else if(GetLocalSymbolStartEnd(my_context->maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL, 0, NULL)) { + SetTraceEmu(s_trace_start, s_trace_end); + printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end); + } else { + printf_log(LOG_NONE, "Warning, Symbol to trace (\"%s\") not found, Disabling trace\n", p); + SetTraceEmu(0, 100); // disabling trace, mostly + } + } + } else { + p = box64_trace; + if(p) + if (strcmp(p, "0")) + SetTraceEmu(0, 1); + } +#endif +} + +void setupTraceMapLib(lib_t* maplib) +{ +#ifdef HAVE_TRACE + if(!trace_func) + return; + char* p = trace_func; + uintptr_t s_trace_start=0, s_trace_end=0; + if(maplib) { + if (GetGlobalSymbolStartEnd(maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL, 0, NULL)) { + SetTraceEmu(s_trace_start, s_trace_end); + printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end); + box_free(trace_func); + trace_func = NULL; + return; + } else if(GetLocalSymbolStartEnd(maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL, 0, NULL)) { + SetTraceEmu(s_trace_start, s_trace_end); + printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end); + box_free(trace_func); + trace_func = NULL; + return; + } else if(GetSymTabStartEnd(maplib, p, &s_trace_start, &s_trace_end)) { + SetTraceEmu(s_trace_start, s_trace_end); + printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end); + box_free(trace_func); + trace_func = NULL; + return; + } + } + if (my_context->elfs && GetGlobalSymbolStartEnd(my_context->maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL, 0, NULL)) { + SetTraceEmu(s_trace_start, s_trace_end); + printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end); + box_free(trace_func); + trace_func = NULL; + } else if(my_context->elfs && GetLocalSymbolStartEnd(my_context->maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL, 0, NULL)) { + SetTraceEmu(s_trace_start, s_trace_end); + printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end); + box_free(trace_func); + trace_func = NULL; + } else if(GetSymTabStartEnd(my_context->maplib, p, &s_trace_start, &s_trace_end)) { + SetTraceEmu(s_trace_start, s_trace_end); + printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end); + box_free(trace_func); + trace_func = NULL; + } else { + printf_log(LOG_NONE, "Warning, Symbol to trace (\"%s\") not found. Trying to set trace later\n", p); + SetTraceEmu(0, 1); // disabling trace, mostly + } +#endif +} + +EXPORTDYN +void setupTrace() +{ +#ifdef HAVE_TRACE + char* p = box64_trace; + if(p) { + setbuf(stdout, NULL); + uintptr_t s_trace_start=0, s_trace_end=0; + if (strcmp(p, "1")==0) + SetTraceEmu(0, 0); + else if (strchr(p,'-')) { + if(sscanf(p, "%ld-%ld", &s_trace_start, &s_trace_end)!=2) { + if(sscanf(p, "0x%lX-0x%lX", &s_trace_start, &s_trace_end)!=2) + sscanf(p, "%lx-%lx", &s_trace_start, &s_trace_end); + } + if(s_trace_start || s_trace_end) { + SetTraceEmu(s_trace_start, s_trace_end); + if(!s_trace_start && s_trace_end==1) { + printf_log(LOG_INFO, "TRACE enabled but inactive\n"); + } else { + printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end); + } + } + } else { + if (my_context->elfs && GetGlobalSymbolStartEnd(my_context->maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL, 0, NULL)) { + SetTraceEmu(s_trace_start, s_trace_end); + printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end); + } else if(my_context->elfs && GetLocalSymbolStartEnd(my_context->maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL, 0, NULL)) { + SetTraceEmu(s_trace_start, s_trace_end); + printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end); + } else { + printf_log(LOG_NONE, "Warning, Symbol to trace (\"%s\") not found. Trying to set trace later\n", p); + SetTraceEmu(0, 1); // disabling trace, mostly + if(trace_func) + box_free(trace_func); + trace_func = box_strdup(p); + } + } + } +#endif +} +#ifndef STATICBUILD +void endMallocHook(); +#endif + +void endBox64() +{ + if(!my_context || box64_quit) + return; + + // then call all the fini + dynarec_log(LOG_DEBUG, "endBox64() called\n"); + box64_quit = 1; + x64emu_t* emu = thread_get_emu(); + void startTimedExit(); + startTimedExit(); + // atexit first + printf_log(LOG_DEBUG, "Calling atexit registered functions (exiting box64)\n"); + CallAllCleanup(emu); + printf_log(LOG_DEBUG, "Calling fini for all loaded elfs and unload native libs\n"); + RunElfFini(my_context->elfs[0], emu); + void closeAllDLOpenned(); + closeAllDLOpenned(); // close residual dlopenned libs + // unload needed libs + needed_libs_t* needed = my_context->elfs[0]->needed; + printf_log(LOG_DEBUG, "Unloaded main elf: Will Dec RefCount of %d libs\n", needed?needed->size:0); + if(needed) + for(int i=0; i<needed->size; ++i) + DecRefCount(&needed->libs[i], emu); + // all done, free context + #ifndef STATICBUILD + endMallocHook(); + #endif + FreeBox64Context(&my_context); + #ifdef DYNAREC + // disable dynarec now + box64_dynarec = 0; + #endif + if(box64_libGL) { + box_free(box64_libGL); + box64_libGL = NULL; + } + if(box64_custom_gstreamer) { + box_free(box64_custom_gstreamer); + box64_custom_gstreamer = NULL; + } +} + + +static void free_contextargv() +{ + for(int i=0; i<my_context->argc; ++i) + box_free(my_context->argv[i]); +} + +static void add_argv(const char* what) { + int there = 0; + for(int i=1; i<my_context->argc && !there; ++i) + if(!strcmp(my_context->argv[i], what)) + there = 1; + if(!there) { + printf_log(LOG_INFO, "Inserting \"%s\" to the argments\n", what); + my_context->argv = (char**)box_realloc(my_context->argv, (my_context->argc+1)*sizeof(char*)); + my_context->argv[my_context->argc] = box_strdup(what); + my_context->argc++; + } +} + +static void load_rcfiles() +{ + #ifndef TERMUX + if(FileExist("/etc/box64.box64rc", IS_FILE)) + LoadRCFile("/etc/box64.box64rc"); + #else + if(FileExist("/data/data/com.termux/files/usr/etc/box64.box64rc", IS_FILE)) + LoadRCFile("/data/data/com.termux/files/usr/etc/box64.box64rc"); + #endif + + else + LoadRCFile(NULL); // load default rcfile + char* p = getenv("HOME"); + if(p) { + char tmp[4096]; + strncpy(tmp, p, 4095); + strncat(tmp, "/.box64rc", 4095); + if(FileExist(tmp, IS_FILE)) + LoadRCFile(tmp); + } +} + +#ifndef STATICBUILD +void pressure_vessel(int argc, const char** argv, int nextarg, const char* prog); +#endif +extern char** environ; + + +int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elfheader_t** elfheader, int exec) +{ + #ifndef STATICBUILD + init_malloc_hook(); + #endif + init_auxval(argc, argv, environ?environ:env); + // analogue to QEMU_VERSION in qemu-user-mode emulation + if(getenv("BOX64_VERSION")) { + PrintBox64Version(); + exit(0); + } + // trying to open and load 1st arg + if(argc==1) { + /*PrintBox64Version(); + PrintHelp(); + return 1;*/ + printf("BOX64: Missing operand after 'box64'\n"); + printf("See 'box64 --help' for more information.\n"); + exit(0); + } + if(argc>1 && !strcmp(argv[1], "/usr/bin/gdb") && getenv("BOX64_TRACE_FILE")) + exit(0); + // uname -m is redirected to box64 -m + if(argc==2 && (!strcmp(argv[1], "-m") || !strcmp(argv[1], "-p") || !strcmp(argv[1], "-i"))) + { + printf("x86_64\n"); + exit(0); + } + + // check BOX64_LOG debug level + LoadLogEnv(); + if(!getenv("BOX64_NORCFILES")) { + load_rcfiles(); + } + char* bashpath = NULL; + { + char* p = getenv("BOX64_BASH"); + if(p) { + if(FileIsX64ELF(p)) { + bashpath = p; + printf_log(LOG_INFO, "Using bash \"%s\"\n", bashpath); + } else { + printf_log(LOG_INFO, "The x86_64 bash \"%s\" is not an x86_64 binary.\n", p); + } + } + } + + const char* prog = argv[1]; + int nextarg = 1; + // check if some options are passed + while(prog && prog[0]=='-') { + if(!strcmp(prog, "-v") || !strcmp(prog, "--version")) { + PrintBox64Version(); + exit(0); + } + if(!strcmp(prog, "-h") || !strcmp(prog, "--help")) { + PrintHelp(); + exit(0); + } + if(!strcmp(prog, "-f") || !strcmp(prog, "--flags")) { + PrintFlags(); + exit(0); + } + // other options? + if(!strcmp(prog, "--")) { + prog = argv[++nextarg]; + break; + } + printf("Warning, Unrecognized option '%s'\n", prog); + prog = argv[++nextarg]; + } + if(!prog || nextarg==argc) { + printf("BOX64: Nothing to run\n"); + exit(0); + } + if(!box64_nobanner) + PrintBox64Version(); + // precheck, for win-preload + if(strstr(prog, "wine-preloader")==(prog+strlen(prog)-strlen("wine-preloader")) + || strstr(prog, "wine64-preloader")==(prog+strlen(prog)-strlen("wine64-preloader"))) { + // wine-preloader detecter, skipping it if next arg exist and is an x86 binary + int x64 = (nextarg<argc)?FileIsX64ELF(argv[nextarg]):0; + if(x64) { + prog = argv[++nextarg]; + printf_log(LOG_INFO, "BOX64: Wine preloader detected, loading \"%s\" directly\n", prog); + wine_preloaded = 1; + } + } + #ifndef STATICBUILD + // pre-check for pressure-vessel-wrap + if(strstr(prog, "pressure-vessel-wrap")==(prog+strlen(prog)-strlen("pressure-vessel-wrap"))) { + printf_log(LOG_INFO, "BOX64: pressure-vessel-wrap detected\n"); + pressure_vessel(argc, argv, nextarg+1, prog); + } + #endif + int ld_libs_args = -1; + int is_custom_gstreamer = 0; + const char* wine_prog = NULL; + // check if this is wine + if(!strcmp(prog, "wine64") + || !strcmp(prog, "wine64-development") + || !strcmp(prog, "wine") + || (strrchr(prog, '/') && !strcmp(strrchr(prog,'/'), "/wine")) + || (strrchr(prog, '/') && !strcmp(strrchr(prog,'/'), "/wine64"))) { + const char* prereserve = getenv("WINEPRELOADRESERVE"); + printf_log(LOG_INFO, "BOX64: Wine64 detected, WINEPRELOADRESERVE=\"%s\"\n", prereserve?prereserve:""); + if(wine_preloaded) { + wine_prereserve(prereserve); + } + // special case for winedbg, doesn't work anyway + if(argv[nextarg+1] && strstr(argv[nextarg+1], "winedbg")==argv[nextarg+1]) { + if(getenv("BOX64_WINEDBG")) { + box64_nobanner = 1; + box64_log = 0; + } else { + printf_log(LOG_NONE, "winedbg detected, not launching it!\n"); + exit(0); // exiting, it doesn't work anyway + } + } + box64_wine = 1; + // check if it's proton, with it's custom gstreamer build, to disable gtk3 loading + char tmp[strlen(prog)+100]; + strcpy(tmp, prog); + char* pp = strrchr(tmp, '/'); + if(pp) { + *pp = '\0'; // remove the wine binary call + strcat(tmp, "/../lib64/gstreamer-1.0"); + // check if it exist + if(FileExist(tmp, 0)) { + //printf_log(LOG_INFO, "BOX64: Custom gstreamer detected, disable gtk wrapping\n"); + //box64_nogtk = 1; + //is_custom_gstreamer = 1; + box64_custom_gstreamer = box_strdup(tmp); + } + } + // Try to get the name of the exe being run, to ApplyParams laters + if(argv[nextarg+1] && argv[nextarg+1][0]!='-' && strlen(argv[nextarg+1])>4 && !strcasecmp(argv[nextarg+1]+strlen(argv[nextarg+1])-4, ".exe")) { + const char* pp = strrchr(argv[nextarg+1], '/'); + if(pp) + wine_prog = pp+1; + else { + pp = strrchr(argv[nextarg+1], '\\'); + if(pp) + wine_prog = pp+1; + else + wine_prog = argv[nextarg+1]; + } + } + if(wine_prog) printf_log(LOG_INFO, "BOX64: Detected running wine with \"%s\"\n", wine_prog); + } else if(strstr(prog, "ld-musl-x86_64.so.1")) { + // check if ld-musl-x86_64.so.1 is used + printf_log(LOG_INFO, "BOX64: ld-musl detected. Trying to workaround and use system ld-linux\n"); + box64_musl = 1; + // skip ld-musl and go through args unti "--" is found, handling "--library-path" to add some libs to BOX64_LD_LIBRARY + ++nextarg; + while(strcmp(argv[nextarg], "--")) { + if(!strcmp(argv[nextarg], "--library-path")) { + ++nextarg; + ld_libs_args = nextarg; + } + ++nextarg; + } + ++nextarg; + prog = argv[nextarg]; + } + // check if this is wineserver + if(!strcmp(prog, "wineserver") || !strcmp(prog, "wineserver64") || (strlen(prog)>9 && !strcmp(prog+strlen(prog)-strlen("/wineserver"), "/wineserver"))) { + box64_wine = 1; + } + if(box64_wine) { + // disabling the use of futex_waitv for now + setenv("WINEFSYNC", "0", 1); + } + // Create a new context + my_context = NewBox64Context(argc - nextarg); + + // check BOX64_LD_LIBRARY_PATH and load it + LoadEnvVars(my_context); + // Append ld_list if it exist + if(ld_libs_args!=-1) + PrependList(&my_context->box64_ld_lib, argv[ld_libs_args], 1); + if(is_custom_gstreamer) + AddPath("libwayland-client.so.0", &my_context->box64_emulated_libs, 0); + + my_context->box64path = ResolveFile(argv[0], &my_context->box64_path); + // prepare all other env. var + my_context->envc = CountEnv(environ?environ:env); + printf_log(LOG_INFO, "Counted %d Env var\n", my_context->envc); + // allocate extra space for new environment variables such as BOX64_PATH + my_context->envv = (char**)box_calloc(my_context->envc+4, sizeof(char*)); + GatherEnv(&my_context->envv, environ?environ:env, my_context->box64path); + if(box64_dump || box64_log<=LOG_DEBUG) { + for (int i=0; i<my_context->envc; ++i) + printf_dump(LOG_DEBUG, " Env[%02d]: %s\n", i, my_context->envv[i]); + } + + path_collection_t ld_preload = {0}; + if(getenv("BOX64_LD_PRELOAD")) { + char* p = getenv("BOX64_LD_PRELOAD"); + ParseList(p, &ld_preload, 0); + if (ld_preload.size && box64_log) { + printf_log(LOG_INFO, "BOX64 trying to Preload "); + for (int i=0; i<ld_preload.size; ++i) + printf_log(LOG_INFO, "%s ", ld_preload.paths[i]); + printf_log(LOG_INFO, "\n"); + } + } else { + if(getenv("LD_PRELOAD")) { + char* p = getenv("LD_PRELOAD"); + if(strstr(p, "libtcmalloc_minimal.so.0")) + box64_tcmalloc_minimal = 1; + if(strstr(p, "libtcmalloc_minimal.so.4")) + box64_tcmalloc_minimal = 1; + if(strstr(p, "libtcmalloc_minimal_debug.so.4")) + box64_tcmalloc_minimal = 1; + if(strstr(p, "libasan.so")) + box64_tcmalloc_minimal = 1; // it seems Address Sanitizer doesn't handle dlsym'd malloc very well + ParseList(p, &ld_preload, 0); + if (ld_preload.size && box64_log) { + printf_log(LOG_INFO, "BOX64 trying to Preload "); + for (int i=0; i<ld_preload.size; ++i) + printf_log(LOG_INFO, "%s ", ld_preload.paths[i]); + printf_log(LOG_INFO, "\n"); + } + } + } + // print PATH and LD_LIB used + PrintCollection(&my_context->box64_ld_lib, "BOX64 LIB PATH"); + PrintCollection(&my_context->box64_path, "BOX64 BIN PATH"); + // lets build argc/argv stuff + printf_log(LOG_INFO, "Looking for %s\n", prog); + my_context->argv[0] = ResolveFile(prog, &my_context->box64_path); + // check if box86 is present + { + my_context->box86path = box_strdup(my_context->box64path); + char* p = strrchr(my_context->box86path, '6'); // get the 6 of box64 + p[0] = '8'; p[1] = '6'; // change 64 to 86 + if(!FileExist(my_context->box86path, IS_FILE)) { + box_free(my_context->box86path); + my_context->box86path = NULL; + } + } + const char* prgname = strrchr(prog, '/'); + if(!prgname) + prgname = prog; + else + ++prgname; + if(box64_wine) { + #ifdef ANDROID + AddPath("libdl.so", &ld_preload, 0); + #else + AddPath("libdl.so.2", &ld_preload, 0); + #endif + } + // special case for zoom + if(strstr(prgname, "zoom")==prgname) { + printf_log(LOG_INFO, "Zoom detected, Trying to use system libturbojpeg if possible\n"); + box64_zoom = 1; + } + // special case for bash (add BOX86_NOBANNER=1 if not there) + if(!strcmp(prgname, "bash")) { + printf_log(LOG_INFO, "bash detected, disabling banner\n"); + if (!box64_nobanner) { + setenv("BOX86_NOBANNER", "1", 0); + setenv("BOX64_NOBANNER", "1", 0); + } + if (!bashpath) { + bashpath = (char*)prog; + setenv("BOX64_BASH", prog, 1); + } + } + if(bashpath) + my_context->bashpath = box_strdup(bashpath); + + /*if(strstr(prgname, "awesomium_process")==prgname) { + printf_log(LOG_INFO, "awesomium_process detected, forcing emulated libpng12\n"); + AddPath("libpng12.so.0", &my_context->box64_emulated_libs, 0); + }*/ + /*if(!strcmp(prgname, "gdb")) { + exit(-1); + }*/ + ApplyParams("*"); // [*] is a special setting for all process + ApplyParams(prgname); + if(box64_wine && wine_prog) { + ApplyParams(wine_prog); + wine_prog = NULL; + } + if(box64_wine) + box64_maxcpu_immutable = 1; // cannot change once wine is loaded + + for(int i=1; i<my_context->argc; ++i) { + my_context->argv[i] = box_strdup(argv[i+nextarg]); + printf_log(LOG_INFO, "argv[%i]=\"%s\"\n", i, my_context->argv[i]); + } + if(box64_nosandbox) + { + add_argv("--no-sandbox"); + } + if(box64_inprocessgpu) + { + add_argv("--in-process-gpu"); + } + if(box64_cefdisablegpu) + { + add_argv("-cef-disable-gpu"); + } + if(box64_cefdisablegpucompositor) + { + add_argv("-cef-disable-gpu-compositor"); + } + + // check if file exist + if(!my_context->argv[0] || !FileExist(my_context->argv[0], IS_FILE)) { + printf_log(LOG_NONE, "Error: File is not found. (check BOX64_PATH)\n"); + free_contextargv(); + FreeBox64Context(&my_context); + FreeCollection(&ld_preload); + return -1; + } + if(!FileExist(my_context->argv[0], IS_FILE|IS_EXECUTABLE)) { + printf_log(LOG_NONE, "Error: %s is not an executable file.\n", my_context->argv[0]); + free_contextargv(); + FreeBox64Context(&my_context); + FreeCollection(&ld_preload); + return -1; + } + if(!(my_context->fullpath = box_realpath(my_context->argv[0], NULL))) + my_context->fullpath = box_strdup(my_context->argv[0]); + if(getenv("BOX64_ARG0")) + my_context->argv[0] = box_strdup(getenv("BOX64_ARG0")); + FILE *f = fopen(my_context->fullpath, "rb"); + if(!f) { + printf_log(LOG_NONE, "Error: Cannot open %s\n", my_context->fullpath); + free_contextargv(); + FreeBox64Context(&my_context); + FreeCollection(&ld_preload); + return -1; + } + elfheader_t *elf_header = LoadAndCheckElfHeader(f, my_context->fullpath, 1); + if(!elf_header) { + int x86 = my_context->box86path?FileIsX86ELF(my_context->fullpath):0; + int script = my_context->bashpath?FileIsShell(my_context->fullpath):0; + printf_log(LOG_NONE, "Error: Reading elf header of %s, Try to launch %s instead\n", my_context->fullpath, x86?"using box86":(script?"using bash":"natively")); + fclose(f); + FreeCollection(&ld_preload); + int ret; + if(x86) { + // duplicate the array and insert 1st arg as box86 + const char** newargv = (const char**)box_calloc(my_context->argc+2, sizeof(char*)); + newargv[0] = my_context->box86path; + for(int i=0; i<my_context->argc; ++i) + newargv[i+1] = my_context->argv[i]; + ret = execvp(newargv[0], (char * const*)newargv); + } else if (script) { + // duplicate the array and insert 1st arg as box64, 2nd is bash + const char** newargv = (const char**)box_calloc(my_context->argc+3, sizeof(char*)); + newargv[0] = my_context->box64path; + newargv[1] = my_context->bashpath; + for(int i=0; i<my_context->argc; ++i) + newargv[i+2] = my_context->argv[i]; + ret = execvp(newargv[0], (char * const*)newargv); + } else { + const char** newargv = (const char**)box_calloc(my_context->argc+1, sizeof(char*)); + for(int i=0; i<my_context->argc; ++i) + newargv[i] = my_context->argv[i]; + ret = execvp(newargv[0], (char * const*)newargv); + } + free_contextargv(); + FreeBox64Context(&my_context); + return ret; + } + AddElfHeader(my_context, elf_header); + *elfheader = elf_header; + + if(CalcLoadAddr(elf_header)) { + printf_log(LOG_NONE, "Error: Reading elf header of %s\n", my_context->fullpath); + FreeElfHeader(&elf_header); + free_contextargv(); + FreeBox64Context(&my_context); + FreeCollection(&ld_preload); + return -1; + } + // allocate memory and load elf + if(AllocLoadElfMemory(my_context, elf_header, 1)) { + printf_log(LOG_NONE, "Error: Loading elf %s\n", my_context->fullpath); + FreeElfHeader(&elf_header); + free_contextargv(); + FreeBox64Context(&my_context); + FreeCollection(&ld_preload); + return -1; + } + if(ElfCheckIfUseTCMallocMinimal(elf_header)) { + if(!box64_tcmalloc_minimal) { + // need to reload with tcmalloc_minimal as a LD_PRELOAD! + printf_log(LOG_INFO, "BOX64: tcmalloc_minimal.so.4 used. Reloading box64 with the lib preladed\n"); + // need to get a new envv variable. so first count it and check if LD_PRELOAD is there + int preload=(getenv("LD_PRELOAD"))?1:0; + int nenv = 0; + while(env[nenv]) nenv++; + // alloc + "LD_PRELOAD" if needd + last NULL ending + char** newenv = (char**)box_calloc(nenv+1+((preload)?0:1), sizeof(char*)); + // copy strings + for (int i=0; i<nenv; ++i) + newenv[i] = box_strdup(env[i]); + // add ld_preload + if(preload) { + // find the line + int l = 0; + while(l<nenv) { + if(strstr(newenv[l], "LD_PRELOAD=")==newenv[l]) { + // found it! + char *old = newenv[l]; + newenv[l] = (char*)box_calloc(strlen(old)+strlen("libtcmalloc_minimal.so.4:")+1, sizeof(char)); + strcpy(newenv[l], "LD_PRELOAD=libtcmalloc_minimal.so.4:"); + strcat(newenv[l], old + strlen("LD_PRELOAD=")); + box_free(old); + // done, end loop + l = nenv; + } else ++l; + } + } else { + //move last one + newenv[nenv] = box_strdup(newenv[nenv-1]); + box_free(newenv[nenv-1]); + newenv[nenv-1] = box_strdup("LD_PRELOAD=libtcmalloc_minimal.so.4"); + } + // duplicate argv too + char** newargv = box_calloc(argc+1, sizeof(char*)); + int narg = 0; + while(argv[narg]) {newargv[narg] = box_strdup(argv[narg]); narg++;} + // launch with new env... + if(execve(newargv[0], newargv, newenv)<0) + printf_log(LOG_NONE, "Failed to relaunch. Error is %d/%s\n", errno, strerror(errno)); + } else { + printf_log(LOG_INFO, "BOX64: Using tcmalloc_minimal.so.4, and it's in the LD_PRELOAD command\n"); + } + } +#if defined(RPI) || defined(RK3399) || defined(RK3326) + // before launching emulation, let's check if this is a mojosetup from GOG + if (((strstr(prog, "bin/linux/x86_64/mojosetup") && getenv("MOJOSETUP_BASE")) || strstr(prog, ".mojosetup/mojosetup")) + && getenv("GTK2_RC_FILES")) { + sanitize_mojosetup_gtk_background(); + } +#endif + // change process name + { + char* p = strrchr(my_context->fullpath, '/'); + if(p) + ++p; + else + p = my_context->fullpath; + if(prctl(PR_SET_NAME, p)==-1) + printf_log(LOG_NONE, "Error setting process name (%s)\n", strerror(errno)); + else + printf_log(LOG_INFO, "Rename process to \"%s\"\n", p); + if(strcmp(prgname, p)) + ApplyParams(p); + // and now all change the argv (so libs libs mesa find the correct program names) + char* endp = (char*)argv[argc-1]; + while(*endp) + ++endp; // find last argv[] address + uintptr_t diff = prog - argv[0]; // this is the difference we need to compensate + for(p=(char*)prog; p<=endp; ++p) + *(p - diff) = *p; // copy all element at argv[nextarg] to argv[0] + memset(endp - diff, 0, diff); // fill reminder with NULL + for(int i=nextarg; i<argc; ++i) + argv[i] -= diff; // adjust strings + my_context->orig_argc = argc; + my_context->orig_argv = (char**)argv; + } + box64_isglibc234 = GetNeededVersionForLib(elf_header, "libc.so.6", "GLIBC_2.34"); + if(box64_isglibc234) + printf_log(LOG_DEBUG, "Program linked with GLIBC 2.34+\n"); + // get and alloc stack size and align + if(CalcStackSize(my_context)) { + printf_log(LOG_NONE, "Error: Allocating stack\n"); + free_contextargv(); + FreeBox64Context(&my_context); + FreeCollection(&ld_preload); + return -1; + } + // init x86_64 emu + x64emu_t *emu = NewX64Emu(my_context, my_context->ep, (uintptr_t)my_context->stack, my_context->stacksz, 0); + // stack setup is much more complicated then just that! + SetupInitialStack(emu); // starting here, the argv[] don't need free anymore + SetupX64Emu(emu, NULL); + SetRSI(emu, my_context->argc); + SetRDX(emu, (uint64_t)my_context->argv); + SetRCX(emu, (uint64_t)my_context->envv); + SetRBP(emu, 0); // Frame pointer so to "No more frame pointer" + + // child fork to handle traces + pthread_atfork(NULL, NULL, my_child_fork); + + thread_set_emu(emu); + + // export symbols + AddSymbols(my_context->maplib, elf_header); + if(wine_preloaded) { + uintptr_t wineinfo = 0; + int ver = -1, veropt = 0; + const char* vername = NULL; + if(!ElfGetGlobalSymbolStartEnd(elf_header, &wineinfo, NULL, "wine_main_preload_info", &ver, &vername, 1, &veropt)) + if(!ElfGetWeakSymbolStartEnd(elf_header, &wineinfo, NULL, "wine_main_preload_info", &ver, &vername, 1, &veropt)) + ElfGetLocalSymbolStartEnd(elf_header, &wineinfo, NULL, "wine_main_preload_info", &ver, &vername, 1, &veropt); + if(!wineinfo) {printf_log(LOG_NONE, "Warning, Symbol wine_main_preload_info not found\n");} + else { + *(void**)wineinfo = get_wine_prereserve(); + printf_log(LOG_DEBUG, "WINE wine_main_preload_info found and updated %p -> %p\n", get_wine_prereserve(), *(void**)wineinfo); + } + #ifdef DYNAREC + dynarec_wine_prereserve(); + #endif + } + AddMainElfToLinkmap(elf_header); + // pre-load lib if needed + if(ld_preload.size) { + my_context->preload = new_neededlib(0); + for(int i=0; i<ld_preload.size; ++i) { + needed_libs_t* tmp = new_neededlib(1); + tmp->names[0] = ld_preload.paths[i]; + if(AddNeededLib(my_context->maplib, 0, 0, 0, tmp, elf_header, my_context, emu)) { + printf_log(LOG_INFO, "Warning, cannot pre-load %s\n", tmp->names[0]); + RemoveNeededLib(my_context->maplib, 0, tmp, my_context, emu); + } else { + for(int j=0; j<tmp->size; ++j) + add1lib_neededlib(my_context->preload, tmp->libs[j], tmp->names[j]); + } + free_neededlib(tmp); + } + } + FreeCollection(&ld_preload); + // Call librarian to load all dependant elf + if(LoadNeededLibs(elf_header, my_context->maplib, 0, 0, 0, my_context, emu)) { + printf_log(LOG_NONE, "Error: Loading needed libs in elf %s\n", my_context->argv[0]); + FreeBox64Context(&my_context); + return -1; + } + // reloc... + printf_log(LOG_DEBUG, "And now export symbols / relocation for %s...\n", ElfName(elf_header)); + if(RelocateElf(my_context->maplib, NULL, 0, 0, elf_header)) { + printf_log(LOG_NONE, "Error: Relocating symbols in elf %s\n", my_context->argv[0]); + FreeBox64Context(&my_context); + return -1; + } + // and handle PLT + RelocateElfPlt(my_context->maplib, NULL, 0, 0, elf_header); + // deferred init + setupTraceInit(); + RunDeferredElfInit(emu); + // update TLS of main elf + RefreshElfTLS(elf_header); + // do some special case check, _IO_2_1_stderr_ and friends, that are setup by libc, but it's already done here, so need to do a copy + ResetSpecialCaseMainElf(elf_header); + // init... + setupTrace(); + + *emulator = emu; + + return 0; +} + +int emulate(x64emu_t* emu, elfheader_t* elf_header) +{ + // get entrypoint + my_context->ep = GetEntryPoint(my_context->maplib, elf_header); + + atexit(endBox64); + loadProtectionFromMap(); + + // emulate! + printf_log(LOG_DEBUG, "Start x64emu on Main\n"); + // Stack is ready, with stacked: NULL env NULL argv argc + SetRIP(emu, my_context->ep); + ResetFlags(emu); + Push64(emu, my_context->exit_bridge); // push to pop it just after + SetRDX(emu, Pop64(emu)); // RDX is exit function + Run(emu, 0); + // Get EAX + int ret = GetEAX(emu); + printf_log(LOG_DEBUG, "Emulation finished, EAX=%d\n", ret); + endBox64(); +#ifdef HAVE_TRACE + if(trace_func) { + box_free(trace_func); + trace_func = NULL; + } +#endif + + return ret; +} \ No newline at end of file diff --git a/src/include/core.h b/src/include/core.h new file mode 100644 index 00000000..c9fec47c --- /dev/null +++ b/src/include/core.h @@ -0,0 +1,13 @@ +#ifndef __CORE_H +#define __CORE_H + +#include "custommem.h" +#include "callback.h" +#include "library.h" + +// exec : 0 = lib, 1 = exec +int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elfheader_t** elfheader, int exec); + +int emulate(x64emu_t* emu, elfheader_t* elf_header); + +#endif // __CORE_H \ No newline at end of file diff --git a/src/main.c b/src/main.c index 38c44df1..5f73ab4b 100644 --- a/src/main.c +++ b/src/main.c @@ -1,2163 +1,12 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <limits.h> -#include <errno.h> -#include <unistd.h> -#include <dirent.h> -#include <signal.h> -#include <sys/syscall.h> -#include <sys/mman.h> -#include <pthread.h> -#include <sys/prctl.h> -#include <stdarg.h> -#ifdef DYNAREC -#ifdef ARM64 -#include <linux/auxvec.h> -#include <asm/hwcap.h> -#endif -#endif +#include "core.h" -#include "build_info.h" -#include "debug.h" -#include "fileutils.h" -#include "box64context.h" -#include "wine_tools.h" -#include "elfloader.h" -#include "custommem.h" -#include "box64stack.h" -#include "auxval.h" -#include "x64emu.h" -#include "threads.h" -#include "x64trace.h" -#include "librarian.h" -#include "x64run.h" -#include "symbols.h" -#include "rcfile.h" -#include "emu/x64run_private.h" -#include "elfs/elfloader_private.h" -#include "library.h" - -box64context_t *my_context = NULL; -int box64_quit = 0; -int box64_exit_code = 0; -int box64_log = LOG_INFO; //LOG_NONE; -int box64_dump = 0; -int box64_nobanner = 0; -int box64_dynarec_log = LOG_NONE; -uintptr_t box64_pagesize; -uintptr_t box64_load_addr = 0; -int box64_nosandbox = 0; -int box64_inprocessgpu = 0; -int box64_cefdisablegpu = 0; -int box64_cefdisablegpucompositor = 0; -int box64_malloc_hack = 0; -int box64_dynarec_test = 0; -int box64_maxcpu = 0; -int box64_maxcpu_immutable = 0; -#if defined(SD845) || defined(SD888) || defined(SD8G2) || defined(TEGRAX1) -int box64_mmap32 = 1; -#else -int box64_mmap32 = 0; -#endif -int box64_ignoreint3 = 0; -int box64_rdtsc = 0; -uint8_t box64_rdtsc_shift = 0; -#ifdef DYNAREC -int box64_dynarec = 1; -int box64_dynarec_dump = 0; -int box64_dynarec_forced = 0; -int box64_dynarec_bigblock = 1; -int box64_dynarec_forward = 128; -int box64_dynarec_strongmem = 0; -int box64_dynarec_x87double = 0; -int box64_dynarec_div0 = 0; -int box64_dynarec_fastnan = 1; -int box64_dynarec_fastround = 1; -int box64_dynarec_safeflags = 1; -int box64_dynarec_callret = 0; -int box64_dynarec_bleeding_edge = 1; -int box64_dynarec_jvm = 1; -int box64_dynarec_tbb = 1; -int box64_dynarec_wait = 1; -int box64_dynarec_missing = 0; -int box64_dynarec_aligned_atomics = 0; -uintptr_t box64_nodynarec_start = 0; -uintptr_t box64_nodynarec_end = 0; -#ifdef ARM64 -int arm64_asimd = 0; -int arm64_aes = 0; -int arm64_pmull = 0; -int arm64_crc32 = 0; -int arm64_atomics = 0; -int arm64_sha1 = 0; -int arm64_sha2 = 0; -int arm64_uscat = 0; -int arm64_flagm = 0; -int arm64_flagm2 = 0; -int arm64_frintts = 0; -int arm64_afp = 0; -#elif defined(RV64) -int rv64_zba = 0; -int rv64_zbb = 0; -int rv64_zbc = 0; -int rv64_zbs = 0; -int rv64_xtheadba = 0; -int rv64_xtheadbb = 0; -int rv64_xtheadbs = 0; -int rv64_xtheadcondmov = 0; -int rv64_xtheadmemidx = 0; -int rv64_xtheadmempair = 0; -int rv64_xtheadfmemidx = 0; -int rv64_xtheadmac = 0; -int rv64_xtheadfmv = 0; -#elif defined(LA64) -int la64_lbt = 0; -#endif -#else //DYNAREC -int box64_dynarec = 0; -#endif -int box64_libcef = 1; -int box64_sdl2_jguid = 0; -int dlsym_error = 0; -int cycle_log = 0; -#ifdef HAVE_TRACE -int trace_xmm = 0; -int trace_emm = 0; -int trace_regsdiff = 0; -uint64_t start_cnt = 0; -uintptr_t trace_start = 0, trace_end = 0; -char* trace_func = NULL; -char* trace_init = NULL; -char* box64_trace = NULL; -#ifdef DYNAREC -int box64_dynarec_trace = 0; -#endif -#endif -int box64_x11threads = 0; -int box64_x11glx = 1; -int allow_missing_libs = 0; -int box64_prefer_emulated = 0; -int box64_prefer_wrapped = 0; -int box64_sse_flushto0 = 0; -int box64_x87_no80bits = 0; -int box64_sync_rounding = 0; -int fix_64bit_inodes = 0; -int box64_dummy_crashhandler = 1; -int box64_mapclean = 0; -int box64_zoom = 0; -int box64_steam = 0; -int box64_wine = 0; -int box64_musl = 0; -int box64_nopulse = 0; -int box64_nogtk = 0; -int box64_novulkan = 0; -int box64_showsegv = 0; -int box64_showbt = 0; -int box64_isglibc234 = 0; -#ifdef BAD_SIGNAL -int box64_futex_waitv = 0; -#else -int box64_futex_waitv = 1; -#endif -char* box64_libGL = NULL; -char* box64_custom_gstreamer = NULL; -uintptr_t fmod_smc_start = 0; -uintptr_t fmod_smc_end = 0; -uint32_t default_gs = 0x53; -int jit_gdb = 0; -int box64_tcmalloc_minimal = 0; - -FILE* ftrace = NULL; -char* ftrace_name = NULL; -int ftrace_has_pid = 0; - -void openFTrace(const char* newtrace) -{ - const char* t = newtrace?newtrace:getenv("BOX64_TRACE_FILE"); - #ifndef MAX_PATH - #define MAX_PATH 4096 - #endif - char tmp[MAX_PATH]; - char tmp2[MAX_PATH]; - const char* p = t; - int append=0; - if(p && strlen(p) && p[strlen(p)-1]=='+') { - strncpy(tmp2, p, sizeof(tmp2)); - tmp2[strlen(p)-1]='\0'; - p = tmp2; - append=1; - } - if(p && strstr(p, "%pid")) { - int next = 0; - do { - strcpy(tmp, p); - char* c = strstr(tmp, "%pid"); - *c = 0; // cut - char pid[16]; - if(next) - sprintf(pid, "%d-%d", getpid(), next); - else - sprintf(pid, "%d", getpid()); - strcat(tmp, pid); - c = strstr(p, "%pid") + strlen("%pid"); - strcat(tmp, c); - ++next; - } while (FileExist(tmp, IS_FILE) && !append); - p = tmp; - ftrace_has_pid = 1; - } - if(ftrace_name) - free(ftrace_name); - ftrace_name = NULL; - if(p) { - if(!strcmp(p, "stderr")) - ftrace = stderr; - else { - if(append) - ftrace = fopen(p, "w+"); - else - ftrace = fopen(p, "w"); - if(!ftrace) { - ftrace = stdout; - printf_log(LOG_INFO, "Cannot open trace file \"%s\" for writing (error=%s)\n", p, strerror(errno)); - } else { - ftrace_name = strdup(p); - /*fclose(ftrace); - ftrace = NULL;*/ - if(!box64_nobanner) - printf("BOX64 Trace %s to \"%s\"\n", append?"appended":"redirected", p); - PrintBox64Version(); - } - } - } -} - -void printf_ftrace(const char* fmt, ...) -{ - if(ftrace_name) { - int fd = fileno(ftrace); - if(fd<0 || lseek(fd, 0, SEEK_CUR)==(off_t)-1) - ftrace=fopen(ftrace_name, "w+"); - } - - va_list args; - va_start(args, fmt); - vfprintf(ftrace, fmt, args); - - fflush(ftrace); - - va_end(args); -} - -void my_child_fork() -{ - if(ftrace_has_pid) { - // open a new ftrace... - if(!ftrace_name) - fclose(ftrace); - openFTrace(NULL); - printf_log(/*LOG_DEBUG*/LOG_INFO, "Forked child of %s\n", GetLastApplyName()); - } -} - -const char* getCpuName(); -int getNCpu(); -#ifdef DYNAREC -void GatherDynarecExtensions() -{ - if(box64_dynarec==0) // no need to check if no dynarec - return; -#ifdef ARM64 -/* -HWCAP_FP - Functionality implied by ID_AA64PFR0_EL1.FP == 0b0000. -HWCAP_ASIMD - Functionality implied by ID_AA64PFR0_EL1.AdvSIMD == 0b0000. -HWCAP_EVTSTRM - The generic timer is configured to generate events at a frequency of - approximately 10KHz. -HWCAP_AES - Functionality implied by ID_AA64ISAR0_EL1.AES == 0b0001. => AESE, AESD, AESMC, and AESIMC instructions are implemented -HWCAP_PMULL - Functionality implied by ID_AA64ISAR0_EL1.AES == 0b0010. => AESE, AESD, AESMC, and AESIMC instructions are implemented plus PMULL/PMULL2 instructions operating on 64-bit data quantities. -HWCAP_SHA1 - Functionality implied by ID_AA64ISAR0_EL1.SHA1 == 0b0001. => SHA1C, SHA1P, SHA1M, SHA1H, SHA1SU0, and SHA1SU1 instructions implemented. -HWCAP_SHA2 - Functionality implied by ID_AA64ISAR0_EL1.SHA2 == 0b0001. => SHA256H, SHA256H2, SHA256SU0 and SHA256SU1 instructions implemented. -HWCAP_CRC32 - Functionality implied by ID_AA64ISAR0_EL1.CRC32 == 0b0001. => CRC32B, CRC32H, CRC32W, CRC32X, CRC32CB, CRC32CH, CRC32CW, and CRC32CX instructions implemented. -HWCAP_ATOMICS - Functionality implied by ID_AA64ISAR0_EL1.Atomic == 0b0010. => LDADD, LDCLR, LDEOR, LDSET, LDSMAX, LDSMIN, LDUMAX, LDUMIN, CAS, CASP, and SWP instructions implemented. -HWCAP_FPHP - Functionality implied by ID_AA64PFR0_EL1.FP == 0b0001. -HWCAP_ASIMDHP - Functionality implied by ID_AA64PFR0_EL1.AdvSIMD == 0b0001. -HWCAP_CPUID - EL0 access to certain ID registers is available. - These ID registers may imply the availability of features. -HWCAP_ASIMDRDM - Functionality implied by ID_AA64ISAR0_EL1.RDM == 0b0001. => SQRDMLAH and SQRDMLSH instructions implemented. -HWCAP_JSCVT - Functionality implied by ID_AA64ISAR1_EL1.JSCVT == 0b0001. => The FJCVTZS instruction is implemented. -HWCAP_FCMA - Functionality implied by ID_AA64ISAR1_EL1.FCMA == 0b0001. => The FCMLA and FCADD instructions are implemented. -HWCAP_LRCPC - Functionality implied by ID_AA64ISAR1_EL1.LRCPC == 0b0001. => LDAPR and variants -HWCAP_DCPOP - Functionality implied by ID_AA64ISAR1_EL1.DPB == 0b0001. -HWCAP_SHA3 - Functionality implied by ID_AA64ISAR0_EL1.SHA3 == 0b0001. => EOR3, RAX1, XAR, and BCAX instructions implemented. -HWCAP_SM3 - Functionality implied by ID_AA64ISAR0_EL1.SM3 == 0b0001. => SM3SS1, SM3TT1A, SM3TT1B, SM3TT2A, SM3TT2B, SM3PARTW1, and SM3PARTW2 instructions implemented. -HWCAP_SM4 - Functionality implied by ID_AA64ISAR0_EL1.SM4 == 0b0001. => SM4E and SM4EKEY instructions implemented. -HWCAP_ASIMDDP - Functionality implied by ID_AA64ISAR0_EL1.DP == 0b0001. => UDOT and SDOT instructions implemented. -HWCAP_SHA512 - Functionality implied by ID_AA64ISAR0_EL1.SHA2 == 0b0010. => SHA512H, SHA512H2, SHA512SU0, and SHA512SU1 instructions implemented. -HWCAP_SVE - Functionality implied by ID_AA64PFR0_EL1.SVE == 0b0001. -HWCAP_ASIMDFHM - Functionality implied by ID_AA64ISAR0_EL1.FHM == 0b0001. => FMLAL and FMLSL instructions are implemented. -HWCAP_DIT - Functionality implied by ID_AA64PFR0_EL1.DIT == 0b0001. -HWCAP_USCAT - Functionality implied by ID_AA64MMFR2_EL1.AT == 0b0001. -HWCAP_ILRCPC - Functionality implied by ID_AA64ISAR1_EL1.LRCPC == 0b0010. => The LDAPUR*, STLUR*, and LDAPR* instructions are implemented. -HWCAP_FLAGM - Functionality implied by ID_AA64ISAR0_EL1.TS == 0b0001. -HWCAP_SSBS - Functionality implied by ID_AA64PFR1_EL1.SSBS == 0b0010. => AArch64 provides the PSTATE.SSBS mechanism to mark regions that are Speculative Store Bypassing Safe, and the MSR and MRS instructions to directly read and write the PSTATE.SSBS field. -HWCAP_SB - Functionality implied by ID_AA64ISAR1_EL1.SB == 0b0001. => SB instruction is implemented. -HWCAP_PACA - Functionality implied by ID_AA64ISAR1_EL1.APA == 0b0001 or - ID_AA64ISAR1_EL1.API == 0b0001. -HWCAP_PACG - Functionality implied by ID_AA64ISAR1_EL1.GPA == 0b0001 or => Generic Authentication using the QARMA algorithm is implemented. This includes the PACGA instruction. - ID_AA64ISAR1_EL1.GPI == 0b0001. -HWCAP2_DCPODP - Functionality implied by ID_AA64ISAR1_EL1.DPB == 0b0010. => DC CVAP and DC CVADP supported -HWCAP2_SVE2 - Functionality implied by ID_AA64ZFR0_EL1.SVEVer == 0b0001. -HWCAP2_SVEAES - Functionality implied by ID_AA64ZFR0_EL1.AES == 0b0001. -HWCAP2_SVEPMULL - Functionality implied by ID_AA64ZFR0_EL1.AES == 0b0010. -HWCAP2_SVEBITPERM - Functionality implied by ID_AA64ZFR0_EL1.BitPerm == 0b0001. -HWCAP2_SVESHA3 - Functionality implied by ID_AA64ZFR0_EL1.SHA3 == 0b0001. -HWCAP2_SVESM4 - Functionality implied by ID_AA64ZFR0_EL1.SM4 == 0b0001. -HWCAP2_FLAGM2 - Functionality implied by ID_AA64ISAR0_EL1.TS == 0b0010. => CFINV, RMIF, SETF16, SETF8, AXFLAG, and XAFLAG instructions are implemented. -HWCAP2_FRINT - Functionality implied by ID_AA64ISAR1_EL1.FRINTTS == 0b0001. => FRINT32Z, FRINT32X, FRINT64Z, and FRINT64X instructions are implemented. -HWCAP2_SVEI8MM - Functionality implied by ID_AA64ZFR0_EL1.I8MM == 0b0001. -HWCAP2_SVEF32MM - Functionality implied by ID_AA64ZFR0_EL1.F32MM == 0b0001. -HWCAP2_SVEF64MM - Functionality implied by ID_AA64ZFR0_EL1.F64MM == 0b0001. -HWCAP2_SVEBF16 - Functionality implied by ID_AA64ZFR0_EL1.BF16 == 0b0001 -HWCAP2_I8MM - Functionality implied by ID_AA64ISAR1_EL1.I8MM == 0b0001. => SMMLA, SUDOT, UMMLA, USMMLA, and USDOT instructions are implemented -HWCAP2_BF16 - Functionality implied by ID_AA64ISAR1_EL1.BF16 == 0b0001. => BFDOT, BFMLAL, BFMLAL2, BFMMLA, BFCVT, and BFCVT2 instructions are implemented. -HWCAP2_DGH - Functionality implied by ID_AA64ISAR1_EL1.DGH == 0b0001. => Data Gathering Hint is implemented. -HWCAP2_RNG - Functionality implied by ID_AA64ISAR0_EL1.RNDR == 0b0001. -HWCAP2_BTI - Functionality implied by ID_AA64PFR0_EL1.BT == 0b0001. -HWCAP2_MTE - Functionality implied by ID_AA64PFR1_EL1.MTE == 0b0010. => Full Memory Tagging Extension is implemented. -HWCAP2_ECV - Functionality implied by ID_AA64MMFR0_EL1.ECV == 0b0001. -*/ - unsigned long hwcap = real_getauxval(AT_HWCAP); - if(!hwcap) // no HWCap: provide a default... - hwcap = HWCAP_ASIMD; - // first, check all needed extensions, lif half, edsp and fastmult - if((hwcap&HWCAP_ASIMD) == 0) { - printf_log(LOG_INFO, "Missing ASMID cpu support, disabling Dynarec\n"); - box64_dynarec=0; - return; - } - if(hwcap&HWCAP_CRC32) - arm64_crc32 = 1; - if(hwcap&HWCAP_PMULL) - arm64_pmull = 1; - if(hwcap&HWCAP_AES) - arm64_aes = 1; - // ATOMIC use are disable for now. They crashes Batman Arkham Knight, bossibly other (also seems to make steamwebhelper unstable) - if(hwcap&HWCAP_ATOMICS) - arm64_atomics = 1; - #ifdef HWCAP_SHA1 - if(hwcap&HWCAP_SHA1) - arm64_sha1 = 1; - #endif - #ifdef HWCAP_SHA2 - if(hwcap&HWCAP_SHA2) - arm64_sha2 = 1; - #endif - #ifdef HWCAP_USCAT - if(hwcap&HWCAP_USCAT) - arm64_uscat = 1; - #endif - #ifdef HWCAP_FLAGM - if(hwcap&HWCAP_FLAGM) - arm64_flagm = 1; - #endif - unsigned long hwcap2 = real_getauxval(AT_HWCAP2); - #ifdef HWCAP2_FLAGM2 - if(hwcap2&HWCAP2_FLAGM2) - arm64_flagm2 = 1; - #endif - #ifdef HWCAP2_FRINT - if(hwcap2&HWCAP2_FRINT) - arm64_frintts = 1; - #endif - #ifdef HWCAP2_AFP - if(hwcap2&HWCAP2_AFP) - arm64_afp = 1; - #endif - printf_log(LOG_INFO, "Dynarec for ARM64, with extension: ASIMD"); - if(arm64_aes) - printf_log(LOG_INFO, " AES"); - if(arm64_crc32) - printf_log(LOG_INFO, " CRC32"); - if(arm64_pmull) - printf_log(LOG_INFO, " PMULL"); - if(arm64_atomics) - printf_log(LOG_INFO, " ATOMICS"); - if(arm64_sha1) - printf_log(LOG_INFO, " SHA1"); - if(arm64_sha2) - printf_log(LOG_INFO, " SHA2"); - if(arm64_uscat) - printf_log(LOG_INFO, " USCAT"); - if(arm64_flagm) - printf_log(LOG_INFO, " FLAGM"); - if(arm64_flagm2) - printf_log(LOG_INFO, " FLAGM2"); - if(arm64_frintts) - printf_log(LOG_INFO, " FRINT"); - if(arm64_afp) - printf_log(LOG_INFO, " AFP"); -#elif defined(LA64) - printf_log(LOG_INFO, "Dynarec for LoongArch "); - char* p = getenv("BOX64_DYNAREC_LA64NOEXT"); - if(p == NULL || p[0] == '0') { - uint32_t cpucfg2 = 0, idx = 2; - // there are other extensions, but we don't care. - asm volatile("cpucfg %0, %1" : "=r"(cpucfg2) : "r"(idx)); - if (la64_lbt = (cpucfg2 >> 18) & 0b1) - printf_log(LOG_INFO, "with extension LBT_X86"); - } -#elif defined(RV64) - void RV64_Detect_Function(); - char *p = getenv("BOX64_DYNAREC_RV64NOEXT"); - if(p == NULL || p[0] == '0') - RV64_Detect_Function(); - printf_log(LOG_INFO, "Dynarec for RISC-V "); - printf_log(LOG_INFO, "With extension: I M A F D C"); - if(rv64_zba) printf_log(LOG_INFO, " Zba"); - if(rv64_zbb) printf_log(LOG_INFO, " Zbb"); - if(rv64_zbc) printf_log(LOG_INFO, " Zbc"); - if(rv64_zbs) printf_log(LOG_INFO, " Zbs"); - if(rv64_xtheadba) printf_log(LOG_INFO, " XTheadBa"); - if(rv64_xtheadbb) printf_log(LOG_INFO, " XTheadBb"); - if(rv64_xtheadbs) printf_log(LOG_INFO, " XTheadBs"); - if(rv64_xtheadcondmov) printf_log(LOG_INFO, " XTheadCondMov"); - if(rv64_xtheadmemidx) printf_log(LOG_INFO, " XTheadMemIdx"); - if(rv64_xtheadmempair) printf_log(LOG_INFO, " XTheadMemPair"); - if(rv64_xtheadfmemidx) printf_log(LOG_INFO, " XTheadFMemIdx"); - if(rv64_xtheadmac) printf_log(LOG_INFO, " XTheadMac"); - if(rv64_xtheadfmv) printf_log(LOG_INFO, " XTheadFmv"); -#else -#error Unsupported architecture -#endif -} -#endif - - -EXPORTDYN -void LoadLogEnv() -{ - ftrace = stdout; - box64_nobanner = isatty(fileno(stdout))?0:1; - const char *p = getenv("BOX64_NOBANNER"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='1') - box64_nobanner = p[0]-'0'; - } - } - // grab BOX64_TRACE_FILE envvar, and change %pid to actual pid is present in the name - openFTrace(NULL); - box64_log = ftrace_name?LOG_INFO:(isatty(fileno(stdout))?LOG_INFO:LOG_NONE); //default LOG value different if stdout is redirected or not - p = getenv("BOX64_LOG"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0'+LOG_NONE && p[0]<='0'+LOG_NEVER) { - box64_log = p[0]-'0'; - if(box64_log == LOG_NEVER) { - --box64_log; - box64_dump = 1; - } - } - } else { - if(!strcasecmp(p, "NONE")) - box64_log = LOG_NONE; - else if(!strcasecmp(p, "INFO")) - box64_log = LOG_INFO; - else if(!strcasecmp(p, "DEBUG")) - box64_log = LOG_DEBUG; - else if(!strcasecmp(p, "DUMP")) { - box64_log = LOG_DEBUG; - box64_dump = 1; - } - } - if(!box64_nobanner) - printf_log(LOG_INFO, "Debug level is %d\n", box64_log); - } - -#if !defined(DYNAREC) && (defined(ARM64) || defined(RV64) || defined(LA64)) - printf_log(LOG_INFO, "Warning: DynaRec is available on this host architecture, an interpreter-only build is probably not intended.\n"); -#endif - - p = getenv("BOX64_ROLLING_LOG"); - if(p) { - int cycle = 0; - if(sscanf(p, "%d", &cycle)==1) - cycle_log = cycle; - if(cycle_log==1) - cycle_log = 16; - if(cycle_log<0) - cycle_log = 0; - if(cycle_log && box64_log>LOG_INFO) { - cycle_log = 0; - printf_log(LOG_NONE, "Incompatible Rolling log and Debug Log, disabling Rolling log\n"); - } - } - if(!box64_nobanner && cycle_log) - printf_log(LOG_INFO, "Rolling log, showing last %d function call on signals\n", cycle_log); - p = getenv("BOX64_DUMP"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='1') - box64_dump = p[0]-'0'; - } - } - if(!box64_nobanner && box64_dump) - printf_log(LOG_INFO, "Elf Dump if ON\n"); -#ifdef DYNAREC - #ifdef ARM64 - // unaligned atomic (with restriction) is supported in hardware - /*if(arm64_uscat) - box64_dynarec_aligned_atomics = 1;*/ // the unaligned support is not good enough for x86 emulation, so diabling - #endif - p = getenv("BOX64_DYNAREC_DUMP"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='2') - box64_dynarec_dump = p[0]-'0'; - } - if (box64_dynarec_dump) printf_log(LOG_INFO, "Dynarec blocks are dumped%s\n", (box64_dynarec_dump>1)?" in color":""); - } - p = getenv("BOX64_DYNAREC_LOG"); - if(p) { - if(strlen(p)==1) { - if((p[0]>='0'+LOG_NONE) && (p[0]<='0'+LOG_NEVER)) - box64_dynarec_log = p[0]-'0'; - } else { - if(!strcasecmp(p, "NONE")) - box64_dynarec_log = LOG_NONE; - else if(!strcasecmp(p, "INFO")) - box64_dynarec_log = LOG_INFO; - else if(!strcasecmp(p, "DEBUG")) - box64_dynarec_log = LOG_DEBUG; - else if(!strcasecmp(p, "VERBOSE")) - box64_dynarec_log = LOG_VERBOSE; - } - printf_log(LOG_INFO, "Dynarec log level is %d\n", box64_dynarec_log); - } - p = getenv("BOX64_DYNAREC"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='1') - box64_dynarec = p[0]-'0'; - } - printf_log(LOG_INFO, "Dynarec is %s\n", box64_dynarec?"on":"off"); - } - p = getenv("BOX64_DYNAREC_FORCED"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='1') - box64_dynarec_forced = p[0]-'0'; - } - if(box64_dynarec_forced) - printf_log(LOG_INFO, "Dynarec is forced on all addresses\n"); - } - p = getenv("BOX64_DYNAREC_BIGBLOCK"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='3') - box64_dynarec_bigblock = p[0]-'0'; - } - if(!box64_dynarec_bigblock) - printf_log(LOG_INFO, "Dynarec will not try to make big block\n"); - else if (box64_dynarec_bigblock>1) - printf_log(LOG_INFO, "Dynarec will try to make bigger blocks%s\n", (box64_dynarec_bigblock>2)?" even on non-elf memory":""); - - } - p = getenv("BOX64_DYNAREC_FORWARD"); - if(p) { - int val = -1; - if(sscanf(p, "%d", &val)==1) { - if(val>=0) - box64_dynarec_forward = val; - } - if(box64_dynarec_forward) - printf_log(LOG_INFO, "Dynarec will continue block for %d bytes on forward jump\n", box64_dynarec_forward); - else - printf_log(LOG_INFO, "Dynarec will not continue block on forward jump\n"); - } - p = getenv("BOX64_DYNAREC_STRONGMEM"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='4') - box64_dynarec_strongmem = p[0]-'0'; - } - if(box64_dynarec_strongmem) - printf_log(LOG_INFO, "Dynarec will try to emulate a strong memory model%s\n", (box64_dynarec_strongmem==1)?" with limited performance loss":((box64_dynarec_strongmem>1)?" with more performance loss":"")); - } - p = getenv("BOX64_DYNAREC_X87DOUBLE"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='1') - box64_dynarec_x87double = p[0]-'0'; - } - if(box64_dynarec_x87double) - printf_log(LOG_INFO, "Dynarec will use only double for x87 emulation\n"); - } - p = getenv("BOX64_DYNAREC_DIV0"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='1') - box64_dynarec_div0 = p[0]-'0'; - } - if(box64_dynarec_div0) - printf_log(LOG_INFO, "Dynarec will check for divide by 0\n"); - } - p = getenv("BOX64_DYNAREC_FASTNAN"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='1') - box64_dynarec_fastnan = p[0]-'0'; - } - if(!box64_dynarec_fastnan) - printf_log(LOG_INFO, "Dynarec will try to normalize generated NAN\n"); - } - p = getenv("BOX64_DYNAREC_FASTROUND"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='1') - box64_dynarec_fastround = p[0]-'0'; - } - if(!box64_dynarec_fastround) - printf_log(LOG_INFO, "Dynarec will try tp generate x86 precise IEEE->int rounding\n"); - } - p = getenv("BOX64_DYNAREC_SAFEFLAGS"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='2') - box64_dynarec_safeflags = p[0]-'0'; - } - if(!box64_dynarec_safeflags) - printf_log(LOG_INFO, "Dynarec will not play it safe with x64 flags\n"); - else - printf_log(LOG_INFO, "Dynarec will play %s safe with x64 flags\n", (box64_dynarec_safeflags==1)?"moderatly":"it"); - } - p = getenv("BOX64_DYNAREC_CALLRET"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='1') - box64_dynarec_callret = p[0]-'0'; - } - if(box64_dynarec_callret) - printf_log(LOG_INFO, "Dynarec will optimize CALL/RET\n"); - else - printf_log(LOG_INFO, "Dynarec will not optimize CALL/RET\n"); - } - p = getenv("BOX64_DYNAREC_BLEEDING_EDGE"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='1') - box64_dynarec_bleeding_edge = p[0]-'0'; - } - if(!box64_dynarec_bleeding_edge) - printf_log(LOG_INFO, "Dynarec will not detect MonoBleedingEdge\n"); - } - p = getenv("BOX64_DYNAREC_JVM"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='1') - box64_dynarec_jvm = p[0]-'0'; - } - if(!box64_dynarec_jvm) - printf_log(LOG_INFO, "Dynarec will not detect libjvm\n"); - } - p = getenv("BOX64_DYNAREC_TBB"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='1') - box64_dynarec_tbb = p[0]-'0'; - } - if(!box64_dynarec_tbb) - printf_log(LOG_INFO, "Dynarec will not detect libtbb\n"); - } - p = getenv("BOX64_DYNAREC_WAIT"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='1') - box64_dynarec_wait = p[0]-'0'; - } - if(!box64_dynarec_wait) - printf_log(LOG_INFO, "Dynarec will not wait for FillBlock to ready and use Interpreter instead\n"); - } - p = getenv("BOX64_DYNAREC_ALIGNED_ATOMICS"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='1') - box64_dynarec_aligned_atomics = p[0]-'0'; - } - if(box64_dynarec_aligned_atomics) - printf_log(LOG_INFO, "Dynarec will generate only aligned atomics code\n"); - } - p = getenv("BOX64_DYNAREC_MISSING"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='1') - box64_dynarec_missing = p[0]-'0'; - } - if(box64_dynarec_missing) - printf_log(LOG_INFO, "Dynarec will print missing opcodes\n"); - } - p = getenv("BOX64_NODYNAREC"); - if(p) { - if (strchr(p,'-')) { - if(sscanf(p, "%ld-%ld", &box64_nodynarec_start, &box64_nodynarec_end)!=2) { - if(sscanf(p, "0x%lX-0x%lX", &box64_nodynarec_start, &box64_nodynarec_end)!=2) - sscanf(p, "%lx-%lx", &box64_nodynarec_start, &box64_nodynarec_end); - } - printf_log(LOG_INFO, "No dynablock creation that start in the range %p - %p\n", (void*)box64_nodynarec_start, (void*)box64_nodynarec_end); - } - } - p = getenv("BOX64_DYNAREC_TEST"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='1') - box64_dynarec_test = p[0]-'0'; - } - if(box64_dynarec_test) { - box64_dynarec_fastnan = 0; - box64_dynarec_fastround = 0; - box64_dynarec_x87double = 1; - box64_dynarec_div0 = 1; - box64_dynarec_callret = 0; - printf_log(LOG_INFO, "Dynarec will compare it's execution with the interpreter (super slow, only for testing)\n"); - } - } - -#endif -#ifdef HAVE_TRACE - p = getenv("BOX64_TRACE_XMM"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='0'+1) - trace_xmm = p[0]-'0'; - } - } - p = getenv("BOX64_TRACE_EMM"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='0'+1) - trace_emm = p[0]-'0'; - } - } - p = getenv("BOX64_TRACE_COLOR"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='0'+1) - trace_regsdiff = p[0]-'0'; - } - } - p = getenv("BOX64_TRACE_START"); - if(p) { - char* p2; - start_cnt = strtoll(p, &p2, 10); - printf_log(LOG_INFO, "Will start trace only after %lu instructions\n", start_cnt); - } -#ifdef DYNAREC - p = getenv("BOX64_DYNAREC_TRACE"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='0'+1) - box64_dynarec_trace = p[0]-'0'; - if(box64_dynarec_trace) - printf_log(LOG_INFO, "Dynarec generated code will also print a trace\n"); - } - } -#endif -#endif - // Other BOX64 env. var. - p = getenv("BOX64_LIBCEF"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='1') - box64_libcef = p[0]-'0'; - } - if(!box64_libcef) - printf_log(LOG_INFO, "BOX64 will not detect libcef\n"); - } - p = getenv("BOX64_SDL2_JGUID"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='1') - box64_sdl2_jguid = p[0]-'0'; - } - if(!box64_sdl2_jguid) - printf_log(LOG_INFO, "BOX64 will workaround the use of SDL_GetJoystickGUIDInfo with 4 args instead of 5\n"); - } - p = getenv("BOX64_LOAD_ADDR"); - if(p) { - if(sscanf(p, "0x%zx", &box64_load_addr)!=1) - box64_load_addr = 0; - if(box64_load_addr) - printf_log(LOG_INFO, "Use a starting load address of %p\n", (void*)box64_load_addr); - } - p = getenv("BOX64_DLSYM_ERROR"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='0'+1) - dlsym_error = p[0]-'0'; - } - } - p = getenv("BOX64_X11THREADS"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='0'+1) - box64_x11threads = p[0]-'0'; - } - if(box64_x11threads) - printf_log(LOG_INFO, "Try to Call XInitThreads if libX11 is loaded\n"); - } - p = getenv("BOX64_X11GLX"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='0'+1) - box64_x11glx = p[0]-'0'; - } - if(box64_x11glx) - printf_log(LOG_INFO, "Hack to force libX11 GLX extension present\n"); - else - printf_log(LOG_INFO, "Disabled Hack to force libX11 GLX extension present\n"); - } - p = getenv("BOX64_LIBGL"); - if(p) - box64_libGL = box_strdup(p); - if(!box64_libGL) { - p = getenv("SDL_VIDEO_GL_DRIVER"); - if(p) - box64_libGL = box_strdup(p); - } - if(box64_libGL) { - printf_log(LOG_INFO, "BOX64 using \"%s\" as libGL.so.1\n", p); - } - p = getenv("BOX64_ALLOWMISSINGLIBS"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='0'+1) - allow_missing_libs = p[0]-'0'; - } - if(allow_missing_libs) - printf_log(LOG_INFO, "Allow missing needed libs\n"); - } - p = getenv("BOX64_CRASHHANDLER"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='0'+1) - box64_dummy_crashhandler = p[0]-'0'; - } - if(!box64_dummy_crashhandler) - printf_log(LOG_INFO, "Don't use dummy crashhandler lib\n"); - } - p = getenv("BOX64_MALLOC_HACK"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='0'+2) - box64_malloc_hack = p[0]-'0'; - } - if(!box64_malloc_hack) { - if(box64_malloc_hack==1) { - printf_log(LOG_INFO, "Malloc hook will not be redirected\n"); - } else - printf_log(LOG_INFO, "Malloc hook will check for mmap/free occurrences\n"); - } - } - p = getenv("BOX64_NOPULSE"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='0'+1) - box64_nopulse = p[0]-'0'; - } - if(box64_nopulse) - printf_log(LOG_INFO, "Disable the use of pulseaudio libs\n"); - } - p = getenv("BOX64_NOGTK"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='0'+1) - box64_nogtk = p[0]-'0'; - } - if(box64_nogtk) - printf_log(LOG_INFO, "Disable the use of wrapped gtk libs\n"); - } - p = getenv("BOX64_NOVULKAN"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='0'+1) - box64_novulkan = p[0]-'0'; - } - if(box64_novulkan) - printf_log(LOG_INFO, "Disable the use of wrapped vulkan libs\n"); - } - p = getenv("BOX64_FUTEX_WAITV"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='0'+1) - box64_futex_waitv = p[0]-'0'; - } - #ifdef BAD_SIGNAL - if(box64_futex_waitv) - printf_log(LOG_INFO, "Enable the use of futex waitv syscall (if available on the system\n"); - #else - if(!box64_futex_waitv) - printf_log(LOG_INFO, "Disable the use of futex waitv syscall\n"); - #endif - } - p = getenv("BOX64_FIX_64BIT_INODES"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='0'+1) - fix_64bit_inodes = p[0]-'0'; - } - if(fix_64bit_inodes) - printf_log(LOG_INFO, "Fix 64bit inodes\n"); - } - p = getenv("BOX64_JITGDB"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='0'+3) - jit_gdb = p[0]-'0'; - } - if(jit_gdb) - printf_log(LOG_INFO, "Launch %s on segfault\n", (jit_gdb==2)?"gdbserver":((jit_gdb==3)?"lldb":"gdb")); - } - p = getenv("BOX64_SHOWSEGV"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='0'+1) - box64_showsegv = p[0]-'0'; - } - if(box64_showsegv) - printf_log(LOG_INFO, "Show Segfault signal even if a signal handler is present\n"); - } - p = getenv("BOX64_SHOWBT"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='0'+1) - box64_showbt = p[0]-'0'; - } - if(box64_showbt) - printf_log(LOG_INFO, "Show a Backtrace when a Segfault signal is caught\n"); - } - p = getenv("BOX64_MAXCPU"); - if(p) { - int maxcpu = 0; - if(sscanf(p, "%d", &maxcpu)==1) - box64_maxcpu = maxcpu; - if(box64_maxcpu<0) - box64_maxcpu = 0; - if(box64_maxcpu) { - printf_log(LOG_NONE, "Will not expose more than %d cpu cores\n", box64_maxcpu); - } else { - printf_log(LOG_NONE, "Will not limit the number of cpu cores exposed\n"); - } - } - p = getenv("BOX64_MMAP32"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='0'+1) - box64_mmap32 = p[0]-'0'; - } - if(box64_mmap32) - printf_log(LOG_INFO, "Will use 32bits address in priority for external MMAP (when 32bits process are detected)\n"); - else - printf_log(LOG_INFO, "Will not use 32bits address in priority for external MMAP (when 32bits process are detected)\n"); - } - p = getenv("BOX64_IGNOREINT3"); - if(p) { - if(strlen(p)==1) { - if(p[0]>='0' && p[0]<='0'+1) - box64_ignoreint3 = p[0]-'0'; - } - if(box64_ignoreint3) - printf_log(LOG_INFO, "Will silently ignore INT3 in the code\n"); - } - // grab pagesize - box64_pagesize = sysconf(_SC_PAGESIZE); - if(!box64_pagesize) - box64_pagesize = 4096; -#ifdef DYNAREC - // grab cpu extensions for dynarec usage - GatherDynarecExtensions(); -#endif - // grab cpu name - int ncpu = getNCpu(); - const char* cpuname = getCpuName(); - printf_log(LOG_INFO, " PageSize:%zd Running on %s with %d Cores\n", box64_pagesize, cpuname, ncpu); - // grab and calibrate hardware counter - int hardware = 0; - #if defined(ARM64) || defined(RV64) - hardware = 1; - box64_rdtsc = 0; // allow hardxare counter - #else - box64_rdtsc = 1; - printf_log(LOG_INFO, "Will use time-based emulation for rdtsc, even if hardware counter are available\n"); - #endif - uint64_t freq = ReadTSCFrequency(NULL); - if(freq<1000000) { - box64_rdtsc = 1; - if(hardware) printf_log(LOG_INFO, "Hardware counter to slow (%d kHz), not using it\n", freq/1000); - hardware = 0; - freq = ReadTSCFrequency(NULL); - } - uint64_t efreq = freq; - while(efreq<500000000) { // minium 500MHz - ++box64_rdtsc_shift; - efreq = freq<<box64_rdtsc_shift; - } - printf_log(LOG_INFO, "Will use %s counter measured at ", box64_rdtsc?"Software":"Hardware"); - int ghz = freq>=1000000000LL; - if(ghz) freq/=100000000LL; else freq/=100000; - if(ghz) printf_log(LOG_INFO, "%d.%d GHz", freq/10, freq%10); - if(!ghz & freq>=1000) printf_log(LOG_INFO, "%d MHz", freq/10); - if(!ghz & freq<1000) printf_log(LOG_INFO, "%d.%d MHz", freq/10, freq%10); - if(box64_rdtsc_shift) { - printf_log(LOG_INFO, " emulating "); - ghz = efreq>=1000000000LL; - if(ghz) efreq/=100000000LL; else efreq/=100000; - if(ghz) printf_log(LOG_INFO, "%d.%d GHz", efreq/10, efreq%10); - if(!ghz & efreq>=1000) printf_log(LOG_INFO, "%d MHz", efreq/10); - if(!ghz & efreq<1000) printf_log(LOG_INFO, "%d.%d MHz", efreq/10, efreq%10); - } - printf_log(LOG_INFO, "\n"); -} - -EXPORTDYN -void LoadEnvPath(path_collection_t *col, const char* defpath, const char* env) -{ - const char* p = getenv(env); - if(p) { - ParseList(p, col, 1); - } else { - ParseList(defpath, col, 1); - } -} - -void PrintCollection(path_collection_t* col, const char* env) -{ - if(LOG_INFO<=box64_log) { - printf_log(LOG_INFO, "%s: ", env); - for(int i=0; i<col->size; i++) - printf_log(LOG_INFO, "%s%s", col->paths[i], (i==col->size-1)?"\n":":"); - } -} - -EXPORTDYN -int CountEnv(char** env) -{ - // count, but remove all BOX64_* environnement - // also remove PATH and LD_LIBRARY_PATH - // but add 2 for default BOX64_PATH and BOX64_LD_LIBRARY_PATH - char** p = env; - int c = 0; - while(*p) { - if(strncmp(*p, "BOX64_", 6)!=0) - //if(!(strncmp(*p, "PATH=", 5)==0 || strncmp(*p, "LD_LIBRARY_PATH=", 16)==0)) - ++c; - ++p; - } - return c+2; -} -EXPORTDYN -int GatherEnv(char*** dest, char** env, char* prog) -{ - // Add all but BOX64_* environnement - // but add 2 for default BOX64_PATH and BOX64_LD_LIBRARY_PATH - char** p = env; - int idx = 0; - int path = 0; - int ld_path = 0; - while(*p) { - if(strncmp(*p, "BOX64_PATH=", 11)==0) { - (*dest)[idx++] = box_strdup(*p+6); - path = 1; - } else if(strncmp(*p, "BOX64_LD_LIBRARY_PATH=", 22)==0) { - (*dest)[idx++] = box_strdup(*p+6); - ld_path = 1; - } else if(strncmp(*p, "_=", 2)==0) { - /*int l = strlen(prog); - char tmp[l+3]; - strcpy(tmp, "_="); - strcat(tmp, prog); - (*dest)[idx++] = box_strdup(tmp);*/ - } else if(strncmp(*p, "BOX64_", 6)!=0) { - (*dest)[idx++] = box_strdup(*p); - /*if(!(strncmp(*p, "PATH=", 5)==0 || strncmp(*p, "LD_LIBRARY_PATH=", 16)==0)) { - }*/ - } - ++p; - } - // update the calloc of envv when adding new variables here - if(!path) { - (*dest)[idx++] = box_strdup("BOX64_PATH=.:bin"); - } - if(!ld_path) { - (*dest)[idx++] = box_strdup("BOX64_LD_LIBRARY_PATH=.:lib:lib64:x86_64:bin64:libs64"); - } - // add "_=prog" at the end... - if(prog) { - int l = strlen(prog); - char tmp[l+3]; - strcpy(tmp, "_="); - strcat(tmp, prog); - (*dest)[idx++] = box_strdup(tmp); - } - // and a final NULL - (*dest)[idx++] = 0; - return 0; -} - -void PrintFlags() { - printf("Environment Variables:\n"); - printf(" BOX64_PATH is the box64 version of PATH (default is '.:bin')\n"); - printf(" BOX64_LD_LIBRARY_PATH is the box64 version LD_LIBRARY_PATH (default is '.:lib:lib64')\n"); - printf(" BOX64_LOG with 0/1/2/3 or NONE/INFO/DEBUG/DUMP to set the printed debug info (level 3 is level 2 + BOX64_DUMP)\n"); - printf(" BOX64_DUMP with 0/1 to dump elf infos\n"); - printf(" BOX64_NOBANNER with 0/1 to enable/disable the printing of box64 version and build at start\n"); -#ifdef DYNAREC - printf(" BOX64_DYNAREC_LOG with 0/1/2/3 or NONE/INFO/DEBUG/DUMP to set the printed dynarec info\n"); - printf(" BOX64_DYNAREC with 0/1 to disable or enable Dynarec (On by default)\n"); - printf(" BOX64_NODYNAREC with address interval (0x1234-0x4567) to forbid dynablock creation in the interval specified\n"); -#endif -#ifdef HAVE_TRACE - printf(" BOX64_TRACE with 1 to enable x86_64 execution trace\n"); - printf(" or with XXXXXX-YYYYYY to enable x86_64 execution trace only between address\n"); - printf(" or with FunctionName to enable x86_64 execution trace only in one specific function\n"); - printf(" use BOX64_TRACE_INIT instead of BOX64_TRACE to start trace before init of Libs and main program\n\t (function name will probably not work then)\n"); - printf(" BOX64_TRACE_EMM with 1 to enable dump of MMX registers along with regular registers\n"); - printf(" BOX64_TRACE_XMM with 1 to enable dump of SSE registers along with regular registers\n"); - printf(" BOX64_TRACE_COLOR with 1 to enable detection of changed general register values\n"); - printf(" BOX64_TRACE_START with N to enable trace after N instructions\n"); -#ifdef DYNAREC - printf(" BOX64_DYNAREC_TRACE with 0/1 to disable or enable Trace on generated code too\n"); -#endif -#endif - printf(" BOX64_TRACE_FILE with FileName to redirect logs in a file (or stderr to use stderr instead of stdout)\n"); - printf(" BOX64_DLSYM_ERROR with 1 to log dlsym errors\n"); - printf(" BOX64_LOAD_ADDR=0xXXXXXX try to load at 0xXXXXXX main binary (if binary is a PIE)\n"); - printf(" BOX64_NOSIGSEGV=1 to disable handling of SigSEGV\n"); - printf(" BOX64_NOSIGILL=1 to disable handling of SigILL\n"); - printf(" BOX64_SHOWSEGV=1 to show Segfault signal even if a signal handler is present\n"); - printf(" BOX64_X11THREADS=1 to call XInitThreads when loading X11 (for old Loki games with Loki_Compat lib)\n"); - printf(" BOX64_LIBGL=libXXXX set the name (and optionnally full path) for libGL.so.1\n"); - printf(" BOX64_LD_PRELOAD=XXXX[:YYYYY] force loading XXXX (and YYYY...) libraries with the binary\n"); - printf(" BOX64_ALLOWMISSINGLIBS with 1 to allow one to continue even if a lib is missing (unadvised, will probably crash later)\n"); - printf(" BOX64_PREFER_EMULATED=1 to prefer emulated libs first (execpt for glibc, alsa, pulse, GL, vulkan and X11)\n"); - printf(" BOX64_PREFER_WRAPPED if box64 will use wrapped libs even if the lib is specified with absolute path\n"); - printf(" BOX64_CRASHHANDLER=0 to not use a dummy crashhandler lib\n"); - printf(" BOX64_NOPULSE=1 to disable the loading of pulseaudio libs\n"); - printf(" BOX64_NOGTK=1 to disable the loading of wrapped gtk libs\n"); - printf(" BOX64_NOVULKAN=1 to disable the loading of wrapped vulkan libs\n"); - printf(" BOX64_ENV='XXX=yyyy' will add XXX=yyyy env. var.\n"); - printf(" BOX64_ENV1='XXX=yyyy' will add XXX=yyyy env. var. and continue with BOX86_ENV2 ... until var doesn't exist\n"); - printf(" BOX64_JITGDB with 1 to launch \"gdb\" when a segfault is trapped, attached to the offending process\n"); - printf(" BOX64_MMAP32=1 to use 32bits address space mmap in priority for external mmap as soon a 32bits process are detected (default for Snapdragon build)\n"); -} - -void PrintHelp() { - printf("This is Box64, The Linux x86_64 emulator with a twist\n"); - printf("\nUsage is 'box64 [options] path/to/software [args]' to launch x86_64 software.\n"); - printf(" options are:\n"); - printf(" '-v'|'--version' to print box64 version and quit\n"); - printf(" '-h'|'--help' to print this and quit\n"); - printf(" '-f'|'--flags' to print box64 flags and quit\n"); -} - -void addNewEnvVar(const char* s) -{ - if(!s) - return; - char* p = box_strdup(s); - char* e = strchr(p, '='); - if(!e) { - printf_log(LOG_INFO, "Invalid specific env. var. '%s'\n", s); - box_free(p); - return; - } - *e='\0'; - ++e; - setenv(p, e, 1); - box_free(p); -} - -EXPORTDYN -void LoadEnvVars(box64context_t *context) -{ - // Check custom env. var. and add them if needed - { - char* p = getenv("BOX64_ENV"); - if(p) - addNewEnvVar(p); - int i = 1; - char box64_env[50]; - do { - sprintf(box64_env, "BOX64_ENV%d", i); - p = getenv(box64_env); - if(p) { - addNewEnvVar(p); - ++i; - } - } while(p); - } - // check BOX64_LD_LIBRARY_PATH and load it - LoadEnvPath(&context->box64_ld_lib, ".:lib:lib64:x86_64:bin64:libs64", "BOX64_LD_LIBRARY_PATH"); - #ifndef TERMUX - if(FileExist("/lib/x86_64-linux-gnu", 0)) - AddPath("/lib/x86_64-linux-gnu", &context->box64_ld_lib, 1); - if(FileExist("/usr/lib/x86_64-linux-gnu", 0)) - AddPath("/usr/lib/x86_64-linux-gnu", &context->box64_ld_lib, 1); - if(FileExist("/usr/x86_64-linux-gnu/lib", 0)) - AddPath("/usr/x86_64-linux-gnu/lib", &context->box64_ld_lib, 1); - #else - //TODO: Add Termux Library Path - Lily - if(FileExist("/data/data/com.termux/files/usr/lib/x86_64-linux-gnu", 0)) - AddPath("/data/data/com.termux/files/usr/lib/x86_64-linux-gnu", &context->box64_ld_lib, 1); - #endif - if(getenv("LD_LIBRARY_PATH")) - PrependList(&context->box64_ld_lib, getenv("LD_LIBRARY_PATH"), 1); // in case some of the path are for x86 world - if(getenv("BOX64_EMULATED_LIBS")) { - char* p = getenv("BOX64_EMULATED_LIBS"); - ParseList(p, &context->box64_emulated_libs, 0); - if (my_context->box64_emulated_libs.size && box64_log) { - printf_log(LOG_INFO, "BOX64 will force the used of emulated libs for "); - for (int i=0; i<context->box64_emulated_libs.size; ++i) - printf_log(LOG_INFO, "%s ", context->box64_emulated_libs.paths[i]); - printf_log(LOG_INFO, "\n"); - } - } - // add libssl and libcrypto (and a few other) to prefer emulated version because of multiple version exist - AddPath("libssl.so.1", &context->box64_emulated_libs, 0); - AddPath("libssl.so.1.0.0", &context->box64_emulated_libs, 0); - AddPath("libcrypto.so.1", &context->box64_emulated_libs, 0); - AddPath("libcrypto.so.1.0.0", &context->box64_emulated_libs, 0); - AddPath("libunwind.so.8", &context->box64_emulated_libs, 0); - AddPath("libpng12.so.0", &context->box64_emulated_libs, 0); - AddPath("libcurl.so.4", &context->box64_emulated_libs, 0); - AddPath("libtbbmalloc.so.2", &context->box64_emulated_libs, 0); - AddPath("libtbbmalloc_proxy.so.2", &context->box64_emulated_libs, 0); - - if(getenv("BOX64_SSE_FLUSHTO0")) { - if (strcmp(getenv("BOX64_SSE_FLUSHTO0"), "1")==0) { - box64_sse_flushto0 = 1; - printf_log(LOG_INFO, "BOX64: Direct apply of SSE Flush to 0 flag\n"); - } - } - if(getenv("BOX64_X87_NO80BITS")) { - if (strcmp(getenv("BOX64_X87_NO80BITS"), "1")==0) { - box64_x87_no80bits = 1; - printf_log(LOG_INFO, "BOX64: All 80bits x87 long double will be handle as double\n"); - } - } - if(getenv("BOX64_SYNC_ROUNDING")) { - if (strcmp(getenv("BOX64_SYNC_ROUNDING"), "1")==0) { - box64_sync_rounding = 1; - printf_log(LOG_INFO, "BOX64: Rouding mode with be synced with fesetround/fegetround\n"); - } - } - if(getenv("BOX64_PREFER_WRAPPED")) { - if (strcmp(getenv("BOX64_PREFER_WRAPPED"), "1")==0) { - box64_prefer_wrapped = 1; - printf_log(LOG_INFO, "BOX64: Prefering Wrapped libs\n"); - } - } - if(getenv("BOX64_PREFER_EMULATED")) { - if (strcmp(getenv("BOX64_PREFER_EMULATED"), "1")==0) { - box64_prefer_emulated = 1; - printf_log(LOG_INFO, "BOX64: Prefering Emulated libs\n"); - } - } - - if(getenv("BOX64_NOSIGSEGV")) { - if (strcmp(getenv("BOX64_NOSIGSEGV"), "1")==0) { - context->no_sigsegv = 1; - printf_log(LOG_INFO, "BOX64: Disabling handling of SigSEGV\n"); - } - } - if(getenv("BOX64_NOSIGILL")) { - if (strcmp(getenv("BOX64_NOSIGILL"), "1")==0) { - context->no_sigill = 1; - printf_log(LOG_INFO, "BOX64: Disabling handling of SigILL\n"); - } - } - // check BOX64_PATH and load it - LoadEnvPath(&context->box64_path, ".:bin", "BOX64_PATH"); - if(getenv("PATH")) - AppendList(&context->box64_path, getenv("PATH"), 1); // in case some of the path are for x86 world -#ifdef HAVE_TRACE - char* p = getenv("BOX64_TRACE"); - if(p) { - if (strcmp(p, "0")) { - context->x64trace = 1; - box64_trace = p; - } - } - p = getenv("BOX64_TRACE_INIT"); - if(p) { - if (strcmp(p, "0")) { - context->x64trace = 1; - trace_init = p; - } - } - if(my_context->x64trace) { - printf_log(LOG_INFO, "Initializing Zydis lib\n"); - if(InitX64Trace(my_context)) { - printf_log(LOG_INFO, "Zydis init failed. No x86 trace activated\n"); - context->x64trace = 0; - } - } -#endif -} - -EXPORTDYN -void setupTraceInit() -{ -#ifdef HAVE_TRACE - char* p = trace_init; - if(p) { - setbuf(stdout, NULL); - uintptr_t s_trace_start=0, s_trace_end=0; - if (strcmp(p, "1")==0) - SetTraceEmu(0, 0); - else if (strchr(p,'-')) { - if(sscanf(p, "%ld-%ld", &s_trace_start, &s_trace_end)!=2) { - if(sscanf(p, "0x%lX-0x%lX", &s_trace_start, &s_trace_end)!=2) - sscanf(p, "%lx-%lx", &s_trace_start, &s_trace_end); - } - if(s_trace_start || s_trace_end) - SetTraceEmu(s_trace_start, s_trace_end); - } else { - if (GetGlobalSymbolStartEnd(my_context->maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL, 0, NULL)) { - SetTraceEmu(s_trace_start, s_trace_end); - printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end); - } else if(GetLocalSymbolStartEnd(my_context->maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL, 0, NULL)) { - SetTraceEmu(s_trace_start, s_trace_end); - printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end); - } else { - printf_log(LOG_NONE, "Warning, Symbol to trace (\"%s\") not found, Disabling trace\n", p); - SetTraceEmu(0, 100); // disabling trace, mostly - } - } - } else { - p = box64_trace; - if(p) - if (strcmp(p, "0")) - SetTraceEmu(0, 1); - } -#endif -} - -void setupTraceMapLib(lib_t* maplib) -{ -#ifdef HAVE_TRACE - if(!trace_func) - return; - char* p = trace_func; - uintptr_t s_trace_start=0, s_trace_end=0; - if(maplib) { - if (GetGlobalSymbolStartEnd(maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL, 0, NULL)) { - SetTraceEmu(s_trace_start, s_trace_end); - printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end); - box_free(trace_func); - trace_func = NULL; - return; - } else if(GetLocalSymbolStartEnd(maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL, 0, NULL)) { - SetTraceEmu(s_trace_start, s_trace_end); - printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end); - box_free(trace_func); - trace_func = NULL; - return; - } else if(GetSymTabStartEnd(maplib, p, &s_trace_start, &s_trace_end)) { - SetTraceEmu(s_trace_start, s_trace_end); - printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end); - box_free(trace_func); - trace_func = NULL; - return; - } - } - if (my_context->elfs && GetGlobalSymbolStartEnd(my_context->maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL, 0, NULL)) { - SetTraceEmu(s_trace_start, s_trace_end); - printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end); - box_free(trace_func); - trace_func = NULL; - } else if(my_context->elfs && GetLocalSymbolStartEnd(my_context->maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL, 0, NULL)) { - SetTraceEmu(s_trace_start, s_trace_end); - printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end); - box_free(trace_func); - trace_func = NULL; - } else if(GetSymTabStartEnd(my_context->maplib, p, &s_trace_start, &s_trace_end)) { - SetTraceEmu(s_trace_start, s_trace_end); - printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end); - box_free(trace_func); - trace_func = NULL; - } else { - printf_log(LOG_NONE, "Warning, Symbol to trace (\"%s\") not found. Trying to set trace later\n", p); - SetTraceEmu(0, 1); // disabling trace, mostly - } -#endif -} - -EXPORTDYN -void setupTrace() -{ -#ifdef HAVE_TRACE - char* p = box64_trace; - if(p) { - setbuf(stdout, NULL); - uintptr_t s_trace_start=0, s_trace_end=0; - if (strcmp(p, "1")==0) - SetTraceEmu(0, 0); - else if (strchr(p,'-')) { - if(sscanf(p, "%ld-%ld", &s_trace_start, &s_trace_end)!=2) { - if(sscanf(p, "0x%lX-0x%lX", &s_trace_start, &s_trace_end)!=2) - sscanf(p, "%lx-%lx", &s_trace_start, &s_trace_end); - } - if(s_trace_start || s_trace_end) { - SetTraceEmu(s_trace_start, s_trace_end); - if(!s_trace_start && s_trace_end==1) { - printf_log(LOG_INFO, "TRACE enabled but inactive\n"); - } else { - printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end); - } - } - } else { - if (my_context->elfs && GetGlobalSymbolStartEnd(my_context->maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL, 0, NULL)) { - SetTraceEmu(s_trace_start, s_trace_end); - printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end); - } else if(my_context->elfs && GetLocalSymbolStartEnd(my_context->maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL, 0, NULL)) { - SetTraceEmu(s_trace_start, s_trace_end); - printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end); - } else { - printf_log(LOG_NONE, "Warning, Symbol to trace (\"%s\") not found. Trying to set trace later\n", p); - SetTraceEmu(0, 1); // disabling trace, mostly - if(trace_func) - box_free(trace_func); - trace_func = box_strdup(p); - } - } - } -#endif -} -#ifndef STATICBUILD -void endMallocHook(); -#endif - -void endBox64() -{ - if(!my_context || box64_quit) - return; - - // then call all the fini - dynarec_log(LOG_DEBUG, "endBox64() called\n"); - box64_quit = 1; - x64emu_t* emu = thread_get_emu(); - void startTimedExit(); - startTimedExit(); - // atexit first - printf_log(LOG_DEBUG, "Calling atexit registered functions (exiting box64)\n"); - CallAllCleanup(emu); - printf_log(LOG_DEBUG, "Calling fini for all loaded elfs and unload native libs\n"); - RunElfFini(my_context->elfs[0], emu); - void closeAllDLOpenned(); - closeAllDLOpenned(); // close residual dlopenned libs - // unload needed libs - needed_libs_t* needed = my_context->elfs[0]->needed; - printf_log(LOG_DEBUG, "Unloaded main elf: Will Dec RefCount of %d libs\n", needed?needed->size:0); - if(needed) - for(int i=0; i<needed->size; ++i) - DecRefCount(&needed->libs[i], emu); - // all done, free context - #ifndef STATICBUILD - endMallocHook(); - #endif - FreeBox64Context(&my_context); - #ifdef DYNAREC - // disable dynarec now - box64_dynarec = 0; - #endif - if(box64_libGL) { - box_free(box64_libGL); - box64_libGL = NULL; - } - if(box64_custom_gstreamer) { - box_free(box64_custom_gstreamer); - box64_custom_gstreamer = NULL; - } -} - - -static void free_contextargv() -{ - for(int i=0; i<my_context->argc; ++i) - box_free(my_context->argv[i]); -} - -static void add_argv(const char* what) { - int there = 0; - for(int i=1; i<my_context->argc && !there; ++i) - if(!strcmp(my_context->argv[i], what)) - there = 1; - if(!there) { - printf_log(LOG_INFO, "Inserting \"%s\" to the argments\n", what); - my_context->argv = (char**)box_realloc(my_context->argv, (my_context->argc+1)*sizeof(char*)); - my_context->argv[my_context->argc] = box_strdup(what); - my_context->argc++; - } -} - -static void load_rcfiles() -{ - #ifndef TERMUX - if(FileExist("/etc/box64.box64rc", IS_FILE)) - LoadRCFile("/etc/box64.box64rc"); - #else - if(FileExist("/data/data/com.termux/files/usr/etc/box64.box64rc", IS_FILE)) - LoadRCFile("/data/data/com.termux/files/usr/etc/box64.box64rc"); - #endif - - else - LoadRCFile(NULL); // load default rcfile - char* p = getenv("HOME"); - if(p) { - char tmp[4096]; - strncpy(tmp, p, 4095); - strncat(tmp, "/.box64rc", 4095); - if(FileExist(tmp, IS_FILE)) - LoadRCFile(tmp); - } -} - -#ifndef STATICBUILD -void pressure_vessel(int argc, const char** argv, int nextarg, const char* prog); -#endif -extern char** environ; int main(int argc, const char **argv, char **env) { - #ifndef STATICBUILD - init_malloc_hook(); - #endif - init_auxval(argc, argv, environ?environ:env); - // analogue to QEMU_VERSION in qemu-user-mode emulation - if(getenv("BOX64_VERSION")) { - PrintBox64Version(); - exit(0); - } - // trying to open and load 1st arg - if(argc==1) { - /*PrintBox64Version(); - PrintHelp(); - return 1;*/ - printf("BOX64: Missing operand after 'box64'\n"); - printf("See 'box64 --help' for more information.\n"); - exit(0); - } - if(argc>1 && !strcmp(argv[1], "/usr/bin/gdb") && getenv("BOX64_TRACE_FILE")) - exit(0); - // uname -m is redirected to box64 -m - if(argc==2 && (!strcmp(argv[1], "-m") || !strcmp(argv[1], "-p") || !strcmp(argv[1], "-i"))) - { - printf("x86_64\n"); - exit(0); - } - - // check BOX64_LOG debug level - LoadLogEnv(); - if(!getenv("BOX64_NORCFILES")) { - load_rcfiles(); - } - char* bashpath = NULL; - { - char* p = getenv("BOX64_BASH"); - if(p) { - if(FileIsX64ELF(p)) { - bashpath = p; - printf_log(LOG_INFO, "Using bash \"%s\"\n", bashpath); - } else { - printf_log(LOG_INFO, "The x86_64 bash \"%s\" is not an x86_64 binary.\n", p); - } - } - } - const char* prog = argv[1]; - int nextarg = 1; - // check if some options are passed - while(prog && prog[0]=='-') { - if(!strcmp(prog, "-v") || !strcmp(prog, "--version")) { - PrintBox64Version(); - exit(0); - } - if(!strcmp(prog, "-h") || !strcmp(prog, "--help")) { - PrintHelp(); - exit(0); - } - if(!strcmp(prog, "-f") || !strcmp(prog, "--flags")) { - PrintFlags(); - exit(0); - } - // other options? - if(!strcmp(prog, "--")) { - prog = argv[++nextarg]; - break; - } - printf("Warning, Unrecognized option '%s'\n", prog); - prog = argv[++nextarg]; - } - if(!prog || nextarg==argc) { - printf("BOX64: Nothing to run\n"); - exit(0); - } - if(!box64_nobanner) - PrintBox64Version(); - // precheck, for win-preload - if(strstr(prog, "wine-preloader")==(prog+strlen(prog)-strlen("wine-preloader")) - || strstr(prog, "wine64-preloader")==(prog+strlen(prog)-strlen("wine64-preloader"))) { - // wine-preloader detecter, skipping it if next arg exist and is an x86 binary - int x64 = (nextarg<argc)?FileIsX64ELF(argv[nextarg]):0; - if(x64) { - prog = argv[++nextarg]; - printf_log(LOG_INFO, "BOX64: Wine preloader detected, loading \"%s\" directly\n", prog); - wine_preloaded = 1; - } - } - #ifndef STATICBUILD - // pre-check for pressure-vessel-wrap - if(strstr(prog, "pressure-vessel-wrap")==(prog+strlen(prog)-strlen("pressure-vessel-wrap"))) { - printf_log(LOG_INFO, "BOX64: pressure-vessel-wrap detected\n"); - pressure_vessel(argc, argv, nextarg+1, prog); - } - #endif - int ld_libs_args = -1; - int is_custom_gstreamer = 0; - const char* wine_prog = NULL; - // check if this is wine - if(!strcmp(prog, "wine64") - || !strcmp(prog, "wine64-development") - || !strcmp(prog, "wine") - || (strrchr(prog, '/') && !strcmp(strrchr(prog,'/'), "/wine")) - || (strrchr(prog, '/') && !strcmp(strrchr(prog,'/'), "/wine64"))) { - const char* prereserve = getenv("WINEPRELOADRESERVE"); - printf_log(LOG_INFO, "BOX64: Wine64 detected, WINEPRELOADRESERVE=\"%s\"\n", prereserve?prereserve:""); - if(wine_preloaded) { - wine_prereserve(prereserve); - } - // special case for winedbg, doesn't work anyway - if(argv[nextarg+1] && strstr(argv[nextarg+1], "winedbg")==argv[nextarg+1]) { - if(getenv("BOX64_WINEDBG")) { - box64_nobanner = 1; - box64_log = 0; - } else { - printf_log(LOG_NONE, "winedbg detected, not launching it!\n"); - exit(0); // exiting, it doesn't work anyway - } - } - box64_wine = 1; - // check if it's proton, with it's custom gstreamer build, to disable gtk3 loading - char tmp[strlen(prog)+100]; - strcpy(tmp, prog); - char* pp = strrchr(tmp, '/'); - if(pp) { - *pp = '\0'; // remove the wine binary call - strcat(tmp, "/../lib64/gstreamer-1.0"); - // check if it exist - if(FileExist(tmp, 0)) { - //printf_log(LOG_INFO, "BOX64: Custom gstreamer detected, disable gtk wrapping\n"); - //box64_nogtk = 1; - //is_custom_gstreamer = 1; - box64_custom_gstreamer = box_strdup(tmp); - } - } - // Try to get the name of the exe being run, to ApplyParams laters - if(argv[nextarg+1] && argv[nextarg+1][0]!='-' && strlen(argv[nextarg+1])>4 && !strcasecmp(argv[nextarg+1]+strlen(argv[nextarg+1])-4, ".exe")) { - const char* pp = strrchr(argv[nextarg+1], '/'); - if(pp) - wine_prog = pp+1; - else { - pp = strrchr(argv[nextarg+1], '\\'); - if(pp) - wine_prog = pp+1; - else - wine_prog = argv[nextarg+1]; - } - } - if(wine_prog) printf_log(LOG_INFO, "BOX64: Detected running wine with \"%s\"\n", wine_prog); - } else if(strstr(prog, "ld-musl-x86_64.so.1")) { - // check if ld-musl-x86_64.so.1 is used - printf_log(LOG_INFO, "BOX64: ld-musl detected. Trying to workaround and use system ld-linux\n"); - box64_musl = 1; - // skip ld-musl and go through args unti "--" is found, handling "--library-path" to add some libs to BOX64_LD_LIBRARY - ++nextarg; - while(strcmp(argv[nextarg], "--")) { - if(!strcmp(argv[nextarg], "--library-path")) { - ++nextarg; - ld_libs_args = nextarg; - } - ++nextarg; - } - ++nextarg; - prog = argv[nextarg]; - } - // check if this is wineserver - if(!strcmp(prog, "wineserver") || !strcmp(prog, "wineserver64") || (strlen(prog)>9 && !strcmp(prog+strlen(prog)-strlen("/wineserver"), "/wineserver"))) { - box64_wine = 1; - } - if(box64_wine) { - // disabling the use of futex_waitv for now - setenv("WINEFSYNC", "0", 1); - } - // Create a new context - my_context = NewBox64Context(argc - nextarg); - - // check BOX64_LD_LIBRARY_PATH and load it - LoadEnvVars(my_context); - // Append ld_list if it exist - if(ld_libs_args!=-1) - PrependList(&my_context->box64_ld_lib, argv[ld_libs_args], 1); - if(is_custom_gstreamer) - AddPath("libwayland-client.so.0", &my_context->box64_emulated_libs, 0); - - my_context->box64path = ResolveFile(argv[0], &my_context->box64_path); - // prepare all other env. var - my_context->envc = CountEnv(environ?environ:env); - printf_log(LOG_INFO, "Counted %d Env var\n", my_context->envc); - // allocate extra space for new environment variables such as BOX64_PATH - my_context->envv = (char**)box_calloc(my_context->envc+4, sizeof(char*)); - GatherEnv(&my_context->envv, environ?environ:env, my_context->box64path); - if(box64_dump || box64_log<=LOG_DEBUG) { - for (int i=0; i<my_context->envc; ++i) - printf_dump(LOG_DEBUG, " Env[%02d]: %s\n", i, my_context->envv[i]); - } - - path_collection_t ld_preload = {0}; - if(getenv("BOX64_LD_PRELOAD")) { - char* p = getenv("BOX64_LD_PRELOAD"); - ParseList(p, &ld_preload, 0); - if (ld_preload.size && box64_log) { - printf_log(LOG_INFO, "BOX64 trying to Preload "); - for (int i=0; i<ld_preload.size; ++i) - printf_log(LOG_INFO, "%s ", ld_preload.paths[i]); - printf_log(LOG_INFO, "\n"); - } - } else { - if(getenv("LD_PRELOAD")) { - char* p = getenv("LD_PRELOAD"); - if(strstr(p, "libtcmalloc_minimal.so.0")) - box64_tcmalloc_minimal = 1; - if(strstr(p, "libtcmalloc_minimal.so.4")) - box64_tcmalloc_minimal = 1; - if(strstr(p, "libtcmalloc_minimal_debug.so.4")) - box64_tcmalloc_minimal = 1; - if(strstr(p, "libasan.so")) - box64_tcmalloc_minimal = 1; // it seems Address Sanitizer doesn't handle dlsym'd malloc very well - ParseList(p, &ld_preload, 0); - if (ld_preload.size && box64_log) { - printf_log(LOG_INFO, "BOX64 trying to Preload "); - for (int i=0; i<ld_preload.size; ++i) - printf_log(LOG_INFO, "%s ", ld_preload.paths[i]); - printf_log(LOG_INFO, "\n"); - } - } - } - // print PATH and LD_LIB used - PrintCollection(&my_context->box64_ld_lib, "BOX64 LIB PATH"); - PrintCollection(&my_context->box64_path, "BOX64 BIN PATH"); - // lets build argc/argv stuff - printf_log(LOG_INFO, "Looking for %s\n", prog); - my_context->argv[0] = ResolveFile(prog, &my_context->box64_path); - // check if box86 is present - { - my_context->box86path = box_strdup(my_context->box64path); - char* p = strrchr(my_context->box86path, '6'); // get the 6 of box64 - p[0] = '8'; p[1] = '6'; // change 64 to 86 - if(!FileExist(my_context->box86path, IS_FILE)) { - box_free(my_context->box86path); - my_context->box86path = NULL; - } - } - const char* prgname = strrchr(prog, '/'); - if(!prgname) - prgname = prog; - else - ++prgname; - if(box64_wine) { - #ifdef ANDROID - AddPath("libdl.so", &ld_preload, 0); - #else - AddPath("libdl.so.2", &ld_preload, 0); - #endif - } - // special case for zoom - if(strstr(prgname, "zoom")==prgname) { - printf_log(LOG_INFO, "Zoom detected, Trying to use system libturbojpeg if possible\n"); - box64_zoom = 1; - } - // special case for bash (add BOX86_NOBANNER=1 if not there) - if(!strcmp(prgname, "bash")) { - printf_log(LOG_INFO, "bash detected, disabling banner\n"); - if (!box64_nobanner) { - setenv("BOX86_NOBANNER", "1", 0); - setenv("BOX64_NOBANNER", "1", 0); - } - if (!bashpath) { - bashpath = (char*)prog; - setenv("BOX64_BASH", prog, 1); - } - } - if(bashpath) - my_context->bashpath = box_strdup(bashpath); - - /*if(strstr(prgname, "awesomium_process")==prgname) { - printf_log(LOG_INFO, "awesomium_process detected, forcing emulated libpng12\n"); - AddPath("libpng12.so.0", &my_context->box64_emulated_libs, 0); - }*/ - /*if(!strcmp(prgname, "gdb")) { - exit(-1); - }*/ - ApplyParams("*"); // [*] is a special setting for all process - ApplyParams(prgname); - if(box64_wine && wine_prog) { - ApplyParams(wine_prog); - wine_prog = NULL; - } - if(box64_wine) - box64_maxcpu_immutable = 1; // cannot change once wine is loaded - - for(int i=1; i<my_context->argc; ++i) { - my_context->argv[i] = box_strdup(argv[i+nextarg]); - printf_log(LOG_INFO, "argv[%i]=\"%s\"\n", i, my_context->argv[i]); - } - if(box64_nosandbox) - { - add_argv("--no-sandbox"); - } - if(box64_inprocessgpu) - { - add_argv("--in-process-gpu"); - } - if(box64_cefdisablegpu) - { - add_argv("-cef-disable-gpu"); - } - if(box64_cefdisablegpucompositor) - { - add_argv("-cef-disable-gpu-compositor"); - } - - // check if file exist - if(!my_context->argv[0] || !FileExist(my_context->argv[0], IS_FILE)) { - printf_log(LOG_NONE, "Error: File is not found. (check BOX64_PATH)\n"); - free_contextargv(); - FreeBox64Context(&my_context); - FreeCollection(&ld_preload); - return -1; - } - if(!FileExist(my_context->argv[0], IS_FILE|IS_EXECUTABLE)) { - printf_log(LOG_NONE, "Error: %s is not an executable file.\n", my_context->argv[0]); - free_contextargv(); - FreeBox64Context(&my_context); - FreeCollection(&ld_preload); + x64emu_t* emu = NULL; + elfheader_t* elf_header = NULL; + if (initialize(argc, argv, env, &emu, &elf_header, 1)) { return -1; } - if(!(my_context->fullpath = box_realpath(my_context->argv[0], NULL))) - my_context->fullpath = box_strdup(my_context->argv[0]); - if(getenv("BOX64_ARG0")) - my_context->argv[0] = box_strdup(getenv("BOX64_ARG0")); - FILE *f = fopen(my_context->fullpath, "rb"); - if(!f) { - printf_log(LOG_NONE, "Error: Cannot open %s\n", my_context->fullpath); - free_contextargv(); - FreeBox64Context(&my_context); - FreeCollection(&ld_preload); - return -1; - } - elfheader_t *elf_header = LoadAndCheckElfHeader(f, my_context->fullpath, 1); - if(!elf_header) { - int x86 = my_context->box86path?FileIsX86ELF(my_context->fullpath):0; - int script = my_context->bashpath?FileIsShell(my_context->fullpath):0; - printf_log(LOG_NONE, "Error: Reading elf header of %s, Try to launch %s instead\n", my_context->fullpath, x86?"using box86":(script?"using bash":"natively")); - fclose(f); - FreeCollection(&ld_preload); - int ret; - if(x86) { - // duplicate the array and insert 1st arg as box86 - const char** newargv = (const char**)box_calloc(my_context->argc+2, sizeof(char*)); - newargv[0] = my_context->box86path; - for(int i=0; i<my_context->argc; ++i) - newargv[i+1] = my_context->argv[i]; - ret = execvp(newargv[0], (char * const*)newargv); - } else if (script) { - // duplicate the array and insert 1st arg as box64, 2nd is bash - const char** newargv = (const char**)box_calloc(my_context->argc+3, sizeof(char*)); - newargv[0] = my_context->box64path; - newargv[1] = my_context->bashpath; - for(int i=0; i<my_context->argc; ++i) - newargv[i+2] = my_context->argv[i]; - ret = execvp(newargv[0], (char * const*)newargv); - } else { - const char** newargv = (const char**)box_calloc(my_context->argc+1, sizeof(char*)); - for(int i=0; i<my_context->argc; ++i) - newargv[i] = my_context->argv[i]; - ret = execvp(newargv[0], (char * const*)newargv); - } - free_contextargv(); - FreeBox64Context(&my_context); - return ret; - } - AddElfHeader(my_context, elf_header); - - if(CalcLoadAddr(elf_header)) { - printf_log(LOG_NONE, "Error: Reading elf header of %s\n", my_context->fullpath); - FreeElfHeader(&elf_header); - free_contextargv(); - FreeBox64Context(&my_context); - FreeCollection(&ld_preload); - return -1; - } - // allocate memory and load elf - if(AllocLoadElfMemory(my_context, elf_header, 1)) { - printf_log(LOG_NONE, "Error: Loading elf %s\n", my_context->fullpath); - FreeElfHeader(&elf_header); - free_contextargv(); - FreeBox64Context(&my_context); - FreeCollection(&ld_preload); - return -1; - } - if(ElfCheckIfUseTCMallocMinimal(elf_header)) { - if(!box64_tcmalloc_minimal) { - // need to reload with tcmalloc_minimal as a LD_PRELOAD! - printf_log(LOG_INFO, "BOX64: tcmalloc_minimal.so.4 used. Reloading box64 with the lib preladed\n"); - // need to get a new envv variable. so first count it and check if LD_PRELOAD is there - int preload=(getenv("LD_PRELOAD"))?1:0; - int nenv = 0; - while(env[nenv]) nenv++; - // alloc + "LD_PRELOAD" if needd + last NULL ending - char** newenv = (char**)box_calloc(nenv+1+((preload)?0:1), sizeof(char*)); - // copy strings - for (int i=0; i<nenv; ++i) - newenv[i] = box_strdup(env[i]); - // add ld_preload - if(preload) { - // find the line - int l = 0; - while(l<nenv) { - if(strstr(newenv[l], "LD_PRELOAD=")==newenv[l]) { - // found it! - char *old = newenv[l]; - newenv[l] = (char*)box_calloc(strlen(old)+strlen("libtcmalloc_minimal.so.4:")+1, sizeof(char)); - strcpy(newenv[l], "LD_PRELOAD=libtcmalloc_minimal.so.4:"); - strcat(newenv[l], old + strlen("LD_PRELOAD=")); - box_free(old); - // done, end loop - l = nenv; - } else ++l; - } - } else { - //move last one - newenv[nenv] = box_strdup(newenv[nenv-1]); - box_free(newenv[nenv-1]); - newenv[nenv-1] = box_strdup("LD_PRELOAD=libtcmalloc_minimal.so.4"); - } - // duplicate argv too - char** newargv = box_calloc(argc+1, sizeof(char*)); - int narg = 0; - while(argv[narg]) {newargv[narg] = box_strdup(argv[narg]); narg++;} - // launch with new env... - if(execve(newargv[0], newargv, newenv)<0) - printf_log(LOG_NONE, "Failed to relaunch. Error is %d/%s\n", errno, strerror(errno)); - } else { - printf_log(LOG_INFO, "BOX64: Using tcmalloc_minimal.so.4, and it's in the LD_PRELOAD command\n"); - } - } -#if defined(RPI) || defined(RK3399) || defined(RK3326) - // before launching emulation, let's check if this is a mojosetup from GOG - if (((strstr(prog, "bin/linux/x86_64/mojosetup") && getenv("MOJOSETUP_BASE")) || strstr(prog, ".mojosetup/mojosetup")) - && getenv("GTK2_RC_FILES")) { - sanitize_mojosetup_gtk_background(); - } -#endif - // change process name - { - char* p = strrchr(my_context->fullpath, '/'); - if(p) - ++p; - else - p = my_context->fullpath; - if(prctl(PR_SET_NAME, p)==-1) - printf_log(LOG_NONE, "Error setting process name (%s)\n", strerror(errno)); - else - printf_log(LOG_INFO, "Rename process to \"%s\"\n", p); - if(strcmp(prgname, p)) - ApplyParams(p); - // and now all change the argv (so libs libs mesa find the correct program names) - char* endp = (char*)argv[argc-1]; - while(*endp) - ++endp; // find last argv[] address - uintptr_t diff = prog - argv[0]; // this is the difference we need to compensate - for(p=(char*)prog; p<=endp; ++p) - *(p - diff) = *p; // copy all element at argv[nextarg] to argv[0] - memset(endp - diff, 0, diff); // fill reminder with NULL - for(int i=nextarg; i<argc; ++i) - argv[i] -= diff; // adjust strings - my_context->orig_argc = argc; - my_context->orig_argv = (char**)argv; - } - box64_isglibc234 = GetNeededVersionForLib(elf_header, "libc.so.6", "GLIBC_2.34"); - if(box64_isglibc234) - printf_log(LOG_DEBUG, "Program linked with GLIBC 2.34+\n"); - // get and alloc stack size and align - if(CalcStackSize(my_context)) { - printf_log(LOG_NONE, "Error: Allocating stack\n"); - free_contextargv(); - FreeBox64Context(&my_context); - FreeCollection(&ld_preload); - return -1; - } - // init x86_64 emu - x64emu_t *emu = NewX64Emu(my_context, my_context->ep, (uintptr_t)my_context->stack, my_context->stacksz, 0); - // stack setup is much more complicated then just that! - SetupInitialStack(emu); // starting here, the argv[] don't need free anymore - SetupX64Emu(emu, NULL); - SetRSI(emu, my_context->argc); - SetRDX(emu, (uint64_t)my_context->argv); - SetRCX(emu, (uint64_t)my_context->envv); - SetRBP(emu, 0); // Frame pointer so to "No more frame pointer" - - // child fork to handle traces - pthread_atfork(NULL, NULL, my_child_fork); - - thread_set_emu(emu); - - // export symbols - AddSymbols(my_context->maplib, elf_header); - if(wine_preloaded) { - uintptr_t wineinfo = 0; - int ver = -1, veropt = 0; - const char* vername = NULL; - if(!ElfGetGlobalSymbolStartEnd(elf_header, &wineinfo, NULL, "wine_main_preload_info", &ver, &vername, 1, &veropt)) - if(!ElfGetWeakSymbolStartEnd(elf_header, &wineinfo, NULL, "wine_main_preload_info", &ver, &vername, 1, &veropt)) - ElfGetLocalSymbolStartEnd(elf_header, &wineinfo, NULL, "wine_main_preload_info", &ver, &vername, 1, &veropt); - if(!wineinfo) {printf_log(LOG_NONE, "Warning, Symbol wine_main_preload_info not found\n");} - else { - *(void**)wineinfo = get_wine_prereserve(); - printf_log(LOG_DEBUG, "WINE wine_main_preload_info found and updated %p -> %p\n", get_wine_prereserve(), *(void**)wineinfo); - } - #ifdef DYNAREC - dynarec_wine_prereserve(); - #endif - } - AddMainElfToLinkmap(elf_header); - // pre-load lib if needed - if(ld_preload.size) { - my_context->preload = new_neededlib(0); - for(int i=0; i<ld_preload.size; ++i) { - needed_libs_t* tmp = new_neededlib(1); - tmp->names[0] = ld_preload.paths[i]; - if(AddNeededLib(my_context->maplib, 0, 0, 0, tmp, elf_header, my_context, emu)) { - printf_log(LOG_INFO, "Warning, cannot pre-load %s\n", tmp->names[0]); - RemoveNeededLib(my_context->maplib, 0, tmp, my_context, emu); - } else { - for(int j=0; j<tmp->size; ++j) - add1lib_neededlib(my_context->preload, tmp->libs[j], tmp->names[j]); - } - free_neededlib(tmp); - } - } - FreeCollection(&ld_preload); - // Call librarian to load all dependant elf - if(LoadNeededLibs(elf_header, my_context->maplib, 0, 0, 0, my_context, emu)) { - printf_log(LOG_NONE, "Error: Loading needed libs in elf %s\n", my_context->argv[0]); - FreeBox64Context(&my_context); - return -1; - } - // reloc... - printf_log(LOG_DEBUG, "And now export symbols / relocation for %s...\n", ElfName(elf_header)); - if(RelocateElf(my_context->maplib, NULL, 0, 0, elf_header)) { - printf_log(LOG_NONE, "Error: Relocating symbols in elf %s\n", my_context->argv[0]); - FreeBox64Context(&my_context); - return -1; - } - // and handle PLT - RelocateElfPlt(my_context->maplib, NULL, 0, 0, elf_header); - // deferred init - setupTraceInit(); - RunDeferredElfInit(emu); - // update TLS of main elf - RefreshElfTLS(elf_header); - // do some special case check, _IO_2_1_stderr_ and friends, that are setup by libc, but it's already done here, so need to do a copy - ResetSpecialCaseMainElf(elf_header); - // init... - setupTrace(); - // get entrypoint - my_context->ep = GetEntryPoint(my_context->maplib, elf_header); - - atexit(endBox64); - loadProtectionFromMap(); - - // emulate! - printf_log(LOG_DEBUG, "Start x64emu on Main\n"); - // Stack is ready, with stacked: NULL env NULL argv argc - SetRIP(emu, my_context->ep); - ResetFlags(emu); - Push64(emu, my_context->exit_bridge); // push to pop it just after - SetRDX(emu, Pop64(emu)); // RDX is exit function - Run(emu, 0); - // Get EAX - int ret = GetEAX(emu); - printf_log(LOG_DEBUG, "Emulation finished, EAX=%d\n", ret); - endBox64(); -#ifdef HAVE_TRACE - if(trace_func) { - box_free(trace_func); - trace_func = NULL; - } -#endif - return ret; + return emulate(emu, elf_header); } |