vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | 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