about summary refs log tree commit diff stats
path: root/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.c')
-rwxr-xr-xsrc/main.c734
1 files changed, 734 insertions, 0 deletions
diff --git a/src/main.c b/src/main.c
new file mode 100755
index 00000000..4858e797
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,734 @@
+#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 "build_info.h"
+#include "debug.h"
+#include "fileutils.h"
+#include "box64context.h"
+#include "wine_tools.h"
+
+box64context_t *my_context = NULL;
+int box64_log = LOG_NONE;
+int box64_nobanner = 0;
+int box64_dynarec_log = LOG_INFO; //LOG_NONE;
+int box64_pagesize;
+int box64_dynarec = 0;
+int dlsym_error = 0;
+int trace_xmm = 0;
+int trace_emm = 0;
+#ifdef HAVE_TRACE
+uint64_t start_cnt = 0;
+#ifdef DYNAREC
+int box64_dynarec_trace = 0;
+#endif
+#endif
+int box64_zoom = 0;
+int x11threads = 0;
+int x11glx = 1;
+int allow_missing_libs = 0;
+int fix_64bit_inodes = 0;
+int box64_steam = 0;
+int box64_nopulse = 0;
+int box64_nogtk = 0;
+int box64_novulkan = 0;
+char* libGL = NULL;
+uintptr_t   trace_start = 0, trace_end = 0;
+char* trace_func = NULL;
+uintptr_t fmod_smc_start = 0;
+uintptr_t fmod_smc_end = 0;
+uint32_t default_fs = 0;
+int jit_gdb = 0;
+int box64_tcmalloc_minimal = 0;
+
+FILE* ftrace = NULL;
+int ftrace_has_pid = 0;
+
+void openFTrace()
+{
+    char* t = getenv("BOX64_TRACE_FILE");
+    char tmp[500];
+    char* p = t;
+    if(p && strstr(t, "%pid")) {
+        strcpy(tmp, p);
+        char* c = strstr(tmp, "%pid");
+        *c = 0; // cut
+        char pid[10];
+        sprintf(pid, "%d", getpid());
+        strcat(tmp, pid);
+        c = strstr(p, "%pid") + strlen("%pid");
+        strcat(tmp, c);
+        p = tmp;
+        ftrace_has_pid = 1;
+    }
+    if(p) {
+        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 {
+            if(!box64_nobanner)
+                printf("BOX64 Trace redirected to \"%s\"\n", p);
+        }
+    }
+}
+
+void my_child_fork()
+{
+    if(ftrace_has_pid) {
+        // open a new ftrace...
+        fclose(ftrace);
+        openFTrace();
+    }
+}
+
+
+EXPORTDYN
+void LoadLogEnv()
+{
+    ftrace = stdout;
+    const char *p = getenv("BOX64_NOBANNER");
+    if(p) {
+        if(strlen(p)==1) {
+            if(p[0]>='0' && p[1]<='1')
+                box64_nobanner = p[0]-'0';
+        }
+    }
+    p = getenv("BOX64_LOG");
+    if(p) {
+        if(strlen(p)==1) {
+            if(p[0]>='0'+LOG_NONE && p[1]<='0'+LOG_DEBUG)
+                box64_log = p[0]-'0';
+        } 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_DUMP;
+        }
+        if(!box64_nobanner)
+            printf_log(LOG_INFO, "Debug level is %d\n", box64_log);
+    }
+#ifdef HAVE_TRACE
+    p = getenv("BOX64_TRACE_XMM");
+    if(p) {
+        if(strlen(p)==1) {
+            if(p[0]>='0' && p[1]<='0'+1)
+                trace_xmm = p[0]-'0';
+        }
+    }
+    p = getenv("BOX64_TRACE_EMM");
+    if(p) {
+        if(strlen(p)==1) {
+            if(p[0]>='0' && p[1]<='0'+1)
+                trace_emm = 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 %llu instructions\n", start_cnt);
+    }
+#endif
+    // grab BOX64_TRACE_FILE envvar, and change %pid to actual pid is present in the name
+    openFTrace();
+    // Other BOX64 env. var.
+    p = getenv("BOX64_DLSYM_ERROR");
+    if(p) {
+        if(strlen(p)==1) {
+            if(p[0]>='0' && p[1]<='0'+1)
+                dlsym_error = p[0]-'0';
+        }
+    }
+    p = getenv("BOX64_X11THREADS");
+    if(p) {
+        if(strlen(p)==1) {
+            if(p[0]>='0' && p[1]<='0'+1)
+                x11threads = p[0]-'0';
+        }
+        if(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[1]<='0'+1)
+                x11glx = p[0]-'0';
+        }
+        if(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)
+        libGL = strdup(p);
+    if(!libGL) {
+        p = getenv("SDL_VIDEO_GL_DRIVER");
+        if(p)
+            libGL = strdup(p);
+    }
+    if(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[1]<='0'+1)
+                allow_missing_libs = p[0]-'0';
+        }
+        if(allow_missing_libs)
+            printf_log(LOG_INFO, "Allow missing needed libs\n");
+    }
+    p = getenv("BOX64_NOPULSE");
+        if(p) {
+        if(strlen(p)==1) {
+            if(p[0]>='0' && p[1]<='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[1]<='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[1]<='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_FIX_64BIT_INODES");
+        if(p) {
+        if(strlen(p)==1) {
+            if(p[0]>='0' && p[1]<='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[1]<='0'+1)
+                jit_gdb = p[0]-'0';
+        }
+        if(jit_gdb)
+            printf_log(LOG_INFO, "Launch %s on segfault\n", (jit_gdb==2)?"gdbserver":"gdb");
+    }
+    box64_pagesize = sysconf(_SC_PAGESIZE);
+    if(!box64_pagesize)
+        box64_pagesize = 4096;
+}
+
+EXPORTDYN
+void LoadEnvPath(path_collection_t *col, const char* defpath, const char* env)
+{
+    const char* p = getenv(env);
+    if(p) {
+        printf_log(LOG_INFO, "%s: ", env);
+        ParseList(p, col, 1);
+    } else {
+        printf_log(LOG_INFO, "Using default %s: ", env);
+        ParseList(defpath, col, 1);
+    }
+    if(LOG_INFO<=box64_log) {
+        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(const 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
+    const 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, const char** env, const char* prog)
+{
+    // Add all but BOX64_* environnement
+    // but add 2 for default BOX64_PATH and BOX64_LD_LIBRARY_PATH
+    const char** p = env;    
+    int idx = 0;
+    int path = 0;
+    int ld_path = 0;
+    while(*p) {
+        if(strncmp(*p, "BOX64_PATH=", 11)==0) {
+            (*dest)[idx++] = strdup(*p+6);
+            path = 1;
+        } else if(strncmp(*p, "BOX64_LD_LIBRARY_PATH=", 22)==0) {
+            (*dest)[idx++] = 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++] = strdup(tmp);*/
+        } else if(strncmp(*p, "BOX64_", 6)!=0) {
+            (*dest)[idx++] = 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++] = strdup("BOX64_PATH=.:bin");
+    }
+    if(!ld_path) {
+        (*dest)[idx++] = strdup("BOX64_LD_LIBRARY_PATH=.:lib");
+    }
+    // add "_=prog" at the end...
+    if(prog) {
+        int l = strlen(prog);
+        char tmp[l+3];
+        strcpy(tmp, "_=");
+        strcat(tmp, prog);
+        (*dest)[idx++] = strdup(tmp);
+    }
+    // and a final NULL
+    (*dest)[idx++] = 0;
+    return 0;
+}
+
+
+void PrintHelp() {
+    printf("\n\nThis is Box86, the Linux x86 emulator with a twist\n");
+    printf("\nUsage is box86 [options] path/to/software [args]\n");
+    printf("to launch x86 software\n");
+    printf(" options can be :\n");
+    printf("    '-v'|'--version' to print box86 version and quit\n");
+    printf("    '-h'|'--help'    to print box86 help and quit\n");
+    printf("You can also set some environment variables:\n");
+    printf(" BOX64_PATH is the box86 version of PATH (default is '.:bin')\n");
+    printf(" BOX64_LD_LIBRARY_PATH is the box86 version LD_LIBRARY_PATH (default is '.:lib')\n");
+    printf(" BOX64_LOG with 0/1/2/3 or NONE/INFO/DEBUG/DUMP to set the printed debug info\n");
+    printf(" BOX64_NOBANNER with 0/1 to enable/disable the printing of box86 version and build at start\n");
+#ifdef HAVE_TRACE
+    printf(" BOX64_TRACE with 1 to enable x86 execution trace\n");
+    printf("    or with XXXXXX-YYYYYY to enable x86 execution trace only between address\n");
+    printf("    or with FunctionName to enable x86 execution trace only in one specific function\n");
+    printf("  use BOX64_TRACE_INIT instead of BOX_TRACE to start trace before init of Libs and main program\n\t (function name will probably not work then)\n");
+    printf(" BOX64_TRACE_XMM with 1 to enable dump of SSE/SSE2 register along with regular registers\n");
+    printf(" BOX64_TRACE_START with N to enable trace after N instructions\n");
+#endif
+    printf(" BOX64_TRACE_FILE with FileName to redirect logs in a file");
+    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_X11THREADS=1 to call XInitThreads when loading X11 (for old Loki games with Loki_Compat lib)");
+    printf(" BOX64_LIBGL=libXXXX set the name (and optionnaly 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 to continue even if a lib is missing (unadvised, will probably  crash later)\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_JITGDB with 1 to launch \"gdb\" when a segfault is trapped, attached to the offending process\n");
+}
+
+EXPORTDYN
+void LoadEnvVars(box64context_t *context)
+{
+    // check BOX64_LD_LIBRARY_PATH and load it
+    LoadEnvPath(&context->box64_ld_lib, ".:lib:lib64:x86_64", "BOX64_LD_LIBRARY_PATH");
+    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("/lib/i686-pc-linux-gnu", 0))
+        AddPath("/lib/i686-pc-linux-gnu", &context->box64_ld_lib, 1);
+    if(FileExist("/usr/lib/i686-pc-linux-gnu", 0))
+        AddPath("/usr/lib/i686-pc-linux-gnu", &context->box64_ld_lib, 1);
+    if(FileExist("/usr/lib32", 0))
+        AddPath("/usr/lib32", &context->box64_ld_lib, 1);
+    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");
+        }
+    }
+
+    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->x86trace = 1;
+    }
+    p = getenv("BOX64_TRACE_INIT");
+    if(p) {
+        if (strcmp(p, "0"))
+            context->x86trace = 1;
+    }
+    if(my_context->x86trace) {
+        /*printf_log(LOG_INFO, "Initializing Zydis lib\n");
+        if(InitX86Trace(my_context)) {
+            printf_log(LOG_INFO, "Zydis init failed, no x86 trace activated\n");
+            context->x86trace = 0;
+        }*/
+            context->x86trace = 0;  // not implemented yet
+    }
+#endif
+}
+
+EXPORTDYN
+void setupTraceInit(box64context_t* context)
+{
+#ifdef HAVE_TRACE
+    char* p = getenv("BOX64_TRACE_INIT");
+    if(p) {
+        setbuf(stdout, NULL);
+        uintptr_t trace_start=0, trace_end=0;
+        if (strcmp(p, "1")==0)
+            SetTraceEmu(0, 0);
+        else if (strchr(p,'-')) {
+            if(sscanf(p, "%d-%d", &trace_start, &trace_end)!=2) {
+                if(sscanf(p, "0x%X-0x%X", &trace_start, &trace_end)!=2)
+                    sscanf(p, "%x-%x", &trace_start, &trace_end);
+            }
+            if(trace_start || trace_end)
+                SetTraceEmu(trace_start, trace_end);
+        } else {
+            if (0/*GetSymbolStartEnd(GetMapSymbol(my_context->maplib), p, &trace_start, &trace_end)*/) {
+                SetTraceEmu(trace_start, trace_end);
+                printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)trace_start, (void*)trace_end);
+            } else {
+                printf_log(LOG_NONE, "Warning, symbol to Traced (\"%s\") not found, disabling trace\n", p);
+                SetTraceEmu(0, 100);  // disabling trace, mostly
+            }
+        }
+    } else {
+        p = getenv("BOX64_TRACE");
+        if(p)
+            if (strcmp(p, "0"))
+                SetTraceEmu(0, 1);
+    }
+#endif
+}
+
+EXPORTDYN
+void setupTrace(box64context_t* context)
+{
+#ifdef HAVE_TRACE
+    char* p = getenv("BOX64_TRACE");
+    if(p) {
+        setbuf(stdout, NULL);
+        uintptr_t trace_start=0, trace_end=0;
+        if (strcmp(p, "1")==0)
+            SetTraceEmu(0, 0);
+        else if (strchr(p,'-')) {
+            if(sscanf(p, "%d-%d", &trace_start, &trace_end)!=2) {
+                if(sscanf(p, "0x%X-0x%X", &trace_start, &trace_end)!=2)
+                    sscanf(p, "%x-%x", &trace_start, &trace_end);
+            }
+            if(trace_start || trace_end) {
+                SetTraceEmu(trace_start, trace_end);
+                if(!trace_start && 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*)trace_start, (void*)trace_end);
+                }
+            }
+        } else {
+            if (0/*GetGlobalSymbolStartEnd(my_context->maplib, p, &trace_start, &trace_end)*/) {
+                SetTraceEmu(trace_start, trace_end);
+                printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)trace_start, (void*)trace_end);
+            } else if(0/*GetLocalSymbolStartEnd(my_context->maplib, p, &trace_start, &trace_end, NULL)*/) {
+                SetTraceEmu(trace_start, trace_end);
+                printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)trace_start, (void*)trace_end);
+            } else {
+                printf_log(LOG_NONE, "Warning, symbol to Traced (\"%s\") not found, trying to set trace later\n", p);
+                SetTraceEmu(0, 1);  // disabling trace, mostly
+                trace_func = strdup(p);
+            }
+        }
+    }
+#endif
+}
+
+void endBox86()
+{
+    if(!my_context)
+        return;
+
+    // all done, free context
+    FreeBox64Context(&my_context);
+    if(libGL) {
+        free(libGL);
+        libGL = NULL;
+    }
+}
+
+
+static void free_contextargv()
+{
+    for(int i=0; i<my_context->argc; ++i)
+        free(my_context->argv[i]);
+}
+
+const char **environ __attribute__((weak)) = NULL;
+int main(int argc, const char **argv, const char **env) {
+
+    //init_auxval(argc, argv, environ?environ:env);
+    // trying to open and load 1st arg
+    if(argc==1) {
+        PrintBox64Version();
+        PrintHelp();
+        return 1;
+    }
+
+    // init random seed
+    srandom(time(NULL));
+
+    // check BOX64_LOG debug level
+    LoadLogEnv();
+    
+    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);
+        }
+        // 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"))) {
+        // 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;
+        }
+    }
+    // check if this is wine
+    if(!strcmp(prog, "wine") || (strlen(prog)>5 && !strcmp(prog+strlen(prog)-strlen("/wine"), "/wine"))) {
+        const char* prereserve = getenv("WINEPRELOADRESERVE");
+        printf_log(LOG_INFO, "BOX64: Wine 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]) {
+            printf_log(LOG_NONE, "winedbg detected, not launching it!\n");
+            exit(0);    // exiting, it doesn't work anyway
+        }
+    }
+    // Create a new context
+    my_context = NewBox64Context(argc - nextarg);
+
+    // check BOX64_LD_LIBRARY_PATH and load it
+    LoadEnvVars(my_context);
+
+    if(argv[0][0]=='/')
+        my_context->box64path = strdup(argv[0]);
+    else
+        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**)calloc(my_context->envc+4, sizeof(char*));
+    GatherEnv(&my_context->envv, environ?environ:env, my_context->box64path);
+    if(box64_log>=LOG_DUMP) {
+        for (int i=0; i<my_context->envc; ++i)
+            printf_log(LOG_DUMP, " 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 try 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.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 try 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");
+            }
+        }
+    }
+    // lets build argc/argv stuff
+    printf_log(LOG_INFO, "Looking for %s\n", prog);
+    if(strchr(prog, '/'))
+        my_context->argv[0] = strdup(prog);
+    else
+        my_context->argv[0] = ResolveFile(prog, &my_context->box64_path);
+
+    const char* prgname = strrchr(prog, '/');
+    if(!prgname)
+        prgname = prog;
+    else
+        ++prgname;
+    // special case for LittleInferno that use an old libvorbis
+    if(strstr(prgname, "LittleInferno.bin.x86")==prgname) {
+        printf_log(LOG_INFO, "LittleInferno detected, forcing emulated libvorbis\n");
+        AddPath("libvorbis.so.0", &my_context->box64_emulated_libs, 0);
+    }
+    // special case for dontstarve that use an old SDL2
+    if(strstr(prgname, "dontstarve")) {
+        printf_log(LOG_INFO, "Dontstarve* detected, forcing emulated SDL2\n");
+        AddPath("libSDL2-2.0.so.0", &my_context->box64_emulated_libs, 0);
+    }
+    // special case for steam that somehow seems to alter libudev opaque pointer (udev_monitor)
+    if(strstr(prgname, "steam")==prgname) {
+        printf_log(LOG_INFO, "steam detected, forcing emulated libudev\n");
+        AddPath("libudev.so.0", &my_context->box64_emulated_libs, 0);
+        box64_steam = 1;
+    }
+    // special case for steam-runtime-check-requirements to fake 64bits suport
+    if(strstr(prgname, "steam-runtime-check-requirements")==prgname) {
+        printf_log(LOG_INFO, "steam-runtime-check-requirements detected, faking All is good!\n");
+        exit(0);    // exiting, not testing anything
+    }
+    // special case for UnrealLinux.bin, it doesn't like "full path resolution"
+    if(!strcmp(prog, "UnrealLinux.bin") && my_context->argv[0]) {
+        free(my_context->argv[0]);
+        my_context->argv[0] = strdup("./UnrealLinux.bin");
+    }
+    #ifdef RPI
+    // special case for TokiTori 2+, that check if texture max size is > = 8192
+    if(strstr(prgname, "TokiTori2.bin.x86")==prgname) {
+        printf_log(LOG_INFO, "TokiTori 2+ detected, runtime patch to fix GPU non-power-of-two faillure\n");
+        box64_tokitori2 = 1;
+    }
+    #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;
+    }
+    /*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);
+    }*/
+
+    for(int i=1; i<my_context->argc; ++i) {
+        my_context->argv[i] = strdup(argv[i+nextarg]);
+        printf_log(LOG_INFO, "argv[%i]=\"%s\"\n", i, my_context->argv[i]);
+    }
+
+    // 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 = realpath(my_context->argv[0], NULL)))
+        my_context->fullpath = strdup(my_context->argv[0]);
+    FILE *f = fopen(my_context->argv[0], "rb");
+    if(!f) {
+        printf_log(LOG_NONE, "Error: Cannot open %s\n", my_context->argv[0]);
+        free_contextargv();
+        FreeBox64Context(&my_context);
+        FreeCollection(&ld_preload);
+        return -1;
+    }
+    /*elfheader_t *elf_header = LoadAndCheckElfHeader(f, my_context->argv[0], 1);
+    if(!elf_header) {
+        printf_log(LOG_NONE, "Error: reading elf header of %s, try to launch natively instead\n", my_context->argv[0]);
+        fclose(f);
+        free_contextargv();
+        FreeBox64Context(&my_context);
+        FreeCollection(&ld_preload);
+        return execvp(argv[1], (char * const*)(argv+1));
+    }
+    AddElfHeader(my_context, elf_header);*/
+    return 0;
+}