diff options
| author | ptitSeb <sebastien.chev@gmail.com> | 2021-03-03 16:43:42 +0100 |
|---|---|---|
| committer | ptitSeb <sebastien.chev@gmail.com> | 2021-03-03 16:43:42 +0100 |
| commit | f4829a8ce42b1abbcc8621802d6c6fad3a56cd5d (patch) | |
| tree | 211276c3587721126ded00be46487bf23b605591 /src/wrapped | |
| parent | f73fbd3cee38b4c0086c934d73972375c9c8c7d6 (diff) | |
| download | box64-f4829a8ce42b1abbcc8621802d6c6fad3a56cd5d.tar.gz box64-f4829a8ce42b1abbcc8621802d6c6fad3a56cd5d.zip | |
More infrastructure added to elf and x64 emu
Diffstat (limited to 'src/wrapped')
| -rw-r--r-- | src/wrapped/generated/functions_list.txt | 15 | ||||
| -rw-r--r-- | src/wrapped/generated/wrapper.c | 102 | ||||
| -rw-r--r-- | src/wrapped/generated/wrapper.h | 50 | ||||
| -rwxr-xr-x | src/wrapped/wrappedldlinux.c | 42 | ||||
| -rwxr-xr-x | src/wrapped/wrappedldlinux_private.h | 25 | ||||
| -rwxr-xr-x | src/wrapped/wrappedlib_init.h | 239 | ||||
| -rwxr-xr-x | src/wrapped/wrappedlib_undefs.h | 23 | ||||
| -rwxr-xr-x | src/wrapped/wrappedlibc.c | 2590 | ||||
| -rwxr-xr-x | src/wrapped/wrappedlibc_private.h | 2238 | ||||
| -rwxr-xr-x | src/wrapped/wrappedlibdl.c | 415 | ||||
| -rwxr-xr-x | src/wrapped/wrappedlibdl_private.h | 14 |
11 files changed, 5753 insertions, 0 deletions
diff --git a/src/wrapped/generated/functions_list.txt b/src/wrapped/generated/functions_list.txt new file mode 100644 index 00000000..147507f1 --- /dev/null +++ b/src/wrapped/generated/functions_list.txt @@ -0,0 +1,15 @@ +#() vFE +#() vFv +#() pFE +#() pFp +#() vFpp +#() iFEp +#() pFEp +#() iFEpp +#() pFEpi +#() pFEpp +#() iFEpip +#() pFEppi +#() pFEppp +#() iFipppi +#() pFEv -> pFE diff --git a/src/wrapped/generated/wrapper.c b/src/wrapped/generated/wrapper.c new file mode 100644 index 00000000..6598ae7e --- /dev/null +++ b/src/wrapped/generated/wrapper.c @@ -0,0 +1,102 @@ +/***************************************************************** + * File automatically generated by rebuild_wrappers.py (v1.2.0.09) + *****************************************************************/ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "wrapper.h" +#include "emu/x64emu_private.h" +#include "emu/x87emu_private.h" +#include "regs.h" +#include "x64emu.h" + +typedef union ui64_s { + int64_t i; + uint64_t u; + uint32_t d[2]; +} ui64_t; + +typedef struct _2uint_struct_s { + uint32_t a; + uint32_t b; +} _2uint_struct_t; + +extern void* my__IO_2_1_stderr_; +extern void* my__IO_2_1_stdin_ ; +extern void* my__IO_2_1_stdout_; + +static void* io_convert(void* v) +{ + if(!v) + return v; + if(v==my__IO_2_1_stderr_) + return stderr; + if(v==my__IO_2_1_stdin_) + return stdin; + if(v==my__IO_2_1_stdout_) + return stdout; + return v; +} + +typedef struct my_GValue_s +{ + int g_type; + union { + int v_int; + int64_t v_int64; + uint64_t v_uint64; + float v_float; + double v_double; + void* v_pointer; + } data[2]; +} my_GValue_t; + +static void alignGValue(my_GValue_t* v, void* value) +{ + v->g_type = *(int*)value; + memcpy(v->data, value+4, 2*sizeof(double)); +} +static void unalignGValue(void* value, my_GValue_t* v) +{ + *(int*)value = v->g_type; + memcpy(value+4, v->data, 2*sizeof(double)); +} + +void* VulkanFromx86(void* src, void** save); +void VulkanTox86(void* src, void* save); + +#define ST0val ST0.d + +int of_convert(int); +typedef void (*vFE_t)(x64emu_t*); +typedef void (*vFv_t)(void); +typedef void* (*pFE_t)(x64emu_t*); +typedef void* (*pFp_t)(void*); +typedef void (*vFpp_t)(void*, void*); +typedef int32_t (*iFEp_t)(x64emu_t*, void*); +typedef void* (*pFEp_t)(x64emu_t*, void*); +typedef int32_t (*iFEpp_t)(x64emu_t*, void*, void*); +typedef void* (*pFEpi_t)(x64emu_t*, void*, int32_t); +typedef void* (*pFEpp_t)(x64emu_t*, void*, void*); +typedef int32_t (*iFEpip_t)(x64emu_t*, void*, int32_t, void*); +typedef void* (*pFEppi_t)(x64emu_t*, void*, void*, int32_t); +typedef void* (*pFEppp_t)(x64emu_t*, void*, void*, void*); +typedef int32_t (*iFipppi_t)(int32_t, void*, void*, void*, int32_t); + +void vFE(x64emu_t *emu, uintptr_t fcn) { vFE_t fn = (vFE_t)fcn; fn(emu); } +void vFv(x64emu_t *emu, uintptr_t fcn) { vFv_t fn = (vFv_t)fcn; fn(); } +void pFE(x64emu_t *emu, uintptr_t fcn) { pFE_t fn = (pFE_t)fcn; R_RAX=(uintptr_t)fn(emu); } +void pFp(x64emu_t *emu, uintptr_t fcn) { pFp_t fn = (pFp_t)fcn; R_RAX=(uintptr_t)fn(*(void**)(R_RSP + 4)); } +void vFpp(x64emu_t *emu, uintptr_t fcn) { vFpp_t fn = (vFpp_t)fcn; fn(*(void**)(R_RSP + 4), *(void**)(R_RSP + 12)); } +void iFEp(x64emu_t *emu, uintptr_t fcn) { iFEp_t fn = (iFEp_t)fcn; R_RAX=fn(emu, *(void**)(R_RSP + 4)); } +void pFEp(x64emu_t *emu, uintptr_t fcn) { pFEp_t fn = (pFEp_t)fcn; R_RAX=(uintptr_t)fn(emu, *(void**)(R_RSP + 4)); } +void iFEpp(x64emu_t *emu, uintptr_t fcn) { iFEpp_t fn = (iFEpp_t)fcn; R_RAX=fn(emu, *(void**)(R_RSP + 4), *(void**)(R_RSP + 12)); } +void pFEpi(x64emu_t *emu, uintptr_t fcn) { pFEpi_t fn = (pFEpi_t)fcn; R_RAX=(uintptr_t)fn(emu, *(void**)(R_RSP + 4), *(int32_t*)(R_RSP + 12)); } +void pFEpp(x64emu_t *emu, uintptr_t fcn) { pFEpp_t fn = (pFEpp_t)fcn; R_RAX=(uintptr_t)fn(emu, *(void**)(R_RSP + 4), *(void**)(R_RSP + 12)); } +void iFEpip(x64emu_t *emu, uintptr_t fcn) { iFEpip_t fn = (iFEpip_t)fcn; R_RAX=fn(emu, *(void**)(R_RSP + 4), *(int32_t*)(R_RSP + 12), *(void**)(R_RSP + 16)); } +void pFEppi(x64emu_t *emu, uintptr_t fcn) { pFEppi_t fn = (pFEppi_t)fcn; R_RAX=(uintptr_t)fn(emu, *(void**)(R_RSP + 4), *(void**)(R_RSP + 12), *(int32_t*)(R_RSP + 20)); } +void pFEppp(x64emu_t *emu, uintptr_t fcn) { pFEppp_t fn = (pFEppp_t)fcn; R_RAX=(uintptr_t)fn(emu, *(void**)(R_RSP + 4), *(void**)(R_RSP + 12), *(void**)(R_RSP + 20)); } +void iFipppi(x64emu_t *emu, uintptr_t fcn) { iFipppi_t fn = (iFipppi_t)fcn; R_RAX=fn(*(int32_t*)(R_RSP + 4), *(void**)(R_RSP + 8), *(void**)(R_RSP + 16), *(void**)(R_RSP + 24), *(int32_t*)(R_RSP + 32)); } + +void pFEv(x64emu_t *emu, uintptr_t fcn) { pFE_t fn = (pFE_t)fcn; R_RAX=(uintptr_t)fn(emu); } diff --git a/src/wrapped/generated/wrapper.h b/src/wrapped/generated/wrapper.h new file mode 100644 index 00000000..19ccf6b3 --- /dev/null +++ b/src/wrapped/generated/wrapper.h @@ -0,0 +1,50 @@ +/***************************************************************** + * File automatically generated by rebuild_wrappers.py (v1.2.0.09) + *****************************************************************/ +#ifndef __WRAPPER_H_ +#define __WRAPPER_H_ +#include <stdint.h> +#include <string.h> + +typedef struct x64emu_s x64emu_t; + +// the generic wrapper pointer functions +typedef void (*wrapper_t)(x64emu_t* emu, uintptr_t fnc); + +// list of defined wrapper +// v = void, i = int32, u = uint32, U/I= (u)int64 +// l = signed long, L = unsigned long (long is an int with the size of a pointer) +// p = pointer, P = callback +// f = float, d = double, D = long double, K = fake long double +// V = vaargs, E = current x86emu struct, e = ref to current x86emu struct +// 0 = constant 0, 1 = constant 1 +// o = stdout +// C = unsigned byte c = char +// W = unsigned short w = short +// O = libc O_ flags bitfield +// S = _IO_2_1_stdXXX_ pointer (or FILE*) +// Q = ... +// 2 = struct of 2 uint +// P = Vulkan struture pointer +// G = a single GValue pointer +// N = ... automatically sending 1 arg +// M = ... automatically sending 2 args + +void vFE(x64emu_t *emu, uintptr_t fnc); +void vFv(x64emu_t *emu, uintptr_t fnc); +void pFE(x64emu_t *emu, uintptr_t fnc); +void pFp(x64emu_t *emu, uintptr_t fnc); +void vFpp(x64emu_t *emu, uintptr_t fnc); +void iFEp(x64emu_t *emu, uintptr_t fnc); +void pFEp(x64emu_t *emu, uintptr_t fnc); +void iFEpp(x64emu_t *emu, uintptr_t fnc); +void pFEpi(x64emu_t *emu, uintptr_t fnc); +void pFEpp(x64emu_t *emu, uintptr_t fnc); +void iFEpip(x64emu_t *emu, uintptr_t fnc); +void pFEppi(x64emu_t *emu, uintptr_t fnc); +void pFEppp(x64emu_t *emu, uintptr_t fnc); +void iFipppi(x64emu_t *emu, uintptr_t fnc); + +void pFEv(x64emu_t *emu, uintptr_t fnc); + +#endif //__WRAPPER_H_ diff --git a/src/wrapped/wrappedldlinux.c b/src/wrapped/wrappedldlinux.c new file mode 100755 index 00000000..56b581a0 --- /dev/null +++ b/src/wrapped/wrappedldlinux.c @@ -0,0 +1,42 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#define _GNU_SOURCE /* See feature_test_macros(7) */ +#include <dlfcn.h> + +#include "wrappedlibs.h" + +#include "debug.h" +#include "wrapper.h" +#include "bridge.h" +#include "librarian/library_private.h" +#include "x64emu.h" +#include "emu/x64emu_private.h" +#include "elfloader.h" +#include "box64context.h" + +typedef struct my_tls_s { + int i; + uint32_t o; +} my_tls_t; + +EXPORT void* my___tls_get_addr(x64emu_t* emu, void* p) +{ + my_tls_t *t = (my_tls_t*)p; + return GetDTatOffset(emu->context, t->i, t->o); +} + +EXPORT void* my____tls_get_addr(x64emu_t* emu) +{ + // the GNU version (with 3 '_') use register for the parameter! + my_tls_t *t = (my_tls_t*)R_RAX; + return GetDTatOffset(emu->context, t->i, t->o); +} + + +const char* ldlinuxName = "ld-linux-x86-64.so.2"; +#define LIBNAME ldlinux + +// define all standard library functions +#include "wrappedlib_init.h" + diff --git a/src/wrapped/wrappedldlinux_private.h b/src/wrapped/wrappedldlinux_private.h new file mode 100755 index 00000000..1c829369 --- /dev/null +++ b/src/wrapped/wrappedldlinux_private.h @@ -0,0 +1,25 @@ +#if defined(GO) && defined(GOM) && defined(GO2) && defined(DATA) + +// _dl_allocate_tls +// _dl_allocate_tls_init +// _dl_argv //type B +// _dl_cache_libcmp +// _dl_deallocate_tls +// _dl_debug_state +// _dl_get_tls_static_info +// _dl_make_stack_executable +// _dl_mcount +// _dl_rtld_di_serinfo +// _dl_tls_setup +DATA(__libc_enable_secure, 4) +DATA(__libc_stack_end, 4) +DATA(__pointer_chk_guard, 4) +// _r_debug //type B +DATA(_rtld_global, 4) +DATA(_rtld_global_ro, 4) +DATA(__stack_chk_guard, 4) +// defini dans glibc/sysdeps/i386/dl-tls.h +GOM(___tls_get_addr, pFEv) //the parameter tls_index is in a register (EAX?) +GOM(__tls_get_addr, pFEp) //same, but the parameter is in the stack + +#endif \ No newline at end of file diff --git a/src/wrapped/wrappedlib_init.h b/src/wrapped/wrappedlib_init.h new file mode 100755 index 00000000..3f946286 --- /dev/null +++ b/src/wrapped/wrappedlib_init.h @@ -0,0 +1,239 @@ +#ifndef LIBNAME +#error Meh +#endif + +#define FUNC3(M,N) wrapped##M##N +#define FUNC2(M,N) FUNC3(M,N) +#define FUNC(N) FUNC2(LIBNAME,N) +#define QUOTE(M) #M +#define PRIVATE2(P) QUOTE(wrapped##P##_private.h) +#define PRIVATE(P) PRIVATE2(P) +#define MAPNAME3(N,M) N##M +#define MAPNAME2(N,M) MAPNAME3(N,M) +#define MAPNAME(N) MAPNAME2(LIBNAME,N) +// prepare the maps +#define GO(N, W) +#define GOW(N, W) +#define GOM(N, W) +#define GOS(N, W) +#define GO2(N, W, O) +#define DATA(N, S) +#define DATAV(N, S) +#define DATAB(N, S) +#define DATAM(N, S) + +// #define the 4 maps first +#undef GO +#define GO(N, W) {#N, W, 0}, +static const map_onesymbol_t MAPNAME(symbolmap)[] = { + #include PRIVATE(LIBNAME) +}; +#undef GO +#define GO(N, W) +#undef GOW +#define GOW(N, W) {#N, W, 1}, +static const map_onesymbol_t MAPNAME(wsymbolmap)[] = { + #include PRIVATE(LIBNAME) +}; +#undef GOW +#define GOW(N, W) +#undef GOM +#define GOM(N, W) {#N, W, 0}, +static const map_onesymbol_t MAPNAME(mysymbolmap)[] = { + #include PRIVATE(LIBNAME) +}; +#undef GOM +#define GOM(N, W) +#undef GOS +#define GOS(N, W) {#N, W, 0}, +static const map_onesymbol_t MAPNAME(stsymbolmap)[] = { + #include PRIVATE(LIBNAME) +}; +#undef GOS +#define GOS(N, W) +#undef GO2 +#define GO2(N, W, O) {#N, W, 0, #O}, +static const map_onesymbol2_t MAPNAME(symbol2map)[] = { + #include PRIVATE(LIBNAME) +}; +#undef GO2 +#define GO2(N, W, O) +#undef DATA +#undef DATAV +#undef DATAB +#define DATA(N, S) {#N, S, 0}, +#define DATAV(N, S) {#N, S, 1}, +#define DATAB(N, S) {#N, S, 0}, +static const map_onedata_t MAPNAME(datamap)[] = { + #include PRIVATE(LIBNAME) +}; +#undef DATA +#undef DATAV +#undef DATAB +#define DATA(N, S) +#define DATAV(N, S) +#define DATAB(N, S) +#undef DATAM +#define DATAM(N, S) {#N, S, 0}, +static const map_onedata_t MAPNAME(mydatamap)[] = { + #include PRIVATE(LIBNAME) +}; +#include "wrappedlib_undefs.h" + + + +int FUNC(_init)(library_t* lib, box64context_t* box64) +{ +// Init first + free(lib->path); lib->path=NULL; +#ifdef PRE_INIT + PRE_INIT +#endif + { + lib->priv.w.lib = dlopen(MAPNAME(Name), RTLD_LAZY | RTLD_GLOBAL); + if(!lib->priv.w.lib) { +#ifdef ALTNAME + lib->priv.w.lib = dlopen(ALTNAME, RTLD_LAZY | RTLD_GLOBAL); + if(!lib->priv.w.lib) +#endif +#ifdef ALTNAME2 + { + lib->priv.w.lib = dlopen(ALTNAME2, RTLD_LAZY | RTLD_GLOBAL); + if(!lib->priv.w.lib) +#endif + return -1; +#ifdef ALTNAME2 + else lib->path = strdup(ALTNAME2); + } else lib->path = strdup(ALTNAME); +#endif + } else lib->path = strdup(MAPNAME(Name)); + } + lib->priv.w.bridge = NewBridge(); +// Create maps + lib->symbolmap = kh_init(symbolmap); + lib->wsymbolmap = kh_init(symbolmap); + lib->mysymbolmap = kh_init(symbolmap); + lib->stsymbolmap = kh_init(symbolmap); + lib->symbol2map = kh_init(symbol2map); + lib->datamap = kh_init(datamap); + lib->wdatamap = kh_init(datamap); + lib->mydatamap = kh_init(datamap); + + khint_t k; + int ret; + int cnt; + + // populates maps... + cnt = sizeof(MAPNAME(symbolmap))/sizeof(map_onesymbol_t); + for (int i=0; i<cnt; ++i) { + k = kh_put(symbolmap, lib->symbolmap, MAPNAME(symbolmap)[i].name, &ret); + kh_value(lib->symbolmap, k) = MAPNAME(symbolmap)[i].w; + } + cnt = sizeof(MAPNAME(wsymbolmap))/sizeof(map_onesymbol_t); + for (int i=0; i<cnt; ++i) { + k = kh_put(symbolmap, lib->wsymbolmap, MAPNAME(wsymbolmap)[i].name, &ret); + kh_value(lib->wsymbolmap, k) = MAPNAME(wsymbolmap)[i].w; + } + cnt = sizeof(MAPNAME(mysymbolmap))/sizeof(map_onesymbol_t); + for (int i=0; i<cnt; ++i) { + k = kh_put(symbolmap, lib->mysymbolmap, MAPNAME(mysymbolmap)[i].name, &ret); + kh_value(lib->mysymbolmap, k) = MAPNAME(mysymbolmap)[i].w; + } + cnt = sizeof(MAPNAME(stsymbolmap))/sizeof(map_onesymbol_t); + for (int i=0; i<cnt; ++i) { + k = kh_put(symbolmap, lib->stsymbolmap, MAPNAME(stsymbolmap)[i].name, &ret); + kh_value(lib->stsymbolmap, k) = MAPNAME(stsymbolmap)[i].w; + } + cnt = sizeof(MAPNAME(symbol2map))/sizeof(map_onesymbol2_t); + for (int i=0; i<cnt; ++i) { + k = kh_put(symbol2map, lib->symbol2map, MAPNAME(symbol2map)[i].name, &ret); + kh_value(lib->symbol2map, k).name = MAPNAME(symbol2map)[i].name2; + kh_value(lib->symbol2map, k).w = MAPNAME(symbol2map)[i].w; + kh_value(lib->symbol2map, k).weak = MAPNAME(symbol2map)[i].weak; + } + cnt = sizeof(MAPNAME(datamap))/sizeof(map_onedata_t); + for (int i=0; i<cnt; ++i) { + if(MAPNAME(datamap)[i].weak) { + k = kh_put(datamap, lib->wdatamap, MAPNAME(datamap)[i].name, &ret); + kh_value(lib->wdatamap, k) = MAPNAME(datamap)[i].sz; + } else { + k = kh_put(datamap, lib->datamap, MAPNAME(datamap)[i].name, &ret); + kh_value(lib->datamap, k) = MAPNAME(datamap)[i].sz; + } + } + cnt = sizeof(MAPNAME(mydatamap))/sizeof(map_onedata_t); + for (int i=0; i<cnt; ++i) { + k = kh_put(datamap, lib->mydatamap, MAPNAME(mydatamap)[i].name, &ret); + kh_value(lib->mydatamap, k) = MAPNAME(mydatamap)[i].sz; + } +#ifdef CUSTOM_INIT + CUSTOM_INIT +#endif + + return 0; +} + +int FUNC(_fini)(library_t* lib) +{ +#ifdef CUSTOM_FINI + CUSTOM_FINI +#endif + if(lib->priv.w.lib) + dlclose(lib->priv.w.lib); + lib->priv.w.lib = NULL; + if(lib->priv.w.altprefix) + free(lib->priv.w.altprefix); + if(lib->priv.w.neededlibs) { + for(int i=0; i<lib->priv.w.needed; ++i) + free(lib->priv.w.neededlibs[i]); + free(lib->priv.w.neededlibs); + } + FreeBridge(&lib->priv.w.bridge); + return 1; +} + +int FUNC(_get)(library_t* lib, const char* name, uintptr_t *offs, uint32_t *sz) +{ + uintptr_t addr = 0; + uint32_t size = 0; +#ifdef CUSTOM_FAIL + void* symbol = NULL; +#endif +//PRE + if (!getSymbolInMaps(lib, name, 0, &addr, &size)) { +#ifdef CUSTOM_FAIL + CUSTOM_FAIL +#else + return 0; +#endif + } +//POST + if(!addr && !size) + return 0; + *offs = addr; + *sz = size; + return 1; +} + +int FUNC(_getnoweak)(library_t* lib, const char* name, uintptr_t *offs, uint32_t *sz) +{ + uintptr_t addr = 0; + uint32_t size = 0; +#ifdef CUSTOM_FAIL + void* symbol = NULL; +#endif +//PRE + if (!getSymbolInMaps(lib, name, 1, &addr, &size)) { +#ifdef CUSTOM_FAIL + CUSTOM_FAIL +#else + return 0; +#endif + } +//POST + if(!addr && !size) + return 0; + *offs = addr; + *sz = size; + return 1; +} diff --git a/src/wrapped/wrappedlib_undefs.h b/src/wrapped/wrappedlib_undefs.h new file mode 100755 index 00000000..7c6ac84b --- /dev/null +++ b/src/wrapped/wrappedlib_undefs.h @@ -0,0 +1,23 @@ +// regular symbol mapped to itself +#undef GO + +// regular symbol mapped to itself, but weak (unimplemented for now) +#undef GOW + +// symbol mapped to my_symbol +#undef GOM + +// symbol mapped to another one +#undef GO2 + +// data +#undef DATA + +// data, Weak (type V) +#undef DATAV + +// data, Uninitialized (type B) +#undef DATAB + +// data, "my_" type +#undef DATAM diff --git a/src/wrapped/wrappedlibc.c b/src/wrapped/wrappedlibc.c new file mode 100755 index 00000000..dce09009 --- /dev/null +++ b/src/wrapped/wrappedlibc.c @@ -0,0 +1,2590 @@ +#define _LARGEFILE_SOURCE 1 +#define _FILE_OFFSET_BITS 64 +#define _GNU_SOURCE /* See feature_test_macros(7) */ +#include <stdlib.h> +#include <stdio.h> +#include <stddef.h> +#include <string.h> +#include <wchar.h> +#include <dlfcn.h> +#include <signal.h> +#include <errno.h> +#include <err.h> +#include <stdarg.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/select.h> +#include <unistd.h> +#include <fcntl.h> +#include <glob.h> +#include <ctype.h> +#include <dirent.h> +#include <search.h> +#include <sys/types.h> +#include <poll.h> +#include <sys/epoll.h> +#include <ftw.h> +#include <sys/syscall.h> +#include <sys/socket.h> +#include <sys/utsname.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/sem.h> +#include <setjmp.h> +#include <sys/vfs.h> +#include <spawn.h> + +#include "wrappedlibs.h" + +#include "box64stack.h" +#include "x64emu.h" +#include "debug.h" +#include "wrapper.h" +#include "bridge.h" +//#include "callback.h" +#include "librarian.h" +#include "librarian/library_private.h" +#include "emu/x64emu_private.h" +#include "box64context.h" +//#include "myalign.h" +//#include "signals.h" +#include "fileutils.h" +#include "auxval.h" +#include "elfloader.h" +#include "bridge.h" + + +#define LIBNAME libc +const char* libcName = "libc.so.6"; + +static library_t* my_lib = NULL; + +typedef int (*iFL_t)(unsigned long); +typedef void (*vFpp_t)(void*, void*); +typedef void (*vFipp_t)(int32_t, void*, void*); +typedef int32_t (*iFpi_t)(void*, int32_t); +typedef int32_t (*iFpp_t)(void*, void*); +typedef int32_t (*iFpL_t)(void*, size_t); +typedef int32_t (*iFiip_t)(int32_t, int32_t, void*); +typedef int32_t (*iFipp_t)(int32_t, void*, void*); +typedef int32_t (*iFppi_t)(void*, void*, int32_t); +typedef int32_t (*iFpup_t)(void*, uint32_t, void*); +typedef int32_t (*iFpuu_t)(void*, uint32_t, uint32_t); +typedef int32_t (*iFiiII_t)(int, int, int64_t, int64_t); +typedef int32_t (*iFiiiV_t)(int, int, int, ...); +typedef int32_t (*iFippi_t)(int32_t, void*, void*, int32_t); +typedef int32_t (*iFpppp_t)(void*, void*, void*, void*); +typedef int32_t (*iFpipp_t)(void*, int32_t, void*, void*); +typedef int32_t (*iFppii_t)(void*, void*, int32_t, int32_t); +typedef int32_t (*iFipuu_t)(int32_t, void*, uint32_t, uint32_t); +typedef int32_t (*iFipiI_t)(int32_t, void*, int32_t, int64_t); +typedef int32_t (*iFipuup_t)(int32_t, void*, uint32_t, uint32_t, void*); +typedef int32_t (*iFiiV_t)(int32_t, int32_t, ...); +typedef void* (*pFp_t)(void*); + +#define SUPER() \ + GO(_ITM_addUserCommitAction, iFpup_t) \ + GO(_IO_file_stat, iFpp_t) + + +typedef struct libc_my_s { + #define GO(A, B) B A; + SUPER() + #undef GO +} libc_my_t; + +void* getLIBCMy(library_t* lib) +{ + libc_my_t* my = (libc_my_t*)calloc(1, sizeof(libc_my_t)); + #define GO(A, W) my->A = (W)dlsym(lib->priv.w.lib, #A); + SUPER() + #undef GO + return my; +} +#undef SUPER + +void freeLIBCMy(void* lib) +{ + // empty for now +} +#if 0 +// utility functions +#define SUPER() \ +GO(0) \ +GO(1) \ +GO(2) \ +GO(3) \ +GO(4) \ +GO(5) \ +GO(6) \ +GO(7) \ +GO(8) \ +GO(9) \ +GO(10) \ +GO(11) \ +GO(12) \ +GO(13) \ +GO(14) \ +GO(15) + +// compare +#define GO(A) \ +static uintptr_t my_compare_fct_##A = 0; \ +static int my_compare_##A(void* a, void* b) \ +{ \ + return (int)RunFunction(my_context, my_compare_fct_##A, 2, a, b);\ +} +SUPER() +#undef GO +static void* findcompareFct(void* fct) +{ + if(!fct) return NULL; + void* p; + if((p = GetNativeFnc((uintptr_t)fct))) return p; + #define GO(A) if(my_compare_fct_##A == (uintptr_t)fct) return my_compare_##A; + SUPER() + #undef GO + #define GO(A) if(my_compare_fct_##A == 0) {my_compare_fct_##A = (uintptr_t)fct; return my_compare_##A; } + SUPER() + #undef GO + printf_log(LOG_NONE, "Warning, no more slot for libc compare callback\n"); + return NULL; +} + +// ftw +#define GO(A) \ +static uintptr_t my_ftw_fct_##A = 0; \ +static int my_ftw_##A(void* fpath, void* sb, int flag) \ +{ \ + return (int)RunFunction(my_context, my_ftw_fct_##A, 3, fpath, sb, flag); \ +} +SUPER() +#undef GO +static void* findftwFct(void* fct) +{ + if(!fct) return NULL; + void* p; + if((p = GetNativeFnc((uintptr_t)fct))) return p; + #define GO(A) if(my_ftw_fct_##A == (uintptr_t)fct) return my_ftw_##A; + SUPER() + #undef GO + #define GO(A) if(my_ftw_fct_##A == 0) {my_ftw_fct_##A = (uintptr_t)fct; return my_ftw_##A; } + SUPER() + #undef GO + printf_log(LOG_NONE, "Warning, no more slot for libc ftw callback\n"); + return NULL; +} + +// ftw64 +#define GO(A) \ +static uintptr_t my_ftw64_fct_##A = 0; \ +static int my_ftw64_##A(void* fpath, void* sb, int flag) \ +{ \ + struct i386_stat64 i386st; \ + UnalignStat64(sb, &i386st); \ + return (int)RunFunction(my_context, my_ftw64_fct_##A, 3, fpath, &i386st, flag); \ +} +SUPER() +#undef GO +static void* findftw64Fct(void* fct) +{ + if(!fct) return NULL; + #define GO(A) if(my_ftw64_fct_##A == (uintptr_t)fct) return my_ftw64_##A; + SUPER() + #undef GO + #define GO(A) if(my_ftw64_fct_##A == 0) {my_ftw64_fct_##A = (uintptr_t)fct; return my_ftw64_##A; } + SUPER() + #undef GO + printf_log(LOG_NONE, "Warning, no more slot for libc ftw64 callback\n"); + return NULL; +} + +// nftw +#define GO(A) \ +static uintptr_t my_nftw_fct_##A = 0; \ +static int my_nftw_##A(void* fpath, void* sb, int flag, void* ftwbuff) \ +{ \ + return (int)RunFunction(my_context, my_nftw_fct_##A, 4, fpath, sb, flag, ftwbuff); \ +} +SUPER() +#undef GO +static void* findnftwFct(void* fct) +{ + if(!fct) return NULL; + void* p; + if((p = GetNativeFnc((uintptr_t)fct))) return p; + #define GO(A) if(my_nftw_fct_##A == (uintptr_t)fct) return my_nftw_##A; + SUPER() + #undef GO + #define GO(A) if(my_nftw_fct_##A == 0) {my_nftw_fct_##A = (uintptr_t)fct; return my_nftw_##A; } + SUPER() + #undef GO + printf_log(LOG_NONE, "Warning, no more slot for libc nftw callback\n"); + return NULL; +} + +// nftw64 +#define GO(A) \ +static uintptr_t my_nftw64_fct_##A = 0; \ +static int my_nftw64_##A(void* fpath, void* sb, int flag, void* ftwbuff) \ +{ \ + struct i386_stat64 i386st; \ + UnalignStat64(sb, &i386st); \ + return (int)RunFunction(my_context, my_nftw64_fct_##A, 4, fpath, &i386st, flag, ftwbuff); \ +} +SUPER() +#undef GO +static void* findnftw64Fct(void* fct) +{ + if(!fct) return NULL; + #define GO(A) if(my_nftw64_fct_##A == (uintptr_t)fct) return my_nftw64_##A; + SUPER() + #undef GO + #define GO(A) if(my_nftw64_fct_##A == 0) {my_nftw64_fct_##A = (uintptr_t)fct; return my_nftw64_##A; } + SUPER() + #undef GO + printf_log(LOG_NONE, "Warning, no more slot for libc nftw64 callback\n"); + return NULL; +} + +// globerr +#define GO(A) \ +static uintptr_t my_globerr_fct_##A = 0; \ +static int my_globerr_##A(void* epath, int eerrno) \ +{ \ + return (int)RunFunction(my_context, my_globerr_fct_##A, 2, epath, eerrno); \ +} +SUPER() +#undef GO +static void* findgloberrFct(void* fct) +{ + if(!fct) return NULL; + void* p; + if((p = GetNativeFnc((uintptr_t)fct))) return p; + #define GO(A) if(my_globerr_fct_##A == (uintptr_t)fct) return my_globerr_##A; + SUPER() + #undef GO + #define GO(A) if(my_globerr_fct_##A == 0) {my_globerr_fct_##A = (uintptr_t)fct; return my_globerr_##A; } + SUPER() + #undef GO + printf_log(LOG_NONE, "Warning, no more slot for libc globerr callback\n"); + return NULL; +} +#undef dirent +// filter_dir +#define GO(A) \ +static uintptr_t my_filter_dir_fct_##A = 0; \ +static int my_filter_dir_##A(const struct dirent* a) \ +{ \ + return (int)RunFunction(my_context, my_filter_dir_fct_##A, 1, a); \ +} +SUPER() +#undef GO +static void* findfilter_dirFct(void* fct) +{ + if(!fct) return NULL; + void* p; + if((p = GetNativeFnc((uintptr_t)fct))) return p; + #define GO(A) if(my_filter_dir_fct_##A == (uintptr_t)fct) return my_filter_dir_##A; + SUPER() + #undef GO + #define GO(A) if(my_filter_dir_fct_##A == 0) {my_filter_dir_fct_##A = (uintptr_t)fct; return my_filter_dir_##A; } + SUPER() + #undef GO + printf_log(LOG_NONE, "Warning, no more slot for libc filter_dir callback\n"); + return NULL; +} +// compare_dir +#define GO(A) \ +static uintptr_t my_compare_dir_fct_##A = 0; \ +static int my_compare_dir_##A(const struct dirent* a, const struct dirent* b) \ +{ \ + return (int)RunFunction(my_context, my_compare_dir_fct_##A, 2, a, b); \ +} +SUPER() +#undef GO +static void* findcompare_dirFct(void* fct) +{ + if(!fct) return NULL; + void* p; + if((p = GetNativeFnc((uintptr_t)fct))) return p; + #define GO(A) if(my_compare_dir_fct_##A == (uintptr_t)fct) return my_compare_dir_##A; + SUPER() + #undef GO + #define GO(A) if(my_compare_dir_fct_##A == 0) {my_compare_dir_fct_##A = (uintptr_t)fct; return my_compare_dir_##A; } + SUPER() + #undef GO + printf_log(LOG_NONE, "Warning, no more slot for libc compare_dir callback\n"); + return NULL; +} + +// filter64 +#define GO(A) \ +static uintptr_t my_filter64_fct_##A = 0; \ +static int my_filter64_##A(const struct dirent64* a) \ +{ \ + return (int)RunFunction(my_context, my_filter64_fct_##A, 1, a); \ +} +SUPER() +#undef GO +static void* findfilter64Fct(void* fct) +{ + if(!fct) return NULL; + void* p; + if((p = GetNativeFnc((uintptr_t)fct))) return p; + #define GO(A) if(my_filter64_fct_##A == (uintptr_t)fct) return my_filter64_##A; + SUPER() + #undef GO + #define GO(A) if(my_filter64_fct_##A == 0) {my_filter64_fct_##A = (uintptr_t)fct; return my_filter64_##A; } + SUPER() + #undef GO + printf_log(LOG_NONE, "Warning, no more slot for libc filter64 callback\n"); + return NULL; +} +// compare64 +#define GO(A) \ +static uintptr_t my_compare64_fct_##A = 0; \ +static int my_compare64_##A(const struct dirent64* a, const struct dirent64* b) \ +{ \ + return (int)RunFunction(my_context, my_compare64_fct_##A, 2, a, b); \ +} +SUPER() +#undef GO +static void* findcompare64Fct(void* fct) +{ + if(!fct) return NULL; + void* p; + if((p = GetNativeFnc((uintptr_t)fct))) return p; + #define GO(A) if(my_compare64_fct_##A == (uintptr_t)fct) return my_compare64_##A; + SUPER() + #undef GO + #define GO(A) if(my_compare64_fct_##A == 0) {my_compare64_fct_##A = (uintptr_t)fct; return my_compare64_##A; } + SUPER() + #undef GO + printf_log(LOG_NONE, "Warning, no more slot for libc compare64 callback\n"); + return NULL; +} + +#undef SUPER + +// some my_XXX declare and defines +int32_t my___libc_start_main(x64emu_t* emu, int *(main) (int, char * *, char * *), + int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), + void (*rtld_fini) (void), void (* stack_end)); // implemented in x86run_private.c +EXPORT void my___libc_init_first(x64emu_t* emu, int argc, char* arg0, char** b) +{ + // do nothing specific for now + return; +} +#endif +uint64_t my_syscall(x64emu_t *emu); // implemented in x86syscall.c +void EXPORT my___stack_chk_fail(x64emu_t* emu) +{ + char buff[200]; + #ifdef HAVE_TRACE + sprintf(buff, "%p: Stack is corrupted, aborting (prev IP=%p->%p)\n", (void*)emu->old_ip, (void*)emu->prev2_ip, (void*)emu->prev_ip); + #else + sprintf(buff, "%p: Stack is corrupted, aborting\n", (void*)emu->old_ip); + #endif + StopEmu(emu, buff); +} +void EXPORT my___gmon_start__(x64emu_t *emu) +{ + printf_log(LOG_DEBUG, "__gmon_start__ called (dummy call)\n"); +} +#if 0 +int EXPORT my___cxa_atexit(x64emu_t* emu, void* p, void* a, void* d) +{ + AddCleanup1Arg(emu, p, a); + return 0; +} +void EXPORT my___cxa_finalize(x64emu_t* emu, void* p) +{ + if(!p) { + // p is null, call (and remove) all Cleanup functions + CallAllCleanup(emu); + return; + } + CallCleanup(emu, p); +} +int EXPORT my_atexit(x64emu_t* emu, void *p) +{ + AddCleanup(emu, p); + return 0; +} + +int my_getcontext(x64emu_t* emu, void* ucp); +int my_setcontext(x64emu_t* emu, void* ucp); +int my_makecontext(x64emu_t* emu, void* ucp, void* fnc, int32_t argc, void* argv); +int my_swapcontext(x64emu_t* emu, void* ucp1, void* ucp2); + +// All signal and context functions defined in signals.c + +// All fts function defined in myfts.c + +// getauxval implemented in auxval.c + + +// this one is defined in elfloader.c +int my_dl_iterate_phdr(x64emu_t *emu, void* F, void *data); + + +pid_t EXPORT my_fork(x64emu_t* emu) +{ + // execute atforks prepare functions, in reverse order + for (int i=my_context->atfork_sz-1; i>=0; --i) + if(my_context->atforks[i].prepare) + RunFunctionWithEmu(emu, 0, my_context->atforks[i].prepare, 0); + int type = emu->type; + pid_t v; + v = fork(); + if(type == EMUTYPE_MAIN) + thread_set_emu(emu); + if(v<0) { + printf_log(LOG_NONE, "BOX86: Warning, fork errored... (%d)\n", v); + // error... + } else if(v>0) { + // execute atforks parent functions + for (int i=0; i<my_context->atfork_sz; --i) + if(my_context->atforks[i].parent) + RunFunctionWithEmu(emu, 0, my_context->atforks[i].parent, 0); + + } else /*if(v==0)*/ { + // execute atforks child functions + for (int i=0; i<my_context->atfork_sz; --i) + if(my_context->atforks[i].child) + RunFunctionWithEmu(emu, 0, my_context->atforks[i].child, 0); + } + return v; +} +pid_t EXPORT my___fork(x64emu_t* emu) __attribute__((alias("my_fork"))); +pid_t EXPORT my_vfork(x64emu_t* emu) +{ + #if 1 + emu->quit = 1; + emu->fork = 1; // use regular fork... + return 0; + #else + return 0; + #endif +} + +int EXPORT my_uname(struct utsname *buf) +{ + // sizeof(struct utsname)==390 on i686, and also on ARM, so this seem safe + int ret = uname(buf); + strcpy(buf->machine, /*(box64_steam)?"x86_64":*/"i686"); + return ret; +} + +// X86_O_RDONLY 0x00 +#define X86_O_WRONLY 0x01 // octal 01 +#define X86_O_RDWR 0x02 // octal 02 +#define X86_O_CREAT 0x40 // octal 0100 +#define X86_O_EXCL 0x80 // octal 0200 +#define X86_O_NOCTTY 0x100 // octal 0400 +#define X86_O_TRUNC 0x200 // octal 01000 +#define X86_O_APPEND 0x400 // octal 02000 +#define X86_O_NONBLOCK 0x800 // octal 04000 +#define X86_O_SYNC 0x101000 // octal 04010000 +#define X86_O_DSYNC 0x1000 // octal 010000 +#define X86_O_RSYNC O_SYNC +#define X86_FASYNC 020000 +#define X86_O_DIRECT 040000 +#define X86_O_LARGEFILE 0100000 +#define X86_O_DIRECTORY 0200000 +#define X86_O_NOFOLLOW 0400000 +#define X86_O_NOATIME 01000000 +#define X86_O_CLOEXEC 02000000 +#define X86_O_TMPFILE 020200000 + +#ifndef O_TMPFILE +#define O_TMPFILE (020000000 | O_DIRECTORY) +#endif + +#define SUPER() \ + GO(O_WRONLY) \ + GO(O_RDWR) \ + GO(O_CREAT) \ + GO(O_EXCL) \ + GO(O_NOCTTY) \ + GO(O_TRUNC) \ + GO(O_APPEND) \ + GO(O_NONBLOCK) \ + GO(O_SYNC) \ + GO(O_DSYNC) \ + GO(O_RSYNC) \ + GO(FASYNC) \ + GO(O_DIRECT) \ + GO(O_LARGEFILE) \ + GO(O_TMPFILE) \ + GO(O_DIRECTORY) \ + GO(O_NOFOLLOW) \ + GO(O_NOATIME) \ + GO(O_CLOEXEC) \ + +// x86->arm +int of_convert(int a) +{ + if(!a || a==-1) return a; + int b=0; + #define GO(A) if((a&X86_##A)==X86_##A) {a&=~X86_##A; b|=A;} + SUPER(); + #undef GO + if(a) { + printf_log(LOG_NONE, "Warning, of_convert(...) left over 0x%x, converted 0x%x\n", a, b); + } + return a|b; +} + +// arm->x86 +int of_unconvert(int a) +{ + if(!a || a==-1) return a; + int b=0; + #define GO(A) if((a&A)==A) {a&=~A; b|=X86_##A;} + SUPER(); + #undef GO + if(a) { + printf_log(LOG_NONE, "Warning, of_unconvert(...) left over 0x%x, converted 0x%x\n", a, b); + } + return a|b; +} +#undef SUPER + + +EXPORT void* my__ZGTtnaX (size_t a) { printf("warning _ZGTtnaX called\n"); return NULL; } +EXPORT void my__ZGTtdlPv (void* a) { printf("warning _ZGTtdlPv called\n"); } +EXPORT uint8_t my__ITM_RU1(const uint8_t * a) { printf("warning _ITM_RU1 called\n"); return 0; } +EXPORT uint32_t my__ITM_RU4(const uint32_t * a) { printf("warning _ITM_RU4 called\n"); return 0; } +EXPORT uint64_t my__ITM_RU8(const uint64_t * a) { printf("warning _ITM_RU8 called\n"); return 0; } +EXPORT void my__ITM_memcpyRtWn(void * a, const void * b, size_t c) {printf("warning _ITM_memcpyRtWn called\n"); } +EXPORT void my__ITM_memcpyRnWt(void * a, const void * b, size_t c) {printf("warning _ITM_memcpyRtWn called\n"); } + +EXPORT void my_longjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p, int32_t __val); +EXPORT void my__longjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p, int32_t __val) __attribute__((alias("my_longjmp"))); +EXPORT void my_siglongjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p, int32_t __val) __attribute__((alias("my_longjmp"))); +EXPORT void my___longjmp_chk(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p, int32_t __val) __attribute__((alias("my_longjmp"))); + +EXPORT int32_t my_setjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p); +EXPORT int32_t my__setjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p) __attribute__((alias("my_setjmp"))); +EXPORT int32_t my___sigsetjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p) __attribute__((alias("my_setjmp"))); +#if 0 +EXPORT void my_exit(x64emu_t *emu, int32_t status) +{ + R_EAX = (uint32_t)status; + emu->quit = 1; +} +EXPORT void my__exit(x64emu_t *emu, int32_t status) __attribute__((alias("my_exit"))); +EXPORT void my__Exit(x64emu_t *emu, int32_t status) __attribute__((alias("my_exit"))); +#endif +void myStackAlign(const char* fmt, uint32_t* st, uint32_t* mystack); // align st into mystack according to fmt (for v(f)printf(...)) +typedef int (*iFpp_t)(void*, void*); +typedef int (*iFppp_t)(void*, void*, void*); +typedef int (*iFpupp_t)(void*, uint32_t, void*, void*); +EXPORT int my_printf(x64emu_t *emu, void* fmt, void* b, va_list V) { + #ifndef NOALIGN + // need to align on arm + myStackAlign((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vprintf; + return ((iFpp_t)f)(fmt, VARARGS); + #else + // other platform don't need that + return vprintf((const char*)fmt, V); + #endif +} +EXPORT int my___printf_chk(x64emu_t *emu, void* fmt, void* b, va_list V) __attribute__((alias("my_printf"))); + +EXPORT int my_vprintf(x64emu_t *emu, void* fmt, void* b, va_list V) { + #ifndef NOALIGN + // need to align on arm + myStackAlign((const char*)fmt, (uint32_t*)b, emu->scratch); + PREPARE_VALIST; + void* f = vprintf; + return ((iFpp_t)f)(fmt, VARARGS); + #else + // other platform don't need that + void* f = vprintf; + return ((iFpp_t)f)(fmt, (uint32_t*)b); + #endif +} +EXPORT int my___vprintf_chk(x64emu_t *emu, void* fmt, void* b, va_list V) __attribute__((alias("my_vprintf"))); + +EXPORT int my_vfprintf(x64emu_t *emu, void* F, void* fmt, void* b) { + #ifndef NOALIGN + // need to align on arm + myStackAlign((const char*)fmt, (uint32_t*)b, emu->scratch); + PREPARE_VALIST; + void* f = vfprintf; + return ((iFppp_t)f)(F, fmt, VARARGS); + #else + // other platform don't need that + void* f = vfprintf; + return ((iFppp_t)f)(F, fmt, (uint32_t*)b); + #endif +} +EXPORT int my___vfprintf_chk(x64emu_t *emu, void* F, void* fmt, void* b) __attribute__((alias("my_vfprintf"))); +EXPORT int my__IO_vfprintf(x64emu_t *emu, void* F, void* fmt, void* b) __attribute__((alias("my_vfprintf"))); + +EXPORT int my_fprintf(x64emu_t *emu, void* F, void* fmt, void* b, va_list V) { + #ifndef NOALIGN + // need to align on arm + myStackAlign((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vfprintf; + return ((iFppp_t)f)(F, fmt, VARARGS); + #else + // other platform don't need that + return vfprintf((FILE*)F, (const char*)fmt, V); + #endif +} +EXPORT int my___fprintf_chk(x64emu_t *emu, void* F, void* fmt, void* b, va_list V) __attribute__((alias("my_fprintf"))); + +EXPORT int my_wprintf(x64emu_t *emu, void* fmt, void* b, va_list V) { + #ifndef NOALIGN + // need to align on arm + myStackAlignW((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vwprintf; + return ((iFpp_t)f)(fmt, VARARGS); + #else + // other platform don't need that + return vwprintf((const wchar_t*)fmt, V); + #endif +} +EXPORT int my___wprintf_chk(x64emu_t *emu, int flag, void* fmt, void* b, va_list V) { + #ifndef NOALIGN + // need to align on arm + myStackAlignW((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vwprintf; + return ((iFpp_t)f)(fmt, VARARGS); + #else + // other platform don't need that + return vwprintf((const wchar_t*)fmt, V); + #endif +} +EXPORT int my_fwprintf(x64emu_t *emu, void* F, void* fmt, void* b, va_list V) { + #ifndef NOALIGN + // need to align on arm + myStackAlignW((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vfwprintf; + return ((iFppp_t)f)(F, fmt, VARARGS); + #else + // other platform don't need that + return vfwprintf((FILE*)F, (const wchar_t*)fmt, V); + #endif +} +EXPORT int my___fwprintf_chk(x64emu_t *emu, void* F, void* fmt, void* b, va_list V) __attribute__((alias("my_fwprintf"))); + +EXPORT int my_vfwprintf(x64emu_t *emu, void* F, void* fmt, void* b) { + #ifndef NOALIGN + myStackAlignW((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vfwprintf; + return ((iFppp_t)f)(F, fmt, VARARGS); + #else + void* f = vfwprintf; + return ((iFppp_t)f)(F, fmt, b); + #endif +} + +EXPORT int my_vwprintf(x64emu_t *emu, void* fmt, void* b) { + #ifndef NOALIGN + myStackAlignW((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vwprintf; + return ((iFpp_t)f)(fmt, VARARGS); + #else + void* f = vwprintf; + return ((iFpp_t)f)(fmt, b); + #endif +} + +EXPORT void *my_div(void *result, int numerator, int denominator) { + *(div_t *)result = div(numerator, denominator); + return result; +} + +EXPORT int my_snprintf(x64emu_t* emu, void* buff, uint32_t s, void * fmt, void * b, va_list V) { + #ifndef NOALIGN + // need to align on arm + myStackAlign((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vsnprintf; + int r = ((iFpupp_t)f)(buff, s, fmt, VARARGS); + return r; + #else + return vsnprintf((char*)buff, s, (char*)fmt, V); + #endif +} +EXPORT int my___snprintf_chk(x64emu_t* emu, void* buff, uint32_t s, void * fmt, void * b, va_list V) __attribute__((alias("my_snprintf"))); +EXPORT int my___snprintf(x64emu_t* emu, void* buff, uint32_t s, void * fmt, void * b, va_list V) __attribute__((alias("my_snprintf"))); + +EXPORT int my_sprintf(x64emu_t* emu, void* buff, void * fmt, void * b, va_list V) { + #ifndef NOALIGN + // need to align on arm + myStackAlign((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vsprintf; + return ((iFppp_t)f)(buff, fmt, VARARGS); + #else + return vsprintf((char*)buff, (char*)fmt, V); + #endif +} +EXPORT int my___sprintf_chk(x64emu_t* emu, void* buff, void * fmt, void * b, va_list V) __attribute__((alias("my_sprintf"))); + +EXPORT int my_asprintf(x64emu_t* emu, void** buff, void * fmt, void * b, va_list V) { + #ifndef NOALIGN + // need to align on arm + myStackAlign((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vasprintf; + return ((iFppp_t)f)(buff, fmt, VARARGS); + #else + return vasprintf((char**)buff, (char*)fmt, V); + #endif +} +EXPORT int my___asprintf(x64emu_t* emu, void** buff, void * fmt, void * b, va_list V) __attribute__((alias("my_asprintf"))); + + +EXPORT int my_vsprintf(x64emu_t* emu, void* buff, void * fmt, void * b, va_list V) { + #ifndef NOALIGN + // need to align on arm + myStackAlign((const char*)fmt, (uint32_t*)b, emu->scratch); + PREPARE_VALIST; + void* f = vsprintf; + int r = ((iFppp_t)f)(buff, fmt, VARARGS); + return r; + #else + void* f = vsprintf; + int r = ((iFppp_t)f)(buff, fmt, (uint32_t*)b); + return r; + #endif +} +EXPORT int my___vsprintf_chk(x64emu_t* emu, void* buff, void * fmt, void * b, va_list V) __attribute__((alias("my_vsprintf"))); + +#ifdef POWERPCLE +EXPORT int my_vfscanf(x64emu_t* emu, void* stream, void* fmt, void* b) // probably uneeded to do a GOM, a simple wrap should enough +{ + //myStackAlign((const char*)fmt, (uint32_t*)b, emu->scratch); + PREPARE_VALIST_(b); + void* f = vfscanf; + + return ((iFppp_t)f)(stream, fmt, VARARGS_(b)); +} + + + +EXPORT int my_vsscanf(x64emu_t* emu, void* stream, void* fmt, void* b) +{ + //myStackAlign((const char*)fmt, (uint32_t*)b, emu->scratch); + PREPARE_VALIST_(b); + void* f = vsscanf; + + return ((iFppp_t)f)(stream, fmt, VARARGS_(b)); +} + +EXPORT int my__vsscanf(x64emu_t* emu, void* stream, void* fmt, void* b) __attribute__((alias("my_vsscanf"))); +EXPORT int my_sscanf(x64emu_t* emu, void* stream, void* fmt, void* b) __attribute__((alias("my_vsscanf"))); + +EXPORT int my__IO_vfscanf(x64emu_t* emu, void* stream, void* fmt, void* b) __attribute__((alias("my_vfscanf"))); +EXPORT int my___isoc99_vsscanf(x64emu_t* emu, void* stream, void* fmt, void* b) __attribute__((alias("my_vsscanf"))); + +EXPORT int my___isoc99_vfscanf(x64emu_t* emu, void* stream, void* fmt, void* b) __attribute__((alias("my_vfscanf"))); +EXPORT int my___isoc99_fscanf(x64emu_t* emu, void* stream, void* fmt, void* b) __attribute__((alias("my_vfscanf"))); + +EXPORT int my___isoc99_sscanf(x64emu_t* emu, void* stream, void* fmt, void* b) +{ + void* f = sscanf; + PREPARE_VALIST; + + return ((iFppp_t)f)(stream, fmt, VARARGS); +} +#endif + +EXPORT int my_vsnprintf(x64emu_t* emu, void* buff, uint32_t s, void * fmt, void * b, va_list V) { + #ifndef NOALIGN + // need to align on arm + myStackAlign((const char*)fmt, (uint32_t*)b, emu->scratch); + PREPARE_VALIST; + void* f = vsnprintf; + int r = ((iFpupp_t)f)(buff, s, fmt, VARARGS); + return r; + #else + void* f = vsnprintf; + int r = ((iFpupp_t)f)(buff, s, fmt, (uint32_t*)b); + return r; + #endif +} +EXPORT int my___vsnprintf(x64emu_t* emu, void* buff, uint32_t s, void * fmt, void * b, va_list V) __attribute__((alias("my_vsnprintf"))); +EXPORT int my___vsnprintf_chk(x64emu_t* emu, void* buff, uint32_t s, void * fmt, void * b, va_list V) __attribute__((alias("my_vsnprintf"))); + +EXPORT int my_vasprintf(x64emu_t* emu, void* strp, void* fmt, void* b, va_list V) +{ + #ifndef NOALIGN + // need to align on arm + myStackAlign((const char*)fmt, (uint32_t*)b, emu->scratch); + PREPARE_VALIST; + void* f = vasprintf; + int r = ((iFppp_t)f)(strp, fmt, VARARGS); + return r; + #else + void* f = vasprintf; + int r = ((iFppp_t)f)(strp, fmt, (uint32_t*)b); + return r; + #endif +} +EXPORT int my___vasprintf_chk(x64emu_t* emu, void* strp, int flags, void* fmt, void* b, va_list V) +{ + #ifndef NOALIGN + // need to align on arm + myStackAlign((const char*)fmt, (uint32_t*)b, emu->scratch); + PREPARE_VALIST; + void* f = vasprintf; + int r = ((iFppp_t)f)(strp, fmt, VARARGS); + return r; + #else + void* f = vasprintf; + int r = ((iFppp_t)f)(strp, fmt, (uint32_t*)b); + return r; + #endif +} + +EXPORT int my___asprintf_chk(x64emu_t* emu, void* result_ptr, int flags, void* fmt, void* b, va_list V) +{ + #ifndef NOALIGN + myStackAlign((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vasprintf; + return ((iFppp_t)f)(result_ptr, fmt, VARARGS); + #else + return vasprintf((char**)result_ptr, (char*)fmt, V); + #endif +} + +EXPORT int my_vswprintf(x64emu_t* emu, void* buff, uint32_t s, void * fmt, void * b, va_list V) { + #ifndef NOALIGN + // need to align on arm + myStackAlignW((const char*)fmt, (uint32_t*)b, emu->scratch); + PREPARE_VALIST; + void* f = vswprintf; + int r = ((iFpupp_t)f)(buff, s, fmt, VARARGS); + return r; + #else + void* f = vswprintf; + int r = ((iFpupp_t)f)(buff, s, fmt, (uint32_t*)b); + return r; + #endif +} +EXPORT int my___vswprintf(x64emu_t* emu, void* buff, uint32_t s, void * fmt, void * b, va_list V) __attribute__((alias("my_vswprintf"))); +EXPORT int my___vswprintf_chk(x64emu_t* emu, void* buff, uint32_t s, void * fmt, void * b, va_list V) __attribute__((alias("my_vswprintf"))); + +EXPORT void my_verr(x64emu_t* emu, int eval, void* fmt, void* b) { + #ifndef NOALIGN + myStackAlignW((const char*)fmt, (uint32_t*)b, emu->scratch); + PREPARE_VALIST; + void* f = verr; + ((vFipp_t)f)(eval, fmt, VARARGS); + #else + void* f = verr; + ((vFipp_t)f)(eval, fmt, (uint32_t*)b); + #endif +} + +EXPORT void my_vwarn(x64emu_t* emu, void* fmt, void* b) { + #ifndef NOALIGN + myStackAlignW((const char*)fmt, (uint32_t*)b, emu->scratch); + PREPARE_VALIST; + void* f = vwarn; + ((vFpp_t)f)(fmt, VARARGS); + #else + void* f = vwarn; + ((vFpp_t)f)(fmt, (uint32_t*)b); + #endif +} + +EXPORT int my___swprintf_chk(x64emu_t* emu, void* s, uint32_t n, int32_t flag, uint32_t slen, void* fmt, void * b) +{ + #ifndef NOALIGN + myStackAlignW((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vswprintf; + int r = ((iFpupp_t)f)(s, n, fmt, VARARGS); + return r; + #else + void* f = vswprintf; + int r = ((iFpupp_t)f)(s, n, fmt, b); + return r; + #endif +} +EXPORT int my_swprintf(x64emu_t* emu, void* s, uint32_t n, void* fmt, void *b) +{ + #ifndef NOALIGN + myStackAlignW((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vswprintf; + int r = ((iFpupp_t)f)(s, n, fmt, VARARGS); + return r; + #else + void* f = vswprintf; + int r = ((iFpupp_t)f)(s, n, fmt, b); + return r; + #endif +} + +EXPORT void my__ITM_addUserCommitAction(x64emu_t* emu, void* cb, uint32_t b, void* c) +{ + // disabled for now... Are all this _ITM_ stuff really mendatory? + #if 0 + // quick and dirty... Should store the callback to be removed later.... + libc_my_t *my = (libc_my_t *)emu->context->libclib->priv.w.p2; + x64emu_t *cbemu = AddCallback(emu, (uintptr_t)cb, 1, c, NULL, NULL, NULL); + my->_ITM_addUserCommitAction(libc1ArgCallback, b, cbemu); + // should keep track of cbemu to remove at some point... + #else + printf("warning _ITM_addUserCommitAction called\n"); + #endif +} +EXPORT void my__ITM_registerTMCloneTable(x64emu_t* emu, void* p, uint32_t s) {} +EXPORT void my__ITM_deregisterTMCloneTable(x64emu_t* emu, void* p) {} + + +struct i386_stat { + uint64_t st_dev; + uint32_t __pad1; + uint32_t st_ino; + uint32_t st_mode; + uint32_t st_nlink; + uint32_t st_uid; + uint32_t st_gid; + uint64_t st_rdev; + uint32_t __pad2; + int32_t st_size; + int32_t st_blksize; + int32_t st_blocks; + int32_t st_atime_sec; + uint32_t st_atime_nsec; + int32_t st_mtime_sec; + uint32_t st_mtime_nsec; + int32_t st_ctime_sec; + uint32_t st_ctime_nsec; + uint32_t __unused4; + uint32_t __unused5; +} __attribute__((packed)); + +static int FillStatFromStat64(int vers, const struct stat64 *st64, void *st32) +{ + struct i386_stat *i386st = (struct i386_stat *)st32; + + if (vers != 3) + { + errno = EINVAL; + return -1; + } + + i386st->st_dev = st64->st_dev; + i386st->__pad1 = 0; + if (fix_64bit_inodes) + { + i386st->st_ino = st64->st_ino ^ (st64->st_ino >> 32); + } + else + { + i386st->st_ino = st64->st_ino; + if ((st64->st_ino >> 32) != 0) + { + errno = EOVERFLOW; + return -1; + } + } + i386st->st_mode = st64->st_mode; + i386st->st_nlink = st64->st_nlink; + i386st->st_uid = st64->st_uid; + i386st->st_gid = st64->st_gid; + i386st->st_rdev = st64->st_rdev; + i386st->__pad2 = 0; + i386st->st_size = st64->st_size; + if ((i386st->st_size >> 31) != (int32_t)(st64->st_size >> 32)) + { + errno = EOVERFLOW; + return -1; + } + i386st->st_blksize = st64->st_blksize; + i386st->st_blocks = st64->st_blocks; + if ((i386st->st_blocks >> 31) != (int32_t)(st64->st_blocks >> 32)) + { + errno = EOVERFLOW; + return -1; + } + i386st->st_atime_sec = st64->st_atim.tv_sec; + i386st->st_atime_nsec = st64->st_atim.tv_nsec; + i386st->st_mtime_sec = st64->st_mtim.tv_sec; + i386st->st_mtime_nsec = st64->st_mtim.tv_nsec; + i386st->st_ctime_sec = st64->st_ctim.tv_sec; + i386st->st_ctime_nsec = st64->st_ctim.tv_nsec; + i386st->__unused4 = 0; + i386st->__unused5 = 0; + return 0; +} + +EXPORT int my___fxstat(x64emu_t *emu, int vers, int fd, void* buf) +{ + if (vers == 1) + { + static iFiip_t f = NULL; + if(!f) { + library_t* lib = my_lib; + if(!lib) + { + errno = EINVAL; + return -1; + } + f = (iFiip_t)dlsym(lib->priv.w.lib, "__fxstat"); + } + + return f(vers, fd, buf); + } + struct stat64 st; + int r = fstat64(fd, &st); + if (r) return r; + r = FillStatFromStat64(vers, &st, buf); + return r; +} + +EXPORT int my___fxstat64(x64emu_t *emu, int vers, int fd, void* buf) +{ + struct stat64 st; + int r = fstat64(fd, &st); + //int r = syscall(__NR_stat64, fd, &st); + UnalignStat64(&st, buf); + return r; +} + +EXPORT int my___xstat(x64emu_t* emu, int v, void* path, void* buf) +{ + if (v == 1) + { + static iFipp_t f = NULL; + if(!f) { + library_t* lib = my_lib; + if(!lib) + { + errno = EINVAL; + return -1; + } + f = (iFipp_t)dlsym(lib->priv.w.lib, "__xstat"); + } + + return f(v, path, buf); + } + struct stat64 st; + int r = stat64((const char*)path, &st); + if (r) return r; + r = FillStatFromStat64(v, &st, buf); + return r; +} + +EXPORT int my___xstat64(x64emu_t* emu, int v, void* path, void* buf) +{ + struct stat64 st; + int r = stat64((const char*)path, &st); + UnalignStat64(&st, buf); + return r; +} + +EXPORT int my___lxstat(x64emu_t* emu, int v, void* name, void* buf) +{ + if (v == 1) + { + static iFipp_t f = NULL; + if(!f) { + library_t* lib = my_lib; + if(!lib) + { + errno = EINVAL; + return -1; + } + f = (iFipp_t)dlsym(lib->priv.w.lib, "__lxstat"); + } + + return f(v, name, buf); + } + struct stat64 st; + int r = lstat64((const char*)name, &st); + if (r) return r; + r = FillStatFromStat64(v, &st, buf); + return r; +} + +EXPORT int my___lxstat64(x64emu_t* emu, int v, void* name, void* buf) +{ + struct stat64 st; + int r = lstat64((const char*)name, &st); + UnalignStat64(&st, buf); + return r; +} + +EXPORT int my___fxstatat(x64emu_t* emu, int v, int d, void* path, void* buf, int flags) +{ + struct stat64 st; + int r = fstatat64(d, path, &st, flags); + if (r) return r; + r = FillStatFromStat64(v, &st, buf); + return r; +} + +EXPORT int my___fxstatat64(x64emu_t* emu, int v, int d, void* path, void* buf, int flags) +{ + struct stat64 st; + int r = fstatat64(d, path, &st, flags); + UnalignStat64(&st, buf); + return r; +} + +EXPORT int my__IO_file_stat(x64emu_t* emu, void* f, void* buf) +{ + struct stat64 st; + libc_my_t *my = (libc_my_t *)emu->context->libclib->priv.w.p2; + int r = my->_IO_file_stat(f, &st); + UnalignStat64(&st, buf); + return r; +} + +EXPORT int my_fstatfs64(int fd, void* buf) +{ + struct statfs64 st; + int r = fstatfs64(fd, &st); + UnalignStatFS64(&st, buf); + return r; +} + +EXPORT int my_statfs64(const char* path, void* buf) +{ + struct statfs64 st; + int r = statfs64(path, &st); + UnalignStatFS64(&st, buf); + return r; +} + + +typedef struct compare_r_s { + x64emu_t* emu; + uintptr_t f; + void* data; + int r; +} compare_r_t; + +static int my_compare_r_cb(void* a, void* b, compare_r_t* arg) +{ + return (int)RunFunctionWithEmu(arg->emu, 0, arg->f, 2+arg->r, a, b, arg->data); +} +EXPORT void my_qsort(x64emu_t* emu, void* base, size_t nmemb, size_t size, void* fnc) +{ + compare_r_t args; + args.emu = emu; args.f = (uintptr_t)fnc; args.r = 0; args.data = NULL; + qsort_r(base, nmemb, size, (__compar_d_fn_t)my_compare_r_cb, &args); +} +EXPORT void my_qsort_r(x64emu_t* emu, void* base, size_t nmemb, size_t size, void* fnc, void* data) +{ + compare_r_t args; + args.emu = emu; args.f = (uintptr_t)fnc; args.r = 1; args.data = data; + qsort_r(base, nmemb, size, (__compar_d_fn_t)my_compare_r_cb, &args); +} + +EXPORT void* my_bsearch(x64emu_t* emu, void* key, void* base, size_t nmemb, size_t size, void* fnc) +{ + return bsearch(key, base, nmemb, size, findcompareFct(fnc)); +} + +EXPORT void* my_lsearch(x64emu_t* emu, void* key, void* base, size_t* nmemb, size_t size, void* fnc) +{ + return lsearch(key, base, nmemb, size, findcompareFct(fnc)); +} +EXPORT void* my_lfind(x64emu_t* emu, void* key, void* base, size_t* nmemb, size_t size, void* fnc) +{ + return lfind(key, base, nmemb, size, findcompareFct(fnc)); +} + + +struct i386_dirent { + uint32_t d_ino; + int32_t d_off; + uint16_t d_reclen; + uint8_t d_type; + char d_name[256]; +}; + +EXPORT void* my_readdir(x64emu_t* emu, void* dirp) +{ + if (fix_64bit_inodes) + { + struct dirent64 *dp64 = readdir64((DIR *)dirp); + if (!dp64) return NULL; + uint32_t ino32 = dp64->d_ino ^ (dp64->d_ino >> 32); + int32_t off32 = dp64->d_off; + struct i386_dirent *dp32 = (struct i386_dirent *)&(dp64->d_off); + dp32->d_ino = ino32; + dp32->d_off = off32; + dp32->d_reclen -= 8; + return dp32; + } + else + { + static pFp_t f = NULL; + if(!f) { + library_t* lib = my_lib; + if(!lib) return NULL; + f = (pFp_t)dlsym(lib->priv.w.lib, "readdir"); + } + + return f(dirp); + } +} + +EXPORT int32_t my_readdir_r(x64emu_t* emu, void* dirp, void* entry, void** result) +{ + struct dirent64 d64, *dp64; + if (fix_64bit_inodes && (sizeof(d64.d_name) > 1)) + { + static iFppp_t f = NULL; + if(!f) { + library_t* lib = my_lib; + if(!lib) + { + *result = NULL; + return 0; + } + f = (iFppp_t)dlsym(lib->priv.w.lib, "readdir64_r"); + } + + int r = f(dirp, &d64, &dp64); + if (r || !dp64 || !entry) + { + *result = NULL; + return r; + } + + struct i386_dirent *dp32 = (struct i386_dirent *)entry; + int namelen = dp64->d_reclen - offsetof(struct dirent64, d_name); + if (namelen > sizeof(dp32->d_name)) + { + *result = NULL; + return ENAMETOOLONG; + } + + dp32->d_ino = dp64->d_ino ^ (dp64->d_ino >> 32); + dp32->d_off = dp64->d_off; + dp32->d_reclen = namelen + offsetof(struct i386_dirent, d_name); + dp32->d_type = dp64->d_type; + memcpy(dp32->d_name, dp64->d_name, namelen); + *result = dp32; + return 0; + } + else + { + static iFppp_t f = NULL; + if(!f) { + library_t* lib = my_lib; + if(!lib) + { + *result = NULL; + return 0; + } + f = (iFppp_t)dlsym(lib->priv.w.lib, "readdir_r"); + } + + return f(dirp, entry, result); + } +} + +static int isProcSelf(const char *path, const char* w) +{ + if(strncmp(path, "/proc/", 6)==0) { + char tmp[64]; + // check if self .... + sprintf(tmp, "/proc/self/%s", w); + if(strcmp((const char*)path, tmp)==0) + return 1; + // check if self PID .... + pid_t pid = getpid(); + sprintf(tmp, "/proc/%d/%s", pid, w); + if(strcmp((const char*)path, tmp)==0) + return 1; + } + return 0; +} + +EXPORT int32_t my_readlink(x64emu_t* emu, void* path, void* buf, uint32_t sz) +{ + if(isProcSelf((const char*)path, "exe")) { + // special case for self... + return strlen(strncpy((char*)buf, emu->context->fullpath, sz)); + } + return readlink((const char*)path, (char*)buf, sz); +} +#ifndef NOALIGN + +static int nCPU = 0; +static double bogoMips = 100.; + +void grabNCpu() { + nCPU = 1; // default number of CPU to 1 + FILE *f = fopen("/proc/cpuinfo", "r"); + size_t dummy; + if(f) { + nCPU = 0; + size_t len = 0; + char* line = NULL; + while ((dummy = getline(&line, &len, f)) != -1) { + if(!strncmp(line, "processor\t", strlen("processor\t"))) + ++nCPU; + if(!nCPU && !strncmp(line, "BogoMIPS\t", strlen("BogoMIPS\t"))) { + // grab 1st BogoMIPS + float tmp; + if(sscanf(line, "BogoMIPS\t: %g", &tmp)==1) + bogoMips = tmp; + } + } + if(line) free(line); + fclose(f); + if(!nCPU) nCPU=1; + } +} +void CreateCPUInfoFile(int fd) +{ + size_t dummy; + char buff[600]; + double freq = 600.0; // default to 600 MHz + // try to get actual ARM max speed: + FILE *f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", "r"); + if(f) { + int r; + if(1==fscanf(f, "%d", &r)) + freq = r/1000.; + fclose(f); + } + if(!nCPU) + grabNCpu(); + int n = nCPU; + // generate fake CPUINFO + int gigahertz=(freq>=1000.); + #define P \ + dummy = write(fd, buff, strlen(buff)) + for (int i=0; i<n; ++i) { + sprintf(buff, "processor\t: %d\n", i); + P; + sprintf(buff, "vendor_id\t: GenuineIntel\n"); + P; + sprintf(buff, "cpu family\t: 6\n"); + P; + sprintf(buff, "model\t\t: 1\n"); + P; + sprintf(buff, "model name\t: Intel Pentium IV @ %g%cHz\n", gigahertz?(freq/1000.):freq, gigahertz?'G':'M'); + P; + sprintf(buff, "stepping\t: 1\nmicrocode\t: 0x10\n"); + P; + sprintf(buff, "cpu MHz\t\t: %g\n", freq); + P; + sprintf(buff, "cache size\t: %d\n", 4096); + P; + sprintf(buff, "physical id\t: %d\nsiblings\t: %d\n", i, n); + P; + sprintf(buff, "core id\t\t:%d\ncpu cores\t: %d\n", i, 1); + P; + sprintf(buff, "bogomips\t: %g\n", bogoMips); + P; + sprintf(buff, "flags\t\t: fpu cx8 sep cmov clflush mmx sse sse2 rdtscp ssse3 fma fxsr cx16 movbe pni\n"); + P; + sprintf(buff, "\n"); + P; + } + (void)dummy; + #undef P +} +static int isCpuTopology(const char* p) { + if(strstr(p, "/sys/devices/system/cpu/cpu")!=p) + return -1; //nope + if( FileExist(p, -1)) + return -1; //no need to fake it + char buf[512]; + const char* p2 = p + strlen("/sys/devices/system/cpu/cpu"); + int n = 0; + while(*p2>='0' && *p2<='9') { + n = n*10+ *p2 - '0'; + ++p2; + } + if(!nCPU) + grabNCpu(); + if(n>=nCPU) // filter for non existing cpu + return -1; + snprintf(buf, 512, "/sys/devices/system/cpu/cpu%d/topology/core_id", n); + if(!strcmp(p, buf)) + return n; + return -1; +} +static void CreateCPUTopologyCoreID(int fd, int cpu) +{ + char buf[512]; + snprintf(buf, 512, "%d\n", cpu); + size_t dummy = write(fd, buf, strlen(buf)); + (void)dummy; +} + + +#define TMP_CPUINFO "box64_tmpcpuinfo" +#define TMP_CPUTOPO "box64_tmpcputopo%d" +#endif +#define TMP_MEMMAP "box64_tmpmemmap" +#define TMP_CMDLINE "box64_tmpcmdline" +EXPORT int32_t my_open(x64emu_t* emu, void* pathname, int32_t flags, uint32_t mode) +{ + if(isProcSelf((const char*) pathname, "cmdline")) { + // special case for self command line... + #if 0 + char tmpcmdline[200] = {0}; + char tmpbuff[100] = {0}; + sprintf(tmpbuff, "%s/cmdlineXXXXXX", getenv("TMP")?getenv("TMP"):"."); + int tmp = mkstemp(tmpbuff); + int dummy; + if(tmp<0) return open(pathname, flags, mode); + dummy = write(tmp, emu->context->fullpath, strlen(emu->context->fullpath)+1); + for (int i=1; i<emu->context->argc; ++i) + dummy = write(tmp, emu->context->argv[i], strlen(emu->context->argv[i])+1); + lseek(tmp, 0, SEEK_SET); + #else + int tmp = shm_open(TMP_CMDLINE, O_RDWR | O_CREAT, S_IRWXU); + if(tmp<0) return open(pathname, flags, mode); + shm_unlink(TMP_CMDLINE); // remove the shm file, but it will still exist because it's currently in use + int dummy = write(tmp, emu->context->fullpath, strlen(emu->context->fullpath)+1); + (void)dummy; + for (int i=1; i<emu->context->argc; ++i) + dummy = write(tmp, emu->context->argv[i], strlen(emu->context->argv[i])+1); + lseek(tmp, 0, SEEK_SET); + #endif + return tmp; + } + if(isProcSelf((const char*)pathname, "exe")) { + return open(emu->context->fullpath, flags, mode); + } + #ifndef NOALIGN + if(strcmp((const char*)pathname, "/proc/cpuinfo")==0) { + // special case for cpuinfo + int tmp = shm_open(TMP_CPUINFO, O_RDWR | O_CREAT, S_IRWXU); + if(tmp<0) return open(pathname, flags, mode); // error fallback + shm_unlink(TMP_CPUINFO); // remove the shm file, but it will still exist because it's currently in use + CreateCPUInfoFile(tmp); + lseek(tmp, 0, SEEK_SET); + return tmp; + } + if(isCpuTopology((const char*)pathname)!=-1) { + int n = isCpuTopology((const char*)pathname); + char buf[512]; + snprintf(buf, 512, TMP_CPUTOPO, n); + int tmp = shm_open(buf, O_RDWR | O_CREAT, S_IRWXU); + if(tmp<0) return open(pathname, flags, mode); // error fallback + shm_unlink(buf); // remove the shm file, but it will still exist because it's currently in use + CreateCPUTopologyCoreID(tmp, n); + lseek(tmp, 0, SEEK_SET); + return tmp; + } + #endif + int ret = open(pathname, flags, mode); + return ret; +} +EXPORT int32_t my___open(x64emu_t* emu, void* pathname, int32_t flags, uint32_t mode) __attribute__((alias("my_open"))); + +#ifdef DYNAREC +static int hasDBFromAddress(uintptr_t addr) +{ + int idx = (addr>>DYNAMAP_SHIFT); + return getDB(idx)?1:0; +} +#endif + +EXPORT int32_t my_read(int fd, void* buf, uint32_t count) +{ + int ret = read(fd, buf, count); +#ifdef DYNAREC + if(ret!=count && ret>0) { + // continue reading... + void* p = buf+ret; + if(hasDBFromAddress((uintptr_t)p)) { + // allow writing the whole block (this happens with HalfLife, libMiles load code directly from .mix and other file like that) + unprotectDB((uintptr_t)p, count-ret); + int l; + do { + l = read(fd, p, count-ret); + if(l>0) { + p+=l; ret+=l; + } + } while(l>0); + } + } +#endif + return ret; +} + +EXPORT int32_t my_open64(x64emu_t* emu, void* pathname, int32_t flags, uint32_t mode) +{ + if(isProcSelf((const char*)pathname, "cmdline")) { + // special case for self command line... + #if 0 + char tmpcmdline[200] = {0}; + char tmpbuff[100] = {0}; + sprintf(tmpbuff, "%s/cmdlineXXXXXX", getenv("TMP")?getenv("TMP"):"."); + int tmp = mkstemp64(tmpbuff); + int dummy; + if(tmp<0) return open64(pathname, flags, mode); + dummy = write(tmp, emu->context->fullpath, strlen(emu->context->fullpath)+1); + for (int i=1; i<emu->context->argc; ++i) + dummy = write(tmp, emu->context->argv[i], strlen(emu->context->argv[i])+1); + lseek64(tmp, 0, SEEK_SET); + #else + int tmp = shm_open(TMP_CMDLINE, O_RDWR | O_CREAT, S_IRWXU); + if(tmp<0) return open64(pathname, flags, mode); + shm_unlink(TMP_CMDLINE); // remove the shm file, but it will still exist because it's currently in use + int dummy = write(tmp, emu->context->fullpath, strlen(emu->context->fullpath)+1); + (void)dummy; + for (int i=1; i<emu->context->argc; ++i) + dummy = write(tmp, emu->context->argv[i], strlen(emu->context->argv[i])+1); + lseek(tmp, 0, SEEK_SET); + #endif + return tmp; + } + if(isProcSelf((const char*)pathname, "exe")) { + return open64(emu->context->fullpath, flags, mode); + } + #ifndef NOALIGN + if(strcmp((const char*)pathname, "/proc/cpuinfo")==0) { + // special case for cpuinfo + int tmp = shm_open(TMP_CPUINFO, O_RDWR | O_CREAT, S_IRWXU); + if(tmp<0) return open64(pathname, flags, mode); // error fallback + shm_unlink(TMP_CPUINFO); // remove the shm file, but it will still exist because it's currently in use + CreateCPUInfoFile(tmp); + lseek(tmp, 0, SEEK_SET); + return tmp; + } + if(isCpuTopology((const char*)pathname)!=-1) { + int n = isCpuTopology((const char*)pathname); + char buf[512]; + snprintf(buf, 512, TMP_CPUTOPO, n); + int tmp = shm_open(buf, O_RDWR | O_CREAT, S_IRWXU); + if(tmp<0) return open64(pathname, flags, mode); // error fallback + shm_unlink(buf); // remove the shm file, but it will still exist because it's currently in use + CreateCPUTopologyCoreID(tmp, n); + lseek(tmp, 0, SEEK_SET); + return tmp; + } + #endif + return open64(pathname, flags, mode); +} + +EXPORT FILE* my_fopen(x64emu_t* emu, const char* path, const char* mode) +{ + if(isProcSelf(path, "maps")) { + // special case for self memory map + int tmp = shm_open(TMP_MEMMAP, O_RDWR | O_CREAT, S_IRWXU); + if(tmp<0) return fopen(path, mode); // error fallback + shm_unlink(TMP_MEMMAP); // remove the shm file, but it will still exist because it's currently in use + CreateMemorymapFile(emu->context, tmp); + lseek(tmp, 0, SEEK_SET); + return fdopen(tmp, mode); + } + #ifndef NOALIGN + if(strcmp(path, "/proc/cpuinfo")==0) { + // special case for cpuinfo + int tmp = shm_open(TMP_CPUINFO, O_RDWR | O_CREAT, S_IRWXU); + if(tmp<0) return fopen(path, mode); // error fallback + shm_unlink(TMP_CPUINFO); // remove the shm file, but it will still exist because it's currently in use + CreateCPUInfoFile(tmp); + lseek(tmp, 0, SEEK_SET); + return fdopen(tmp, mode); + } + if(isCpuTopology(path)!=-1) { + int n = isCpuTopology(path); + char buf[512]; + snprintf(buf, 512, TMP_CPUTOPO, n); + int tmp = shm_open(buf, O_RDWR | O_CREAT, S_IRWXU); + if(tmp<0) return fopen(path, mode); // error fallback + shm_unlink(buf); // remove the shm file, but it will still exist because it's currently in use + CreateCPUTopologyCoreID(tmp, n); + lseek(tmp, 0, SEEK_SET); + return fdopen(tmp, mode);; + } + #endif + if(isProcSelf(path, "exe")) { + return fopen(emu->context->fullpath, mode); + } + return fopen(path, mode); +} + +EXPORT FILE* my_fopen64(x64emu_t* emu, const char* path, const char* mode) +{ + if(isProcSelf(path, "maps")) { + // special case for self memory map + int tmp = shm_open(TMP_MEMMAP, O_RDWR | O_CREAT, S_IRWXU); + if(tmp<0) return fopen64(path, mode); // error fallback + shm_unlink(TMP_MEMMAP); // remove the shm file, but it will still exist because it's currently in use + CreateMemorymapFile(emu->context, tmp); + lseek(tmp, 0, SEEK_SET); + return fdopen(tmp, mode); + } + #ifndef NOALIGN + if(strcmp(path, "/proc/cpuinfo")==0) { + // special case for cpuinfo + int tmp = shm_open(TMP_CPUINFO, O_RDWR | O_CREAT, S_IRWXU); + if(tmp<0) return fopen64(path, mode); // error fallback + shm_unlink(TMP_CPUINFO); // remove the shm file, but it will still exist because it's currently in use + CreateCPUInfoFile(tmp); + lseek(tmp, 0, SEEK_SET); + return fdopen(tmp, mode); + } + if(isCpuTopology(path)!=-1) { + int n = isCpuTopology(path); + char buf[512]; + snprintf(buf, 512, TMP_CPUTOPO, n); + int tmp = shm_open(buf, O_RDWR | O_CREAT, S_IRWXU); + if(tmp<0) return fopen(path, mode); // error fallback + shm_unlink(buf); // remove the shm file, but it will still exist because it's currently in use + CreateCPUTopologyCoreID(tmp, n); + lseek(tmp, 0, SEEK_SET); + return fdopen(tmp, mode);; + } + #endif + if(isProcSelf(path, "exe")) { + return fopen64(emu->context->fullpath, mode); + } + return fopen64(path, mode); +} + + +EXPORT int my_mkstemps64(x64emu_t* emu, char* template, int suffixlen) +{ + library_t* lib = my_lib; + if(!lib) return 0; + void* f = dlsym(lib->priv.w.lib, "mkstemps64"); + if(f) + return ((iFpi_t)f)(template, suffixlen); + // implement own version... + // TODO: check size of template, and if really XXXXXX is there + char* fname = strdup(template); + do { + strcpy(fname, template); + char num[8]; + sprintf(num, "%06d", rand()%999999); + memcpy(fname+strlen(fname)-suffixlen-6, num, 6); + } while(!FileExist(fname, -1)); + int ret = open64(fname, O_EXCL); + free(fname); + return ret; +} + +EXPORT int32_t my_ftw(x64emu_t* emu, void* pathname, void* B, int32_t nopenfd) +{ + static iFppi_t f = NULL; + if(!f) { + library_t* lib = my_lib; + if(!lib) return 0; + f = (iFppi_t)dlsym(lib->priv.w.lib, "ftw"); + } + + return f(pathname, findftwFct(B), nopenfd); +} + +EXPORT int32_t my_nftw(x64emu_t* emu, void* pathname, void* B, int32_t nopenfd, int32_t flags) +{ + static iFppii_t f = NULL; + if(!f) { + library_t* lib = my_lib; + if(!lib) return 0; + f = (iFppii_t)dlsym(lib->priv.w.lib, "nftw"); + } + + return f(pathname, findnftwFct(B), nopenfd, flags); +} + +EXPORT void* my_ldiv(x64emu_t* emu, void* p, int32_t num, int32_t den) +{ + *((ldiv_t*)p) = ldiv(num, den); + return p; +} + +#ifndef NOALIGN +EXPORT int my_epoll_create(x64emu_t* emu, int size) +{ + return epoll_create(size); +} +EXPORT int my_epoll_create1(x64emu_t* emu, int flags) +{ + return epoll_create1(flags); +} +EXPORT int32_t my_epoll_ctl(x64emu_t* emu, int32_t epfd, int32_t op, int32_t fd, void* event) +{ + struct epoll_event _event[1] = {0}; + if(event && (op!=EPOLL_CTL_DEL)) + AlignEpollEvent(_event, event, 1); + return epoll_ctl(epfd, op, fd, event?_event:event); +} +EXPORT int32_t my_epoll_wait(x64emu_t* emu, int32_t epfd, void* events, int32_t maxevents, int32_t timeout) +{ + struct epoll_event _events[maxevents]; + //AlignEpollEvent(_events, events, maxevents); + int32_t ret = epoll_wait(epfd, events?_events:NULL, maxevents, timeout); + if(ret>0) + UnalignEpollEvent(events, _events, ret); + return ret; +} +#endif + +EXPORT int32_t my_glob(x64emu_t *emu, void* pat, int32_t flags, void* errfnc, void* pglob) +{ + static iFpipp_t f = NULL; + if(!f) { + library_t* lib = my_lib; + if(!lib) return 0; + f = (iFpipp_t)dlsym(lib->priv.w.lib, "glob"); + } + + return f(pat, flags, findgloberrFct(errfnc), pglob); +} + +EXPORT int32_t my_glob64(x64emu_t *emu, void* pat, int32_t flags, void* errfnc, void* pglob) +{ + return glob64(pat, flags, findgloberrFct(errfnc), pglob); +} + +EXPORT int my_scandir64(x64emu_t *emu, void* dir, void* namelist, void* sel, void* comp) +{ + return scandir64(dir, namelist, findfilter64Fct(sel), findcompare64Fct(comp)); +} + +EXPORT int my_scandir(x64emu_t *emu, void* dir, void* namelist, void* sel, void* comp) +{ + static iFpppp_t f = NULL; + if(!f) { + library_t* lib = my_lib; + if(!lib) return 0; + f = (iFpppp_t)dlsym(lib->priv.w.lib, "scandir"); + } + + return f(dir, namelist, findfilter_dirFct(sel), findcompare_dirFct(comp)); +} + +EXPORT int my_ftw64(x64emu_t* emu, void* filename, void* func, int descriptors) +{ + return ftw64(filename, findftw64Fct(func), descriptors); +} + +EXPORT int32_t my_nftw64(x64emu_t* emu, void* pathname, void* B, int32_t nopenfd, int32_t flags) +{ + return nftw64(pathname, findnftw64Fct(B), nopenfd, flags); +} + +EXPORT int32_t my_execv(x64emu_t* emu, const char* path, char* const argv[]) +{ + int self = isProcSelf(path, "exe"); + int x86 = FileIsX86ELF(path); + printf_log(LOG_DEBUG, "execv(\"%s\", %p) is x86=%d\n", path, argv, x86); + #if 1 + if ((x86 || self) && argv) { + int skip_first = 0; + if(strlen(path)>=strlen("wine-preloader") && strcmp(path+strlen(path)-strlen("wine-preloader"), "wine-preloader")==0) + skip_first++; + // count argv... + int n=skip_first; + while(argv[n]) ++n; + const char** newargv = (const char**)calloc(n+2, sizeof(char*)); + newargv[0] = emu->context->box64path; + memcpy(newargv+1, argv+skip_first, sizeof(char*)*(n+1)); + if(self) newargv[1] = emu->context->fullpath; + printf_log(LOG_DEBUG, " => execv(\"%s\", %p [\"%s\", \"%s\", \"%s\"...:%d])\n", emu->context->box64path, newargv, newargv[0], n?newargv[1]:"", (n>1)?newargv[2]:"",n); + int ret = execv(newargv[0], (char* const*)newargv); + free(newargv); + return ret; + } + #endif + if(self && !argv) + return execv(emu->context->box64path, argv); + return execv(path, argv); +} + +EXPORT int32_t my_execve(x64emu_t* emu, const char* path, char* const argv[], char* const envp[]) +{ + int self = isProcSelf(path, "exe"); + int x86 = FileIsX86ELF(path); + printf_log(LOG_DEBUG, "execv(\"%s\", %p) is x86=%d\n", path, argv, x86); + #if 1 + if ((x86 || self) && argv) { + int skip_first = 0; + if(strlen(path)>=strlen("wine-preloader") && strcmp(path+strlen(path)-strlen("wine-preloader"), "wine-preloader")==0) + skip_first++; + // count argv... + int n=skip_first; + while(argv[n]) ++n; + const char** newargv = (const char**)calloc(n+2, sizeof(char*)); + newargv[0] = emu->context->box64path; + memcpy(newargv+1, argv+skip_first, sizeof(char*)*(n+1)); + if(self) newargv[1] = emu->context->fullpath; + printf_log(LOG_DEBUG, " => execv(\"%s\", %p [\"%s\", \"%s\", \"%s\"...:%d])\n", emu->context->box64path, newargv, newargv[0], n?newargv[1]:"", (n>1)?newargv[2]:"",n); + int ret = execve(newargv[0], (char* const*)newargv, envp); + free(newargv); + return ret; + } + #endif + if(self && !argv) + return execve(emu->context->box64path, argv, envp); + return execve(path, argv, envp); +} + +// execvp should use PATH to search for the program first +EXPORT int32_t my_execvp(x64emu_t* emu, const char* path, char* const argv[]) +{ + // need to use BOX86_PATH / PATH here... + char* fullpath = ResolveFile(path, &my_context->box64_path); + // use fullpath... + int self = isProcSelf(fullpath, "exe"); + int x86 = FileIsX86ELF(fullpath); + printf_log(LOG_DEBUG, "execvp(\"%s\", %p), IsX86=%d / fullpath=\"%s\"\n", path, argv, x86, fullpath); + free(fullpath); + if ((x86 || self) && argv) { + // count argv... + int i=0; + while(argv[i]) ++i; + char** newargv = (char**)calloc(i+2, sizeof(char*)); + newargv[0] = emu->context->box64path; + for (int j=0; j<i; ++j) + newargv[j+1] = argv[j]; + if(self) newargv[1] = emu->context->fullpath; + printf_log(LOG_DEBUG, " => execvp(\"%s\", %p [\"%s\", \"%s\"...:%d])\n", newargv[0], newargv, newargv[1], i?newargv[2]:"", i); + int ret = execvp(newargv[0], newargv); + free(newargv); + return ret; + } + if(self && !argv) + return execvp(emu->context->box64path, argv); + // fullpath is gone, so the search will only be on PATH, not on BOX86_PATH (is that an issue?) + return execvp(path, argv); +} + +// execvp should use PATH to search for the program first +EXPORT int32_t my_posix_spawnp(x64emu_t* emu, pid_t* pid, const char* path, + const posix_spawn_file_actions_t *actions, const posix_spawnattr_t* attrp, char* const argv[], char* const envp[]) +{ + // need to use BOX86_PATH / PATH here... + char* fullpath = ResolveFile(path, &my_context->box64_path); + // use fullpath... + int self = isProcSelf(fullpath, "exe"); + int x86 = FileIsX86ELF(fullpath); + printf_log(LOG_DEBUG, "posix_spawnp(%p, \"%s\", %p, %p, %p, %p), IsX86=%d / fullpath=\"%s\"\n", pid, path, actions, attrp, argv, envp, x86, fullpath); + free(fullpath); + if ((x86 || self)) { + // count argv... + int i=0; + while(argv[i]) ++i; + char** newargv = (char**)calloc(i+2, sizeof(char*)); + newargv[0] = emu->context->box64path; + for (int j=0; j<i; ++j) + newargv[j+1] = argv[j]; + if(self) newargv[1] = emu->context->fullpath; + printf_log(LOG_DEBUG, " => posix_spawnp(%p, \"%s\", %p, %p, %p [\"%s\", \"%s\"...:%d], %p)\n", pid, newargv[0], actions, attrp, newargv, newargv[1], i?newargv[2]:"", i, envp); + int ret = posix_spawnp(pid, newargv[0], actions, attrp, newargv, envp); + printf_log(LOG_DEBUG, "posix_spawnp returned %d\n", ret); + //free(newargv); + return ret; + } + // fullpath is gone, so the search will only be on PATH, not on BOX86_PATH (is that an issue?) + return posix_spawnp(pid, path, actions, attrp, argv, envp); +} + +EXPORT void my__Jv_RegisterClasses() {} + +EXPORT int32_t my___cxa_thread_atexit_impl(x64emu_t* emu, void* dtor, void* obj, void* dso) +{ + printf_log(LOG_INFO, "Warning, call to __cxa_thread_atexit_impl(%p, %p, %p) ignored\n", dtor, obj, dso); + return 0; +} + +extern void __chk_fail(); +EXPORT unsigned long int my___fdelt_chk (unsigned long int d) +{ + if (d >= FD_SETSIZE) + __chk_fail (); + + return d / __NFDBITS; +} + +EXPORT int32_t my_getrandom(x64emu_t* emu, void* buf, uint32_t buflen, uint32_t flags) +{ + // not always implemented on old linux version... + library_t* lib = my_lib; + if(!lib) return 0; + void* f = dlsym(lib->priv.w.lib, "getrandom"); + if(f) + return ((iFpuu_t)f)(buf, buflen, flags); + // do what should not be done, but it's better then nothing.... + FILE * rnd = fopen("/dev/urandom", "rb"); + uint32_t r = fread(buf, 1, buflen, rnd); + fclose(rnd); + return r; +} + +EXPORT int32_t my_recvmmsg(x64emu_t* emu, int32_t fd, void* msgvec, uint32_t vlen, uint32_t flags, void* timeout) +{ + // Implemented starting glibc 2.12+ + library_t* lib = my_lib; + if(!lib) return 0; + void* f = dlsym(lib->priv.w.lib, "recvmmsg"); + if(f) + return ((iFipuup_t)f)(fd, msgvec, vlen, flags, timeout); + // Use the syscall + return syscall(__NR_recvmmsg, fd, msgvec, vlen, flags, timeout); +} + +EXPORT int32_t my___sendmmsg(x64emu_t* emu, int32_t fd, void* msgvec, uint32_t vlen, uint32_t flags) +{ + // Implemented starting glibc 2.14+ + library_t* lib = my_lib; + if(!lib) return 0; + void* f = dlsym(lib->priv.w.lib, "__sendmmsg"); + if(f) + return ((iFipuu_t)f)(fd, msgvec, vlen, flags); + // Use the syscall + return syscall(__NR_sendmmsg, fd, msgvec, vlen, flags); +} + +EXPORT int32_t my___register_atfork(x64emu_t *emu, void* prepare, void* parent, void* child, void* handle) +{ + // this is partly incorrect, because the emulated funcionts should be executed by actual fork and not by my_atfork... + if(my_context->atfork_sz==my_context->atfork_cap) { + my_context->atfork_cap += 4; + my_context->atforks = (atfork_fnc_t*)realloc(my_context->atforks, my_context->atfork_cap*sizeof(atfork_fnc_t)); + } + my_context->atforks[my_context->atfork_sz].prepare = (uintptr_t)prepare; + my_context->atforks[my_context->atfork_sz].parent = (uintptr_t)parent; + my_context->atforks[my_context->atfork_sz].child = (uintptr_t)child; + my_context->atforks[my_context->atfork_sz].handle = handle; + return 0; +} + +EXPORT uint64_t my___umoddi3(uint64_t a, uint64_t b) +{ + return a%b; +} +EXPORT uint64_t my___udivdi3(uint64_t a, uint64_t b) +{ + return a/b; +} +EXPORT int64_t my___divdi3(int64_t a, int64_t b) +{ + return a/b; +} + +EXPORT int32_t my___poll_chk(void* a, uint32_t b, int c, int l) +{ + return poll(a, b, c); // no check... +} + +EXPORT int32_t my_fcntl64(x64emu_t* emu, int32_t a, int32_t b, uint32_t d1, uint32_t d2, uint32_t d3, uint32_t d4, uint32_t d5, uint32_t d6) +{ + // Implemented starting glibc 2.14+ + library_t* lib = my_lib; + if(!lib) return 0; + iFiiV_t f = dlsym(lib->priv.w.lib, "fcntl64"); + if(b==F_SETFL) + d1 = of_convert(d1); + if(b==F_GETLK64 || b==F_SETLK64 || b==F_SETLKW64) + { + my_flock64_t fl; + AlignFlock64(&fl, (void*)d1); + int ret = f?f(a, b, &fl):fcntl(a, b, &fl); + UnalignFlock64((void*)d1, &fl); + return ret; + } + //TODO: check if better to use the syscall or regular fcntl? + //return syscall(__NR_fcntl64, a, b, d1); // should be enough + int ret = f?f(a, b, d1):fcntl(a, b, d1); + + if(b==F_GETFL && ret!=-1) + ret = of_unconvert(ret); + + return ret; +} + +EXPORT int32_t my_fcntl(x64emu_t* emu, int32_t a, int32_t b, uint32_t d1, uint32_t d2, uint32_t d3, uint32_t d4, uint32_t d5, uint32_t d6) +{ + if(b==F_SETFL && d1==0xFFFFF7FF) { + // special case for ~O_NONBLOCK... + int flags = fcntl(a, F_GETFL); + if(flags&O_NONBLOCK) { + flags &= ~O_NONBLOCK; + return fcntl(a, b, flags); + } + return 0; + } + if(b==F_SETFL) + d1 = of_convert(d1); + if(b==F_GETLK64 || b==F_SETLK64 || b==F_SETLKW64) + { + my_flock64_t fl; + AlignFlock64(&fl, (void*)d1); + int ret = fcntl(a, b, &fl); + UnalignFlock64((void*)d1, &fl); + return ret; + } + int ret = fcntl(a, b, d1); + if(b==F_GETFL && ret!=-1) + ret = of_unconvert(ret); + + return ret; +} +EXPORT int32_t my___fcntl(x64emu_t* emu, int32_t a, int32_t b, uint32_t d1, uint32_t d2, uint32_t d3, uint32_t d4, uint32_t d5, uint32_t d6) __attribute__((alias("my_fcntl"))); + +EXPORT int32_t my_preadv64(x64emu_t* emu, int32_t fd, void* v, int32_t c, int64_t o) +{ + library_t* lib = my_lib; + if(!lib) return 0; + void* f = dlsym(lib->priv.w.lib, "preadv64"); + if(f) + return ((iFipiI_t)f)(fd, v, c, o); + return syscall(__NR_preadv, fd, v, c,(uint32_t)(o&0xffffffff), (uint32_t)((o>>32)&0xffffffff)); +} + +EXPORT int32_t my_pwritev64(x64emu_t* emu, int32_t fd, void* v, int32_t c, int64_t o) +{ + library_t* lib = my_lib; + if(!lib) return 0; + void* f = dlsym(lib->priv.w.lib, "pwritev64"); + if(f) + return ((iFipiI_t)f)(fd, v, c, o); + #ifdef __arm__ + return syscall(__NR_pwritev, fd, v, c, 0, (uint32_t)(o&0xffffffff), (uint32_t)((o>>32)&0xffffffff)); + // on arm, 64bits args needs to be on even/odd register, so need to put a 0 for aligment + #else + return syscall(__NR_pwritev, fd, v, c,(uint32_t)(o&0xffffffff), (uint32_t)((o>>32)&0xffffffff)); + #endif +} + +EXPORT int32_t my_accept4(x64emu_t* emu, int32_t fd, void* a, void* l, int32_t flags) +{ + library_t* lib = my_lib; + if(!lib) return 0; + void* f = dlsym(lib->priv.w.lib, "accept4"); + if(f) + return ((iFippi_t)f)(fd, a, l, flags); + if(!flags) + return accept(fd, a, l); + return syscall(__NR_accept4, fd, a, l, flags); +} + +EXPORT int32_t my_fallocate64(int fd, int mode, int64_t offs, int64_t len) +{ + iFiiII_t f = NULL; + static int done = 0; + if(!done) { + library_t* lib = my_lib; + f = (iFiiII_t)dlsym(lib->priv.w.lib, "fallocate64"); + done = 1; + } + if(f) + return f(fd, mode, offs, len); + else + return syscall(__NR_fallocate, fd, mode, (uint32_t)(offs&0xffffffff), (uint32_t)((offs>>32)&0xffffffff), (uint32_t)(len&0xffffffff), (uint32_t)((len>>32)&0xffffffff)); + //return posix_fallocate64(fd, offs, len); +} + +EXPORT struct __processor_model +{ + unsigned int __cpu_vendor; + unsigned int __cpu_type; + unsigned int __cpu_subtype; + unsigned int __cpu_features[1]; +} my___cpu_model; + +#include "cpu_info.h" +void InitCpuModel() +{ + // some pseudo random cpu info... + my___cpu_model.__cpu_vendor = VENDOR_INTEL; + my___cpu_model.__cpu_type = INTEL_PENTIUM_M; + my___cpu_model.__cpu_subtype = 0; // N/A + my___cpu_model.__cpu_features[0] = (1<<FEATURE_CMOV) + | (1<<FEATURE_MMX) + | (1<<FEATURE_SSE) + | (1<<FEATURE_SSE2) + | (1<<FEATURE_SSE3) + | (1<<FEATURE_SSSE3) + | (1<<FEATURE_MOVBE) + | (1<<FEATURE_ADX); +} +#endif +EXPORT const unsigned short int *my___ctype_b; +EXPORT const int32_t *my___ctype_tolower; +EXPORT const int32_t *my___ctype_toupper; + +void ctSetup() +{ + my___ctype_b = *(__ctype_b_loc()); + my___ctype_toupper = *(__ctype_toupper_loc()); + my___ctype_tolower = *(__ctype_tolower_loc()); +} + +EXPORT void* my___libc_stack_end; +void stSetup(box64context_t* context) +{ + my___libc_stack_end = context->stack; // is this the end, or should I add stasz? +} + +EXPORT void my___register_frame_info(void* a, void* b) +{ + // nothing +} +EXPORT void* my___deregister_frame_info(void* a) +{ + return NULL; +} + +EXPORT void* my____brk_addr = NULL; +#if 0 +// longjmp / setjmp +typedef struct jump_buff_i386_s { + uint32_t save_ebx; + uint32_t save_esi; + uint32_t save_edi; + uint32_t save_ebp; + uint32_t save_esp; + uint32_t save_eip; +} jump_buff_i386_t; + +typedef struct __jmp_buf_tag_s { + jump_buff_i386_t __jmpbuf; + int __mask_was_saved; + __sigset_t __saved_mask; +} __jmp_buf_tag_t; + +void EXPORT my_longjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p, int32_t __val) +{ + jump_buff_i386_t *jpbuff = &((__jmp_buf_tag_t*)p)->__jmpbuf; + //restore regs + R_EBX = jpbuff->save_ebx; + R_ESI = jpbuff->save_esi; + R_EDI = jpbuff->save_edi; + R_EBP = jpbuff->save_ebp; + R_ESP = jpbuff->save_esp; + // jmp to saved location, plus restore val to eax + R_EAX = __val; + R_EIP = jpbuff->save_eip; + if(emu->quitonlongjmp) { + emu->longjmp = 1; + emu->quit = 1; + } +} + +EXPORT int32_t my_setjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p) +{ + jump_buff_i386_t *jpbuff = &((__jmp_buf_tag_t*)p)->__jmpbuf; + // save the buffer + jpbuff->save_ebx = R_EBX; + jpbuff->save_esi = R_ESI; + jpbuff->save_edi = R_EDI; + jpbuff->save_ebp = R_EBP; + jpbuff->save_esp = R_ESP+4; // include "return address" + jpbuff->save_eip = *(uint32_t*)(R_ESP); + // and that's it.. Nothing more for now + return 0; +} + +EXPORT void my___explicit_bzero_chk(x64emu_t* emu, void* dst, uint32_t len, uint32_t dstlen) +{ + memset(dst, 0, len); +} + +EXPORT void* my_realpath(x64emu_t* emu, void* path, void* resolved_path) +{ + + if(isProcSelf(path, "exe")) { + return realpath(emu->context->fullpath, resolved_path); + } + return realpath(path, resolved_path); +} + +EXPORT void* my_mmap(x64emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, int offset) +{ + if(prot&PROT_WRITE) + prot|=PROT_READ; // PROT_READ is implicit with PROT_WRITE on i386 + if(box64_log<LOG_DEBUG) {dynarec_log(LOG_DEBUG, "mmap(%p, %lu, 0x%x, 0x%x, %d, %d) =>", addr, length, prot, flags, fd, offset);} + void* ret = mmap(addr, length, prot, flags, fd, offset); + if(box64_log<LOG_DEBUG) {dynarec_log(LOG_DEBUG, "%p\n", ret);} + #ifdef DYNAREC + if(box64_dynarec && ret!=(void*)-1) { + if(flags&0x100000 && addr!=ret) + { + // program used MAP_FIXED_NOREPLACE but the host linux didn't support it + // and responded with a different address, so ignore it + } else { + if(prot& PROT_EXEC) + addDBFromAddressRange((uintptr_t)ret, length); + else + cleanDBFromAddressRange((uintptr_t)ret, length, prot?0:1); + } + } + #endif + if(ret!=(void*)-1) + setProtection((uintptr_t)ret, length, prot); + return ret; +} + +EXPORT void* my_mmap64(x64emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, int64_t offset) +{ + if(prot&PROT_WRITE) + prot|=PROT_READ; // PROT_READ is implicit with PROT_WRITE on i386 + if(box64_log<LOG_DEBUG) {dynarec_log(LOG_DEBUG, "mmap64(%p, %lu, 0x%x, 0x%x, %d, %lld) =>", addr, length, prot, flags, fd, offset);} + void* ret = mmap64(addr, length, prot, flags, fd, offset); + if(box64_log<LOG_DEBUG) {dynarec_log(LOG_DEBUG, "%p\n", ret);} + #ifdef DYNAREC + if(box64_dynarec && ret!=(void*)-1) { + if(flags&0x100000 && addr!=ret) + { + // program used MAP_FIXED_NOREPLACE but the host linux didn't support it + // and responded with a different address, so ignore it + } else { + if(prot& PROT_EXEC) + addDBFromAddressRange((uintptr_t)ret, length); + else + cleanDBFromAddressRange((uintptr_t)ret, length, prot?0:1); + } + } + #endif + if(ret!=(void*)-1) + setProtection((uintptr_t)ret, length, prot); + return ret; +} + +EXPORT void* my_mremap(x64emu_t* emu, void* old_addr, size_t old_size, size_t new_size, int flags, void* new_addr) +{ + dynarec_log(/*LOG_DEBUG*/LOG_NONE, "mremap(%p, %u, %u, %d, %p)=>", old_addr, old_size, new_size, flags, new_addr); + void* ret = mremap(old_addr, old_size, new_size, flags, new_addr); + if(ret==(void*)-1) + return ret; // failed... + uint32_t prot = getProtection((uintptr_t)old_addr)&~PROT_DYNAREC; + if(ret==old_addr) { + if(old_size && old_size<new_size) { + setProtection((uintptr_t)ret+old_size, new_size-old_size, prot); + #ifdef DYNAREC + if(box64_dynarec) + addDBFromAddressRange((uintptr_t)ret+old_size, new_size-old_size); + #endif + } else if(old_size && new_size<old_size) { + setProtection((uintptr_t)ret+new_size, old_size-new_size, 0); + #ifdef DYNAREC + if(box64_dynarec) + cleanDBFromAddressRange((uintptr_t)ret+new_size, new_size-old_size, 1); + #endif + } else if(!old_size) { + setProtection((uintptr_t)ret, new_size, prot); + #ifdef DYNAREC + if(box64_dynarec) + addDBFromAddressRange((uintptr_t)ret, new_size); + #endif + } + } else { + if(old_size + #ifdef MREMAP_DONTUNMAP + && flags&MREMAP_DONTUNMAP==0 + #endif + ) { + setProtection((uintptr_t)old_addr, old_size, 0); + #ifdef DYNAREC + if(box64_dynarec) + cleanDBFromAddressRange((uintptr_t)old_addr, old_size, 1); + #endif + } + setProtection((uintptr_t)ret, new_size, prot); // should copy the protection from old block + #ifdef DYNAREC + if(box64_dynarec) + addDBFromAddressRange((uintptr_t)ret, new_size); + #endif + } + return ret; +} + +EXPORT int my_munmap(x64emu_t* emu, void* addr, unsigned long length) +{ + dynarec_log(LOG_DEBUG, "munmap(%p, %lu)\n", addr, length); + #ifdef DYNAREC + if(box64_dynarec) { + cleanDBFromAddressRange((uintptr_t)addr, length, 1); + } + #endif + int ret = munmap(addr, length); + if(!ret) + setProtection((uintptr_t)addr, length, 0); + return ret; +} + +EXPORT int my_mprotect(x64emu_t* emu, void *addr, unsigned long len, int prot) +{ + dynarec_log(LOG_DEBUG, "mprotect(%p, %lu, 0x%x)\n", addr, len, prot); + if(prot&PROT_WRITE) + prot|=PROT_READ; // PROT_READ is implicit with PROT_WRITE on i386 + int ret = mprotect(addr, len, prot); + #ifdef DYNAREC + if(box64_dynarec) { + if(prot& PROT_EXEC) + addDBFromAddressRange((uintptr_t)addr, len); + else + cleanDBFromAddressRange((uintptr_t)addr, len, 0); + } + #endif + if(!ret) + updateProtection((uintptr_t)addr, len, prot); + return ret; +} + +typedef struct my_cookie_s { + uintptr_t r, w, s, c; + void* cookie; +} my_cookie_t; + +static ssize_t my_cookie_read(void *p, char *buf, size_t size) +{ + my_cookie_t* cookie = (my_cookie_t*)p; + return (ssize_t)RunFunction(my_context, cookie->r, 3, cookie->cookie, buf, size); +} +static ssize_t my_cookie_write(void *p, const char *buf, size_t size) +{ + my_cookie_t* cookie = (my_cookie_t*)p; + return (ssize_t)RunFunction(my_context, cookie->w, 3, cookie->cookie, buf, size); +} +static int my_cookie_seek(void *p, off64_t *offset, int whence) +{ + my_cookie_t* cookie = (my_cookie_t*)p; + return RunFunction(my_context, cookie->s, 3, cookie->cookie, offset, whence); +} +static int my_cookie_close(void *p) +{ + my_cookie_t* cookie = (my_cookie_t*)p; + int ret = 0; + if(cookie->c) + ret = RunFunction(my_context, cookie->c, 1, cookie->cookie); + free(cookie); + return ret; +} +EXPORT void* my_fopencookie(x64emu_t* emu, void* cookie, void* mode, void* read, void* write, void* seek, void* close) +{ + cookie_io_functions_t io_funcs = {read?my_cookie_read:NULL, write?my_cookie_write:NULL, seek?my_cookie_seek:NULL, my_cookie_close}; + my_cookie_t *cb = (my_cookie_t*)calloc(1, sizeof(my_cookie_t)); + cb->r = (uintptr_t)read; + cb->w = (uintptr_t)write; + cb->s = (uintptr_t)seek; + cb->c = (uintptr_t)close; + cb->cookie = cookie; + return fopencookie(cb, mode, io_funcs); +} + +EXPORT long my_prlimit64(void* pid, uint32_t res, void* new_rlim, void* old_rlim) +{ + return syscall(__NR_prlimit64, pid, res, new_rlim, old_rlim); +} + +EXPORT void* my_reallocarray(void* ptr, size_t nmemb, size_t size) +{ + return realloc(ptr, nmemb*size); +} + +#ifndef __OPEN_NEEDS_MODE +# define __OPEN_NEEDS_MODE(oflag) \ + (((oflag) & O_CREAT) != 0) +// || ((oflag) & __O_TMPFILE) == __O_TMPFILE) +#endif +EXPORT int my___open_nocancel(x64emu_t* emu, void* file, int oflag, int* b) +{ + int mode = 0; + if (__OPEN_NEEDS_MODE (oflag)) + mode = b[0]; + return openat(AT_FDCWD, file, oflag, mode); +} + +EXPORT int my___libc_alloca_cutoff(x64emu_t* emu, size_t size) +{ + // not always implemented on old linux version... + library_t* lib = my_lib; + if(!lib) return 0; + void* f = dlsym(lib->priv.w.lib, "__libc_alloca_cutoff"); + if(f) + return ((iFL_t)f)(size); + // approximate version but it's better than nothing.... + return (size<=(65536*4)); +} + +// DL functions from wrappedlibdl.c +void* my_dlopen(x64emu_t* emu, void *filename, int flag); +int my_dlclose(x64emu_t* emu, void *handle); +void* my_dlsym(x64emu_t* emu, void *handle, void *symbol); +EXPORT int my___libc_dlclose(x64emu_t* emu, void* handle) +{ + return my_dlclose(emu, handle); +} +EXPORT void* my___libc_dlopen_mode(x64emu_t* emu, void* name, int mode) +{ + return my_dlopen(emu, name, mode); +} +EXPORT void* my___libc_dlsym(x64emu_t* emu, void* handle, void* name) +{ + return my_dlsym(emu, handle, name); +} + +// all obstack function defined in obstack.c file +void obstackSetup(); + +EXPORT int my_nanosleep(const struct timespec *req, struct timespec *rem) +{ + if(!req) + return 0; // workaround for some strange calls + return nanosleep(req, rem); +} + +#ifndef NOALIGN +// wrapped malloc using calloc, it seems x86 malloc set alloc'd block to zero somehow +EXPORT void* my_malloc(unsigned long size) +{ + return calloc(1, size); +} +#endif + +#ifdef PANDORA +#define RENAME_NOREPLACE (1 << 0) +#define RENAME_EXCHANGE (1 << 1) +#define RENAME_WHITEOUT (1 << 2) +EXPORT int my_renameat2(int olddirfd, void* oldpath, int newdirfd, void* newpath, uint32_t flags) +{ + // simulate that function, but + if(flags&RENAME_NOREPLACE) { + if(FileExist(newpath, -1)) { + errno = EEXIST; + return -1; + } + flags &= ~RENAME_NOREPLACE; + } + if(!flags) return renameat(olddirfd, oldpath, newdirfd, newpath); + if(flags&RENAME_WHITEOUT) { + errno = EINVAL; + return -1; // not handling that + } + if((flags&RENAME_EXCHANGE) && (olddirfd==-1) && (newdirfd==-1)) { + // cannot do atomically... + char* tmp = (char*)malloc(strlen(oldpath)+10); // create a temp intermediary + tmp = strcat(oldpath, ".tmp"); + int ret = renameat(-1, oldpath, -1, tmp); + if(ret==-1) return -1; + ret = renameat(-1, newpath, -1, oldpath); + if(ret==-1) return -1; + ret = renameat(-1, tmp, -1, newpath); + free(tmp); + return ret; + } + return -1; // unknown flags +} +#endif + +#ifndef __NR_memfd_create +#define MFD_CLOEXEC 0x0001U +#define MFD_ALLOW_SEALING 0x0002U +EXPORT int my_memfd_create(x64emu_t* emu, void* name, uint32_t flags) +{ + // try to simulate that function + uint32_t fl = O_RDWR | O_CREAT; + if(flags&MFD_CLOEXEC) + fl |= O_CLOEXEC; + int tmp = shm_open(name, fl, S_IRWXU); + if(tmp<0) return -1; + shm_unlink(name); // remove the shm file, but it will still exist because it's currently in use + return tmp; +} +#endif + +#ifndef GRND_RANDOM +#define GRND_RANDOM 0x0002 +#endif +EXPORT int my_getentropy(x64emu_t* emu, void* buffer, size_t length) +{ + library_t* lib = my_lib; + if(!lib) return 0; + void* f = dlsym(lib->priv.w.lib, "getentropy"); + if(f) + return ((iFpL_t)f)(buffer, length); + // custom implementation + if(length>256) { + errno = EIO; + return -1; + } + int ret = my_getrandom(emu, buffer, length, GRND_RANDOM); + if(ret!=length) { + errno = EIO; + return -1; + } + return 0; +} + +EXPORT void my_mcount(void* frompc, void* selfpc) +{ + // stub doing nothing... + return; +} + +union semun { + int val; /* Value for SETVAL */ + struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */ + unsigned short *array; /* Array for GETALL, SETALL */ + struct seminfo *__buf; /* Buffer for IPC_INFO + (Linux-specific) */ +}; + +EXPORT int my_semctl(x64emu_t* emu, int semid, int semnum, int cmd, union semun b) +{ + iFiiiV_t f = semctl; + return ((iFiiiV_t)f)(semid, semnum, cmd, b); +} +#endif + +EXPORT char** my_environ = NULL; +EXPORT char** my__environ = NULL; +EXPORT char** my___environ = NULL; // all aliases + +EXPORT char* my___progname = NULL; +EXPORT char* my___progname_full = NULL; +EXPORT char* my_program_invocation_name = NULL; +EXPORT char* my_program_invocation_short_name = NULL; + +#define PRE_INIT\ + if(box64_tcmalloc_minimal) \ + lib->priv.w.lib = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL); \ + else + +#define CUSTOM_INIT \ + box64->libclib = lib; \ + my_lib = lib; \ + /*InitCpuModel();*/ \ + ctSetup(); \ + stSetup(box64); \ + /*obstackSetup();*/ \ + my_environ = my__environ = my___environ = box64->envv; \ + my___progname_full = my_program_invocation_name = box64->argv[0]; \ + my___progname = my_program_invocation_short_name = \ + strrchr(box64->argv[0], '/'); \ + lib->priv.w.p2 = getLIBCMy(lib); \ + lib->priv.w.needed = 3; \ + lib->priv.w.neededlibs = (char**)calloc(lib->priv.w.needed, sizeof(char*)); \ + lib->priv.w.neededlibs[0] = strdup("ld-linux-x86-64.so.2"); \ + lib->priv.w.neededlibs[1] = strdup("libpthread.so.0"); \ + lib->priv.w.neededlibs[2] = strdup("librt.so.1"); + +#define CUSTOM_FINI \ + freeLIBCMy(lib->priv.w.p2); \ + free(lib->priv.w.p2); \ + my_lib = NULL; + +#include "wrappedlib_init.h" diff --git a/src/wrapped/wrappedlibc_private.h b/src/wrapped/wrappedlibc_private.h new file mode 100755 index 00000000..4efac07b --- /dev/null +++ b/src/wrapped/wrappedlibc_private.h @@ -0,0 +1,2238 @@ +#if !(defined(GO) && defined(GOM) && defined(GO2) && defined(DATA) && defined(GOS)) +#error Meh... +#endif + +//GO(a64l, +//GO(abort, +//DATAB(__abort_msg, +//GO(abs, +//GO(accept, +//GO(accept4, +//GOW(access, +//GO(acct, +//GOW(addmntent, +//GOW(addseverity, +//GOW(adjtime, +//GO(__adjtimex, +//GOW(adjtimex, +//GOW(advance, +//GO(alarm, +//GOW(aligned_alloc, +//GOW(alphasort, +//GOW(alphasort64, +//GO(__arch_prctl, +//GOW(arch_prctl, +//DATA(argp_err_exit_status, +//GOW(argp_error, +//GOW(argp_failure, +//GOW(argp_help, +//GOW(argp_parse, +//DATAB(argp_program_bug_address, +//DATAB(argp_program_version, +//DATAB(argp_program_version_hook, +//GOW(argp_state_help, +//GOW(argp_usage, +//GOW(argz_add, +//GOW(argz_add_sep, +//GOW(argz_append, +//GO(__argz_count, +//GOW(argz_count, +//GOW(argz_create, +//GOW(argz_create_sep, +//GO(argz_delete, +//GOW(argz_extract, +//GOW(argz_insert, +//GO(__argz_next, +//GOW(argz_next, +//GOW(argz_replace, +//GO(__argz_stringify, +//GOW(argz_stringify, +//GO(asctime, +//GOW(asctime_r, +//GO(__asprintf, +//GOW(asprintf, +//GO(__asprintf_chk, +//GO(__assert, +//GO(__assert_fail, +//GO(__assert_perror_fail, +//GO(atof, +//GO(atoi, +//GO(atol, +//GO(atoll, +//GO(authdes_create, +//GO(authdes_getucred, +//GO(authdes_pk_create, +//GO(_authenticate, +//GO(authnone_create, +//GO(authunix_create, +//GO(authunix_create_default, +//GO(__backtrace, +//GOW(backtrace, +//GO(__backtrace_symbols, +//GOW(backtrace_symbols, +//GO(__backtrace_symbols_fd, +//GOW(backtrace_symbols_fd, +//GOW(basename, +//GO(bcopy, +//GO(bdflush, +//GOW(bind, +//GO(bindresvport, +//GOW(bindtextdomain, +//GOW(bind_textdomain_codeset, +//GOW(brk, +//GO(__bsd_getpgrp, +//GOW(bsd_signal, +//GO(bsearch, +//GOW(btowc, +//GO(__bzero, +//GOW(bzero, +//GO(c16rtomb, +//GOW(c32rtomb, +//GOW(calloc, +//GO(callrpc, +//GO(__call_tls_dtors, +//GOW(canonicalize_file_name, +//GO(capget, +//GO(capset, +//GO(catclose, +//GO(catgets, +//GO(catopen, +//GO(cbc_crypt, +//GO(cfgetispeed, +//GO(cfgetospeed, +//GO(cfmakeraw, +//GO(cfree, +//GO(cfsetispeed, +//GO(cfsetospeed, +//GO(cfsetspeed, +//GOW(chdir, +//DATA(__check_rhosts_file, +//GO(chflags, +//GO(__chk_fail, +//GOW(chmod, +//GOW(chown, +//GO(chroot, +//GOW(clearenv, +//GO(clearerr, +//GO(clearerr_unlocked, +//GO(clnt_broadcast, +//GO(clnt_create, +//GO(clnt_pcreateerror, +//GO(clnt_perrno, +//GO(clnt_perror, +//GO(clntraw_create, +//GO(clnt_spcreateerror, +//GO(clnt_sperrno, +//GO(clnt_sperror, +//GO(clnttcp_create, +//GO(clntudp_bufcreate, +//GO(clntudp_create, +//GO(clntunix_create, +//GO(clock, +//GO(clock_adjtime, +//GO(__clock_getcpuclockid, +//GOW(clock_getcpuclockid, +//GO(__clock_getres, +//GOW(clock_getres, +//GO(__clock_gettime, +//GOW(clock_gettime, +//GO(__clock_nanosleep, +//GOW(clock_nanosleep, +//GO(__clock_settime, +//GOW(clock_settime, +//GO(__clone, +//GOW(clone, +//GO(__close, +//GOW(close, +//GOW(closedir, +//GO(closelog, +//GO(__close_nocancel, +//GO(__cmsg_nxthdr, +//GO(confstr, +//GO(__confstr_chk, +//GOW(__connect, +//GOW(connect, +//GO(copy_file_range, +//GO(__copy_grp, +//GOW(copysign, +//GOW(copysignf, +//GOW(copysignl, +//GOW(creat, +//GOW(creat64, +//GO(create_module, +//GO(ctermid, +//GO(ctime, +//GO(ctime_r, +//DATA(__ctype32_b, +//DATA(__ctype32_tolower, +//DATA(__ctype32_toupper, +//DATA(__ctype_b, +//GO(__ctype_b_loc, +//GOW(__ctype_get_mb_cur_max, +//GO(__ctype_init, +//DATA(__ctype_tolower, +//GO(__ctype_tolower_loc, +//DATA(__ctype_toupper, +//GO(__ctype_toupper_loc, +//DATAB(__curbrk, +//GO(cuserid, +//GO(__cxa_atexit, +//GO(__cxa_at_quick_exit, +//GO(__cxa_finalize, +//GO(__cxa_thread_atexit_impl, +//GO(__cyg_profile_func_enter, +//GO(__cyg_profile_func_exit, +//GO(daemon, +//DATAB(__daylight, +//GO(__dcgettext, +//GOW(dcgettext, +//GOW(dcngettext, +//GO(__default_morecore, +//GO(delete_module, +//GO(des_setparity, +//GO(__dgettext, +//GOW(dgettext, +//GO(difftime, +//GO(dirfd, +//GO(dirname, +//GO(div, +//GO(_dl_addr, +//GO(_dl_catch_error, +//GO(_dl_catch_exception, +//GOW(dl_iterate_phdr, +//GO(_dl_mcount_wrapper, +//GO(_dl_mcount_wrapper_check, +//DATAB(_dl_open_hook, +//DATAB(_dl_open_hook2, +//GO(_dl_signal_error, +//GO(_dl_signal_exception, +//GO(_dl_sym, +//GO(_dl_vsym, +//GOW(dngettext, +//GO(dprintf, +//GO(__dprintf_chk, +//GO(drand48, +//GO(drand48_r, +//GOW(dup, +//GO(__dup2, +//GOW(dup2, +//GOW(dup3, +//GO(__duplocale, +//GOW(duplocale, +//GO(dysize, +//GOW(eaccess, +//GO(ecb_crypt, +//GO(ecvt, +//GOW(ecvt_r, +//GO(endaliasent, +//GO(endfsent, +//GO(endgrent, +//GO(endhostent, +//GO(__endmntent, +//GOW(endmntent, +//GO(endnetent, +//GO(endnetgrent, +//GO(endprotoent, +//GO(endpwent, +//GO(endrpcent, +//GO(endservent, +//GO(endsgent, +//GO(endspent, +//GOW(endttyent, +//GO(endusershell, +//GOW(endutent, +//GO(endutxent, +//DATAB(__environ, +//GO(envz_add, +//GO(envz_entry, +//GO(envz_get, +//GO(envz_merge, +//GO(envz_remove, +//GO(envz_strip, +//GO(epoll_create, +//GO(epoll_create1, +//GO(epoll_ctl, +//GO(epoll_pwait, +//GO(epoll_wait, +//GO(erand48, +//GOW(erand48_r, +//GO(err, +//DATAB(errno, +//GO(__errno_location, +//GOW(error, +//GOW(error_at_line, +//DATAB(error_message_count, +//DATAB(error_one_per_line, +//DATAB(error_print_progname, +//GO(errx, +//GO(ether_aton, +//GO(ether_aton_r, +//GO(ether_hostton, +//GO(ether_line, +//GO(ether_ntoa, +//GO(ether_ntoa_r, +//GO(ether_ntohost, +//GOW(euidaccess, +//GO(eventfd, +//GO(eventfd_read, +//GO(eventfd_write, +//GO(execl, +//GO(execle, +//GO(execlp, +//GO(execv, +//GOW(execve, +//GO(execvp, +//GOW(execvpe, +//GO(_exit, +//GO(exit, +//GOW(_Exit, +//GO(explicit_bzero, +//GO(__explicit_bzero_chk, +//GO(faccessat, +//GOW(fallocate, +//GO(fallocate64, +//GO(fanotify_init, +//GO(fanotify_mark, +//GO(fattach, +//GO(__fbufsize, +//GOW(fchdir, +//GO(fchflags, +//GOW(fchmod, +//GO(fchmodat, +//GOW(fchown, +//GO(fchownat, +//GO(fclose, +//GOW(fcloseall, +//GOW(__fcntl, +//GOW(fcntl, +//GOW(fcntl64, +//GO(fcvt, +//GOW(fcvt_r, +//GO(fdatasync, +//GO(__fdelt_chk, +//GO(__fdelt_warn, +//GO(fdetach, +//GO(fdopen, +//GOW(fdopendir, +//GO(__fentry__, +//GOW(feof, +//GOW(feof_unlocked, +//GOW(ferror, +//GOW(ferror_unlocked, +//GO(fexecve, +//GOW(fflush, +//GOW(fflush_unlocked, +//GO(__ffs, +//GO(ffs, +//GOW(ffsl, +//GO(ffsll, +//GOW(fgetc, +//GOW(fgetc_unlocked, +//GO(fgetgrent, +//GOW(fgetgrent_r, +//GO(fgetpos, +//GO(fgetpos64, +//GO(fgetpwent, +//GOW(fgetpwent_r, +//GOW(fgets, +//GO(__fgets_chk, +//GO(fgetsgent, +//GOW(fgetsgent_r, +//GO(fgetspent, +//GOW(fgetspent_r, +//GOW(fgets_unlocked, +//GO(__fgets_unlocked_chk, +//GOW(fgetwc, +//GOW(fgetwc_unlocked, +//GO(fgetws, +//GO(__fgetws_chk, +//GO(fgetws_unlocked, +//GO(__fgetws_unlocked_chk, +//GO(fgetxattr, +//GOW(fileno, +//GOW(fileno_unlocked, +//GO(__finite, +//GOW(finite, +//GO(__finitef, +//GOW(finitef, +//GO(__finitel, +//GOW(finitel, +//GO(__flbf, +//GO(flistxattr, +//GOW(flock, +//GOW(flockfile, +//GOW(_flushlbf, +//GO(fmemopen, +//GO(fmemopen, +//GO(fmtmsg, +//GO(fnmatch, +//GO(fopen, +//GOW(fopen64, +//GO(fopencookie, +//GO(__fork, +//GOW(fork, +//GO(__fortify_fail, +//GOW(fpathconf, +//GO(__fpending, +//GO(fprintf, +//GO(__fprintf_chk, +//DATA(__fpu_control, +//GO(__fpurge, +//GO(fputc, +//GO(fputc_unlocked, +//GOW(fputs, +//GOW(fputs_unlocked, +//GO(fputwc, +//GO(fputwc_unlocked, +//GO(fputws, +//GO(fputws_unlocked, +//GOW(fread, +//GO(__freadable, +//GO(__fread_chk, +//GO(__freading, +//GOW(fread_unlocked, +//GO(__fread_unlocked_chk, +//GO(free, +//GO(freeaddrinfo, +//GOW(freeifaddrs, +//GO(__freelocale, +//GOW(freelocale, +//GO(fremovexattr, +//GO(freopen, +//GO(freopen64, +//GOW(frexp, +//GOW(frexpf, +//GOW(frexpl, +//GO(fscanf, +//GO(fseek, +//GOW(fseeko, +//GO(__fseeko64, +//GOW(fseeko64, +//GO(__fsetlocking, +//GO(fsetpos, +//GO(fsetpos64, +//GO(fsetxattr, +//GOW(fstatfs, +//GOW(fstatfs64, +//GOW(fstatvfs, +//GOW(fstatvfs64, +//GO(fsync, +//GOW(ftell, +//GOW(ftello, +//GO(__ftello64, +//GOW(ftello64, +//GO(ftime, +//GO(ftok, +//GOW(ftruncate, +//GOW(ftruncate64, +//GOW(ftrylockfile, +//GOW(fts64_children, +//GOW(fts64_close, +//GOW(fts64_open, +//GOW(fts64_read, +//GOW(fts64_set, +//GO(fts_children, +//GO(fts_close, +//GO(fts_open, +//GO(fts_read, +//GO(fts_set, +//GO(ftw, +//GOW(ftw64, +//GOW(funlockfile, +//GO(futimens, +//GOW(futimes, +//GO(futimesat, +//GO(fwide, +//GOW(fwprintf, +//GO(__fwprintf_chk, +//GO(__fwritable, +//GOW(fwrite, +//GO(fwrite_unlocked, +//GO(__fwriting, +//GO(fwscanf, +//GO(__fxstat, +//GO(__fxstat64, +//GO(__fxstatat, +//GO(__fxstatat64, +//GO(__gai_sigqueue, +//GO(gai_strerror, +//GO(__gconv_get_alias_db, +//GO(__gconv_get_cache, +//GO(__gconv_get_modules_db, +//GO(__gconv_transliterate, +//GO(gcvt, +//GO(getaddrinfo, +//GO(getaliasbyname, +//GO(getaliasbyname_r, +//GO(getaliasent, +//GO(getaliasent_r, +//GO(__getauxval, +//GOW(getauxval, +//GOW(get_avphys_pages, +//GOW(getc, +//GO(getchar, +//GO(getchar_unlocked, +//GOW(getcontext, +//GOW(getc_unlocked, +//GO(get_current_dir_name, +//GOW(getcwd, +//GO(__getcwd_chk, +//GO(getdate, +//DATAB(getdate_err, +//GOW(getdate_r, +//GOW(__getdelim, +//GOW(getdelim, +//GOW(getdirentries, +//GO(getdirentries64, +//GO(getdomainname, +//GO(__getdomainname_chk, +//GOW(getdtablesize, +//GOW(getegid, +//GO(getentropy, +//GO(getenv, +//GOW(geteuid, +//GO(getfsent, +//GO(getfsfile, +//GO(getfsspec, +//GOW(getgid, +//GO(getgrent, +//GO(getgrent_r, +//GO(getgrgid, +//GO(getgrgid_r, +//GO(getgrnam, +//GO(getgrnam_r, +//GO(getgrouplist, +//GOW(getgroups, +//GO(__getgroups_chk, +//GO(gethostbyaddr, +//GO(gethostbyaddr_r, +//GO(gethostbyname, +//GO(gethostbyname2, +//GO(gethostbyname2_r, +//GO(gethostbyname_r, +//GO(gethostent, +//GO(gethostent_r, +//GO(gethostid, +//GOW(gethostname, +//GO(__gethostname_chk, +//GOW(getifaddrs, +//GO(getipv4sourcefilter, +//GOW(getitimer, +//GO(get_kernel_syms, +//GOW(getline, +//GO(getloadavg, +//GO(getlogin, +//GOW(getlogin_r, +//GO(__getlogin_r_chk, +//GO(getmntent, +//GO(__getmntent_r, +//GOW(getmntent_r, +//GO(getmsg, +//GO(get_myaddress, +//GO(getnameinfo, +//GO(getnetbyaddr, +//GO(getnetbyaddr_r, +//GO(getnetbyname, +//GO(getnetbyname_r, +//GO(getnetent, +//GO(getnetent_r, +//GO(getnetgrent, +//GOW(getnetgrent_r, +//GO(getnetname, +//GOW(get_nprocs, +//GOW(get_nprocs_conf, +//GO(getopt, +//GO(getopt_long, +//GO(getopt_long_only, +//GO(__getpagesize, +//GOW(getpagesize, +//GO(getpass, +//GOW(getpeername, +//GO(__getpgid, +//GOW(getpgid, +//GO(getpgrp, +//GOW(get_phys_pages, +//GO(__getpid, +//GOW(getpid, +//GO(getpmsg, +//GOW(getppid, +//GOW(getpriority, +//GO(getprotobyname, +//GO(getprotobyname_r, +//GO(getprotobynumber, +//GO(getprotobynumber_r, +//GO(getprotoent, +//GO(getprotoent_r, +//GOW(getpt, +//GO(getpublickey, +//GOW(getpw, +//GO(getpwent, +//GO(getpwent_r, +//GO(getpwnam, +//GO(getpwnam_r, +//GO(getpwuid, +//GO(getpwuid_r, +//GO(getrandom, +//GO(getresgid, +//GO(getresuid, +//GO(__getrlimit, +//GOW(getrlimit, +//GOW(getrlimit64, +//GO(getrpcbyname, +//GO(getrpcbyname_r, +//GO(getrpcbynumber, +//GO(getrpcbynumber_r, +//GO(getrpcent, +//GO(getrpcent_r, +//GO(getrpcport, +//GOW(getrusage, +//GOW(gets, +//GO(__gets_chk, +//GO(getsecretkey, +//GO(getservbyname, +//GO(getservbyname_r, +//GO(getservbyport, +//GO(getservbyport_r, +//GO(getservent, +//GO(getservent_r, +//GO(getsgent, +//GO(getsgent_r, +//GO(getsgnam, +//GO(getsgnam_r, +//GO(getsid, +//GOW(getsockname, +//GOW(getsockopt, +//GO(getsourcefilter, +//GO(getspent, +//GO(getspent_r, +//GO(getspnam, +//GO(getspnam_r, +//GO(getsubopt, +//GOW(gettext, +//GOW(getttyent, +//GOW(getttynam, +//GOW(getuid, +//GO(getusershell, +//GOW(getutent, +//GOW(getutent_r, +//GOW(getutid, +//GOW(getutid_r, +//GOW(getutline, +//GOW(getutline_r, +//GO(getutmp, +//GO(getutmpx, +//GO(getutxent, +//GO(getutxid, +//GO(getutxline, +//GO(getw, +//GOW(getwc, +//GO(getwchar, +//GO(getwchar_unlocked, +//GOW(getwc_unlocked, +//GO(getwd, +//GO(__getwd_chk, +//GO(getxattr, +//GO(glob, +//GO(glob, +//GO(glob64, +//GO(glob64, +//GO(globfree, +//GOW(globfree64, +//GOW(glob_pattern_p, +//GO(gmtime, +//GO(__gmtime_r, +//GOW(gmtime_r, +//GOW(gnu_dev_major, +//GOW(gnu_dev_makedev, +//GOW(gnu_dev_minor, +//GOW(gnu_get_libc_release, +//GOW(gnu_get_libc_version, +//GO(grantpt, +//GOW(group_member, +//GOW(gsignal, +//GO(gtty, +//GOW(hasmntopt, +//GO(hcreate, +//GOW(hcreate_r, +//GOW(hdestroy, +//GOW(hdestroy_r, +//DATA(h_errlist, +//DATAB(__h_errno, +//GO(__h_errno_location, +//GO(herror, +//GO(host2netname, +//GO(hsearch, +//GOW(hsearch_r, +//GO(hstrerror, +//GO(htonl, +//GO(htons, +//GO(iconv, +//GO(iconv_close, +//GO(iconv_open, +//GO(__idna_from_dns_encoding, +//GO(__idna_to_dns_encoding, +//GOW(if_freenameindex, +//GOW(if_indextoname, +//GOW(if_nameindex, +//GOW(if_nametoindex, +//GOW(imaxabs, +//GOW(imaxdiv, +//GO(inet6_opt_append, +//GO(inet6_opt_find, +//GO(inet6_opt_finish, +//GO(inet6_opt_get_val, +//GO(inet6_opt_init, +//GO(inet6_option_alloc, +//GO(inet6_option_append, +//GO(inet6_option_find, +//GO(inet6_option_init, +//GO(inet6_option_next, +//GO(inet6_option_space, +//GO(inet6_opt_next, +//GO(inet6_opt_set_val, +//GO(inet6_rth_add, +//GO(inet6_rth_getaddr, +//GO(inet6_rth_init, +//GO(inet6_rth_reverse, +//GO(inet6_rth_segments, +//GO(inet6_rth_space, +//GO(__inet6_scopeid_pton, +//GOW(inet_addr, +//GOW(inet_aton, +//GO(__inet_aton_exact, +//GO(inet_lnaof, +//GOW(inet_makeaddr, +//GO(inet_netof, +//GO(inet_network, +//GO(inet_nsap_addr, +//GO(inet_nsap_ntoa, +//GO(inet_ntoa, +//GO(inet_ntop, +//GOW(inet_pton, +//GO(__inet_pton_length, +//GO(initgroups, +//GO(init_module, +//GOW(initstate, +//GOW(initstate_r, +//GO(innetgr, +//GO(inotify_add_watch, +//GO(inotify_init, +//GO(inotify_init1, +//GO(inotify_rm_watch, +//GO(insque, +//GO(__internal_endnetgrent, +//GO(__internal_getnetgrent_r, +//GO(__internal_setnetgrent, +//DATA(_IO_2_1_stderr_, +//DATA(_IO_2_1_stdin_, +//DATA(_IO_2_1_stdout_, +//GO(_IO_adjust_column, +//GO(_IO_adjust_wcolumn, +//GOW(ioctl, +//GO(_IO_default_doallocate, +//GO(_IO_default_finish, +//GO(_IO_default_pbackfail, +//GO(_IO_default_uflow, +//GO(_IO_default_xsgetn, +//GO(_IO_default_xsputn, +//GO(_IO_doallocbuf, +//GO(_IO_do_write, +//GO(_IO_enable_locks, +//GO(_IO_fclose, +//GO(_IO_fdopen, +//GO(_IO_feof, +//GO(_IO_ferror, +//GO(_IO_fflush, +//GO(_IO_fgetpos, +//GO(_IO_fgetpos64, +//GO(_IO_fgets, +//GO(_IO_file_attach, +//GO(_IO_file_close, +//GO(_IO_file_close_it, +//GO(_IO_file_doallocate, +//GO(_IO_file_finish, +//GO(_IO_file_fopen, +//GO(_IO_file_init, +//DATA(_IO_file_jumps, +//GO(_IO_file_open, +//GO(_IO_file_overflow, +//GO(_IO_file_read, +//GO(_IO_file_seek, +//GO(_IO_file_seekoff, +//GO(_IO_file_setbuf, +//GO(_IO_file_stat, +//GO(_IO_file_sync, +//GO(_IO_file_underflow, +//GO(_IO_file_write, +//GO(_IO_file_xsputn, +//GO(_IO_flockfile, +//GO(_IO_flush_all, +//GO(_IO_flush_all_linebuffered, +//GO(_IO_fopen, +//GOW(_IO_fprintf, +//GO(_IO_fputs, +//GO(_IO_fread, +//GO(_IO_free_backup_area, +//GO(_IO_free_wbackup_area, +//GO(_IO_fsetpos, +//GO(_IO_fsetpos64, +//GO(_IO_ftell, +//GO(_IO_ftrylockfile, +//GO(_IO_funlockfile, +//GO(_IO_fwrite, +//GO(_IO_getc, +//GO(_IO_getline, +//GO(_IO_getline_info, +//GO(_IO_gets, +//GO(_IO_init, +//GO(_IO_init_marker, +//GO(_IO_init_wmarker, +//GO(_IO_iter_begin, +//GO(_IO_iter_end, +//GO(_IO_iter_file, +//GO(_IO_iter_next, +//GO(_IO_least_wmarker, +//GO(_IO_link_in, +//DATA(_IO_list_all, +//GO(_IO_list_lock, +//GO(_IO_list_resetlock, +//GO(_IO_list_unlock, +//GO(_IO_marker_delta, +//GO(_IO_marker_difference, +//GO(_IO_padn, +//GO(_IO_peekc_locked, +//GO(ioperm, +//GO(iopl, +//GO(_IO_popen, +//GO(_IO_printf, +//GO(_IO_proc_close, +//GO(_IO_proc_open, +//GO(_IO_putc, +//GO(_IO_puts, +//GO(_IO_remove_marker, +//GO(_IO_seekmark, +//GO(_IO_seekoff, +//GO(_IO_seekpos, +//GO(_IO_seekwmark, +//GO(_IO_setb, +//GO(_IO_setbuffer, +//GO(_IO_setvbuf, +//GO(_IO_sgetn, +//GO(_IO_sprintf, +//GO(_IO_sputbackc, +//GO(_IO_sputbackwc, +//GO(_IO_sscanf, +//GO(_IO_str_init_readonly, +//GO(_IO_str_init_static, +//GO(_IO_str_overflow, +//GO(_IO_str_pbackfail, +//GO(_IO_str_seekoff, +//GO(_IO_str_underflow, +//GO(_IO_sungetc, +//GO(_IO_sungetwc, +//GO(_IO_switch_to_get_mode, +//GO(_IO_switch_to_main_wget_area, +//GO(_IO_switch_to_wbackup_area, +//GO(_IO_switch_to_wget_mode, +//GO(_IO_ungetc, +//GO(_IO_un_link, +//GO(_IO_unsave_markers, +//GO(_IO_unsave_wmarkers, +//GO(_IO_vfprintf, +//GO(_IO_vfscanf, +//GO(_IO_vsprintf, +//GO(_IO_wdefault_doallocate, +//GO(_IO_wdefault_finish, +//GO(_IO_wdefault_pbackfail, +//GO(_IO_wdefault_uflow, +//GO(_IO_wdefault_xsgetn, +//GO(_IO_wdefault_xsputn, +//GO(_IO_wdoallocbuf, +//GO(_IO_wdo_write, +//DATA(_IO_wfile_jumps, +//GO(_IO_wfile_overflow, +//GO(_IO_wfile_seekoff, +//GO(_IO_wfile_sync, +//GO(_IO_wfile_underflow, +//GO(_IO_wfile_xsputn, +//GO(_IO_wmarker_delta, +//GO(_IO_wsetb, +//GO(iruserok, +//GO(iruserok_af, +//GO(isalnum, +//GO(__isalnum_l, +//GOW(isalnum_l, +//GO(isalpha, +//GO(__isalpha_l, +//GOW(isalpha_l, +//GO(isascii, +//GOW(__isascii_l, +//GO(isastream, +//GOW(isatty, +//GO(isblank, +//GO(__isblank_l, +//GOW(isblank_l, +//GO(iscntrl, +//GO(__iscntrl_l, +//GOW(iscntrl_l, +//GO(__isctype, +//GOW(isctype, +//GO(isdigit, +//GO(__isdigit_l, +//GOW(isdigit_l, +//GO(isfdtype, +//GO(isgraph, +//GO(__isgraph_l, +//GOW(isgraph_l, +//GO(__isinf, +//GOW(isinf, +//GO(__isinff, +//GOW(isinff, +//GO(__isinfl, +//GOW(isinfl, +//GO(islower, +//GO(__islower_l, +//GOW(islower_l, +//GO(__isnan, +//GOW(isnan, +//GO(__isnanf, +//GOW(isnanf, +//GO(__isnanl, +//GOW(isnanl, +//GO(__isoc99_fscanf, +//GO(__isoc99_fwscanf, +//GO(__isoc99_scanf, +//GO(__isoc99_sscanf, +//GO(__isoc99_swscanf, +//GO(__isoc99_vfscanf, +//GO(__isoc99_vfwscanf, +//GO(__isoc99_vscanf, +//GO(__isoc99_vsscanf, +//GO(__isoc99_vswscanf, +//GO(__isoc99_vwscanf, +//GO(__isoc99_wscanf, +//GO(isprint, +//GO(__isprint_l, +//GOW(isprint_l, +//GO(ispunct, +//GO(__ispunct_l, +//GOW(ispunct_l, +//GO(isspace, +//GO(__isspace_l, +//GOW(isspace_l, +//GO(isupper, +//GO(__isupper_l, +//GOW(isupper_l, +//GOW(iswalnum, +//GO(__iswalnum_l, +//GOW(iswalnum_l, +//GOW(iswalpha, +//GO(__iswalpha_l, +//GOW(iswalpha_l, +//GOW(iswblank, +//GO(__iswblank_l, +//GOW(iswblank_l, +//GOW(iswcntrl, +//GO(__iswcntrl_l, +//GOW(iswcntrl_l, +//GO(__iswctype, +//GOW(iswctype, +//GO(__iswctype_l, +//GOW(iswctype_l, +//GOW(iswdigit, +//GO(__iswdigit_l, +//GOW(iswdigit_l, +//GOW(iswgraph, +//GO(__iswgraph_l, +//GOW(iswgraph_l, +//GOW(iswlower, +//GO(__iswlower_l, +//GOW(iswlower_l, +//GOW(iswprint, +//GO(__iswprint_l, +//GOW(iswprint_l, +//GOW(iswpunct, +//GO(__iswpunct_l, +//GOW(iswpunct_l, +//GOW(iswspace, +//GO(__iswspace_l, +//GOW(iswspace_l, +//GOW(iswupper, +//GO(__iswupper_l, +//GOW(iswupper_l, +//GOW(iswxdigit, +//GO(__iswxdigit_l, +//GOW(iswxdigit_l, +//GO(isxdigit, +//GO(__isxdigit_l, +//GOW(isxdigit_l, +//GO(__ivaliduser, +//GO(jrand48, +//GOW(jrand48_r, +//GO(key_decryptsession, +//GO(key_decryptsession_pk, +//DATAB(__key_decryptsession_pk_LOCAL, +//GO(key_encryptsession, +//GO(key_encryptsession_pk, +//DATAB(__key_encryptsession_pk_LOCAL, +//GO(key_gendes, +//DATAB(__key_gendes_LOCAL, +//GO(key_get_conv, +//GO(key_secretkey_is_set, +//GO(key_setnet, +//GO(key_setsecret, +//GOW(kill, +//GO(killpg, +//GO(klogctl, +//GO(l64a, +//GO(labs, +//GO(lchmod, +//GOW(lchown, +//GOW(lckpwdf, +//GO(lcong48, +//GOW(lcong48_r, +//GOW(ldexp, +//GOW(ldexpf, +//GOW(ldexpl, +//GO(ldiv, +//GO(lfind, +//GO(lgetxattr, +//GO(__libc_alloca_cutoff, +//GO(__libc_allocate_once_slow, +//GO(__libc_allocate_rtsig, +//GO(__libc_allocate_rtsig_private, +//GO(__libc_alloc_buffer_alloc_array, +//GO(__libc_alloc_buffer_allocate, +//GO(__libc_alloc_buffer_copy_bytes, +//GO(__libc_alloc_buffer_copy_string, +//GO(__libc_alloc_buffer_create_failure, +//GO(__libc_calloc, +//GO(__libc_clntudp_bufcreate, +//GO(__libc_current_sigrtmax, +//GO(__libc_current_sigrtmax_private, +//GO(__libc_current_sigrtmin, +//GO(__libc_current_sigrtmin_private, +//GO(__libc_dlclose, +//GO(__libc_dlopen_mode, +//GO(__libc_dlsym, +//GO(__libc_dlvsym, +//GO(__libc_dynarray_at_failure, +//GO(__libc_dynarray_emplace_enlarge, +//GO(__libc_dynarray_finalize, +//GO(__libc_dynarray_resize, +//GO(__libc_dynarray_resize_clear, +//GO(__libc_fatal, +//GO(__libc_fcntl64, +//GO(__libc_fork, +//GO(__libc_free, +//GO(__libc_freeres, +//GO(__libc_ifunc_impl_list, +//GO(__libc_init_first, +//GO(__libc_longjmp, +//GO(__libc_mallinfo, +//GO(__libc_malloc, +//GO(__libc_mallopt, +//GO(__libc_memalign, +//GO(__libc_msgrcv, +//GO(__libc_msgsnd, +//GO(__libc_pread, +//GO(__libc_pthread_init, +//GO(__libc_pvalloc, +//GO(__libc_pwrite, +//GO(__libc_readline_unlocked, +//GO(__libc_realloc, +//GO(__libc_reallocarray, +//GO(__libc_rpc_getport, +//GO(__libc_sa_len, +//GO(__libc_scratch_buffer_grow, +//GO(__libc_scratch_buffer_grow_preserve, +//GO(__libc_scratch_buffer_set_array_size, +//GOW(__libc_secure_getenv, +//GO(__libc_siglongjmp, +//GO(__libc_start_main, +//GO(__libc_system, +//GO(__libc_thread_freeres, +//GO(__libc_valloc, +//GO(__libc_vfork, +//GOW(link, +//GO(linkat, +//GOW(listen, +//GO(listxattr, +//GO(llabs, +//GO(lldiv, +//GO(llistxattr, +//GO(llseek, +//DATAB(loc1, +//DATAB(loc2, +//GO(localeconv, +//GO(localtime, +//GOW(localtime_r, +//GO(lockf, +//GOW(lockf64, +//DATAB(locs, +//GOW(_longjmp, +//GOW(longjmp, +//GO(__longjmp_chk, +//GO(lrand48, +//GO(lrand48_r, +//GO(lremovexattr, +//GO(lsearch, +//GO(__lseek, +//GOW(lseek, +//GOW(lseek64, +//GO(lsetxattr, +//GO(lutimes, +//GO(__lxstat, +//GO(__lxstat64, +//GO(__madvise, +//GOW(madvise, +//GOW(makecontext, +//GOW(mallinfo, +//GO(malloc, +//GO(malloc_get_state, +//GOW(malloc_info, +//GO(malloc_set_state, +//GOW(malloc_stats, +//GOW(malloc_trim, +//GOW(malloc_usable_size, +//GOW(mallopt, +//DATAB(mallwatch, +//GO(mblen, +//GO(__mbrlen, +//GOW(mbrlen, +//GO(mbrtoc16, +//GOW(mbrtoc32, +//GO(__mbrtowc, +//GOW(mbrtowc, +//GOW(mbsinit, +//GOW(mbsnrtowcs, +//GO(__mbsnrtowcs_chk, +//GOW(mbsrtowcs, +//GO(__mbsrtowcs_chk, +//GO(mbstowcs, +//GO(__mbstowcs_chk, +//GO(mbtowc, +//GO(mcheck, +//GO(mcheck_check_all, +//GO(mcheck_pedantic, +//GO(_mcleanup, +//GO(_mcount, +//GOW(mcount, +//GOW(memalign, +//GOW(memccpy, +//GO(memcpy, +//GO(memfd_create, +//GO(memfrob, +//GOW(memmem, +//GO(__mempcpy_small, +//GO(__merge_grp, +//GO(mincore, +//GOW(mkdir, +//GO(mkdirat, +//GO(mkdtemp, +//GO(mkfifo, +//GO(mkfifoat, +//GO(mkostemp, +//GOW(mkostemp64, +//GO(mkostemps, +//GOW(mkostemps64, +//GO(mkstemp, +//GOW(mkstemp64, +//GO(mkstemps, +//GOW(mkstemps64, +//GO(__mktemp, +//GOW(mktemp, +//GO(mktime, +//GO(mlock, +//GO(mlock2, +//GO(mlockall, +//GO(__mmap, +//GOW(mmap, +//GOW(mmap64, +//GOW(modf, +//GOW(modff, +//GOW(modfl, +//GOW(modify_ldt, +//GOW(moncontrol, +//GO(__monstartup, +//GOW(monstartup, +//DATA(__morecore, +//GOW(mount, +//GO(mprobe, +//GO(__mprotect, +//GOW(mprotect, +//GO(mrand48, +//GO(mrand48_r, +//GOW(mremap, +//GO(msgctl, +//GO(msgget, +//GOW(msgrcv, +//GOW(msgsnd, +//GO(msync, +//GO(mtrace, +//GO(munlock, +//GO(munlockall, +//GO(__munmap, +//GOW(munmap, +//GO(muntrace, +GO(name_to_handle_at, iFipppi) +//GO(__nanosleep, +//GOW(nanosleep, +//GO(__nanosleep_nocancel, +//GO(__netlink_assert_response, +//GO(netname2host, +//GO(netname2user, +//GO(__newlocale, +//GOW(newlocale, +//GO(nfsservctl, +//GO(nftw, +//GO(nftw, +//GO(nftw64, +//GO(nftw64, +//GOW(ngettext, +//GO(nice, +//DATAB(_nl_domain_bindings, +//GO(nl_langinfo, +//GO(__nl_langinfo_l, +//GOW(nl_langinfo_l, +//DATAB(_nl_msg_cat_cntr, +//GO(nrand48, +//GOW(nrand48_r, +//GO(__nss_configure_lookup, +//GO(__nss_database_lookup, +//GO(__nss_disable_nscd, +//GO(_nss_files_parse_grent, +//GO(_nss_files_parse_pwent, +//GO(_nss_files_parse_sgent, +//GO(_nss_files_parse_spent, +//GO(__nss_group_lookup, +//GO(__nss_group_lookup2, +//GO(__nss_hash, +//GO(__nss_hostname_digits_dots, +//GO(__nss_hosts_lookup, +//GO(__nss_hosts_lookup2, +//GO(__nss_lookup, +//GO(__nss_lookup_function, +//GO(__nss_next, +//GO(__nss_next2, +//GO(__nss_passwd_lookup, +//GO(__nss_passwd_lookup2, +//GO(__nss_services_lookup2, +//GOW(ntohl, +//GOW(ntohs, +//GOW(ntp_adjtime, +//GO(ntp_gettime, +//GO(ntp_gettimex, +//DATAB(_null_auth, +//DATAB(_obstack, +//GO(_obstack_allocated_p, +//DATA(obstack_alloc_failed_handler, +//GO(_obstack_begin, +//GO(_obstack_begin_1, +//DATA(obstack_exit_failure, +//GO(_obstack_free, +//GO(obstack_free, +//GO(_obstack_memory_used, +//GO(_obstack_newchunk, +//GOW(obstack_printf, +//GO(__obstack_printf_chk, +//GOW(obstack_vprintf, +//GO(__obstack_vprintf_chk, +//GOW(on_exit, +//GOW(__open, +//GOW(open, +//GO(__open_2, +//GOW(__open64, +//GOW(open64, +//GO(__open64_2, +//GO(__open64_nocancel, +//GOW(openat, +//GO(__openat_2, +//GOW(openat64, +//GO(__openat64_2, +//GO(open_by_handle_at, +//GO(__open_catalog, +//GOW(opendir, +//GO(openlog, +//GOW(open_memstream, +//GO(__open_nocancel, +//GO(open_wmemstream, +//DATAB(optarg, +//DATA(opterr, +//DATA(optind, +//DATA(optopt, +//GO(__overflow, +//GO(parse_printf_format, +//GO(passwd2des, +//GOW(pathconf, +//GOW(pause, +//GO(__pause_nocancel, +//GO(pclose, +//GO(perror, +//GOW(personality, +//GO(__pipe, +//GOW(pipe, +//GOW(pipe2, +//GO(pivot_root, +//GO(pkey_alloc, +//GO(pkey_free, +//GO(pkey_get, +//GO(pkey_mprotect, +//GO(pkey_set, +//GO(pmap_getmaps, +//GO(pmap_getport, +//GO(pmap_rmtcall, +//GO(pmap_set, +//GO(pmap_unset, +//GO(__poll, +//GOW(poll, +//GO(__poll_chk, +//GO(popen, +//GO(posix_fadvise, +//GOW(posix_fadvise64, +//GO(posix_fallocate, +//GO(posix_fallocate64, +//GO(__posix_getopt, +//GO(posix_madvise, +//GOW(posix_memalign, +//GOW(posix_openpt, +//GO(posix_spawn, +//GO(posix_spawn, +//GO(posix_spawnattr_destroy, +//GO(posix_spawnattr_getflags, +//GO(posix_spawnattr_getpgroup, +//GO(posix_spawnattr_getschedparam, +//GO(posix_spawnattr_getschedpolicy, +//GO(posix_spawnattr_getsigdefault, +//GO(posix_spawnattr_getsigmask, +//GO(posix_spawnattr_init, +//GO(posix_spawnattr_setflags, +//GO(posix_spawnattr_setpgroup, +//GO(posix_spawnattr_setschedparam, +//GO(posix_spawnattr_setschedpolicy, +//GO(posix_spawnattr_setsigdefault, +//GO(posix_spawnattr_setsigmask, +//GO(posix_spawn_file_actions_addclose, +//GO(posix_spawn_file_actions_adddup2, +//GO(posix_spawn_file_actions_addopen, +//GO(posix_spawn_file_actions_destroy, +//GO(posix_spawn_file_actions_init, +//GO(posix_spawnp, +//GO(posix_spawnp, +//GO(ppoll, +//GO(__ppoll_chk, +//GOW(prctl, +//GOW(pread, +//GOW(__pread64, +//GOW(pread64, +//GO(__pread64_chk, +//GO(__pread_chk, +//GO(preadv, +//GO(preadv2, +//GO(preadv64, +//GO(preadv64v2, +//GO(printf, +//GO(__printf_chk, +//GO(__printf_fp, +//GO(printf_size, +//GO(printf_size_info, +//GO(prlimit, +//GOW(prlimit64, +//GO(process_vm_readv, +//GO(process_vm_writev, +//GOW(profil, +//GO(__profile_frequency, +//DATA(__progname, +//DATA(__progname_full, +//GOW(pselect, +//GO(psiginfo, +//GO(psignal, +//GO(pthread_attr_destroy, +//GO(pthread_attr_getdetachstate, +//GO(pthread_attr_getinheritsched, +//GO(pthread_attr_getschedparam, +//GO(pthread_attr_getschedpolicy, +//GO(pthread_attr_getscope, +//GO(pthread_attr_init, +//GO(pthread_attr_setdetachstate, +//GO(pthread_attr_setinheritsched, +//GO(pthread_attr_setschedparam, +//GO(pthread_attr_setschedpolicy, +//GO(pthread_attr_setscope, +//GO(pthread_condattr_destroy, +//GO(pthread_condattr_init, +//GO(pthread_cond_broadcast, +//GO(pthread_cond_broadcast, +//GO(pthread_cond_destroy, +//GO(pthread_cond_destroy, +//GO(pthread_cond_init, +//GO(pthread_cond_init, +//GO(pthread_cond_signal, +//GO(pthread_cond_signal, +//GO(pthread_cond_timedwait, +//GO(pthread_cond_timedwait, +//GO(pthread_cond_wait, +//GO(pthread_cond_wait, +//GO(pthread_equal, +//GO(pthread_exit, +//GO(pthread_getschedparam, +//GO(pthread_mutex_destroy, +//GO(pthread_mutex_init, +//GO(pthread_mutex_lock, +//GO(pthread_mutex_unlock, +//GO(pthread_self, +//GO(pthread_setcancelstate, +//GO(pthread_setcanceltype, +//GO(pthread_setschedparam, +//GO(ptrace, +//GO(ptsname, +//GOW(ptsname_r, +//GO(__ptsname_r_chk, +//GOW(putc, +//GO(putchar, +//GO(putchar_unlocked, +//GOW(putc_unlocked, +//GO(putenv, +//GO(putgrent, +//GO(putmsg, +//GO(putpmsg, +//GO(putpwent, +//GOW(puts, +//GO(putsgent, +//GO(putspent, +//GOW(pututline, +//GO(pututxline, +//GO(putw, +//GO(putwc, +//GO(putwchar, +//GO(putwchar_unlocked, +//GO(putwc_unlocked, +//GOW(pvalloc, +//GOW(pwrite, +//GOW(__pwrite64, +//GOW(pwrite64, +//GO(pwritev, +//GO(pwritev2, +//GO(pwritev64, +//GO(pwritev64v2, +//GO(qecvt, +//GOW(qecvt_r, +//GO(qfcvt, +//GOW(qfcvt_r, +//GO(qgcvt, +//GO(qsort, +//GOW(qsort_r, +//GO(query_module, +//GO(quick_exit, +//GO(quick_exit, +//GO(quotactl, +//GO(raise, +//GO(rand, +//GOW(random, +//GOW(random_r, +//GO(rand_r, +//GO(rcmd, +//GO(rcmd_af, +//DATAB(__rcmd_errstr, +//GO(__read, +//GO(read, +//GOW(readahead, +//GO(__read_chk, +//GOW(readdir, +//GOW(readdir64, +//GOW(readdir64_r, +//GOW(readdir_r, +//GOW(readlink, +//GO(readlinkat, +//GO(__readlinkat_chk, +//GO(__readlink_chk, +//GO(__read_nocancel, +//GOW(readv, +//GO(realloc, +//GOW(reallocarray, +//GO(realpath, +//GO(realpath, +//GO(__realpath_chk, +//GO(reboot, +//GOW(re_comp, +//GOW(re_compile_fastmap, +//GOW(re_compile_pattern, +//GOW(__recv, +//GOW(recv, +//GO(__recv_chk, +//GOW(recvfrom, +//GO(__recvfrom_chk, +//GO(recvmmsg, +//GOW(recvmsg, +//GOW(re_exec, +//GOW(regcomp, +//GOW(regerror, +//GO(regexec, +//GO(regexec, +//GOW(regfree, +//GO(__register_atfork, +//GOW(register_printf_function, +//GOW(register_printf_modifier, +//GOW(register_printf_specifier, +//GOW(register_printf_type, +//GO(registerrpc, +//GOW(remap_file_pages, +//GOW(re_match, +//GOW(re_match_2, +//DATA(re_max_failures, +//GO(remove, +//GO(removexattr, +//GO(remque, +//GO(rename, +//GOW(renameat, +//GOW(renameat2, +//DATAB(_res, +//GOW(re_search, +//GOW(re_search_2, +//GOW(re_set_registers, +//GOW(re_set_syntax, +//DATAB(_res_hconf, +//GO(__res_iclose, +//GO(__res_init, +//GO(__res_nclose, +//GO(__res_ninit, +//GO(__resolv_context_get, +//GO(__resolv_context_get_override, +//GO(__resolv_context_get_preinit, +//GO(__resolv_context_put, +//DATA(__resp, +//GO(__res_randomid, +//GO(__res_state, +//DATAB(re_syntax_options, +//GOW(revoke, +//GO(rewind, +//GOW(rewinddir, +//GO(rexec, +//GO(rexec_af, +//DATAB(rexecoptions, +//GOW(rmdir, +//DATAB(rpc_createerr, +//GO(_rpc_dtablesize, +//GO(__rpc_thread_createerr, +//GO(__rpc_thread_svc_fdset, +//GO(__rpc_thread_svc_max_pollfd, +//GO(__rpc_thread_svc_pollfd, +//GO(rpmatch, +//GO(rresvport, +//GO(rresvport_af, +//GO(rtime, +//GO(ruserok, +//GO(ruserok_af, +//GO(ruserpass, +//GO(__sbrk, +//GOW(sbrk, +//GOW(scalbn, +//GOW(scalbnf, +//GOW(scalbnl, +//GOW(scandir, +//GOW(scandir64, +//GOW(scandirat, +//GO(scandirat64, +//GO(scanf, +//GO(__sched_cpualloc, +//GO(__sched_cpufree, +//GO(sched_getaffinity, +//GO(sched_getaffinity, +//GO(sched_getcpu, +//GO(__sched_getparam, +//GOW(sched_getparam, +//GO(__sched_get_priority_max, +//GOW(sched_get_priority_max, +//GO(__sched_get_priority_min, +//GOW(sched_get_priority_min, +//GO(__sched_getscheduler, +//GOW(sched_getscheduler, +//GOW(sched_rr_get_interval, +//GO(sched_setaffinity, +//GO(sched_setaffinity, +//GOW(sched_setparam, +//GO(__sched_setscheduler, +//GOW(sched_setscheduler, +//GO(__sched_yield, +//GOW(sched_yield, +//GOW(__secure_getenv, +//GOW(secure_getenv, +//GO(seed48, +//GOW(seed48_r, +//GO(seekdir, +//GO(__select, +//GOW(select, +//GO(semctl, +//GO(semget, +//GO(semop, +//GO(semtimedop, +//GO(__send, +//GOW(send, +//GO(sendfile, +//GOW(sendfile64, +//GO(__sendmmsg, +//GOW(sendmmsg, +//GOW(sendmsg, +//GOW(sendto, +//GO(setaliasent, +//GO(setbuf, +//GOW(setbuffer, +//GOW(setcontext, +//GO(setdomainname, +//GO(setegid, +//GOW(setenv, +//GO(_seterr_reply, +//GO(seteuid, +//GO(setfsent, +//GO(setfsgid, +//GO(setfsuid, +//GOW(setgid, +//GO(setgrent, +//GO(setgroups, +//GO(sethostent, +//GO(sethostid, +//GO(sethostname, +//GO(setipv4sourcefilter, +//GOW(setitimer, +//GO(_setjmp, +//GO(setjmp, +//GO(setlinebuf, +//GO(setlocale, +//GO(setlogin, +//GO(setlogmask, +//GO(__setmntent, +//GOW(setmntent, +//GO(setnetent, +//GO(setnetgrent, +//GO(setns, +//GO(__setpgid, +//GOW(setpgid, +//GO(setpgrp, +//GOW(setpriority, +//GO(setprotoent, +//GO(setpwent, +//GOW(setregid, +//GOW(setresgid, +//GOW(setresuid, +//GOW(setreuid, +//GOW(setrlimit, +//GOW(setrlimit64, +//GO(setrpcent, +//GO(setservent, +//GO(setsgent, +//GOW(setsid, +//GOW(setsockopt, +//GO(setsourcefilter, +//GO(setspent, +//GOW(setstate, +//GOW(setstate_r, +//GOW(settimeofday, +//GOW(setttyent, +//GOW(setuid, +//GO(setusershell, +//GOW(setutent, +//GO(setutxent, +//GOW(setvbuf, +//GO(setxattr, +//GO(sgetsgent, +//GOW(sgetsgent_r, +//GO(sgetspent, +//GOW(sgetspent_r, +//GO(shmat, +//GO(shmctl, +//GO(shmdt, +//GO(shmget, +//GOW(shutdown, +//GOW(__sigaction, +//GOW(sigaction, +//GO(__sigaddset, +//GO(sigaddset, +//GOW(sigaltstack, +//GO(sigandset, +//GOW(sigblock, +//GO(__sigdelset, +//GO(sigdelset, +//GO(sigemptyset, +//GO(sigfillset, +//GO(siggetmask, +//GO(sighold, +//GO(sigignore, +//GO(siginterrupt, +//GO(sigisemptyset, +//GO(__sigismember, +//GO(sigismember, +//GOW(siglongjmp, +//GOW(signal, +//GO(signalfd, +//GO(__signbit, +//GO(__signbitf, +//GO(__signbitl, +//GO(sigorset, +//GO(__sigpause, +//GOW(sigpause, +//GO(sigpending, +//GOW(sigprocmask, +//GOW(sigqueue, +//GO(sigrelse, +//GOW(sigreturn, +//GO(sigset, +//GO(__sigsetjmp, +//GOW(sigsetmask, +//GO(sigstack, +//GO(__sigsuspend, +//GOW(sigsuspend, +//GO(__sigtimedwait, +//GOW(sigtimedwait, +//GO(sigvec, +//GOW(sigwait, +//GOW(sigwaitinfo, +//GOW(sleep, +//GO(__snprintf, +//GOW(snprintf, +//GO(__snprintf_chk, +//GO(sockatmark, +//GO(__socket, +//GOW(socket, +//GOW(socketpair, +//GO(splice, +//GO(sprintf, +//GO(__sprintf_chk, +//GOW(sprofil, +//GOW(srand, +//GO(srand48, +//GOW(srand48_r, +//GOW(srandom, +//GOW(srandom_r, +//GO(sscanf, +//GOW(ssignal, +//GO(sstk, +GOM(__stack_chk_fail, vFE) +//GO(__statfs, +//GOW(statfs, +//GOW(statfs64, +//GOW(statvfs, +//GOW(statvfs64, +//GO(statx, +//DATA(stderr, +//DATA(stdin, +//DATA(stdout, +//GOW(step, +//GO(stime, +//GO(__stpcpy_chk, +//GO(__stpcpy_small, +//GO(__stpncpy_chk, +//GO(__strcasestr, +//GOW(strcasestr, +//GO(__strcat_chk, +//GO(strcoll, +//GO(__strcoll_l, +//GOW(strcoll_l, +//GO(__strcpy_chk, +//GO(__strcpy_small, +//GO(__strcspn_c1, +//GO(__strcspn_c2, +//GO(__strcspn_c3, +//GO(__strdup, +//GOW(strdup, +//GO(strerror, +//GO(strerror_l, +//GO(__strerror_r, +//GOW(strerror_r, +//GO(strfmon, +//GO(__strfmon_l, +//GOW(strfmon_l, +//GO(strfromd, +//GO(strfromf, +//GO(strfromf128, +//GOW(strfromf32, +//GOW(strfromf32x, +//GOW(strfromf64, +//GOW(strfromf64x, +//GO(strfroml, +//GO(strfry, +//GO(strftime, +//GO(__strftime_l, +//GOW(strftime_l, +//GO(__strncat_chk, +//GO(__strncpy_chk, +//GO(__strndup, +//GOW(strndup, +//GO(__strpbrk_c2, +//GO(__strpbrk_c3, +//GO(strptime, +//GOW(strptime_l, +//GOW(strsep, +//GO(__strsep_1c, +//GO(__strsep_2c, +//GO(__strsep_3c, +//GO(__strsep_g, +//GO(strsignal, +//GO(__strspn_c1, +//GO(__strspn_c2, +//GO(__strspn_c3, +//GO(strtod, +//GO(__strtod_internal, +//GO(__strtod_l, +//GOW(strtod_l, +//GO(__strtod_nan, +//GO(strtof, +//GO(strtof128, +//GO(__strtof128_internal, +//GOW(strtof128_l, +//GO(__strtof128_nan, +//GOW(strtof32, +//GOW(strtof32_l, +//GOW(strtof32x, +//GOW(strtof32x_l, +//GOW(strtof64, +//GOW(strtof64_l, +//GOW(strtof64x, +//GOW(strtof64x_l, +//GO(__strtof_internal, +//GO(__strtof_l, +//GOW(strtof_l, +//GO(__strtof_nan, +//GO(strtoimax, +//GO(strtok, +//GO(__strtok_r, +//GOW(strtok_r, +//GO(__strtok_r_1c, +//GOW(strtol, +//GO(strtold, +//GO(__strtold_internal, +//GO(__strtold_l, +//GOW(strtold_l, +//GO(__strtold_nan, +//GO(__strtol_internal, +//GO(__strtol_l, +//GOW(strtol_l, +//GOW(strtoll, +//GO(__strtoll_internal, +//GOW(__strtoll_l, +//GOW(strtoll_l, +//GOW(strtoq, +//GOW(strtoul, +//GO(__strtoul_internal, +//GO(__strtoul_l, +//GOW(strtoul_l, +//GOW(strtoull, +//GO(__strtoull_internal, +//GOW(__strtoull_l, +//GOW(strtoull_l, +//GO(strtoumax, +//GOW(strtouq, +//GO(__strverscmp, +//GOW(strverscmp, +//GO(strxfrm, +//GO(__strxfrm_l, +//GOW(strxfrm_l, +//GO(stty, +//DATAB(svcauthdes_stats, +//GO(svcerr_auth, +//GO(svcerr_decode, +//GO(svcerr_noproc, +//GO(svcerr_noprog, +//GO(svcerr_progvers, +//GO(svcerr_systemerr, +//GO(svcerr_weakauth, +//GO(svc_exit, +//GO(svcfd_create, +//DATAB(svc_fdset, +//GO(svc_getreq, +//GO(svc_getreq_common, +//GO(svc_getreq_poll, +//GO(svc_getreqset, +//DATAB(svc_max_pollfd, +//DATAB(svc_pollfd, +//GO(svcraw_create, +//GO(svc_register, +//GO(svc_run, +//GO(svc_sendreply, +//GO(svctcp_create, +//GO(svcudp_bufcreate, +//GO(svcudp_create, +//GO(svcudp_enablecache, +//GO(svcunix_create, +//GO(svcunixfd_create, +//GO(svc_unregister, +//GO(swab, +//GOW(swapcontext, +//GOW(swapoff, +//GOW(swapon, +//GO(swprintf, +//GO(__swprintf_chk, +//GO(swscanf, +//GOW(symlink, +//GO(symlinkat, +//GO(sync, +//GO(sync_file_range, +//GO(syncfs, +//GO(syscall, +//GO(__sysconf, +//GOW(sysconf, +//GO(__sysctl, +//GOW(sysctl, +//DATA(_sys_errlist, +//DATA(_sys_errlist, +//DATA(_sys_errlist, +//DATA(_sys_errlist, +//DATA(sys_errlist, +//DATA(sys_errlist, +//DATA(sys_errlist, +//DATA(sys_errlist, +//GOW(sysinfo, +//GO(syslog, +//GO(__syslog_chk, +//DATA(sys_sigabbrev, +//DATA(sys_sigabbrev, +//DATA(_sys_siglist, +//DATA(_sys_siglist, +//DATA(sys_siglist, +//DATA(sys_siglist, +//GOW(system, +//GO(__sysv_signal, +//GOW(sysv_signal, +//GOW(tcdrain, +//GO(tcflow, +//GO(tcflush, +//GOW(tcgetattr, +//GO(tcgetpgrp, +//GO(tcgetsid, +//GO(tcsendbreak, +//GO(tcsetattr, +//GO(tcsetpgrp, +//GO(__tdelete, +//GOW(tdelete, +//GOW(tdestroy, +//GO(tee, +//GO(telldir, +//GO(tempnam, +//GOW(textdomain, +//GO(__tfind, +//GOW(tfind, +//GO(thrd_current, +//GO(thrd_equal, +//GO(thrd_sleep, +//GO(thrd_yield, +//GO(timegm, +//GOW(timelocal, +//GO(timerfd_create, +//GO(timerfd_gettime, +//GO(timerfd_settime, +//GOW(times, +//GO(timespec_get, +//DATAB(__timezone, +//GO(tmpfile, +//GOW(tmpfile64, +//GO(tmpnam, +//GO(tmpnam_r, +//GO(toascii, +//GOW(__toascii_l, +//GO(_tolower, +//GO(tolower, +//GO(__tolower_l, +//GOW(tolower_l, +//GO(_toupper, +//GO(toupper, +//GO(__toupper_l, +//GOW(toupper_l, +//GO(__towctrans, +//GOW(towctrans, +//GO(__towctrans_l, +//GOW(towctrans_l, +//GOW(towlower, +//GO(__towlower_l, +//GOW(towlower_l, +//GOW(towupper, +//GO(__towupper_l, +//GOW(towupper_l, +//GO(tr_break, +//GOW(truncate, +//GOW(truncate64, +//GO(__tsearch, +//GOW(tsearch, +//GO(ttyname, +//GOW(ttyname_r, +//GO(__ttyname_r_chk, +//GO(ttyslot, +//GO(__twalk, +//GOW(twalk, +DATA(__tzname, 4) +GOW(tzset, vFv) +//GO(ualarm, +//GO(__uflow, +//GOW(ulckpwdf, +//GOW(ulimit, +//GOW(umask, +//GOW(umount, +//GOW(umount2, +//GOW(uname, +//GO(__underflow, +//GOW(ungetc, +//GO(ungetwc, +//GOW(unlink, +//GO(unlinkat, +//GO(unlockpt, +//GOW(unsetenv, +//GO(unshare, +//GOW(updwtmp, +//GO(updwtmpx, +//GO(uselib, +//GO(__uselocale, +//GOW(uselocale, +//GO(user2netname, +//GO(usleep, +//GO(ustat, +//GO(utime, +//GO(utimensat, +//GOW(utimes, +//GOW(utmpname, +//GO(utmpxname, +//GOW(valloc, +//GOW(vasprintf, +//GO(__vasprintf_chk, +//GOW(vdprintf, +//GO(__vdprintf_chk, +//GO(verr, +//GO(verrx, +//GOW(versionsort, +//GOW(versionsort64, +//GO(__vfork, +//GOW(vfork, +//GO(vfprintf, +//GO(__vfprintf_chk, +//GO(__vfscanf, +//GOW(vfscanf, +//GOW(vfwprintf, +//GO(__vfwprintf_chk, +//GOW(vfwscanf, +//GO(vhangup, +//GO(vlimit, +//GO(vmsplice, +//GO(vprintf, +//GO(__vprintf_chk, +//GOW(vscanf, +//GOW(__vsnprintf, +//GOW(vsnprintf, +//GO(__vsnprintf_chk, +//GOW(vsprintf, +//GO(__vsprintf_chk, +//GOW(__vsscanf, +//GOW(vsscanf, +//GOW(vswprintf, +//GO(__vswprintf_chk, +//GO(vswscanf, +//GO(vsyslog, +//GO(__vsyslog_chk, +//GO(vtimes, +//GO(vwarn, +//GO(vwarnx, +//GO(vwprintf, +//GO(__vwprintf_chk, +//GO(vwscanf, +//GOW(__wait, +//GOW(wait, +//GOW(wait3, +//GOW(wait4, +//GOW(waitid, +//GO(__waitpid, +//GOW(waitpid, +//GO(warn, +//GO(warnx, +//GOW(wcpcpy, +//GO(__wcpcpy_chk, +//GOW(wcpncpy, +//GO(__wcpncpy_chk, +//GOW(wcrtomb, +//GO(__wcrtomb_chk, +//GOW(wcscasecmp, +//GO(__wcscasecmp_l, +//GOW(wcscasecmp_l, +//GOW(wcscat, +//GO(__wcscat_chk, +//GOW(wcschrnul, +//GOW(wcscoll, +//GO(__wcscoll_l, +//GOW(wcscoll_l, +//GO(__wcscpy_chk, +//GO(wcscspn, +//GO(wcsdup, +//GO(wcsftime, +//GO(__wcsftime_l, +//GOW(wcsftime_l, +//GOW(wcsncasecmp, +//GO(__wcsncasecmp_l, +//GOW(wcsncasecmp_l, +//GO(wcsncat, +//GO(__wcsncat_chk, +//GOW(wcsncpy, +//GO(__wcsncpy_chk, +//GOW(wcsnrtombs, +//GO(__wcsnrtombs_chk, +//GO(wcspbrk, +//GOW(wcsrtombs, +//GO(__wcsrtombs_chk, +//GO(wcsspn, +//GO(wcsstr, +//GO(wcstod, +//GO(__wcstod_internal, +//GO(__wcstod_l, +//GOW(wcstod_l, +//GO(wcstof, +//GO(wcstof128, +//GO(__wcstof128_internal, +//GOW(wcstof128_l, +//GOW(wcstof32, +//GOW(wcstof32_l, +//GOW(wcstof32x, +//GOW(wcstof32x_l, +//GOW(wcstof64, +//GOW(wcstof64_l, +//GOW(wcstof64x, +//GOW(wcstof64x_l, +//GO(__wcstof_internal, +//GO(__wcstof_l, +//GOW(wcstof_l, +//GO(wcstoimax, +//GO(wcstok, +//GOW(wcstol, +//GO(wcstold, +//GO(__wcstold_internal, +//GO(__wcstold_l, +//GOW(wcstold_l, +//GO(__wcstol_internal, +//GO(__wcstol_l, +//GOW(wcstol_l, +//GOW(wcstoll, +//GO(__wcstoll_internal, +//GOW(__wcstoll_l, +//GOW(wcstoll_l, +//GO(wcstombs, +//GO(__wcstombs_chk, +//GOW(wcstoq, +//GOW(wcstoul, +//GO(__wcstoul_internal, +//GO(__wcstoul_l, +//GOW(wcstoul_l, +//GOW(wcstoull, +//GO(__wcstoull_internal, +//GOW(__wcstoull_l, +//GOW(wcstoull_l, +//GO(wcstoumax, +//GOW(wcstouq, +//GOW(wcswcs, +//GO(wcswidth, +//GO(wcsxfrm, +//GO(__wcsxfrm_l, +//GOW(wcsxfrm_l, +//GO(wctob, +//GO(wctomb, +//GO(__wctomb_chk, +//GOW(wctrans, +//GO(__wctrans_l, +//GOW(wctrans_l, +//GOW(wctype, +//GO(__wctype_l, +//GOW(wctype_l, +//GO(wcwidth, +//GOW(wmemcpy, +//GO(__wmemcpy_chk, +//GOW(wmemmove, +//GO(__wmemmove_chk, +//GOW(wmempcpy, +//GO(__wmempcpy_chk, +//GO(wordexp, +//GO(wordfree, +//GO(__woverflow, +//GO(wprintf, +//GO(__wprintf_chk, +//GOW(__write, +//GOW(write, +//GO(__write_nocancel, +//GOW(writev, +//GO(wscanf, +//GO(__wuflow, +//GO(__wunderflow, +//GO(xdecrypt, +//GO(xdr_accepted_reply, +//GO(xdr_array, +//GO(xdr_authdes_cred, +//GO(xdr_authdes_verf, +//GO(xdr_authunix_parms, +//GO(xdr_bool, +//GO(xdr_bytes, +//GO(xdr_callhdr, +//GO(xdr_callmsg, +//GO(xdr_char, +//GO(xdr_cryptkeyarg, +//GO(xdr_cryptkeyarg2, +//GO(xdr_cryptkeyres, +//GO(xdr_des_block, +//GO(xdr_double, +//GO(xdr_enum, +//GO(xdr_float, +//GO(xdr_free, +//GO(xdr_getcredres, +//GO(xdr_hyper, +//GO(xdr_int, +//GO(xdr_int16_t, +//GO(xdr_int32_t, +//GO(xdr_int64_t, +//GO(xdr_int8_t, +//GO(xdr_keybuf, +//GO(xdr_key_netstarg, +//GO(xdr_key_netstres, +//GO(xdr_keystatus, +//GO(xdr_long, +//GO(xdr_longlong_t, +//GO(xdrmem_create, +//GO(xdr_netnamestr, +//GO(xdr_netobj, +//GO(xdr_opaque, +//GO(xdr_opaque_auth, +//GO(xdr_pmap, +//GO(xdr_pmaplist, +//GO(xdr_pointer, +//GO(xdr_quad_t, +//GO(xdrrec_create, +//GO(xdrrec_endofrecord, +//GO(xdrrec_eof, +//GO(xdrrec_skiprecord, +//GO(xdr_reference, +//GO(xdr_rejected_reply, +//GO(xdr_replymsg, +//GO(xdr_rmtcall_args, +//GO(xdr_rmtcallres, +//GO(xdr_short, +//GO(xdr_sizeof, +//GO(xdrstdio_create, +//GO(xdr_string, +//GO(xdr_u_char, +//GO(xdr_u_hyper, +//GO(xdr_u_int, +//GO(xdr_uint16_t, +//GO(xdr_uint32_t, +//GO(xdr_uint64_t, +//GO(xdr_uint8_t, +//GO(xdr_u_long, +//GO(xdr_u_longlong_t, +//GO(xdr_union, +//GO(xdr_unixcred, +//GO(xdr_u_quad_t, +//GO(xdr_u_short, +//GO(xdr_vector, +//GO(xdr_void, +//GO(xdr_wrapstring, +//GO(xencrypt, +//GO(__xmknod, +//GO(__xmknodat, +//GO(__xpg_basename, +//GOW(__xpg_sigpause, +//GO(__xpg_strerror_r, +//GO(xprt_register, +//GO(xprt_unregister, +//GO(__xstat, +//GO(__xstat64, + +GOM(__register_frame_info, vFpp) // faked function +GOM(__deregister_frame_info, pFp) diff --git a/src/wrapped/wrappedlibdl.c b/src/wrapped/wrappedlibdl.c new file mode 100755 index 00000000..95c23f7f --- /dev/null +++ b/src/wrapped/wrappedlibdl.c @@ -0,0 +1,415 @@ +#define _GNU_SOURCE /* See feature_test_macros(7) */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dlfcn.h> +#include <elf.h> + +#include "wrappedlibs.h" + +#include "debug.h" +#include "wrapper.h" +#include "bridge.h" +#include "librarian/library_private.h" +#include "emu/x64emu_private.h" +#include "library.h" +#include "librarian.h" +#include "box64context.h" +#include "elfloader.h" +#include "elfs/elfloader_private.h" + +typedef struct dlprivate_s { + library_t **libs; + size_t *count; + size_t *dlopened; + size_t lib_sz; + size_t lib_cap; + char* last_error; +} dlprivate_t; + +dlprivate_t *NewDLPrivate() { + dlprivate_t* dl = (dlprivate_t*)calloc(1, sizeof(dlprivate_t)); + return dl; +} +void FreeDLPrivate(dlprivate_t **lib) { + free((*lib)->last_error); + free(*lib); +} + +void* my_dlopen(x64emu_t* emu, void *filename, int flag) EXPORT; +void* my_dlmopen(x64emu_t* emu, void* mlid, void *filename, int flag) EXPORT; +char* my_dlerror(x64emu_t* emu) EXPORT; +void* my_dlsym(x64emu_t* emu, void *handle, void *symbol) EXPORT; +int my_dlclose(x64emu_t* emu, void *handle) EXPORT; +int my_dladdr(x64emu_t* emu, void *addr, void *info) EXPORT; +void* my_dlvsym(x64emu_t* emu, void *handle, void *symbol, void *version) EXPORT; +int my_dlinfo(x64emu_t* emu, void* handle, int request, void* info) EXPORT; + +#define LIBNAME libdl +const char* libdlName = "libdl.so.2"; + +// define all standard library functions +#include "wrappedlib_init.h" + +#define CLEARERR if(dl->last_error) free(dl->last_error); dl->last_error = NULL; + +extern int box64_zoom; +// Implementation +void* my_dlopen(x64emu_t* emu, void *filename, int flag) +{ + //void *dlopen(const char *filename, int flag); + // TODO, handling special values for filename, like RTLD_SELF? + // TODO, handling flags? + library_t *lib = NULL; + dlprivate_t *dl = emu->context->dlprivate; + size_t dlopened = 0; + int is_local = (flag&0x100)?0:1; // if not global, then local, and that means symbols are not put in the global "pot" for pther libs + CLEARERR + if(filename) { + char* rfilename = (char*)filename; + if(box64_zoom && strstr(rfilename, "/libturbojpeg.so")) { + void* sys = my_dlopen(emu, "libturbojpeg.so.0", flag); + if(sys) + return sys; + } + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "Call to dlopen(\"%s\"/%p, %X)\n", rfilename, filename, flag); + } + printf_log(LOG_DEBUG, "Call to dlopen(\"%s\"/%p, %X)\n", rfilename, filename, flag); + // check if alread dlopenned... + for (size_t i=0; i<dl->lib_sz; ++i) { + if(IsSameLib(dl->libs[i], rfilename)) { + if(dl->count[i]==0 && dl->dlopened[i]) { // need to lauch init again! + int idx = GetElfIndex(dl->libs[i]); + if(idx!=-1) { + if(dlsym_error || box64_log>=LOG_DEBUG) { + printf_log(LOG_NONE, "dlopen: Recycling, calling Init for %p (%s)\n", (void*)(i+1), rfilename); + } + ReloadLibrary(dl->libs[i], emu); // reset memory image, redo reloc, run inits + } + } + dl->count[i] = dl->count[i]+1; + if(dlsym_error || box64_log>=LOG_DEBUG) { + printf_log(LOG_NONE, "dlopen: Recycling %s/%p count=%ld (dlopened=%ld, elf_index=%d)\n", rfilename, (void*)(i+1), dl->count[i], dl->dlopened[i], GetElfIndex(dl->libs[i])); + } + return (void*)(i+1); + } + } + dlopened = (GetLibInternal(rfilename)==NULL); + // Then open the lib + if(AddNeededLib(NULL, NULL, is_local, rfilename, emu->context, emu)) { + printf_log(LOG_INFO, "Warning: Cannot dlopen(\"%s\"/%p, %X)\n", rfilename, filename, flag); + if(!dl->last_error) + dl->last_error = malloc(129); + snprintf(dl->last_error, 129, "Cannot dlopen(\"%s\"/%p, %X)\n", rfilename, filename, flag); + return NULL; + } + lib = GetLibInternal(rfilename); + } else { + // check if already dlopenned... + for (size_t i=0; i<dl->lib_sz; ++i) { + if(!dl->libs[i]) { + dl->count[i] = dl->count[i]+1; + return (void*)(i+1); + } + } + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "Call to dlopen(NULL, %X)\n", flag); + } + printf_log(LOG_DEBUG, "Call to dlopen(NULL, %X)\n", flag); + } + //get the lib and add it to the collection + + if(dl->lib_sz == dl->lib_cap) { + dl->lib_cap += 4; + dl->libs = (library_t**)realloc(dl->libs, sizeof(library_t*)*dl->lib_cap); + dl->count = (size_t*)realloc(dl->count, sizeof(size_t)*dl->lib_cap); + dl->dlopened = (size_t*)realloc(dl->dlopened, sizeof(size_t)*dl->lib_cap); + // memset count... + memset(dl->count+dl->lib_sz, 0, (dl->lib_cap-dl->lib_sz)*sizeof(size_t)); + } + dl->libs[dl->lib_sz] = lib; + dl->count[dl->lib_sz] = dl->count[dl->lib_sz]+1; + dl->dlopened[dl->lib_sz] = dlopened; + if(dlsym_error || box64_log>=LOG_DEBUG) { + printf_log(LOG_NONE, "dlopen: New handle %p (%s), dlopened=%ld\n", (void*)(dl->lib_sz+1), (char*)filename, dlopened); + } + return (void*)(++dl->lib_sz); +} +void* my_dlmopen(x64emu_t* emu, void* lmid, void *filename, int flag) +{ + if(lmid) { + printf_log(LOG_INFO, "Warning, dlmopen(%p, %p(\"%s\"), 0x%x) called with lmid not LMID_ID_BASE (unsupported)\n", lmid, filename, filename?(char*)filename:"self", flag); + } + // lmid is ignored for now... + return my_dlopen(emu, filename, flag); +} +char* my_dlerror(x64emu_t* emu) +{ + dlprivate_t *dl = emu->context->dlprivate; + return dl->last_error; +} + +KHASH_SET_INIT_INT(libs); + +int recursive_dlsym_lib(kh_libs_t* collection, library_t* lib, const char* rsymbol, uintptr_t *start, uintptr_t *end) +{ + if(!lib) + return 0; + khint_t k = kh_get(libs, collection, (uintptr_t)lib); + if(k != kh_end(collection)) + return 0; + int ret; + kh_put(libs, collection, (uintptr_t)lib, &ret); + // look in the library itself + if(lib->get(lib, rsymbol, start, end)) + return 1; + // look in other libs + int n = GetNeededLibN(lib); + for (int i=0; i<n; ++i) { + library_t *l = GetNeededLib(lib, i); + if(recursive_dlsym_lib(collection, l, rsymbol, start, end)) + return 1; + } + + return 0; +} + +int my_dlsym_lib(library_t* lib, const char* rsymbol, uintptr_t *start, uintptr_t *end) +{ + kh_libs_t *collection = kh_init(libs); + int ret = recursive_dlsym_lib(collection, lib, rsymbol, start, end); + kh_destroy(libs, collection); + + return ret; +} +void* my_dlsym(x64emu_t* emu, void *handle, void *symbol) +{ + dlprivate_t *dl = emu->context->dlprivate; + uintptr_t start, end; + char* rsymbol = (char*)symbol; + CLEARERR + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "Call to dlsym(%p, %s) :", handle, rsymbol); + } + printf_log(LOG_DEBUG, "Call to dlsym(%p, \"%s\")\n", handle, rsymbol); + if(handle==NULL) { + // special case, look globably + if(GetGlobalSymbolStartEnd(emu->context->maplib, rsymbol, &start, &end)) { + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "%p\n", (void*)start); + } + return (void*)start; + } + if(!dl->last_error) + dl->last_error = malloc(129); + snprintf(dl->last_error, 129, "Symbol \"%s\" not found in %p)\n", rsymbol, handle); + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "%p\n", NULL); + } + return NULL; + } + if(handle==(void*)0xFFFFFFFF) { + // special case, look globably but no self (RTLD_NEXT) + elfheader_t *elf = FindElfAddress(emu->context, *(uint32_t*)R_RSP); // use return address to guess "self" + if(GetNoSelfSymbolStartEnd(emu->context->maplib, rsymbol, &start, &end, elf)) { + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "%p\n", (void*)start); + } + return (void*)start; + } + if(!dl->last_error) + dl->last_error = malloc(129); + snprintf(dl->last_error, 129, "Symbol \"%s\" not found in %p)\n", rsymbol, handle); + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "%p\n", NULL); + } + return NULL; + } + size_t nlib = (size_t)handle; + --nlib; + if(nlib<0 || nlib>=dl->lib_sz) { + if(!dl->last_error) + dl->last_error = malloc(129); + snprintf(dl->last_error, 129, "Bad handle %p)\n", handle); + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "%p\n", NULL); + } + return NULL; + } + if(dl->count[nlib]==0) { + if(!dl->last_error) + dl->last_error = malloc(129); + snprintf(dl->last_error, 129, "Bad handle %p (already closed))\n", handle); + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "%p\n", (void*)NULL); + } + return NULL; + } + if(dl->libs[nlib]) { + if(my_dlsym_lib(dl->libs[nlib], rsymbol, &start, &end)==0) { + // not found + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "%p\nCall to dlsym(%s, \"%s\") Symbol not found\n", NULL, GetNameLib(dl->libs[nlib]), rsymbol); + } + printf_log(LOG_DEBUG, " Symbol not found\n"); + if(!dl->last_error) + dl->last_error = malloc(129); + snprintf(dl->last_error, 129, "Symbol \"%s\" not found in %p(%s)", rsymbol, handle, GetNameLib(dl->libs[nlib])); + return NULL; + } + } else { + // still usefull? + if(GetSymbolStartEnd(GetLocalSymbol(emu->context->maplib), rsymbol, &start, &end)) { + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "%p\n", (void*)start); + } + return (void*)start; + } + if(GetSymbolStartEnd(GetWeakSymbol(emu->context->maplib), rsymbol, &start, &end)) { + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "%p\n", (void*)start); + } + return (void*)start; + } + if(GetSymbolStartEnd(GetMapSymbol(emu->context->maplib), rsymbol, &start, &end)) { + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "%p\n", (void*)start); + } + return (void*)start; + } + // not found + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "%p\nCall to dlsym(%s, \"%s\") Symbol not found\n", NULL, "Self", rsymbol); + } + printf_log(LOG_DEBUG, " Symbol not found\n"); + if(!dl->last_error) + dl->last_error = malloc(129); + snprintf(dl->last_error, 129, "Symbol \"%s\" not found in %p)\n", rsymbol, handle); + return NULL; + } + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "%p\n", (void*)start); + } + return (void*)start; +} +int my_dlclose(x64emu_t* emu, void *handle) +{ + if(dlsym_error || box64_log>=LOG_DEBUG) { + printf_log(LOG_NONE, "Call to dlclose(%p)\n", handle); + } + dlprivate_t *dl = emu->context->dlprivate; + CLEARERR + size_t nlib = (size_t)handle; + --nlib; + if(nlib<0 || nlib>=dl->lib_sz) { + if(!dl->last_error) + dl->last_error = malloc(129); + snprintf(dl->last_error, 129, "Bad handle %p)\n", handle); + if(dlsym_error || box64_log>=LOG_DEBUG) { + printf_log(LOG_NONE, "dlclose: %s\n", dl->last_error); + } + return -1; + } + if(dl->count[nlib]==0) { + if(!dl->last_error) + dl->last_error = malloc(129); + snprintf(dl->last_error, 129, "Bad handle %p (already closed))\n", handle); + if(dlsym_error || box64_log>=LOG_DEBUG) { + printf_log(LOG_NONE, "dlclose: %s\n", dl->last_error); + } + return -1; + } + dl->count[nlib] = dl->count[nlib]-1; + if(dl->count[nlib]==0 && dl->dlopened[nlib]) { // need to call Fini... + int idx = GetElfIndex(dl->libs[nlib]); + if(idx!=-1) { + if(dlsym_error || box64_log>=LOG_DEBUG) { + printf_log(LOG_NONE, "dlclose: Call to Fini for %p\n", handle); + } + RunElfFini(emu->context->elfs[idx], emu); + InactiveLibrary(dl->libs[nlib]); + } + } + return 0; +} +int my_dladdr(x64emu_t* emu, void *addr, void *i) +{ + //int dladdr(void *addr, Dl_info *info); + dlprivate_t *dl = emu->context->dlprivate; + CLEARERR + Dl_info *info = (Dl_info*)i; + printf_log(LOG_DEBUG, "Warning: partially unimplement call to dladdr(%p, %p)\n", addr, info); + + //emu->quit = 1; + info->dli_saddr = NULL; + info->dli_fname = NULL; + info->dli_sname = FindSymbolName(emu->context->maplib, addr, &info->dli_saddr, NULL, &info->dli_fname, &info->dli_fbase); + printf_log(LOG_DEBUG, " dladdr return saddr=%p, fname=\"%s\", sname=\"%s\"\n", info->dli_saddr, info->dli_sname?info->dli_sname:"", info->dli_fname?info->dli_fname:""); + return (info->dli_sname)?1:0; // success is non-null here... +} +void* my_dlvsym(x64emu_t* emu, void *handle, void *symbol, void *version) +{ + dlprivate_t *dl = emu->context->dlprivate; + CLEARERR + //void *dlvsym(void *handle, char *symbol, char *version); + char* rsymbol = (char*)symbol; + char* rversion = (char*)version; + printf_log(LOG_INFO, "Warning: unimplement call to dlvsym(%p, %s, %s), fallback to dlsym\n", handle, rsymbol, rversion); + + return my_dlsym(emu, handle, symbol); +} + +typedef struct link_map_s { + uintptr_t l_addr; + char* l_name; + Elf64_Dyn* l_ld; +} link_map_t; + +int my_dlinfo(x64emu_t* emu, void* handle, int request, void* info) +{ + if(dlsym_error || box64_log>=LOG_DEBUG) { + printf_log(LOG_NONE, "Call to dlinfo(%p, %d, %p)\n", handle, request, info); + } + dlprivate_t *dl = emu->context->dlprivate; + CLEARERR + size_t nlib = (size_t)handle; + --nlib; + if(nlib<0 || nlib>=dl->lib_sz) { + if(!dl->last_error) + dl->last_error = malloc(129); + snprintf(dl->last_error, 129, "Bad handle %p)\n", handle); + if(dlsym_error || box64_log>=LOG_DEBUG) { + printf_log(LOG_NONE, "dlinfo: %s\n", dl->last_error); + } + return -1; + } + if(dl->count[nlib]==0) { + if(!dl->last_error) + dl->last_error = malloc(129); + snprintf(dl->last_error, 129, "Bad handle %p (already closed))\n", handle); + if(dlsym_error || box64_log>=LOG_DEBUG) { + printf_log(LOG_NONE, "dlinfo: %s\n", dl->last_error); + } + return -1; + } + library_t *lib = dl->libs[nlib]; + elfheader_t *h = (GetElfIndex(lib)>-1)?my_context->elfs[GetElfIndex(lib)]:NULL; + switch(request) { + case 2: // RTLD_DI_LINKMAP + { + static link_map_t map = {0}; //cheating, creating a structure on demand... + *(link_map_t**)info = ↦ + map.l_addr = h?h->delta:0; + map.l_name = lib->path; + map.l_ld = h?h->Dynamic:NULL; + } + return 0; + default: + printf_log(LOG_NONE, "Warning, unsupported call to dlinfo(%p, %d, %p)\n", handle, request, info); + if(!dl->last_error) + dl->last_error = malloc(129); + snprintf(dl->last_error, 129, "unsupported call to dlinfo request:%d\n", request); + } + return -1; +} \ No newline at end of file diff --git a/src/wrapped/wrappedlibdl_private.h b/src/wrapped/wrappedlibdl_private.h new file mode 100755 index 00000000..35a45d49 --- /dev/null +++ b/src/wrapped/wrappedlibdl_private.h @@ -0,0 +1,14 @@ +#if defined(GO) && defined(GOM) && defined(GO2) && defined(DATA) + +GOM(dladdr, iFEpp) +// dladdr1 +GOM(dlclose, iFEp) +GOM(dlerror, pFE) +DATAB(_dlfcn_hook, 4) +GOM(dlinfo, iFEpip) +GOM(dlmopen, pFEppi) +GOM(dlopen, pFEpi) +GOM(dlsym, pFEpp) +GOM(dlvsym, pFEppp) // Weak + +#endif \ No newline at end of file |