about summary refs log tree commit diff stats
path: root/src/emu/x86syscall_32.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/x86syscall_32.c')
-rw-r--r--src/emu/x86syscall_32.c447
1 files changed, 447 insertions, 0 deletions
diff --git a/src/emu/x86syscall_32.c b/src/emu/x86syscall_32.c
new file mode 100644
index 00000000..cae7b40b
--- /dev/null
+++ b/src/emu/x86syscall_32.c
@@ -0,0 +1,447 @@
+#define _GNU_SOURCE         /* See feature_test_macros(7) */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/syscall.h>   /* For SYS_xxx definitions */
+#include <unistd.h>
+#include <time.h>
+#include <sys/mman.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <asm/stat.h>
+#include <errno.h>
+#include <sched.h>
+#include <sys/wait.h>
+#include <sys/utsname.h>
+#ifndef __NR_socketcall
+#include <linux/net.h>
+#include <sys/socket.h>
+#endif
+#include <sys/resource.h>
+#include <poll.h>
+
+#include "debug.h"
+#include "box64stack.h"
+#include "x64emu.h"
+#include "x64run.h"
+#include "x64emu_private.h"
+#include "x64trace.h"
+#include "myalign32.h"
+#include "box64context.h"
+#include "callback.h"
+#include "signals.h"
+#include "x64tls.h"
+#include "box32.h"
+
+
+// Syscall table for x86_64 can be found 
+typedef struct scwrap_s {
+    uint32_t x86s;
+    int nats;
+    int nbpars;
+} scwrap_t;
+
+static const scwrap_t syscallwrap[] = {
+    //{ 2, __NR_fork, 1 },  
+    //{ 3, __NR_read, 3 },  // wrapped so SA_RESTART can be handled by libc
+    //{ 4, __NR_write, 3 }, // same
+    //{ 5, __NR_open, 3 },  // flags need transformation
+    //{ 6, __NR_close, 1 },   // wrapped so SA_RESTART can be handled by libc
+    //{ 7, __NR_waitpid, 3 },
+    //{ 10, __NR_unlink, 1 },
+    //{ 12, __NR_chdir, 1 },
+    //{ 13, __NR_time, 1 },
+    //{ 15, __NR_chmod, 2 },
+    //{ 19, __NR_lseek, 3 },
+    //{ 20, __NR_getpid, 0 },
+    //{ 24, __NR_getuid, 0 },
+    //{ 33, __NR_access, 2 },
+    //{ 37, __NR_kill, 2 },
+    //{ 38, __NR_rename, 2 },
+    //{ 39, __NR_mkdir, 2 },
+    //{ 40, __NR_rmdir, 1 },
+    //{ 41, __NR_dup, 1 },
+    //{ 42, __NR_pipe, 1 },
+    //{ 45, __NR_brk, 1 },
+    //{ 47, __NR_getgid, 0 },
+    //{ 49, __NR_geteuid, 0 },
+    //{ 50, __NR_getegid, 0 },
+    //{ 54, __NR_ioctl, 3 },    // should be wrapped to allow SA_RESTART handling by libc, but syscall is only 3 arguments, ioctl can be 5
+    //{ 55, __NR_fcntl, 3 },    // wrapped to allow filter of F_SETFD
+    //{ 60, __NR_umask, 1 },
+    //{ 63, __NR_dup2, 2 },
+    //{ 64, __NR_getppid, 0 },
+    //{ 66, __NR_setsid, 0 },
+    //{ 75, __NR_setrlimit, 2 },
+    //{ 76, __NR_getrlimit, 2 },
+    //{ 77, __NR_getrusage, 2 },
+    //{ 78, __NR_gettimeofday, 2 },
+    //{ 83, __NR_symlink, 2 },
+    //{ 82, __NR_select, 5 },
+    //{ 85, __NR_readlink, 3 },
+    //{ 91, __NR_munmap, 2 },
+    //{ 94, __NR_fchmod, 2 },
+    //{ 99, __NR_statfs, 2 },
+    //{ 102, __NR_socketcall, 2 },
+    //{ 104, __NR_setitimer, 3 },
+    //{ 105, __NR_getitimer, 2 },
+    //{ 106, __NR_newstat, 2 },
+    //{ 106, __NR_stat, 2 },
+    //{ 107, __NR_newlstat, 2 },
+    //{ 107, __NR_lstat, 2 },
+    //{ 108, __NR_newfstat, 2 },
+    //{ 108, __NR_fstat, 2 },
+    //{ 109, __NR_olduname, 1 },
+    //{ 110, __NR_iopl, 1 },
+    //{ 114, __NR_wait4, 4 }, //TODO: check struct rusage alignment
+    //{ 117, __NR_ipc, 6 },
+    //{ 119, __NR_sigreturn, 0},
+    //{ 120, __NR_clone, 5 },    // need works
+    //{ 122, __NR_uname, 1 },
+    //{ 123, __NR_modify_ldt },
+    //{ 125, __NR_mprotect, 3 },
+    //{ 136, __NR_personality, 1 },
+    //{ 140, __NR__llseek, 5 },
+    //{ 141, __NR_getdents, 3 },
+    //{ 142, __NR__newselect, 5 },
+    //{ 143, __NR_flock,  2 },
+    //{ 144, __NR_msync, 3 },
+    //{ 145, __NR_readv, 3 },
+    //{ 146, __NR_writev, 3 },
+    //{ 148, __NR_fdatasync, 1 },
+    //{ 149, __NR__sysctl, 1 },    // need wrapping?
+    //{ 156, __NR_sched_setscheduler, 3 },
+    //{ 157, __NR_sched_getscheduler, 1 },
+    //{ 158, __NR_sched_yield, 0 },
+    //{ 162, __NR_nanosleep, 2 },
+    //{ 164, __NR_setresuid, 3 },
+    //{ 168, __NR_poll, 3 },    // wrapped to allow SA_RESTART wrapping by libc
+    //{ 172, __NR_prctl, 5 },
+    //{ 173, __NR_rt_sigreturn, 0 },
+    //{ 175, __NR_rt_sigprocmask, 4 },
+    //{ 179, __NR_rt_sigsuspend, 2 },
+    //{ 183, __NR_getcwd, 2 },
+    //{ 184, __NR_capget, 2},
+    //{ 185, __NR_capset, 2},
+    //{ 186, __NR_sigaltstack, 2 },    // neeed wrap or something?
+    //{ 191, __NR_ugetrlimit, 2 },
+//    { 192, __NR_mmap2, 6},
+    //{ 195, __NR_stat64, 2 },  // need proprer wrap because of structure size change
+    //{ 196, __NR_lstat64, 2 }, // need proprer wrap because of structure size change
+    //{ 197, __NR_fstat64, 2 },  // need proprer wrap because of structure size change
+    //{ 199, __NR_getuid32, 0 },
+    //{ 200, __NR_getgid32, 0 },
+    //{ 201, __NR_geteuid32, 0 },
+    //{ 202, __NR_getegid32, 0 },
+    //{ 208, __NR_setresuid32, 3 },
+    //{ 209, __NR_getresuid32, 3 },
+    //{ 210, __NR_setresgid32, 3 },
+    //{ 211, __NR_getresgid32, 3 },
+    //{ 220, __NR_getdents64, 3 },
+    //{ 221, __NR_fcntl64, 3 },
+    { 224, __NR_gettid, 0 },
+    //{ 240, __NR_futex, 6 },
+    //{ 241, __NR_sched_setaffinity, 3 },
+    //{ 242, __NR_sched_getaffinity, 3 },
+    //{ 252, __NR_exit_group, 1 },
+    //{ 254, __NR_epoll_create, 1 },
+    //{ 255, __NR_epoll_ctl, 4 },
+    //{ 256, __NR_epoll_wait, 4 },
+    //{ 265, __NR_clock_gettime, 2 },
+    //{ 266, __NR_clock_getres, 2 },
+    //{ 270, __NR_tgkill, 3 },
+    //{ 271, __NR_utimes, 2 },
+    //{ 291, __NR_inotify_init, 0},
+    //{ 292, __NR_inotify_add_watch, 3},
+    //{ 293, __NR_inotify_rm_watch, 2},
+    //{ 311, __NR_set_robust_list, 2 },
+    //{ 312, __NR_get_robust_list, 4 },
+    //{ 318, __NR_getcpu, 3},
+    //{ 328, __NR_eventfd2, 2},
+    //{ 329, __NR_epoll_create1, 1 },
+    //{ 331, __NR_pipe2, 2},
+    //{ 332, __NR_inotify_init1, 1},
+    //{ 355, __NR_getrandom, 3 },
+    //{ 356, __NR_memfd_create, 2},
+    //{ 449, __NR_futex_waitv, 5},
+};
+
+struct mmap_arg_struct {
+    unsigned long addr;
+    unsigned long len;
+    unsigned long prot;
+    unsigned long flags;
+    unsigned long fd;
+    unsigned long offset;
+};
+
+#undef st_atime
+#undef st_ctime
+#undef st_mtime
+
+struct x64_pt_regs {
+    long ebx;
+    long ecx;
+    long edx;
+    long esi;
+    long edi;
+    long ebp;
+    long eax;
+    int  xds;
+    int  xes;
+    int  xfs;
+    int  xgs;
+    long orig_eax;
+    long eip;
+    int  xcs;
+    long eflags;
+    long esp;
+    int  xss;
+};
+
+#ifndef __NR_olduname
+struct oldold_utsname {
+        char sysname[9];
+        char nodename[9];
+        char release[9];
+        char version[9];
+        char machine[9];
+};
+#endif
+struct old_utsname {
+        char sysname[65];
+        char nodename[65];
+        char release[65];
+        char version[65];
+        char machine[65];
+};
+
+struct i386_user_desc {
+    unsigned int  entry_number;
+    unsigned long base_addr;
+    unsigned int  limit;
+    unsigned int  seg_32bit:1;
+    unsigned int  contents:2;
+    unsigned int  read_exec_only:1;
+    unsigned int  limit_in_pages:1;
+    unsigned int  seg_not_present:1;
+    unsigned int  useable:1;
+};
+
+int32_t my32_open(x64emu_t* emu, void* pathname, int32_t flags, uint32_t mode);
+int32_t my32_execve(x64emu_t* emu, const char* path, char* const argv[], char* const envp[]);
+int my32_munmap(x64emu_t* emu, void* addr, unsigned long length);
+
+void EXPORT x86Syscall(x64emu_t *emu)
+{
+    uint32_t s = R_EAX;
+    printf_log(LOG_DEBUG, "%p: Calling 32bits syscall 0x%02X (%d) %p %p %p %p %p", (void*)R_RIP, s, s, (void*)(uintptr_t)R_EBX, (void*)(uintptr_t)R_ECX, (void*)(uintptr_t)R_EDX, (void*)(uintptr_t)R_ESI, (void*)(uintptr_t)R_EDI); 
+    // check wrapper first
+    int cnt = sizeof(syscallwrap) / sizeof(scwrap_t);
+    for (int i=0; i<cnt; i++) {
+        if(syscallwrap[i].x86s == s) {
+            int sc = syscallwrap[i].nats;
+            switch(syscallwrap[i].nbpars) {
+                case 0: *(int32_t*)&R_EAX = syscall(sc); break;
+                case 1: *(int32_t*)&R_EAX = syscall(sc, R_EBX); break;
+                case 2: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX); break;
+                case 3: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX, R_EDX); break;
+                case 4: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX, R_EDX, R_ESI); break;
+                case 5: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI); break;
+                case 6: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI, R_EBP); break;
+                default:
+                   printf_log(LOG_NONE, "ERROR, Unimplemented syscall wrapper (%d, %d)\n", s, syscallwrap[i].nbpars); 
+                   emu->quit = 1;
+                   return;
+            }
+            if(R_EAX==0xffffffff && errno>0)
+                R_EAX = (uint32_t)-errno;
+            printf_log(LOG_DEBUG, " => 0x%x\n", R_EAX);
+            return;
+        }
+    }
+    switch (s) {
+        case 1: // sys_exit
+            emu->quit = 1;
+            emu->exit = 1;
+            //R_EAX = syscall(__NR_exit, R_EBX);  // the syscall should exit only current thread
+            R_EAX = R_EBX; // faking the syscall here, we don't want to really terminate the thread now
+            break;
+        case 3:  // sys_read
+            S_EAX = read((int)R_EBX, from_ptrv(R_ECX), from_ulong(R_EDX));
+            break;
+        case 4:  // sys_write
+            S_EAX = write((int)R_EBX, from_ptrv(R_ECX), from_ulong(R_EDX));
+            break;
+        case 5: // sys_open
+            if(s==5) {printf_log(LOG_DEBUG, " => sys_open(\"%s\", %d, %d)", (char*)from_ptrv(R_EBX), of_convert32(R_ECX), R_EDX);}; 
+            //S_EAX = open((void*)R_EBX, of_convert32(R_ECX), R_EDX);
+            S_EAX = my32_open(emu, from_ptrv(R_EBX), of_convert32(R_ECX), R_EDX);
+            break;
+        case 6:  // sys_close
+            S_EAX = close((int)R_EBX);
+            break;
+        /*case 123:   // SYS_modify_ldt
+            R_EAX = my32_modify_ldt(emu, R_EBX, (thread_area_t*)(uintptr_t)R_ECX, R_EDX);
+            if(R_EAX==0xffffffff && errno>0)
+                R_EAX = (uint32_t)-errno;
+            break;*/
+        case 243: // set_thread_area
+            R_EAX = my_set_thread_area_32(emu, (thread_area_32_t*)(uintptr_t)R_EBX);
+            if(R_EAX==0xffffffff && errno>0)
+                R_EAX = (uint32_t)-errno;
+            break;
+        default:
+            printf_log(LOG_INFO, "Warning: Unsupported Syscall 0x%02Xh (%d)\n", s, s);
+            R_EAX = (uint32_t)-ENOSYS;
+            return;
+    }
+    printf_log(LOG_DEBUG, " => 0x%x\n", R_EAX);
+}
+
+#ifdef BOX32
+#define stack(n) (b[(n)/4])
+#define i32(n)  (int32_t)stack(n)
+#define u32(n)  (uint32_t)stack(n)
+#define p(n)    from_ptrv(stack(n))
+
+uint32_t EXPORT my32_syscall(x64emu_t *emu, ptr_t* b)
+{
+    static uint32_t warned = 0;
+    uint32_t s = u32(0);
+    printf_log(LOG_DEBUG, "%p: Calling libc syscall 0x%02X (%d) %p %p %p %p %p\n", from_ptrv(R_EIP), s, s, from_ptrv(u32(4)), from_ptrv(u32(8)), from_ptrv(u32(12)), from_ptrv(u32(16)), from_ptrv(u32(20))); 
+    // check wrapper first
+    int cnt = sizeof(syscallwrap) / sizeof(scwrap_t);
+    for (int i=0; i<cnt; i++) {
+        if(syscallwrap[i].x86s == s) {
+            int sc = syscallwrap[i].nats;
+            switch(syscallwrap[i].nbpars) {
+                case 0: return syscall(sc);
+                case 1: return syscall(sc, u32(4));
+                case 2: return syscall(sc, u32(4), u32(8));
+                case 3: return syscall(sc, u32(4), u32(8), u32(12));
+                case 4: return syscall(sc, u32(4), u32(8), u32(12), u32(16));
+                case 5: return syscall(sc, u32(4), u32(8), u32(12), u32(16), u32(20));
+                case 6: return syscall(sc, u32(4), u32(8), u32(12), u32(16), u32(20), u32(24));
+                default:
+                   printf_log(LOG_NONE, "ERROR, Unimplemented syscall wrapper (%d, %d)\n", s, syscallwrap[i].nbpars); 
+                   emu->quit = 1;
+                   return 0;
+            }
+        }
+    }
+    switch (s) {
+        case 1: // __NR_exit
+            emu->quit = 1;
+            return u32(4); // faking the syscall here, we don't want to really terminate the program now
+        case 3:  // sys_read
+            return (uint32_t)read(i32(4), p(8), u32(12));
+        case 4:  // sys_write
+            return (uint32_t)write(i32(4), p(8), u32(12));
+        case 5: // sys_open
+            return my32_open(emu, p(4), of_convert32(u32(8)), u32(12));
+        case 6:  // sys_close
+            return (uint32_t)close(i32(4));
+        case 11: // execve
+            return (uint32_t)my32_execve(emu, p(4), p(8), p(12));
+        case 91:   // munmap
+            return (uint32_t)my32_munmap(emu, p(4), u32(8));
+#if 0
+        case 120:   // clone
+            // x86 raw syscall is long clone(unsigned long flags, void *stack, int *parent_tid, unsigned long tls, int *child_tid);
+            // so flags=u(4), stack=p(8), parent_tid=p(12), tls=p(16), child_tid=p(20)
+            if(p(8))
+            {
+                void* stack_base = p(8);
+                int stack_size = 0;
+                if(!stack_base) {
+                    // allocate a new stack...
+                    int currstack = 0;
+                    if((R_ESP>=(uintptr_t)emu->init_stack) && (R_ESP<=((uintptr_t)emu->init_stack+emu->size_stack)))
+                        currstack = 1;
+                    stack_size = (currstack)?emu->size_stack:(1024*1024);
+                    stack_base = mmap(NULL, stack_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_GROWSDOWN, -1, 0);
+                    // copy value from old stack to new stack
+                    if(currstack)
+                        memcpy(stack_base, emu->init_stack, stack_size);
+                    else {
+                        int size_to_copy = (uintptr_t)emu->init_stack + emu->size_stack - (R_ESP);
+                        memcpy(stack_base+stack_size-size_to_copy, (void*)R_ESP, size_to_copy);
+                    }
+                }
+                x64emu_t * newemu = NewX86Emu(emu->context, R_EIP, (uintptr_t)stack_base, stack_size, (p(8))?0:1);
+                SetupX86Emu(newemu);
+                CloneEmu(newemu, emu);
+                Push32(newemu, 0);
+                PushExit(newemu);
+                void* mystack = NULL;
+                if(my32_context->stack_clone_used) {
+                    mystack = malloc(1024*1024);  // stack for own process... memory leak, but no practical way to remove it
+                } else {
+                    if(!my32_context->stack_clone)
+                        my32_context->stack_clone = malloc(1024*1024);
+                    mystack = my32_context->stack_clone;
+                    my32_context->stack_clone_used = 1;
+                }
+                // x86_64 raw clone is long clone(unsigned long flags, void *stack, int *parent_tid, int *child_tid, unsigned long tls);
+                long ret = clone(clone_fn, (void*)((uintptr_t)mystack+1024*1024), u32(4), newemu, p(12), p(16), p(20));
+                return (uint32_t)ret;
+            }
+            else
+                return (uint32_t)syscall(__NR_clone, u32(4), p(8), p(12), p(16), p(20));
+            break;
+        case 123:   // SYS_modify_ldt
+            return my32_modify_ldt(emu, i32(4), (thread_area_t*)p(8), i32(12));
+        case 125:   // mprotect
+            return (uint32_t)my32_mprotect(emu, p(4), u32(8), i32(12));
+        case 174:   // sys_rt_sigaction
+            return (uint32_t)my32_sigaction(emu, i32(4), (x86_sigaction_t*)p(8), (x86_sigaction_t*)p(12));
+        case 192:   // mmap2
+            return (uint32_t)my32_mmap64(emu, p(4), u32(8), i32(12), i32(16), i32(20), u32(24));
+        case 243: // set_thread_area
+            return my32_set_thread_area((thread_area_t*)p(4));
+#ifndef NOALIGN
+        case 254: // epoll_create
+            return my32_epoll_create(emu, i32(4));
+        case 255: // epoll_ctl
+            return my32_epoll_ctl(emu, i32(4), i32(8), i32(12), p(16));
+        case 256: // epoll_wait
+            return my32_epoll_wait(emu, i32(4), p(8), i32(12), i32(16));
+#endif
+        case 270: //_NR_tgkill
+            /*if(!u32(12))*/ {
+                //printf("tgkill(%u, %u, %u) => ", u32(4), u32(8), u32(12));
+                uint32_t ret = (uint32_t)syscall(__NR_tgkill, u32(4), u32(8), u32(12));
+                //printf("%u (errno=%d)\n", ret, (ret==(uint32_t)-1)?errno:0);
+                return ret;
+            }/* else {
+                printf_log(LOG_INFO, "Warning: ignoring libc Syscall tgkill (%u, %u, %u)\n", u32(4), u32(8), u32(12));
+            }*/
+            return 0;
+#ifndef NOALIGN
+        case 329:   // epoll_create1
+            return my32_epoll_create1(emu, of_convert32(i32(4)));
+#endif
+#ifndef __NR_getrandom
+        case 355:  // getrandom
+            return (uint32_t)my32_getrandom(emu, p(4), u32(8), u32(12));
+#endif
+#ifndef __NR_memfd_create
+        case 356:  // memfd_create
+            return (uint32_t)my32_memfd_create(emu, (void*)R_EBX, R_ECX);
+#endif
+#endif
+        default:
+            if(!(warned&(1<<s))) {
+                printf_log(LOG_INFO, "Warning: Unsupported libc Syscall 0x%02X (%d)\n", s, s);
+                warned|=(1<<s);
+            }
+            errno = ENOSYS;
+            return -1;
+    }
+    return 0;
+}
+#endif //BOX32
\ No newline at end of file