vxlinux.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       vxlinux.c (5983B)
       ---
            1 #define _GNU_SOURCE // for syscall in unistd.h
            2 #include <stdio.h>
            3 #include <stdlib.h>
            4 #include <stdarg.h>
            5 #include <string.h>
            6 #include <assert.h>
            7 #include <unistd.h>
            8 #include <errno.h>
            9 #include <pthread.h>
           10 #include <sys/stat.h>
           11 #include <sys/time.h>
           12 #include <sys/wait.h>
           13 #include <sys/syscall.h>
           14 #include <fcntl.h>
           15 #include "vx32.h"
           16 
           17 #define nelem(x) (sizeof(x)/sizeof((x)[0]))
           18 
           19 extern char *strsyscall(int);  // strsyscall.c
           20 
           21 static const char *progname;
           22 
           23 static void fatal(const char *fmt, ...)
           24 {
           25         va_list ap;
           26         fprintf(stderr, "%s: fatal error: ", progname);
           27         va_start(ap, fmt);
           28         vfprintf(stderr, fmt, ap);
           29         va_end(ap);
           30         fputc('\n', stderr);
           31         exit(2);
           32 }
           33 
           34 static void dumpregs(struct vxproc *p)
           35 {
           36         struct vxcpu *c = p->cpu;
           37 
           38         fprintf(stderr, "eax %08x  ecx %08x  edx %08x  ebx %08x\n",
           39                 c->reg[EAX], c->reg[ECX], c->reg[EDX], c->reg[EBX]);
           40         fprintf(stderr, "esp %08x  ebp %08x  esi %08x  edi %08x\n",
           41                 c->reg[ESP], c->reg[EBP], c->reg[ESI], c->reg[EDI]);
           42         fprintf(stderr, "eip %08x  eflags %08x\n",
           43                 c->eip, c->eflags);
           44 
           45 //        for (int i = 0; i < 8; i++) {
           46 //                int32_t *val = r.xmm[i].i32;
           47 //                fprintf(stderr, "xmm%d %08x%08x%08x%08x\n",
           48 //                        i, val[3], val[2], val[1], val[0]);
           49 //        }
           50 }
           51 
           52 int trace;
           53 
           54 // macros for use within system calls
           55 #define NUM proc->cpu->reg[EAX]
           56 #define ARG1 proc->cpu->reg[EBX]
           57 #define ARG2 proc->cpu->reg[ECX]
           58 #define ARG3 proc->cpu->reg[EDX]
           59 #define ARG4 proc->cpu->reg[ESI]
           60 #define ARG5 proc->cpu->reg[EDI]
           61 
           62 #define SYSCALL(x) static int x(vxproc *proc, vxmmap *m)
           63 
           64 // Translate pointer - guest to host
           65 #define TX(a) ((a) ? (a)+m->base : 0)
           66 
           67 SYSCALL(sys0) { return syscall(NUM); }
           68 SYSCALL(sys1I) { return syscall(NUM, ARG1); }
           69 SYSCALL(sys1P) { return syscall(NUM, TX(ARG1)); }
           70 SYSCALL(sys2II) { return syscall(NUM, ARG1, ARG2); }
           71 SYSCALL(sys2IP) { return syscall(NUM, ARG1, TX(ARG2)); }
           72 SYSCALL(sys2PI) { return syscall(NUM, TX(ARG1), ARG2); }
           73 SYSCALL(sys2PP) { return syscall(NUM, TX(ARG1), TX(ARG2)); }
           74 SYSCALL(sys3IIP) { return syscall(NUM, ARG1, ARG2, TX(ARG3)); }
           75 SYSCALL(sys3III) { return syscall(NUM, ARG1, ARG2, ARG3); }
           76 SYSCALL(sys3PII) { return syscall(NUM, TX(ARG1), ARG2, ARG3); }
           77 SYSCALL(sys3PPI) { return syscall(NUM, TX(ARG1), TX(ARG2), ARG3); }
           78 SYSCALL(sys3IPI) { return syscall(NUM, ARG1, TX(ARG2), ARG3); }
           79 SYSCALL(sys4IPPI) { return syscall(NUM, ARG1, TX(ARG2), TX(ARG3), ARG4); }
           80 SYSCALL(sys5IIIPI) { return syscall(NUM, ARG1, ARG2, ARG3, TX(ARG4), ARG5); }
           81 
           82 // Linux brk doesn't follow the usual system call conventions.
           83 // It returns the new brk on success, the old one on failure.
           84 SYSCALL(sysbrk)
           85 {
           86         uint32_t oaddr = m->size;
           87         uint32_t addr = ARG1;
           88         if (addr == 0)
           89                 return oaddr;
           90         if (addr == oaddr)
           91                 return oaddr;
           92         if (vxmem_resize(proc->mem, addr) < 0)
           93                 return oaddr;
           94         if (addr > oaddr)
           95                 vxmem_setperm(proc->mem, oaddr, addr - oaddr, VXPERM_READ|VXPERM_WRITE);
           96         return addr;
           97 }
           98 
           99 SYSCALL(sysinval)
          100 {
          101         errno = EINVAL;
          102         return -1;
          103 }
          104 
          105 SYSCALL(sysfcntl64)
          106 {
          107         switch (ARG1) {
          108         default:
          109                 errno = EINVAL;
          110                 return -1;
          111 
          112         case F_DUPFD:
          113         case F_GETFD:
          114         case F_SETFD:
          115         case F_GETFL:
          116         case F_SETFL:
          117         case F_GETOWN:
          118         case F_SETOWN:
          119         case F_GETSIG:
          120         case F_SETSIG:
          121         case F_GETLEASE:
          122         case F_SETLEASE:
          123         case F_NOTIFY:
          124                 return syscall(NUM, ARG1, ARG2, ARG3);
          125         
          126         case F_GETLK:
          127         case F_SETLK:
          128         case F_SETLKW:
          129                 return syscall(NUM, ARG1, ARG2, TX(ARG3));
          130         }
          131 }
          132 
          133 static int (*syscalls[])(vxproc*, vxmmap*) =
          134 {
          135         [SYS_brk]           sysbrk,
          136         [SYS_close]         sys1I,
          137         [SYS_chmod]         sys2PI,
          138         [SYS_chown]         sys3PII,
          139         [SYS_creat]         sys2PI,
          140         [SYS_dup]           sys1I,
          141         [SYS_dup2]          sys2II,
          142         [SYS_exit_group]    sys1I,
          143         [SYS_fcntl64]       sysfcntl64,
          144         [SYS_fchmod]        sys2II,
          145         [SYS_fchown]        sys3III,
          146         [SYS_fstat64]       sys2IP,
          147         [SYS_getegid32]     sys0,
          148         [SYS_geteuid32]     sys0,
          149         [SYS_getgid32]      sys0,
          150         [SYS_getpid]        sys0,
          151         [SYS_getuid32]      sys0,
          152         [SYS_ioctl]         sys3IIP,
          153         [SYS__llseek]       sys5IIIPI,
          154         [SYS_lchown]        sys3PII,
          155         [SYS_link]          sys2PP,
          156         [SYS_lseek]         sys3III,
          157         [SYS_mkdir]         sys2PI,
          158         [SYS_mmap]          sysinval,
          159         [SYS_mmap2]         sysinval,
          160         [SYS_open]          sys3PII,
          161         [SYS_read]          sys3IPI,
          162         [SYS_readlink]      sys3PPI,
          163         [SYS_rmdir]         sys1P,
          164         [SYS_rt_sigaction]  sys4IPPI,
          165         [SYS_stat64]        sys2PP,
          166         [SYS_symlink]       sys2PP,
          167         [SYS_time]          sys1P,
          168         [SYS_uname]         sys1P,
          169         [SYS_unlink]        sys1P,
          170         [SYS_write]         sys3IPI,
          171 };
          172 
          173 static void dosyscall(vxproc *proc)
          174 {
          175         int n = NUM;
          176         if (trace)
          177                 fprintf(stderr, "%s %08x %08x %08x %08x %08x\n", 
          178                         strsyscall(NUM), ARG1, ARG2, ARG3, ARG4, ARG5);
          179         if (n < nelem(syscalls) && n >= 0 && syscalls[n]) {
          180                 vxmmap *m = vxmem_map(proc->mem, 0);
          181                 int ret = syscalls[n](proc, m);
          182                 if (n != SYS_brk && ret < 0)
          183                         ret = -errno;
          184                 vxmem_unmap(proc->mem, m);
          185                 proc->cpu->reg[EAX] = ret;
          186                 return;
          187         }
          188         dumpregs(proc);
          189         fatal("syscall not implemented - %s", strsyscall(NUM));
          190 }
          191 
          192 extern char **environ;
          193 
          194 int main(int argc, const char *const *argv)
          195 {
          196         int i;
          197         progname = argv[0];
          198 
          199         if (argc > 1 && strcmp(argv[1], "-t") == 0){
          200                 argc--;
          201                 argv++;
          202                 trace++;
          203         }
          204 
          205         if (argc < 2) {
          206                 fprintf(stderr, "Usage: %s <vx-program> <args>\n",
          207                         progname);
          208                 exit(1);
          209         }
          210         const char *loadname = argv[1];
          211 
          212         FILE *f = fopen("/dev/tty", "w");
          213         if(f){
          214                 char buf[1000];
          215                 if(getcwd(buf, sizeof buf) != NULL)
          216                         fprintf(f, "cd %s\n", buf);
          217                 fprintf(f, "vxlinux");
          218                 for(i=1; i<argc; i++)
          219                         fprintf(f, " %s", argv[i]);
          220                 fprintf(f, "\n");
          221         }
          222 
          223         vxproc *p = vxproc_alloc();
          224         if (p == NULL)
          225                 fatal("vxproc_new: %s\n", strerror(errno));
          226         p->allowfp = 1;
          227 
          228         if (vxproc_loadelffile(p, loadname, &argv[1], (const char**)environ) < 0)
          229                 fatal("vxproc_loadfile: %s\n", strerror(errno));
          230 
          231         vx32_siginit();
          232         dumpregs(p);
          233 
          234         // Simple execution loop.
          235         for (;;) {
          236                 int rc = vxproc_run(p);
          237                 if (rc < 0)
          238                         fatal("vxproc_run: %s\n", strerror(errno));
          239                 if (rc == VXTRAP_SOFT + 0x80) {
          240                         dosyscall(p);
          241                         continue;
          242                 }
          243                 dumpregs(p);
          244                 fatal("vxproc_run trap %#x\n", rc);
          245         }
          246         return 0;        // not reached
          247 }
          248