static void print_execve(const struct syscallname *name, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) { abi_ulong arg_ptr_addr; char *s; if (!(s = lock_user_string(arg1))) return; gemu_log("%s(\"%s\",{", name->name, s); unlock_user(s, arg1, 0); for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(abi_ulong)) { abi_ulong *arg_ptr, arg_addr, s_addr; arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1); if (!arg_ptr) return; arg_addr = tswapl(*arg_ptr); unlock_user(arg_ptr, arg_ptr_addr, 0); if (!arg_addr) break; if ((s = lock_user_string(arg_addr))) { gemu_log("\"%s\",", s); unlock_user(s, s_addr, 0); } } gemu_log("NULL})"); }
void do_m68k_semihosting(CPUM68KState *env, int nr) { uint32_t args; void *p; void *q; uint32_t len; uint32_t result; args = env->dregs[1]; switch (nr) { case HOSTED_EXIT: gdb_exit(env, env->dregs[0]); exit(env->dregs[0]); case HOSTED_OPEN: if (use_gdb_syscalls()) { gdb_do_syscall(m68k_semi_cb, "open,%s,%x,%x", ARG(0), (int)ARG(1), ARG(2), ARG(3)); return; } else { if (!(p = lock_user_string(ARG(0)))) { /* FIXME - check error code? */ result = -1; } else { result = open(p, translate_openflags(ARG(2)), ARG(3)); unlock_user(p, ARG(0), 0); } } break; case HOSTED_CLOSE: { /* Ignore attempts to close stdin/out/err. */ int fd = ARG(0); if (fd > 2) { if (use_gdb_syscalls()) { gdb_do_syscall(m68k_semi_cb, "close,%x", ARG(0)); return; } else { result = close(fd); } } else { result = 0; } break; } case HOSTED_READ: len = ARG(2); if (use_gdb_syscalls()) { gdb_do_syscall(m68k_semi_cb, "read,%x,%x,%x", ARG(0), ARG(1), len); return; } else { if (!(p = lock_user(VERIFY_WRITE, ARG(1), len, 0))) { /* FIXME - check error code? */ result = -1; } else { result = read(ARG(0), p, len); unlock_user(p, ARG(1), len); } } break; case HOSTED_WRITE: len = ARG(2); if (use_gdb_syscalls()) { gdb_do_syscall(m68k_semi_cb, "write,%x,%x,%x", ARG(0), ARG(1), len); return; } else { if (!(p = lock_user(VERIFY_READ, ARG(1), len, 1))) { /* FIXME - check error code? */ result = -1; } else { result = write(ARG(0), p, len); unlock_user(p, ARG(0), 0); } } break; case HOSTED_LSEEK: { uint64_t off; off = (uint32_t)ARG(2) | ((uint64_t)ARG(1) << 32); if (use_gdb_syscalls()) { m68k_semi_is_fseek = 1; gdb_do_syscall(m68k_semi_cb, "fseek,%x,%lx,%x", ARG(0), off, ARG(3)); } else { off = lseek(ARG(0), off, ARG(3)); /* FIXME - handle put_user() failure */ put_user_u32(off >> 32, args); put_user_u32(off, args + 4); put_user_u32(errno, args + 8); } return; } case HOSTED_RENAME: if (use_gdb_syscalls()) { gdb_do_syscall(m68k_semi_cb, "rename,%s,%s", ARG(0), (int)ARG(1), ARG(2), (int)ARG(3)); return; } else { p = lock_user_string(ARG(0)); q = lock_user_string(ARG(2)); if (!p || !q) { /* FIXME - check error code? */ result = -1; } else { result = rename(p, q); } unlock_user(p, ARG(0), 0); unlock_user(q, ARG(2), 0); } break; case HOSTED_UNLINK: if (use_gdb_syscalls()) { gdb_do_syscall(m68k_semi_cb, "unlink,%s", ARG(0), (int)ARG(1)); return; } else { if (!(p = lock_user_string(ARG(0)))) { /* FIXME - check error code? */ result = -1; } else { result = unlink(p); unlock_user(p, ARG(0), 0); } } break; case HOSTED_STAT: if (use_gdb_syscalls()) { gdb_do_syscall(m68k_semi_cb, "stat,%s,%x", ARG(0), (int)ARG(1), ARG(2)); return; } else { struct stat s; if (!(p = lock_user_string(ARG(0)))) { /* FIXME - check error code? */ result = -1; } else { result = stat(p, &s); unlock_user(p, ARG(0), 0); } if (result == 0) { translate_stat(env, ARG(2), &s); } } break; case HOSTED_FSTAT: if (use_gdb_syscalls()) { gdb_do_syscall(m68k_semi_cb, "fstat,%x,%x", ARG(0), ARG(1)); return; } else { struct stat s; result = fstat(ARG(0), &s); if (result == 0) { translate_stat(env, ARG(1), &s); } } break; case HOSTED_GETTIMEOFDAY: if (use_gdb_syscalls()) { gdb_do_syscall(m68k_semi_cb, "gettimeofday,%x,%x", ARG(0), ARG(1)); return; } else { qemu_timeval tv; struct gdb_timeval *p; result = qemu_gettimeofday(&tv); if (result != 0) { if (!(p = lock_user(VERIFY_WRITE, ARG(0), sizeof(struct gdb_timeval), 0))) { /* FIXME - check error code? */ result = -1; } else { p->tv_sec = cpu_to_be32(tv.tv_sec); p->tv_usec = cpu_to_be64(tv.tv_usec); unlock_user(p, ARG(0), sizeof(struct gdb_timeval)); } } } break; case HOSTED_ISATTY: if (use_gdb_syscalls()) { gdb_do_syscall(m68k_semi_cb, "isatty,%x", ARG(0)); return; } else { result = isatty(ARG(0)); } break; case HOSTED_SYSTEM: if (use_gdb_syscalls()) { gdb_do_syscall(m68k_semi_cb, "system,%s", ARG(0), (int)ARG(1)); return; } else { if (!(p = lock_user_string(ARG(0)))) { /* FIXME - check error code? */ result = -1; } else { result = system(p); unlock_user(p, ARG(0), 0); } } break; case HOSTED_INIT_SIM: #if defined(CONFIG_USER_ONLY) { TaskState *ts = env->opaque; /* Allocate the heap using sbrk. */ if (!ts->heap_limit) { abi_ulong ret; uint32_t size; uint32_t base; base = do_brk(0); size = SEMIHOSTING_HEAP_SIZE; /* Try a big heap, and reduce the size if that fails. */ for (;;) { ret = do_brk(base + size); if (ret >= (base + size)) { break; } size >>= 1; } ts->heap_limit = base + size; } /* This call may happen before we have writable memory, so return values directly in registers. */ env->dregs[1] = ts->heap_limit; env->aregs[7] = ts->stack_base; } #else /* FIXME: This is wrong for boards where RAM does not start at address zero. */ env->dregs[1] = ram_size; env->aregs[7] = ram_size; #endif return; default: cpu_abort(env, "Unsupported semihosting syscall %d\n", nr); result = 0; }
abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) { abi_long ret; void *p; #ifdef DEBUG gemu_log("openbsd syscall %d\n", num); #endif if(do_strace) print_openbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); switch(num) { case TARGET_OPENBSD_NR_exit: #ifdef TARGET_GPROF _mcleanup(); #endif gdb_exit(cpu_env, arg1); /* XXX: should free thread stack and CPU env */ _exit(arg1); ret = 0; /* avoid warning */ break; case TARGET_OPENBSD_NR_read: if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) goto efault; ret = get_errno(read(arg1, p, arg3)); unlock_user(p, arg2, ret); break; case TARGET_OPENBSD_NR_write: if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) goto efault; ret = get_errno(write(arg1, p, arg3)); unlock_user(p, arg2, 0); break; case TARGET_OPENBSD_NR_open: if (!(p = lock_user_string(arg1))) goto efault; ret = get_errno(open(path(p), target_to_host_bitmask(arg2, fcntl_flags_tbl), arg3)); unlock_user(p, arg1, 0); break; case TARGET_OPENBSD_NR_mmap: ret = get_errno(target_mmap(arg1, arg2, arg3, target_to_host_bitmask(arg4, mmap_flags_tbl), arg5, arg6)); break; case TARGET_OPENBSD_NR_mprotect: ret = get_errno(target_mprotect(arg1, arg2, arg3)); break; case TARGET_OPENBSD_NR_syscall: case TARGET_OPENBSD_NR___syscall: ret = do_openbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0); break; default: ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); break; } fail: #ifdef DEBUG gemu_log(" = %ld\n", ret); #endif if (do_strace) print_openbsd_syscall_ret(num, ret); return ret; efault: ret = -TARGET_EFAULT; goto fail; }
/* do_syscall() should always have a single exit point at the end so that actions, such as logging of syscall results, can be performed. All errnos that do_syscall() returns must be -TARGET_<errcode>. */ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6, abi_long arg7, abi_long arg8) { abi_long ret; void *p; #ifdef DEBUG gemu_log("freebsd syscall %d\n", num); #endif if(do_strace) print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); switch(num) { case TARGET_FREEBSD_NR_exit: #ifdef TARGET_GPROF _mcleanup(); #endif gdb_exit(cpu_env, arg1); /* XXX: should free thread stack and CPU env */ _exit(arg1); ret = 0; /* avoid warning */ break; case TARGET_FREEBSD_NR_read: if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) goto efault; ret = get_errno(read(arg1, p, arg3)); unlock_user(p, arg2, ret); break; case TARGET_FREEBSD_NR_write: if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) goto efault; ret = get_errno(write(arg1, p, arg3)); unlock_user(p, arg2, 0); break; case TARGET_FREEBSD_NR_writev: { int count = arg3; struct iovec *vec; vec = alloca(count * sizeof(struct iovec)); if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0) goto efault; ret = get_errno(writev(arg1, vec, count)); unlock_iovec(vec, arg2, count, 0); } break; case TARGET_FREEBSD_NR_open: if (!(p = lock_user_string(arg1))) goto efault; ret = get_errno(open(path(p), target_to_host_bitmask(arg2, fcntl_flags_tbl), arg3)); unlock_user(p, arg1, 0); break; case TARGET_FREEBSD_NR_mmap: ret = get_errno(target_mmap(arg1, arg2, arg3, target_to_host_bitmask(arg4, mmap_flags_tbl), arg5, arg6)); break; case TARGET_FREEBSD_NR_mprotect: ret = get_errno(target_mprotect(arg1, arg2, arg3)); break; case TARGET_FREEBSD_NR_break: ret = do_obreak(arg1); break; #ifdef __FreeBSD__ case TARGET_FREEBSD_NR___sysctl: ret = do_freebsd_sysctl(arg1, arg2, arg3, arg4, arg5, arg6); break; #endif case TARGET_FREEBSD_NR_sysarch: ret = do_freebsd_sysarch(cpu_env, arg1, arg2); break; case TARGET_FREEBSD_NR_syscall: case TARGET_FREEBSD_NR___syscall: ret = do_freebsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,arg7,arg8,0); break; default: ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)); break; } fail: #ifdef DEBUG gemu_log(" = %ld\n", ret); #endif if (do_strace) print_freebsd_syscall_ret(num, ret); return ret; efault: ret = -TARGET_EFAULT; goto fail; }
uint32_t do_syscall_arm(ProgramBase *prog, uint32_t num, uint32_t arg1,uint32_t arg2, uint32_t arg3,uint32_t arg4,uint32_t arg5, uint32_t arg6, FILE *syscallTrace) { #ifdef DEBUG2 printf ("syscall %d \n", num); #endif uint32_t ret; void *p; #if defined (CONFIG_ESESC_system) || defined (CONFIG_ESESC_user) struct timespec startTime; clock_gettime(CLOCK_REALTIME,&startTime); #endif char tmp_str[128]; char pc[32]; char systrace_syscall_num[32]; char emul_syscall_num[32]; int i, j, ret1; regex_t re1; regmatch_t match[3]; if (syscallTrace != NULL) { // Example trace file section // //---------- //pc: 0x8174 //syscall: 122 //Linux //masca1 //3.0.0-1205-omap4 //#10-Ubuntu SMP PREEMPT Thu Sep 29 03:57:24 UTC 2011 //armv7l //---------- //pc: 0x8230 //syscall: 4 //---------- //printf("Advance to the section \n"); fgets(tmp_str, sizeof tmp_str, syscallTrace); tmp_str[strlen (tmp_str) - 1] = '\0'; memset(tmp_str, '\0', 128); // read pc fgets(pc, sizeof pc, syscallTrace); pc[strlen (pc) - 1] = '\0'; // read syscall number fgets(tmp_str, sizeof tmp_str, syscallTrace); tmp_str[strlen (tmp_str) - 1] = '\0'; //printf("pc %s, syscall %s \n", pc, tmp_str); ret1 = regcomp(&re1, "syscall: ([0-9]+)", REG_EXTENDED); ret1 = regexec(&re1, tmp_str, 2, match, 0); if(!ret1) { j = 0; for(i = match[1].rm_so; i < match[1].rm_eo; i++) { systrace_syscall_num[j] = tmp_str[i]; j++; } systrace_syscall_num[j] = '\0'; }else{ I(0); } sprintf(emul_syscall_num, "%d", num); // Sanity check for syscall number if (strcmp(systrace_syscall_num, emul_syscall_num) != 0) { printf("Emulator syscall trace and expected syscall trace are out of sync \n"); printf(" syscall num - Expected: %s, Emulator: %s\n", systrace_syscall_num, emul_syscall_num); I(0); // exit(0); } } switch(num) { case TARGET_NR_exit: exit(arg1); return 0; break; case TARGET_NR_exit_group: exit(arg1); return 0; break; case TARGET_NR_write: ret = write(arg1, prog->g2h(arg2), arg3); return ret; break; case TARGET_NR_read: if (arg3 == 0) { ret = 0; }else{ ret = read(arg1, prog->g2h(arg2), arg3); } return ret; break; /* case TARGET_NR_ioctl: do_ioctl(prog, arg1, arg2, arg3); return 0; break;*/ case TARGET_NR_lseek: ret = lseek(arg1, arg2, arg3); return ret; break; case TARGET_NR_gettimeofday: { // FIXME: Not correct struct timeval tv; gettimeofday(&tv, NULL); } return 0; break; case TARGET_NR_open: // FIXME: how to check if this is a open(a,b,c) or open(a,b) ret = open((const char *)prog->g2h(arg1), arg2); return ret; break; case TARGET_NR_close: ret = close(arg1); return ret; break; case TARGET_NR_mkdir: p = lock_user_string(prog, arg1); ret = mkdir((const char *)p, arg2); return ret; break; case TARGET_NR_rmdir: p = lock_user_string(prog, arg1); ret = rmdir((const char *)p); return ret; break; case TARGET_NR_rename: { void *p2; p = lock_user_string(prog, arg1); p2 = lock_user_string(prog, arg2); if (!p || !p2) ret = -TARGET_EFAULT; else rename((const char *)p, (const char *)p2); } return 0; break; case TARGET_NR_uname: // copy 390 bytes from syscalltrace to buf //Linux //masca1 //3.0.0-1205-omap4 //#10-Ubuntu SMP PREEMPT Thu Sep 29 03:57:24 UTC 2011 { struct utsname *uts_buf = (struct utsname *)prog->g2h(arg1); if (syscallTrace != NULL) { for (i = 0; i < 5; i++) { memset(tmp_str, '\0', 65); fgets(tmp_str, sizeof tmp_str, syscallTrace); tmp_str[strlen (tmp_str) - 1] = '\0'; if(i == 0) strcpy(uts_buf->sysname, tmp_str); else if(i == 1) strcpy(uts_buf->nodename, tmp_str); else if(i == 2) strcpy(uts_buf->release, tmp_str); else if(i == 3) strcpy(uts_buf->version, tmp_str); else if(i == 4) strcpy(uts_buf->machine, tmp_str); } } else { if (uname(uts_buf) < 0) return (-1); } } return 0; break; case TARGET_NR_brk: { if (!arg1) { return target_brk; } else if(arg1 < target_original_brk) { return target_brk; } else { if(arg1 < brk_page) { if(arg1 > target_brk) { // initialize as it may contain garbage due to a previous heap usage // (grown then shrunken) memset(prog->g2h(target_brk), 0, arg1 - target_brk); } // deallocate is handled automatically here. target_brk = arg1; return target_brk; } // Need to allocate memory. // We can't call local host brk() system call which tends to change the // simulator program's brk_addr. // What we need to adjust here is the simulated virtual memory data segment. // so simulate brk here by calling realloc to reallocate simulator data segment. uint32_t size_incr = PAGE_ALIGN_UP(arg1 - brk_page); uint32_t old_size; uint32_t *data_ptr = NULL; data_ptr = prog->get_data_buffer(&old_size); uint8_t *new_data_ptr = (uint8_t *)realloc(data_ptr, (old_size + size_incr)); if (new_data_ptr != NULL) { prog->set_data_buffer((old_size + size_incr), new_data_ptr); target_brk = arg1; brk_page = PAGE_ALIGN_UP(target_brk); return target_brk; } else { return (-1); } } } return target_brk;; break; case TARGET_NR_fstat64: { if (syscallTrace == NULL) { ret = fstat(arg1, (struct stat *)prog->g2h(arg2)); return ret; } else { // copy 144 bytes (size of stat structure) from systrace file // number of lines in the file: total 144 bytes/8 bytes per line = 18 lines for (i=0; i < 18; i++) { memset(tmp_str, '\0', 128); fgets(tmp_str, 128, syscallTrace); long long int val = strtoull(tmp_str, NULL, 16); memcpy( (prog->g2h(arg2 + (i * 8) )), &val, 8); } } } return 0; break; case TARGET_NR_mmap2: { if (arg1 != 0x00000000) { // FIXME: This is the non-zero address case. // The address gives a hint to the kernel about where to map the file. // We might still do a malloc but need to remember a mapping of the native // address (i.e arg1) to pointer returned by malloc. printf("TARGET_NR_mmap2 map address not zero!!! This case is not handled \n"); exit(-1); } uint8_t *p = (uint8_t *)malloc(arg2); if (p == MAP_FAILED) return -1; else { prog->set_mem_mapped_file_endpts((long)p, arg2); return (long)p; } } return 0; printf("return address 0x%08x \n", p); break; case TARGET_NR_getpid: getpid(); return 0; break; case TARGET_NR_kill: kill(arg1, target_to_host_signal(arg2)); return 0; break; case TARGET_NR_pause: pause(); return 0; break; #ifdef TARGET_NR_shutdown case TARGET_NR_shutdown: shutdown(arg1, arg2); return 0; break; #endif #ifdef TARGET_NR_semget case TARGET_NR_semget: semget(arg1, arg2, arg3); return 0; break; #endif case TARGET_NR_setdomainname: p = lock_user_string(prog, arg1); setdomainname((const char *)p, arg2); return 0; break; case TARGET_NR_getsid: getsid(arg1); return 0; break; #if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */ case TARGET_NR_fdatasync: fdatasync(arg1); return 0; break; #endif #ifdef TARGET_NR_getuid32 case TARGET_NR_getuid32: getuid(); return 0; break; #endif case TARGET_NR_ioctl: printf("ioctl syscall not implemented\n"); return 0; break; default: printf("syscall %d is not implemented\n", num); exit(-1); } }