vxrun.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       vxrun.c (11583B)
       ---
            1 #include <stdio.h>
            2 #include <stdlib.h>
            3 #include <stdarg.h>
            4 #include <string.h>
            5 #include <assert.h>
            6 #include <unistd.h>
            7 #include <errno.h>
            8 #include <pthread.h>
            9 #include <sys/stat.h>
           10 #include <sys/time.h>
           11 #include <sys/wait.h>
           12 #include <fcntl.h>
           13 #include <setjmp.h>
           14 #include "vx32.h"
           15 #include "args.h"
           16 #include "libvxc_dat.h"
           17 
           18 #define syscall xxxsyscall // FIXME
           19 #include "libvxc/syscall.h"
           20 
           21 #define V (void*)(uintptr_t)
           22 
           23 const char *argv0;
           24 
           25 extern int vx_elfbigmem;
           26 
           27 static const char *progname;
           28 static pid_t progpid;
           29 
           30 static int verbose = 0;
           31 
           32 static int runreps = 1;
           33 static jmp_buf exitbuf;
           34 
           35 static void fatal(const char *fmt, ...)
           36 {
           37         va_list ap;
           38         fprintf(stderr, "%s: fatal error: ", progname);
           39         va_start(ap, fmt);
           40         vfprintf(stderr, fmt, ap);
           41         va_end(ap);
           42         fputc('\n', stderr);
           43         exit(2);
           44 }
           45 
           46 static void dumpregs(struct vxproc *p)
           47 {
           48         struct vxcpu *c = p->cpu;
           49 
           50         fprintf(stderr, "eax %08x  ecx %08x  edx %08x  ebx %08x\n",
           51                 c->reg[EAX], c->reg[ECX], c->reg[EDX], c->reg[EBX]);
           52         fprintf(stderr, "esp %08x  ebp %08x  esi %08x  edi %08x\n",
           53                 c->reg[ESP], c->reg[EBP], c->reg[ESI], c->reg[EDI]);
           54         fprintf(stderr, "eip %08x  eflags %08x\n",
           55                 c->eip, c->eflags);
           56 
           57 //        for (int i = 0; i < 8; i++) {
           58 //                int32_t *val = r.xmm[i].i32;
           59 //                fprintf(stderr, "xmm%d %08x%08x%08x%08x\n",
           60 //                        i, val[3], val[2], val[1], val[0]);
           61 //        }
           62 }
           63 
           64 static uint32_t mode2vxc(uint32_t st)
           65 {
           66         uint32_t vxc = st & 0x0777;  // At least we agree on this!
           67         if (st & S_ISVTX)
           68                 vxc |= VXC_S_ISVTX;
           69         if (st & S_ISGID)
           70                 vxc |= VXC_S_ISGID;
           71         if (st & S_ISUID)
           72                 vxc |= VXC_S_ISUID;
           73         switch (st & S_IFMT) {
           74         case S_IFREG:
           75                 vxc |= VXC_S_IFREG;
           76                 break;
           77         case S_IFDIR:
           78                 vxc |= VXC_S_IFDIR;
           79                 break;
           80         case S_IFLNK:
           81                 vxc |= VXC_S_IFLNK;
           82                 break;
           83         case S_IFSOCK:
           84                 vxc |= VXC_S_IFSOCK;
           85                 break;
           86         case S_IFIFO:
           87                 vxc |= VXC_S_IFIFO;
           88                 break;
           89         case S_IFBLK:
           90                 vxc |= VXC_S_IFBLK;
           91                 break;
           92         default:
           93         case S_IFCHR:
           94                 vxc |= VXC_S_IFCHR;
           95                 break;
           96         }
           97         return vxc;
           98 }
           99 
          100 static void stat2vxc(struct vxc_stat *vst, struct stat *st)
          101 {
          102         vst->dev = st->st_dev;
          103         vst->ino = st->st_ino;
          104         vst->mode = mode2vxc(st->st_mode);
          105         vst->nlink = st->st_nlink;
          106         vst->uid = st->st_uid;
          107         vst->gid = st->st_gid;
          108         vst->rdev = st->st_rdev;
          109         vst->blksize = st->st_blksize;
          110         vst->blocks = st->st_blocks;
          111         vst->size = st->st_size;
          112         vst->atime = st->st_atime;
          113         vst->mtime = st->st_mtime;
          114         vst->ctime = st->st_ctime;
          115 }
          116 
          117 static int checkstring(vxmem *mem, char *base, uint32_t addr)
          118 {
          119         uint32_t eaddr;
          120 
          121         for (;;) {
          122                 if (!vxmem_checkperm(mem, addr, 1, VXPERM_READ, NULL))
          123                         return 0;
          124                 eaddr = (addr + 4096) & ~(4096-1);
          125                 if (memchr(base + addr, 0, eaddr - addr))
          126                         return 1;
          127                 addr = eaddr;
          128         }
          129 }
          130 
          131 static int doexec(vxproc*, char*, uint32_t, uint32_t, uint32_t);
          132 
          133 int trace;
          134 
          135 #define RET proc->cpu->reg[EAX]
          136 #define NUM proc->cpu->reg[EAX]
          137 #define ARG1 proc->cpu->reg[EDX]
          138 #define ARG2 proc->cpu->reg[ECX]
          139 #define ARG3 proc->cpu->reg[EBX]
          140 #define ARG4 proc->cpu->reg[EDI]
          141 #define ARG5 proc->cpu->reg[ESI]
          142 
          143 static void dosyscall(vxproc *proc)
          144 {
          145         int fd, p[2], *vp, ret, mode, umode;
          146         uint32_t addr, saddr, oaddr;
          147         int len;
          148         vxmmap *m;
          149         struct stat st;
          150         uint32_t inc;
          151         uint32_t secs;
          152         
          153         m = vxmem_map(proc->mem, 0);
          154 
          155         switch (NUM) {
          156         case VXSYSEXIT:
          157                 if (ARG1 != 0 || runreps == 1)
          158                         exit(ARG1);
          159                 longjmp(exitbuf, 1);        // back for more repetitions...
          160         
          161         case VXSYSBRK:
          162                 addr = ARG1;
          163                 inc = 1<<20;
          164                 addr = (addr + inc - 1) & ~(inc - 1);
          165                 oaddr = m->size;
          166                 if (addr == oaddr) {
          167                         ret = 0;
          168                         break;
          169                 }
          170                 ret = 0;
          171                 if (addr > m->size)
          172                         ret = vxmem_resize(proc->mem, addr);
          173                 if (trace)
          174                         fprintf(stderr, "sbrk %p -> %p / %p; %d\n", V oaddr, V addr, V ARG1, ret);
          175                 if (ret < 0)
          176                         fprintf(stderr, "warning: sbrk failed. caller will be unhappy!\n");
          177                 if (ret >= 0) {
          178                         if (addr > oaddr)
          179                                 ret = vxmem_setperm(proc->mem, oaddr, addr - oaddr, VXPERM_READ|VXPERM_WRITE);
          180                         if(ret < 0)
          181                                 fprintf(stderr, "setperm is failing! %p + %p > %p ? \n", V oaddr, V(addr - oaddr), V m->size);
          182                 }
          183                 break;
          184 
          185         case VXSYSREAD:
          186                 fd = ARG1;
          187                 addr = ARG2;
          188                 len = ARG3;
          189                 if (!vxmem_checkperm(proc->mem, addr, len, VXPERM_WRITE, NULL))
          190                         fatal("bad arguments to read");
          191                 ret = read(fd, (char*)m->base + addr, len);
          192                 break;
          193         
          194         case VXSYSWRITE:
          195                 fd = ARG1;
          196                 addr = ARG2;
          197                 len = ARG3;
          198                 if (!vxmem_checkperm(proc->mem, addr, len, VXPERM_READ, NULL))
          199                         fatal("bad arguments to write");
          200                 ret = write(fd, (char*)m->base + addr, len);
          201                 break;
          202         
          203         case VXSYSSTAT:
          204                 addr = ARG1;
          205                 saddr = ARG2;
          206                 if (!checkstring(proc->mem, m->base, addr) ||
          207                     !vxmem_checkperm(proc->mem, saddr, sizeof(struct vxc_stat), VXPERM_WRITE, NULL)){
          208                 einval:
          209                         RET = -EINVAL;
          210                         goto out;
          211                 }
          212                 if ((ret = stat((char*)m->base + addr, &st)) >= 0)
          213                         stat2vxc((struct vxc_stat*)((char*)m->base + saddr), &st);
          214                 if (trace)
          215                         fprintf(stderr, "stat %x/%s => %d\n", addr, (char*)m->base+addr, ret);
          216                 break;
          217 
          218         case VXSYSFSTAT:
          219                 fd = ARG1;
          220                 saddr = ARG2;
          221                 if (!vxmem_checkperm(proc->mem, saddr, sizeof(struct vxc_stat), VXPERM_WRITE, NULL)){
          222                         RET = -EINVAL;
          223                         goto out;
          224                 }
          225                 if ((ret = fstat(fd, &st)) >= 0)
          226                         stat2vxc((struct vxc_stat*)((char*)m->base + saddr), &st);
          227                 if (trace)
          228                         fprintf(stderr, "fstat %d => %d\n", fd, ret);
          229                 break;
          230 
          231         case VXSYSREMOVE:
          232                 addr = ARG1;
          233                 if (!checkstring(proc->mem, m->base, addr))
          234                         goto einval;
          235                 char *name = (char*)m->base+addr;
          236                 if (stat(name, &st) >= 0 && S_ISDIR(st.st_mode))
          237                         ret = rmdir(name);
          238                 else
          239                         ret = unlink(name);
          240                 break;
          241                 
          242         case VXSYSOPEN:
          243                 addr = ARG1;
          244                 mode = ARG2;
          245                 umode = mode&3;
          246                 if(mode & VXC_O_CREAT)
          247                         umode |= O_CREAT;
          248                 if(mode & VXC_O_EXCL)
          249                         umode |= O_EXCL;
          250                 if(mode & VXC_O_NOCTTY)
          251                         umode |= O_NOCTTY;
          252                 if(mode & VXC_O_TRUNC)
          253                         umode |= O_TRUNC;
          254                 if(mode & VXC_O_APPEND)
          255                         umode |= O_APPEND;
          256                 if(mode & VXC_O_NONBLOCK)
          257                         umode |= O_NONBLOCK;
          258                 if(mode & VXC_O_SYNC)
          259                         umode |= O_SYNC;
          260                 if (!checkstring(proc->mem, m->base, addr))
          261                         goto einval;
          262                 ret = open((char*)m->base+addr, umode, ARG3);
          263                 if(trace)
          264                         fprintf(stderr, "open %s %#x %#o => %d\n", (char*)m->base+addr, ARG2, ARG3, ret);
          265                 break;
          266 
          267         case VXSYSMKDIR:
          268                 addr = ARG1;
          269                 if (!checkstring(proc->mem, m->base, addr))
          270                         goto einval;
          271                 ret = mkdir((char*)m->base+addr, ARG2);
          272                 if (trace)
          273                         fprintf(stderr, "mkdir %s %#o => %d\n", (char*)m->base+addr, ARG2, ret);
          274                 break;
          275 
          276         case VXSYSCLOSE:
          277                 fd = ARG1;
          278                 if (fd < 0)
          279                         goto einval;
          280                 ret = close(fd);
          281                 break;
          282         
          283         case VXSYSLSEEK:
          284                 ret = lseek(ARG1, (int32_t)ARG2, ARG3);
          285                 break;
          286 
          287         case VXSYSTIME:
          288                 addr = ARG1;
          289                 if (!vxmem_checkperm(proc->mem, addr, sizeof(struct vxc_timeval), VXPERM_WRITE, NULL))
          290                         goto einval;
          291                 struct timeval tv;
          292                 gettimeofday(&tv, NULL);
          293                 struct vxc_timeval *vtv = (void*)((char*)m->base + addr);
          294                 vtv->tv_sec = tv.tv_sec;
          295                 vtv->tv_usec = tv.tv_usec;
          296                 ret = 0;
          297                 break;
          298 
          299         case VXSYSFCNTL:
          300                 // TODO: check better
          301                 ret = fcntl(ARG1, ARG2, ARG3);
          302                 if(trace)
          303                         fprintf(stderr, "fcntl %d %d %d => %d\n", ARG1, ARG2, ARG3, ret);
          304                 break;
          305         
          306         case VXSYSDUP:
          307                 if(ARG2 == -1)
          308                         ret = dup(ARG1);
          309                 else
          310                         ret = dup2(ARG1, ARG2);
          311                 break;
          312 
          313         case VXSYSFORK:
          314                 vxmem_unmap(proc->mem, m);
          315                 vxmem_unmap(proc->mem, proc->mem->mapped);
          316                 proc->mem->mapped = NULL;
          317 
          318                 vxmem *nmem = vxmem_chunk_copy(proc->mem);
          319                 if (nmem == NULL) {
          320                         RET = -errno;
          321                         return;
          322                 }
          323                 ret = fork();
          324                 if (ret < 0)
          325                         ret = -errno;
          326                 if (ret == 0) {
          327                         vxmem_free(proc->mem);
          328                         proc->mem = nmem;
          329                 } else {
          330                         vxmem_free(nmem);
          331                 }
          332                 RET = ret;
          333                 return;
          334         
          335         case VXSYSWAITPID:
          336                 addr = ARG2;
          337                 if (addr && !vxmem_checkperm(proc->mem, addr, 4, VXPERM_WRITE, NULL))
          338                         goto einval;
          339                 ret = waitpid(ARG1, addr ? (int*)((char*)m->base+addr) : 0, ARG3);
          340                 break;
          341 
          342         case VXSYSEXEC:
          343                 ret = doexec(proc, m->base, ARG1, ARG2, ARG3);
          344                 break;
          345 
          346         case VXSYSPIPE:
          347                 addr = ARG1;
          348                 if (!vxmem_checkperm(proc->mem, addr, 8, VXPERM_WRITE, NULL))
          349                         goto einval;
          350                 ret = pipe(p);
          351                 if (ret >= 0) {
          352                         vp = (int*)((char*)m->base + addr);
          353                         vp[0] = p[0];
          354                         vp[1] = p[1];
          355                 }
          356                 break;
          357         
          358         case VXSYSSLEEP:
          359                 secs = ARG1;
          360                 if(trace)
          361                         fprintf(stderr, "sleep %d\n", secs);
          362                 if (secs == 0)
          363                         ret = 0;
          364                 else
          365                         ret = sleep(secs);
          366                 break;
          367 
          368         // Just to provide the classic "null system call" test...
          369         case VXSYSGETPID:
          370                 fprintf(stderr, "getpid\n");
          371                 ret = progpid;
          372                 break;
          373 
          374         default:
          375                 dumpregs(proc);
          376                 fatal("vxrun: bad system call %d", NUM);
          377                 ret = -1;
          378         }
          379         
          380         if (ret < 0)
          381                 ret = -errno;
          382         RET = ret;
          383 out:
          384         //vxmem_unmap(proc->mem, m);         XXX get rid of ref count?
          385         ;
          386 }
          387 
          388 static char**
          389 convertargs(vxproc *proc, char *base, uint32_t args)
          390 {
          391         int n;
          392         uint32_t a, s;
          393         char **argv;
          394 
          395         if (args == 0)
          396                 return NULL;
          397         for (a=args;; a+=4) {
          398                 if (!vxmem_checkperm(proc->mem, a, 4, VXPERM_READ, NULL)){
          399                         if(trace)
          400                                 fprintf(stderr, "bad args addr %p\n", V a);
          401                         return NULL;
          402                 }
          403                 s = *(uint32_t*)(base+a);
          404                 if (s == 0)
          405                         break;
          406                 if (!checkstring(proc->mem, base, s)){
          407                         if(trace)
          408                                 fprintf(stderr, "bad arg string %p\n", V s);
          409                         return NULL;
          410                 }
          411         }
          412         n = (a - args) / 4 + 1;
          413         argv = malloc(n*sizeof argv[0]);
          414         if (argv == NULL)
          415                 return NULL;
          416         n = 0;
          417         for (a=args;; a+=4) {
          418                 s = *(uint32_t*)(base+a);
          419                 if (s == 0)
          420                         break;
          421                 argv[n++] = base+s;
          422         }
          423         argv[n] = NULL;
          424         return argv;
          425 }
          426 
          427 static int
          428 doexec(vxproc *proc, char *base, uint32_t exe, uint32_t args, uint32_t envs)
          429 {
          430         int i;
          431 
          432         if(!checkstring(proc->mem, base, exe)){
          433                 if(trace)
          434                         fprintf(stderr, "exec [bad string %p]\n", V exe);
          435         einval:
          436                 errno = EINVAL;
          437                 return -1;
          438         }
          439         if(trace)
          440                 fprintf(stderr, "exec %s\n", base+exe);
          441         char **argv = convertargs(proc, base, args);
          442         if(args && !argv)
          443                 goto einval;
          444         char **envv = convertargs(proc, base, envs);
          445         if(envs && !envv){
          446                 free(argv);
          447                 goto einval;
          448         }
          449         if(trace){
          450                 fprintf(stderr, "exec %s", base+exe);
          451                 if(argv)
          452                         for(i=0; argv[i]; i++)
          453                                 fprintf(stderr, " %s", argv[i]);
          454                 fprintf(stderr, "\n");
          455         }
          456         execve(base+exe, argv, envv);
          457         free(argv);
          458         free(envv);
          459         return -1;
          460 }
          461 
          462 extern char **environ;
          463 
          464 void runprog(const char *const *argv)
          465 {
          466         vxproc *volatile p = vxproc_alloc();
          467         if (p == NULL)
          468                 fatal("vxproc_new: %s\n", strerror(errno));
          469         p->allowfp = 1;
          470 
          471         const char *loadname = argv[0];
          472         if (vxproc_loadelffile(p, loadname, &argv[0],
          473                         (const char**)environ) < 0)
          474                 fatal("vxproc_loadelffile: %s\n", strerror(errno));
          475 
          476         // Come back here and return if the guest process calls exit(0)
          477         // and we still have more repetitions to run.
          478         if (setjmp(exitbuf)) {
          479                 vxproc_free(p);
          480                 return;
          481         }
          482 
          483         // Simple execution loop.
          484         for (;;) {
          485                 int rc = vxproc_run(p);
          486                 if (rc < 0)
          487                         fatal("vxproc_run: %s\n", strerror(errno));
          488                 if (rc == VXTRAP_SYSCALL) {
          489                         dosyscall(p);
          490                         continue;
          491                 }
          492                 dumpregs(p);
          493                 fatal("vxproc_run trap %#x\n", rc);
          494         }
          495 }
          496 
          497 int main(int argc, const char *const *argv)
          498 {
          499         int i;
          500         progname = argv[0];
          501         progpid = getpid();
          502         int reps = 1;
          503 
          504         vx_elfbigmem = 1;
          505 
          506         ARGBEGIN{
          507         case 't':
          508                 trace++;
          509                 break;
          510         case 'd':
          511                 vx32_debugxlate++;
          512                 break;
          513         case 'v':
          514                 verbose++;
          515                 break;
          516         case 'r':
          517                 runreps = atoi(ARGF());
          518                 if (runreps < 1) {
          519                         fprintf(stderr, "Invalid repeat count %d\n", runreps);
          520                         exit(1);
          521                 }
          522                 break;
          523         default:
          524         usage:
          525                 fprintf(stderr, "Usage: %s [-dtv] <vx-program> <args>\n",
          526                         progname);
          527                 exit(1);
          528         }ARGEND
          529         
          530         if (argc < 1)
          531                 goto usage;
          532 
          533         FILE *f = fopen("/dev/tty", "w");
          534         if(f && verbose){
          535                 char buf[1000];
          536                 if(getcwd(buf, sizeof buf) != NULL)
          537                         fprintf(f, "cd %s\n", buf);
          538                 fprintf(f, "vxrun");
          539                 for(i=0; i<argc; i++)
          540                         fprintf(f, " %s", argv[i]);
          541                 fprintf(f, "\n");
          542         }
          543 
          544         vx32_siginit();
          545 
          546         // Repeatedly load, execute, and unload the guest process
          547         // as many times as requested.
          548         do {
          549                 //fprintf(stderr, "run, reps=%d\n", runreps);
          550                 runprog(argv);
          551         } while (--runreps > 0);
          552 
          553         return 0;        // not reached
          554 }
          555