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