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