--- trunk/src/useremul.c 2007/10/08 16:18:31 11 +++ trunk/src/useremul.c 2007/10/08 16:18:38 12 @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: useremul.c,v 1.46 2005/04/14 21:01:54 debug Exp $ + * $Id: useremul.c,v 1.62 2005/08/16 06:49:26 debug Exp $ * * Userland (syscall) emulation. * @@ -67,6 +67,7 @@ #include #include #include +#include #include #include "cpu.h" @@ -132,13 +133,26 @@ { debug("useremul__freebsd_setup(): TODO\n"); - if (cpu->machine->arch != ARCH_ALPHA) { + switch (cpu->machine->arch) { + case ARCH_ALPHA: + /* According to FreeBSD's /usr/src/lib/csu/alpha/crt1.c: */ + /* a0 = char **ap */ + /* a1 = void (*cleanup)(void) from shared loader */ + /* a2 = struct Struct_Obj_Entry *obj from shared loader */ + /* a3 = struct ps_strings *ps_strings */ + cpu->cd.alpha.r[ALPHA_A0] = 0; + cpu->cd.alpha.r[ALPHA_A1] = 0; + cpu->cd.alpha.r[ALPHA_A2] = 0; + cpu->cd.alpha.r[ALPHA_A3] = 0; + + /* What is a good stack pointer? TODO */ + cpu->cd.alpha.r[ALPHA_SP] = 0x120000000ULL + + 1048576 * cpu->machine->physical_ram_in_mb - 1024; + break; + default: fatal("non-Alpha not yet implemented for freebsd emul.\n"); exit(1); } - - /* What is a good stack pointer? TODO */ - /* cpu->cd.alpha.gpr[...] = ... */ } @@ -186,7 +200,7 @@ /* The userland stack: */ cpu->cd.mips.gpr[MIPS_GPR_SP] = stack_top - stack_margin; add_symbol_name(&cpu->machine->symbol_context, - stack_top - stacksize, stacksize, "userstack", 0); + stack_top - stacksize, stacksize, "userstack", 0, 0); /* Stack contents: (TODO: is this correct?) */ store_32bit_word(cpu, stack_top - stack_margin, argc); @@ -218,6 +232,10 @@ } break; + case ARCH_ARM: + debug("useremul__netbsd_setup(): ARM: TODO\n"); + break; + case ARCH_PPC: debug("useremul__netbsd_setup(): PPC: TODO\n"); @@ -260,7 +278,7 @@ /* The userland stack: */ cpu->cd.mips.gpr[MIPS_GPR_SP] = stack_top - stack_margin; add_symbol_name(&cpu->machine->symbol_context, - stack_top - stacksize, stacksize, "userstack", 0); + stack_top - stacksize, stacksize, "userstack", 0, 0); /* Stack contents: (TODO: is this correct?) */ store_32bit_word(cpu, stack_top - stack_margin, argc); @@ -339,15 +357,15 @@ * TODO: combine this with get_userland_string() in some way */ static unsigned char *get_userland_buf(struct cpu *cpu, - uint64_t baseaddr, int len) + uint64_t baseaddr, uint64_t len) { unsigned char *charbuf; - int i; + ssize_t i; charbuf = malloc(len); if (charbuf == NULL) { fprintf(stderr, "get_userland_buf(): out of memory (trying" - " to allocate %i bytes)\n", len); + " to allocate %lli bytes)\n", (long long)len); exit(1); } @@ -380,47 +398,325 @@ } +/*****************************************************************************/ + + +/* + * useremul_exit(): + */ +int useremul_exit(struct cpu *cpu, uint64_t arg0) +{ + debug("[ exit(%i) ]\n", (int)arg0); + cpu->running = 0; + cpu->machine->exit_without_entering_debugger = 1; + return 0; +} + + +/* + * useremul_write(): + */ +int64_t useremul_write(struct cpu *cpu, int64_t *errnop, + uint64_t arg0, uint64_t arg1, uint64_t arg2) +{ + int64_t res = 0; + *errnop = 0; + debug("[ write(%i,0x%llx,%lli) ]\n", + (int)arg0, (long long)arg1, (long long)arg2); + if (arg2 != 0) { + unsigned char *cp = get_userland_buf(cpu, arg1, arg2); + res = write(arg0, cp, arg2); + if (res < 0) + *errnop = errno; + free(cp); + } + return res; +} + + +/* + * useremul_break(): + */ +int64_t useremul_break(struct cpu *cpu, uint64_t arg0) +{ + debug("[ break(0x%llx): TODO ]\n", (long long)arg0); + + /* TODO */ + return 0; +} + + +/* + * useremul_getpid(): + */ +int64_t useremul_getpid(struct cpu *cpu) +{ + int64_t pid = getpid(); + debug("[ getpid(): %lli ]\n", (long long)pid); + return pid; +} + + +/* + * useremul_getuid(): + */ +int64_t useremul_getuid(struct cpu *cpu) +{ + int64_t uid = getuid(); + debug("[ getuid(): %lli ]\n", (long long)uid); + return uid; +} + + +/* + * useremul_getegid(): + */ +int64_t useremul_getegid(struct cpu *cpu) +{ + int64_t egid = getegid(); + debug("[ getegid(): %lli ]\n", (long long)egid); + return egid; +} + + +/* + * useremul_getgid(): + */ +int64_t useremul_getgid(struct cpu *cpu) +{ + int64_t gid = getgid(); + debug("[ getgid(): %lli ]\n", (long long)gid); + return gid; +} + + +/* + * useremul_sync(): + */ +int useremul_sync(struct cpu *cpu) +{ + debug("[ sync() ]\n"); + sync(); + return 0; +} + + +/* + * useremul_readlink(): + */ +int64_t useremul_readlink(struct cpu *cpu, int64_t *errnop, + uint64_t arg0, uint64_t arg1, int64_t arg2) +{ + int64_t res = 0; + unsigned char *charbuf = get_userland_string(cpu, arg0); + unsigned char *buf2; + + debug("[ readlink(\"%s\",0x%llx,%lli) ]\n", + charbuf, (long long)arg1, (long long)arg2); + if (arg2 == 0 || arg2 > 150000) { + fprintf(stderr, "[ useremul_readlink(): TODO ]\n"); + exit(1); + } + + buf2 = malloc(arg2); + if (buf2 == NULL) { + fprintf(stderr, "[ useremul_readlink(): out of memory ]\n"); + exit(1); + } + res = readlink((char *)charbuf, (char *)buf2, arg2); + buf2[arg2-1] = '\0'; + if (res < 0) + *errnop = errno; + else + store_string(cpu, arg1, (char *)buf2); + free(buf2); + free(charbuf); + return res; +} + + +/* + * useremul_getrusage(): + */ +int64_t useremul_getrusage(struct cpu *cpu, int64_t *errnop, + uint64_t arg0, uint64_t arg1) +{ + int64_t res; + struct rusage rusage; + debug("[ getrusage(%i,0x%llx) ]\n", (int)arg0, (long long)arg1); + res = getrusage(arg0, &rusage); + + fatal("TODO: convert rusage into emulated memory!\n"); + store_64bit_word(cpu, arg1 + 0, rusage.ru_utime.tv_sec); + store_64bit_word(cpu, arg1 + 8, rusage.ru_utime.tv_usec); + store_64bit_word(cpu, arg1 + 16, rusage.ru_stime.tv_sec); + store_64bit_word(cpu, arg1 + 24, rusage.ru_stime.tv_usec); + + return res; +} + + +/* + * useremul_fstat(): + */ +int64_t useremul_fstat(struct cpu *cpu, int64_t *errnop, + int64_t arg0, uint64_t arg1) +{ + int64_t res; + struct stat sb; + debug("[ fstat(%i,0x%llx) ]\n", (int)arg0, (long long)arg1); + res = fstat(arg0, &sb); + if (res < 0) + *errnop = errno; + else { + fatal("TODO: convert sb into emulated memory!\n"); + +/* NOTE: FreeBSD/alpha only */ + + store_32bit_word(cpu, arg1 + 0, sb.st_dev); + store_32bit_word(cpu, arg1 + 4, sb.st_ino); +/* store_16bit_word(cpu, arg1 + 8, sb.st_mode); +*/ store_16bit_word(cpu, arg1 + 10, sb.st_nlink); + store_32bit_word(cpu, arg1 + 12, sb.st_uid); + store_32bit_word(cpu, arg1 + 16, sb.st_gid); + store_32bit_word(cpu, arg1 + 20, sb.st_rdev); +#if 0 + store_64bit_word(cpu, arg1 + 24, sb.st_atimespec.tv_sec); + store_64bit_word(cpu, arg1 + 32, sb.st_atimespec.tv_nsec); + store_64bit_word(cpu, arg1 + 40, sb.st_mtimespec.tv_sec); + store_64bit_word(cpu, arg1 + 48, sb.st_mtimespec.tv_nsec); + store_64bit_word(cpu, arg1 + 56, sb.st_ctimespec.tv_sec); + store_64bit_word(cpu, arg1 + 64, sb.st_ctimespec.tv_nsec); + + store_64bit_word(cpu, arg1 + 72, sb.st_size); + store_64bit_word(cpu, arg1 + 80, sb.st_blocks); + store_64bit_word(cpu, arg1 + 88, sb.st_blksize); + store_64bit_word(cpu, arg1 + 92, sb.st_flags); + store_64bit_word(cpu, arg1 + 96, sb.st_gen); +#endif + } + return res; +} + + +/* + * useremul_mmap(): + */ +int64_t useremul_mmap(struct cpu *cpu, int64_t *errnop, + uint64_t arg0, int64_t arg1, int64_t arg2, + int64_t arg3, int64_t arg4, uint64_t arg5) +{ + int64_t res = 0; + + /* arg0..5: addr, len, prot, flags, fd, offset */ + debug("[ mmap(0x%llx,%lli,%i,%i,%i,%lli) ]\n", + (long long)arg0, (long long)arg1, + (int)arg2, (int)arg3, (int)arg4, (long long)arg5); + + if (arg4 != -1) { + fatal("[ useremul_mmap(): fd != -1: TODO ]\n"); + cpu->running = 0; + return 0; + } + + /* Anonymous allocation. */ + if (arg0 != 0) { + fatal("[ useremul_mmap(): addr != 0: TODO ]\n"); + cpu->running = 0; + return 0; + } + + fatal("[ useremul_mmap(): TODO ]\n"); + +res = 0x18000000ULL; + + return res; +} + + +/*****************************************************************************/ + + /* * useremul__freebsd(): * - * FreeBSD syscall emulation. + * FreeBSD/Alpha syscall emulation. * * TODO: How to make this work nicely with non-Alpha archs. */ static void useremul__freebsd(struct cpu *cpu, uint32_t code) { -#if 0 - unsigned char *cp; int nr; - uint64_t arg0, arg1, arg2, arg3; + int64_t res = 0, err = 0; + uint64_t arg0, arg1, arg2, arg3, arg4, arg5; - nr = cpu->cd.ppc.gpr[0]; - arg0 = cpu->cd.ppc.gpr[3]; - arg1 = cpu->cd.ppc.gpr[4]; - arg2 = cpu->cd.ppc.gpr[5]; - arg3 = cpu->cd.ppc.gpr[6]; + nr = cpu->cd.alpha.r[ALPHA_V0]; + arg0 = cpu->cd.alpha.r[ALPHA_A0]; + arg1 = cpu->cd.alpha.r[ALPHA_A1]; + arg2 = cpu->cd.alpha.r[ALPHA_A2]; + arg3 = cpu->cd.alpha.r[ALPHA_A3]; + arg4 = cpu->cd.alpha.r[ALPHA_A4]; + arg5 = cpu->cd.alpha.r[ALPHA_A5]; + + if (nr == 198) { + /* ___syscall */ + nr = arg0; + arg0 = arg1; + arg1 = arg2; + arg2 = arg3; + arg3 = arg4; + arg4 = arg5; + /* TODO: stack arguments */ + } switch (nr) { - case LINUX_PPC_SYS_exit: - debug("[ exit(%i) ]\n", (int)arg0); - cpu->running = 0; + case 1: res = useremul_exit(cpu, arg0); break; - case LINUX_PPC_SYS_write: - debug("[ write(%i,0x%llx,%lli) ]\n", - (int)arg0, (long long)arg1, (long long)arg2); - cp = get_userland_buf(cpu, arg1, arg2); - write(arg0, cp, arg2); - free(cp); + case 4: res = useremul_write(cpu, &err, arg0, arg1, arg2); break; - default: - fatal("useremul__linux(): syscall %i not yet implemented\n", - nr); + case 17:res = useremul_break(cpu, arg0); + break; + + case 20:res = useremul_getpid(cpu); + break; + + case 24:res = useremul_getuid(cpu); + break; + + case 43:res = useremul_getegid(cpu); + break; + + case 47:res = useremul_getgid(cpu); + break; + + case 58:res = useremul_readlink(cpu, &err, arg0, arg1, arg2); + break; + + case 117:res = useremul_getrusage(cpu, &err, arg0, arg1); + break; + + case 189:res = useremul_fstat(cpu, &err, arg0, arg1); + break; + + case 197:res = useremul_mmap(cpu, &err, arg0, arg1, arg2, arg3, + arg4, arg5); + break; + + default:fatal("useremul__freebsd(): syscall %i not yet " + "implemented\n", nr); cpu->running = 0; } -#endif + + if (err) { + cpu->cd.alpha.r[ALPHA_A3] = 1; + cpu->cd.alpha.r[ALPHA_V0] = err; + } else { + cpu->cd.alpha.r[ALPHA_A3] = 0; + cpu->cd.alpha.r[ALPHA_V0] = res; + } } @@ -434,7 +730,7 @@ static void useremul__linux(struct cpu *cpu, uint32_t code) { int nr; - unsigned char *cp; + int64_t res = 0, err = 0; uint64_t arg0, arg1, arg2, arg3; if (code != 0) { @@ -451,16 +747,11 @@ switch (nr) { case LINUX_PPC_SYS_exit: - debug("[ exit(%i) ]\n", (int)arg0); - cpu->running = 0; + res = useremul_exit(cpu, arg0); break; case LINUX_PPC_SYS_write: - debug("[ write(%i,0x%llx,%lli) ]\n", - (int)arg0, (long long)arg1, (long long)arg2); - cp = get_userland_buf(cpu, arg1, arg2); - write(arg0, cp, arg2); - free(cp); + res = useremul_write(cpu, &err, arg0, arg1, arg2); break; default: @@ -468,6 +759,8 @@ nr); cpu->running = 0; } + + /* return res: TODO */ } @@ -481,7 +774,7 @@ int error_flag = 0, result_high_set = 0; uint64_t arg0=0,arg1=0,arg2=0,arg3=0,stack0=0,stack1=0,stack2=0; int sysnr = 0; - uint64_t error_code = 0; + int64_t error_code = 0; uint64_t result_low = 0; uint64_t result_high = 0; struct timeval tv; @@ -632,8 +925,7 @@ break; case NETBSD_SYS_getuid: - debug("[ getuid() ]\n"); - result_low = getuid(); + result_low = useremul_getuid(cpu); break; case NETBSD_SYS_geteuid: @@ -691,32 +983,16 @@ break; case NETBSD_SYS_break: - debug("[ break(0x%llx): TODO ]\n", (long long)arg0); - /* TODO */ + useremul_break(cpu, arg0); break; case NETBSD_SYS_readlink: - charbuf = get_userland_string(cpu, arg0); - debug("[ readlink(\"%s\",0x%lli,%lli) ]\n", - charbuf, (long long)arg1, (long long)arg2); - if (arg2 != 0 && arg2 < 50000) { - unsigned char *buf2 = malloc(arg2); - buf2[arg2-1] = '\0'; - result_low = readlink((char *)charbuf, - (char *)buf2, arg2 - 1); - if ((int64_t)result_low < 0) { - error_flag = 1; - error_code = errno; - } else - store_string(cpu, arg1, (char *)buf2); - free(buf2); - } - free(charbuf); + result_low = useremul_readlink(cpu, &error_code, + arg0, arg1, arg2); break; case NETBSD_SYS_sync: - debug("[ sync() ]\n"); - sync(); + useremul_sync(cpu); break; case NETBSD_SYS_gettimeofday: @@ -952,7 +1228,7 @@ int error_flag = 0, result_high_set = 0; uint64_t arg0,arg1,arg2,arg3,stack0=0,stack1=0,stack2; int sysnr = 0; - uint64_t error_code = 0; + int64_t error_code = 0; uint64_t result_low = 0; uint64_t result_high = 0; struct timeval tv; @@ -1073,18 +1349,15 @@ break; case ULTRIX_SYS_break: - debug("[ break(0x%llx): TODO ]\n", (long long)arg0); - /* TODO */ + useremul_break(cpu, arg0); break; case ULTRIX_SYS_sync: - debug("[ sync() ]\n"); - sync(); + useremul_sync(cpu); break; case ULTRIX_SYS_getuid: - debug("[ getuid() ]\n"); - result_low = getuid(); + result_low = useremul_getuid(cpu); break; case ULTRIX_SYS_getgid: @@ -1190,24 +1463,7 @@ break; case ULTRIX_SYS_fstat: - debug("[ fstat(%i, 0x%llx): TODO ]\n", - (int)arg0, (long long)arg1); - - if (arg1 != 0) { - struct stat st; - result_low = fstat(arg0, &st); - if ((int64_t)result_low < 0) { - error_flag = 1; - error_code = errno; - } else { - /* Fill in the Ultrix stat struct at arg1: */ - - /* TODO */ - } - } else { - error_flag = 1; - error_code = 1111; /* TODO: ultrix ENOMEM? */ - } + result_low = useremul_fstat(cpu, &error_code, arg0, arg1); break; case ULTRIX_SYS_getpagesize: @@ -1473,13 +1729,16 @@ add_useremul("NetBSD/pmax", ARCH_MIPS, "R3000", useremul__netbsd, useremul__netbsd_setup); + add_useremul("NetBSD/arm", ARCH_ARM, "ARM", + useremul__netbsd, useremul__netbsd_setup); + add_useremul("NetBSD/amd64", ARCH_X86, "AMD64", useremul__netbsd, useremul__netbsd_setup); add_useremul("Linux/PPC64", ARCH_PPC, "PPC970", useremul__linux, useremul__linux_setup); - add_useremul("FreeBSD/Alpha", ARCH_ALPHA, "EV4", + add_useremul("FreeBSD/Alpha", ARCH_ALPHA, "Alpha", useremul__freebsd, useremul__freebsd_setup); }