From 94d15a1c1edd6ee247adc8a7d2f32f07ecccf400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trung=20L=C3=AA?= <8@tle.id.au> Date: Fri, 20 Mar 2026 22:48:30 +1100 Subject: [PATCH 1/4] [WRAPPER] Add iFEiLp wrapper and wrappedlibctypes.h ioctl type entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the iFEiLp wrapper signature — int32_t fn(x64emu_t*, int32_t, uintptr_t, void*) — needed by the PPC64LE ioctl wrapper (GOWM). Also add the iFiLp_t typedef and GO(ioctl, iFiLp_t) entry to wrappedlibctypes.h so the libc wrapper type table includes ioctl. --- src/wrapped/generated/functions_list.txt | 1 + src/wrapped/generated/wrappedlibctypes.h | 2 ++ src/wrapped/generated/wrapper.c | 2 ++ src/wrapped/generated/wrapper.h | 1 + 4 files changed, 6 insertions(+) diff --git a/src/wrapped/generated/functions_list.txt b/src/wrapped/generated/functions_list.txt index 912dbb4fa2..1a34dcdaf3 100644 --- a/src/wrapped/generated/functions_list.txt +++ b/src/wrapped/generated/functions_list.txt @@ -1161,6 +1161,7 @@ #() iFEiiu #() iFEiip #() iFEiiN +#() iFEiLp #() iFEipp #() iFEipV #() iFEipA diff --git a/src/wrapped/generated/wrappedlibctypes.h b/src/wrapped/generated/wrappedlibctypes.h index 6f9e91396c..c98fce1346 100644 --- a/src/wrapped/generated/wrappedlibctypes.h +++ b/src/wrapped/generated/wrappedlibctypes.h @@ -54,6 +54,7 @@ typedef void (*vFppV_t)(void*, void*, ...); typedef int32_t (*iFiiu_t)(int32_t, int32_t, uint32_t); typedef int32_t (*iFiip_t)(int32_t, int32_t, void*); typedef int32_t (*iFiiN_t)(int32_t, int32_t, ...); +typedef int32_t (*iFiLp_t)(int32_t, uintptr_t, void*); typedef int32_t (*iFiuu_t)(int32_t, uint32_t, uint32_t); typedef int32_t (*iFipu_t)(int32_t, void*, uint32_t); typedef int32_t (*iFipp_t)(int32_t, void*, void*); @@ -241,6 +242,7 @@ typedef int32_t (*iFppipppp_t)(void*, void*, int32_t, void*, void*, void*, void* GO(__fcntl, iFiiN_t) \ GO(fcntl, iFiiN_t) \ GO(fcntl64, iFiiN_t) \ + GO(ioctl, iFiLp_t) \ GO(fsmount, iFiuu_t) \ GO(fspick, iFipu_t) \ GO(__lxstat, iFipp_t) \ diff --git a/src/wrapped/generated/wrapper.c b/src/wrapped/generated/wrapper.c index 175e29a235..680c3d80f0 100644 --- a/src/wrapped/generated/wrapper.c +++ b/src/wrapped/generated/wrapper.c @@ -1191,6 +1191,7 @@ typedef int8_t (*cFpipp_t)(void*, int32_t, void*, void*); typedef int32_t (*iFEiiu_t)(x64emu_t*, int32_t, int32_t, uint32_t); typedef int32_t (*iFEiip_t)(x64emu_t*, int32_t, int32_t, void*); typedef int32_t (*iFEiiN_t)(x64emu_t*, int32_t, int32_t, ...); +typedef int32_t (*iFEiLp_t)(x64emu_t*, int32_t, uintptr_t, void*); typedef int32_t (*iFEipp_t)(x64emu_t*, int32_t, void*, void*); typedef int32_t (*iFEipV_t)(x64emu_t*, int32_t, void*, void*); typedef int32_t (*iFEipA_t)(x64emu_t*, int32_t, void*, void*); @@ -5366,6 +5367,7 @@ void cFpipp(x64emu_t *emu, uintptr_t fcn) { cFpipp_t fn = (cFpipp_t)fcn; R_RAX=( void iFEiiu(x64emu_t *emu, uintptr_t fcn) { iFEiiu_t fn = (iFEiiu_t)fcn; R_RAX=(int)fn(emu, (int32_t)R_RDI, (int32_t)R_RSI, (uint32_t)R_RDX); } void iFEiip(x64emu_t *emu, uintptr_t fcn) { iFEiip_t fn = (iFEiip_t)fcn; R_RAX=(int)fn(emu, (int32_t)R_RDI, (int32_t)R_RSI, (void*)R_RDX); } void iFEiiN(x64emu_t *emu, uintptr_t fcn) { iFEiiN_t fn = (iFEiiN_t)fcn; R_RAX=(int)fn(emu, (int32_t)R_RDI, (int32_t)R_RSI, (void*)R_RDX); } +void iFEiLp(x64emu_t *emu, uintptr_t fcn) { iFEiLp_t fn = (iFEiLp_t)fcn; R_RAX=(int)fn(emu, (int32_t)R_RDI, (uintptr_t)R_RSI, (void*)R_RDX); } void iFEipp(x64emu_t *emu, uintptr_t fcn) { iFEipp_t fn = (iFEipp_t)fcn; R_RAX=(int)fn(emu, (int32_t)R_RDI, (void*)R_RSI, (void*)R_RDX); } void iFEipV(x64emu_t *emu, uintptr_t fcn) { iFEipV_t fn = (iFEipV_t)fcn; R_RAX=(int)fn(emu, (int32_t)R_RDI, (void*)R_RSI, (void*)(R_RSP + 8)); } void iFEipA(x64emu_t *emu, uintptr_t fcn) { iFEipA_t fn = (iFEipA_t)fcn; R_RAX=(int)fn(emu, (int32_t)R_RDI, (void*)R_RSI, (void*)R_RDX); } diff --git a/src/wrapped/generated/wrapper.h b/src/wrapped/generated/wrapper.h index 51cb7e0e31..2dbd45acd1 100644 --- a/src/wrapped/generated/wrapper.h +++ b/src/wrapped/generated/wrapper.h @@ -1198,6 +1198,7 @@ void cFpipp(x64emu_t *emu, uintptr_t fnc); void iFEiiu(x64emu_t *emu, uintptr_t fnc); void iFEiip(x64emu_t *emu, uintptr_t fnc); void iFEiiN(x64emu_t *emu, uintptr_t fnc); +void iFEiLp(x64emu_t *emu, uintptr_t fnc); void iFEipp(x64emu_t *emu, uintptr_t fnc); void iFEipV(x64emu_t *emu, uintptr_t fnc); void iFEipA(x64emu_t *emu, uintptr_t fnc); From 0d5ce9cb94e9151afee35581b6c26b6fdba988c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trung=20L=C3=AA?= <8@tle.id.au> Date: Fri, 20 Mar 2026 22:48:51 +1100 Subject: [PATCH 2/4] [PPC64LE] Add ioctl_convert() for x86_64 -> PPC64LE ioctl number translation x86_64 and PPC64LE encode ioctl numbers differently: - Direction bits: x86 uses 2 bits (NONE=0, WRITE=1, READ=2) at bit 30; PPC uses 3 bits (NONE=1, READ=2, WRITE=4) at bit 29 - Size field: x86 uses 14 bits; PPC uses 13 bits - Old-style terminal ioctls have entirely different hardcoded values (e.g. x86 TCGETS=0x5401 vs PPC TCGETS=_IOR('t',19,termios)) Add ioctl_convert() under #ifdef PPC64LE with: - Switch-based lookup for ~35 old-style terminal/file ioctls (TCGETS, FIONREAD, TIOCGWINSZ, etc.) - Algorithmic translation for _IOC-encoded ioctls: decompose x86 fields, remap direction bits, recompose as PPC64LE - Debug logging via printf_log(LOG_DEBUG, ...) Also add my_ioctl() handler that calls ioctl_convert() then native ioctl(), to be hooked via GOWM in the next commit. --- src/wrapped/wrappedlibc.c | 170 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) diff --git a/src/wrapped/wrappedlibc.c b/src/wrapped/wrappedlibc.c index 9de15bdd4a..2669dc84f7 100644 --- a/src/wrapped/wrappedlibc.c +++ b/src/wrapped/wrappedlibc.c @@ -836,6 +836,176 @@ int of_unconvert(int a) } #undef SUPER + +#ifdef PPC64LE +// ioctl number translation: x86_64 -> PPC64LE +// x86_64 _IOC encoding: dir(2 bits, 30-31) | size(14 bits, 16-29) | type(8 bits, 8-15) | nr(8 bits, 0-7) +// PPC64LE _IOC encoding: dir(3 bits, 29-31) | size(13 bits, 16-28) | type(8 bits, 8-15) | nr(8 bits, 0-7) +// Direction bits: x86: NONE=0, WRITE=1, READ=2 PPC: NONE=1, READ=2, WRITE=4 + +// x86_64 _IOC field extraction +#define X86_IOC_NRBITS 8 +#define X86_IOC_TYPEBITS 8 +#define X86_IOC_SIZEBITS 14 +#define X86_IOC_DIRBITS 2 +#define X86_IOC_NRSHIFT 0 +#define X86_IOC_TYPESHIFT (X86_IOC_NRSHIFT + X86_IOC_NRBITS) +#define X86_IOC_SIZESHIFT (X86_IOC_TYPESHIFT + X86_IOC_TYPEBITS) +#define X86_IOC_DIRSHIFT (X86_IOC_SIZESHIFT + X86_IOC_SIZEBITS) +#define X86_IOC_NRMASK ((1 << X86_IOC_NRBITS) - 1) +#define X86_IOC_TYPEMASK ((1 << X86_IOC_TYPEBITS) - 1) +#define X86_IOC_SIZEMASK ((1 << X86_IOC_SIZEBITS) - 1) +#define X86_IOC_DIRMASK ((1 << X86_IOC_DIRBITS) - 1) +#define X86_IOC_DIR(nr) (((nr) >> X86_IOC_DIRSHIFT) & X86_IOC_DIRMASK) +#define X86_IOC_TYPE(nr) (((nr) >> X86_IOC_TYPESHIFT) & X86_IOC_TYPEMASK) +#define X86_IOC_NR(nr) (((nr) >> X86_IOC_NRSHIFT) & X86_IOC_NRMASK) +#define X86_IOC_SIZE(nr) (((nr) >> X86_IOC_SIZESHIFT) & X86_IOC_SIZEMASK) + +// x86_64 direction values +#define X86_IOC_NONE 0 +#define X86_IOC_WRITE 1 +#define X86_IOC_READ 2 + +// Old-style x86 terminal/file ioctl values (not _IOC-encoded) +#define X86_TCGETS 0x5401 +#define X86_TCSETS 0x5402 +#define X86_TCSETSW 0x5403 +#define X86_TCSETSF 0x5404 +#define X86_TCGETA 0x5405 +#define X86_TCSETA 0x5406 +#define X86_TCSETAW 0x5407 +#define X86_TCSETAF 0x5408 +#define X86_TCSBRK 0x5409 +#define X86_TCXONC 0x540A +#define X86_TCFLSH 0x540B +#define X86_TIOCEXCL 0x540C +#define X86_TIOCNXCL 0x540D +#define X86_TIOCSCTTY 0x540E +#define X86_TIOCGPGRP 0x540F +#define X86_TIOCSPGRP 0x5410 +#define X86_TIOCOUTQ 0x5411 +#define X86_TIOCSTI 0x5412 +#define X86_TIOCGWINSZ 0x5413 +#define X86_TIOCSWINSZ 0x5414 +#define X86_TIOCMGET 0x5415 +#define X86_TIOCMBIS 0x5416 +#define X86_TIOCMBIC 0x5417 +#define X86_TIOCMSET 0x5418 +#define X86_TIOCGSOFTCAR 0x5419 +#define X86_TIOCSSOFTCAR 0x541A +#define X86_FIONREAD 0x541B +#define X86_TIOCLINUX 0x541C +#define X86_TIOCCONS 0x541D +#define X86_TIOCGSERIAL 0x541E +#define X86_TIOCSSERIAL 0x541F +#define X86_TIOCPKT 0x5420 +#define X86_FIONBIO 0x5421 +#define X86_TIOCNOTTY 0x5422 +#define X86_TIOCSETD 0x5423 +#define X86_TIOCGETD 0x5424 +#define X86_TCSBRKP 0x5425 +#define X86_TIOCGSID 0x5429 +#define X86_FIONCLEX 0x5450 +#define X86_FIOCLEX 0x5451 +#define X86_FIOASYNC 0x5452 +#define X86_FIOQSIZE 0x5460 + +#include +#include + +unsigned long ioctl_convert(unsigned long x86_req) +{ + // Lookup table for old-style x86 terminal/file ioctls + switch(x86_req) + { + case X86_TCGETS: return TCGETS; + case X86_TCSETS: return TCSETS; + case X86_TCSETSW: return TCSETSW; + case X86_TCSETSF: return TCSETSF; + case X86_TCGETA: return TCGETA; + case X86_TCSETA: return TCSETA; + case X86_TCSETAW: return TCSETAW; + case X86_TCSETAF: return TCSETAF; + case X86_TCSBRK: return TCSBRK; + case X86_TCXONC: return TCXONC; + case X86_TCFLSH: return TCFLSH; + case X86_TIOCEXCL: return TIOCEXCL; + case X86_TIOCNXCL: return TIOCNXCL; + case X86_TIOCSCTTY: return TIOCSCTTY; + case X86_TIOCGPGRP: return TIOCGPGRP; + case X86_TIOCSPGRP: return TIOCSPGRP; + case X86_TIOCOUTQ: return TIOCOUTQ; + case X86_TIOCSTI: return TIOCSTI; + case X86_TIOCGWINSZ: return TIOCGWINSZ; + case X86_TIOCSWINSZ: return TIOCSWINSZ; + case X86_TIOCMGET: return TIOCMGET; + case X86_TIOCMBIS: return TIOCMBIS; + case X86_TIOCMBIC: return TIOCMBIC; + case X86_TIOCMSET: return TIOCMSET; + case X86_TIOCGSOFTCAR: return TIOCGSOFTCAR; + case X86_TIOCSSOFTCAR: return TIOCSSOFTCAR; + case X86_FIONREAD: return FIONREAD; + case X86_TIOCLINUX: return TIOCLINUX; + case X86_TIOCCONS: return TIOCCONS; + case X86_TIOCGSERIAL: return TIOCGSERIAL; + case X86_TIOCSSERIAL: return TIOCSSERIAL; + case X86_TIOCPKT: return TIOCPKT; + case X86_FIONBIO: return FIONBIO; + case X86_TIOCNOTTY: return TIOCNOTTY; + case X86_TIOCSETD: return TIOCSETD; + case X86_TIOCGETD: return TIOCGETD; + case X86_TCSBRKP: return TCSBRKP; + case X86_TIOCGSID: return TIOCGSID; + case X86_FIONCLEX: return FIONCLEX; + case X86_FIOCLEX: return FIOCLEX; + case X86_FIOASYNC: return FIOASYNC; + case X86_FIOQSIZE: return FIOQSIZE; + } + + // For _IOC-encoded ioctls, translate the encoding + unsigned long x86_dir = X86_IOC_DIR(x86_req); + unsigned long x86_type = X86_IOC_TYPE(x86_req); + unsigned long x86_nr = X86_IOC_NR(x86_req); + unsigned long x86_size = X86_IOC_SIZE(x86_req); + + // If it looks like a small raw number (not _IOC encoded), pass through + if(x86_dir == 0 && x86_type == 0) { + return x86_req; + } + + // Translate x86 direction bits to PPC direction bits + unsigned long ppc_dir = 0; + if(x86_dir == X86_IOC_NONE) { + // x86 NONE=0, but if type!=0 it's a real _IOC_NONE ioctl + ppc_dir = 1; // PPC _IOC_NONE = 1 + } else { + if(x86_dir & X86_IOC_READ) ppc_dir |= 2; // PPC _IOC_READ = 2 + if(x86_dir & X86_IOC_WRITE) ppc_dir |= 4; // PPC _IOC_WRITE = 4 + } + + // PPC64LE: size is 13 bits (max 8191) + if(x86_size > 8191) { + printf_log(LOG_DEBUG, "Warning: ioctl size %lu exceeds PPC64LE 13-bit limit, clamping\n", x86_size); + x86_size = 8191; + } + + // Recompose as PPC64LE _IOC: dir(3 bits, 29-31) | size(13 bits, 16-28) | type(8, 8-15) | nr(8, 0-7) + unsigned long ppc_req = (ppc_dir << 29) | (x86_size << 16) | (x86_type << 8) | x86_nr; + + printf_log(LOG_DEBUG, "ioctl_convert: x86=0x%lx -> ppc=0x%lx (dir %lu->%lu, type 0x%lx, nr 0x%lx, size %lu)\n", + x86_req, ppc_req, X86_IOC_DIR(x86_req), ppc_dir, x86_type, x86_nr, x86_size); + + return ppc_req; +} + +EXPORT int my_ioctl(x64emu_t* emu, int fd, unsigned long req, void* arg) +{ + (void)emu; + unsigned long native_req = ioctl_convert(req); + return ioctl(fd, native_req, arg); +} +#endif + EXPORT void* my__ZGTtnaX (size_t a) { (void)a; printf("warning _ZGTtnaX called\n"); return NULL; } EXPORT void* my__ZGTtnam (size_t a) { (void)a; printf("warning _ZGTtnam called\n"); return NULL; } EXPORT void my__ZGTtdlPv (void* a) { (void)a; printf("warning _ZGTtdlPv called\n"); } From a2ea2ba00431fceaca2ca84d5b8260eaadcc2592 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trung=20L=C3=AA?= <8@tle.id.au> Date: Fri, 20 Mar 2026 22:49:11 +1100 Subject: [PATCH 3/4] [PPC64LE] Hook ioctl translation in libc wrapper and syscall paths Wire up the ioctl number translation via both code paths that x86_64 programs use to call ioctl: 1. Libc wrapper path: Under #ifdef PPC64LE, change GOW(ioctl, iFiLN) to GOWM(ioctl, iFEiLp) so calls go through my_ioctl() which translates the ioctl number before calling native ioctl(). 2. Syscall path: Add case 16 (sys_ioctl) under #ifdef PPC64LE in x64Syscall_linux() that calls ioctl_convert() before the native ioctl syscall. Guard the generic table entry [16] with #ifndef PPC64LE to avoid conflict. --- src/emu/x64syscall.c | 12 ++++++++++++ src/wrapped/wrappedlibc_private.h | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/src/emu/x64syscall.c b/src/emu/x64syscall.c index cbc2282e89..c6f2b6fd17 100644 --- a/src/emu/x64syscall.c +++ b/src/emu/x64syscall.c @@ -52,6 +52,9 @@ extern int fchmodat (int __fd, const char *__file, mode_t __mode, int __flag); //int32_t my_getrandom(x64emu_t* emu, void* buf, uint32_t buflen, uint32_t flags); int of_convert(int flag); int32_t my_open(x64emu_t* emu, void* pathname, int32_t flags, uint32_t mode); +#ifdef PPC64LE +unsigned long ioctl_convert(unsigned long x86_req); +#endif ssize_t my_readlink(x64emu_t* emu, void* path, void* buf, size_t sz); int my_readlinkat(x64emu_t* emu, int fd, void* path, void* buf, size_t bufsize); int my_stat(x64emu_t *emu, void* filename, void* buf); @@ -108,7 +111,9 @@ static const scwrap_t syscallwrap[] = { //[13] = {__NR_rt_sigaction, 4}, // wrapped to use my_ version [14] = {__NR_rt_sigprocmask, 4}, [15] = {__NR_rt_sigreturn, 1}, + #ifndef PPC64LE [16] = {__NR_ioctl, 3}, + #endif [17] = {__NR_pread64, 4}, [18] = {__NR_pwrite64, 4}, [19] = {__NR_readv, 3}, @@ -579,6 +584,13 @@ void EXPORT x64Syscall_linux(x64emu_t *emu) if(S_RAX==-1) S_RAX = -errno; break; + #ifdef PPC64LE + case 16: // sys_ioctl (PPC64LE needs ioctl number translation) + S_RAX = ioctl(S_EDI, ioctl_convert(R_RSI), R_RDX); + if(S_RAX==-1) + S_RAX = -errno; + break; + #endif case 6: // sys_lstat S_RAX = my_lstat(emu, (void*)R_RDI, (void*)R_RSI); if(S_RAX==-1) diff --git a/src/wrapped/wrappedlibc_private.h b/src/wrapped/wrappedlibc_private.h index c6a0254fbd..7354266413 100644 --- a/src/wrapped/wrappedlibc_private.h +++ b/src/wrapped/wrappedlibc_private.h @@ -861,7 +861,11 @@ DATA(_IO_2_1_stdin_, 224) DATA(_IO_2_1_stdout_, 224) //GO(_IO_adjust_column, //GO(_IO_adjust_wcolumn, +#ifdef PPC64LE +GOWM(ioctl, iFEiLp) +#else GOW(ioctl, iFiLN) +#endif GO(_IO_default_doallocate, iFS) GO(_IO_default_finish, vFSi) GO(_IO_default_pbackfail, iFSi) From 7d864e4bc5bfe775b94244db593e2da3dfdc4a42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trung=20L=C3=AA?= <8@tle.id.au> Date: Fri, 20 Mar 2026 22:57:36 +1100 Subject: [PATCH 4/4] [PPC64LE] Add x64printer trace entry for iFEiLp wrapper Add debug trace formatting for the iFEiLp signature under #ifdef PPC64LE so BOX64_LOG=1 output shows readable argument values for ioctl calls: int32_t fd, uintptr_t request, void* arg. --- src/emu/x64printer.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/emu/x64printer.c b/src/emu/x64printer.c index be956c09d9..cee1c3f8e9 100644 --- a/src/emu/x64printer.c +++ b/src/emu/x64printer.c @@ -7578,6 +7578,12 @@ void x64Print(x64emu_t* emu, char* buff, size_t buffsz, const char* func, int ti snprintf(buff, buffsz, "%04d|%p: Calling %s(%" PRIi32 ", %" PRIi32 ", %" PRIu64 ", %" PRIu64 ", %" PRIi32 ", %" PRIp ", %" PRIp ", %" PRIp ")", tid, *(void**)(R_RSP), func, (int32_t)R_RDI, (int32_t)R_RSI, (uint64_t)R_RDX, (uintptr_t)R_RCX, (int32_t)R_R8, (void*)R_R9, *(void**)(R_RSP + 8), *(void**)(R_RSP + 16)); } else if (w == lFpLpdddddd) { snprintf(buff, buffsz, "%04d|%p: Calling %s(%" PRIp ", %" PRIu64 ", %" PRIp ", %" PRIf ", %" PRIf ", %" PRIf ", %" PRIf ", %" PRIf ", %" PRIf ")", tid, *(void**)(R_RSP), func, (void*)R_RDI, (uintptr_t)R_RSI, (void*)R_RDX, emu->xmm[0].d[0], emu->xmm[1].d[0], emu->xmm[2].d[0], emu->xmm[3].d[0], emu->xmm[4].d[0], emu->xmm[5].d[0]); +#endif +#if defined(PPC64LE) + } else if (w == iFEiLp) { + snprintf(buff, buffsz, "%04d|%p: Calling %s(%" PRIi32 ", %" PRIu64 ", %" PRIp ")", tid, *(void**)(R_RSP), func, (int32_t)R_RDI, (uintptr_t)R_RSI, (void*)R_RDX); +#endif +#if !defined(PPC64LE) #endif } else