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