static void print_syscall(int num, const struct syscallname *scnames, unsigned int nscnames, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) { unsigned int i; const char *format="%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ")"; gemu_log("%d ", getpid() ); for (i = 0; i < nscnames; i++) if (scnames[i].nr == num) { if (scnames[i].call != NULL) { scnames[i].call(&scnames[i], arg1, arg2, arg3, arg4, arg5, arg6); } else { /* XXX: this format system is broken because it uses host types and host pointers for strings */ if (scnames[i].format != NULL) format = scnames[i].format; gemu_log(format, scnames[i].name, arg1, arg2, arg3, arg4, arg5, arg6); } return; } gemu_log("Unknown syscall %d\n", num); }
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})"); }
static void print_syscall_ret_addr(const struct syscallname *name, abi_long ret) { if( ret == -1 ) { gemu_log(" = -1 errno=%d (%s)\n", errno, strerror(errno)); } else { gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret); } }
long do_getattrlist(void * arg1, void * arg2, void * arg3, uint32_t arg4, uint32_t arg5) { struct attrlist * attrlist = (void *)arg2; long ret; #if defined(TARGET_I386) ^ defined(__i386__) || defined(TARGET_PPC) ^ defined(__ppc__) gemu_log("SYS_getdirentriesattr unimplemented\n"); return -ENOTSUP; #endif /* XXX: don't let the %s stay in there */ DPRINTF("getattrlist(%s, %p, %p, 0x%x, 0x%x)\n", (char *)arg1, arg2, arg3, arg4, arg5); if(arg2) /* XXX: We should handle that in a copy especially if the structure is not writable */ byteswap_attrlist(attrlist); ret = get_errno(getattrlist((const char* )arg1, attrlist, (void *)arg3, arg4, arg5)); if(!is_error(ret)) { byteswap_attrbuf((void *)arg3, attrlist); byteswap_attrlist(attrlist); } return ret; }
/* ------------------------------------------------------------ thread type syscall handling */ long do_thread_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8) { extern uint32_t cthread_set_self(uint32_t); extern uint32_t processor_facilities_used(); long ret = 0; arg1 = tswap32(arg1); arg2 = tswap32(arg2); arg3 = tswap32(arg3); arg4 = tswap32(arg4); arg5 = tswap32(arg5); arg6 = tswap32(arg6); arg7 = tswap32(arg7); arg8 = tswap32(arg8); DPRINTF("thread syscall %d : " , num); switch(num) { #ifdef TARGET_I386 case 0x3: #endif case 0x7FF1: /* cthread_set_self */ DPRINTF("cthread_set_self(0x%x)\n", (unsigned int)arg1); ret = cthread_set_self(arg1); #ifdef TARGET_I386 /* we need to update the LDT with the address of the thread */ write_dt((void *)(((CPUX86State *) cpu_env)->ldt.base + (4 * sizeof(uint64_t))), arg1, 1, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); /* New i386 convention, %gs should be set to our this LDT entry */ cpu_x86_load_seg(cpu_env, R_GS, 0x27); /* Old i386 convention, the kernel returns the selector for the cthread (pre-10.4.8?)*/ ret = 0x27; #endif break; case 0x7FF2: /* Called the super-fast pthread_self handler by the apple guys */ DPRINTF("pthread_self()\n"); ret = (uint32_t)pthread_self(); break; case 0x7FF3: DPRINTF("processor_facilities_used()\n"); #ifdef __i386__ qerror("processor_facilities_used: not implemented!\n"); #else ret = (uint32_t)processor_facilities_used(); #endif break; default: gemu_log("qemu: Unsupported thread syscall: %d(0x%x)\n", num, num); gdb_handlesig (cpu_env, SIGTRAP); exit(0); break; } return ret; }
long unimpl_unix_syscall(void *cpu_env, int num) { if( (num < 0) || (num > SYS_MAXSYSCALL-1) ) qerror("unix syscall %d is out of unix syscall bounds (0-%d) " , num, SYS_MAXSYSCALL-1); gemu_log("qemu: Unsupported unix syscall %s %d\n", unix_syscall_table[num].name , num); gdb_handlesig (cpu_env, SIGTRAP); exit(-1); }
static void print_syscall_ret(int num, abi_long ret, const struct syscallname *scnames, unsigned int nscnames) { unsigned int i; for (i = 0; i < nscnames; i++) if (scnames[i].nr == num) { if (scnames[i].result != NULL) { scnames[i].result(&scnames[i], ret); } else { if( ret < 0 ) { gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n", -ret, strerror(-ret)); } else { gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret); } } break; } }
long do_sigprocmask(uint32_t arg1, uint32_t * arg2, uint32_t * arg3) { long ret; DPRINTF("sigprocmask(%d, %p, %p)\n", arg1, arg2, arg3); gemu_log("XXX: sigprocmask not tested (%d, %p, %p)\n", arg1, arg2, arg3); if(arg2) tswap32s(arg2); ret = get_errno(sigprocmask(arg1, (void *)arg2, (void *)arg3)); if((!is_error(ret)) && arg3) tswap32s(arg3); if(arg2) tswap32s(arg2); return ret; }
static inline void print_syctl(int * mib, int count) { int i; struct sysctl_dir * sysctl = sysctls; struct sysctl_dir * ret = NULL; for(i = 0; i < count; i++) { if(!(ret = sysctl = get_sysctl_entry_for_mib(mib[i], sysctl))){ gemu_log("print_syctl: can't find mib %d\n", mib[i]); return; } DPRINTF("%s.", sysctl->name); if(!(sysctl = sysctl->childs)) break; } DPRINTF("\n"); }
static inline long bswap_syctl(int * mib, int count, void *buf, int size) { int i; struct sysctl_dir * sysctl = sysctls; struct sysctl_dir * ret = NULL; for(i = 0; i < count; i++) { if(!(ret = sysctl = get_sysctl_entry_for_mib(mib[i], sysctl))) { gemu_log("bswap_syctl: can't find mib %d\n", mib[i]); return -ENOTDIR; } if(!(sysctl = sysctl->childs)) break; } if(ret->childs) qerror("we shouldn't have a directory element\n"); ret->swap_func(buf, size); return 0; }
static inline void bswap_fcntl_arg(int cmd, void * arg) { switch(cmd) { case F_DUPFD: case F_GETFD: case F_SETFD: case F_GETFL: case F_SETFL: case F_GETOWN: case F_SETOWN: case F_SETSIZE: case F_RDAHEAD: case F_FULLFSYNC: break; case F_GETLK: case F_SETLK: case F_SETLKW: bswap_flock(arg); break; case F_PREALLOCATE: bswap_fstore(arg); break; case F_RDADVISE: bswap_radvisory(arg); break; case F_READBOOTSTRAP: case F_WRITEBOOTSTRAP: bswap_fbootstraptransfer(arg); break; case F_LOG2PHYS: bswap_log2phys(arg); break; default: gemu_log("unknow cmd in fcntl\n"); } }
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; }
/* * Variants for the return value output function */ static void print_syscall_ret_addr(const struct syscallname *name, abi_long ret) { if( ret == -1 ) { gemu_log(" = -1 errno=%d (%s)\n", errno, strerror(errno)); } else { gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret); } } #if 0 /* currently unused */ static void print_syscall_ret_raw(struct syscallname *name, abi_long ret) { gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret); }
/* ??? Implement proper locking for ioctls. */ static long do_ioctl(long fd, long cmd, long arg) { const IOCTLEntry *ie; const argtype *arg_type; int ret; uint8_t buf_temp[MAX_STRUCT_SIZE]; int target_size; void *argptr; ie = ioctl_entries; for(;;) { if (ie->target_cmd == 0) { gemu_log("Unsupported ioctl: cmd=0x%04lx\n", cmd); return -ENOSYS; } if (ie->target_cmd == cmd) break; ie++; } arg_type = ie->arg_type; #if defined(DEBUG) gemu_log("ioctl: cmd=0x%04lx (%s)\n", cmd, ie->name); #endif switch(arg_type[0]) { case TYPE_NULL: /* no argument */ ret = get_errno(ioctl(fd, ie->host_cmd)); break; case TYPE_PTRVOID: case TYPE_INT: /* int argment */ ret = get_errno(ioctl(fd, ie->host_cmd, arg)); break; case TYPE_PTR: arg_type++; target_size = thunk_type_size(arg_type, 0); switch(ie->access) { case IOC_R: ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); if (!is_error(ret)) { argptr = lock_user(arg, target_size, 0); thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET); unlock_user(argptr, arg, target_size); } break; case IOC_W: argptr = lock_user(arg, target_size, 1); thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); unlock_user(argptr, arg, 0); ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); break; default: case IOC_RW: argptr = lock_user(arg, target_size, 1); thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); unlock_user(argptr, arg, 0); ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); if (!is_error(ret)) { argptr = lock_user(arg, target_size, 0); thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET); unlock_user(argptr, arg, target_size); } break; } break; default: gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n", cmd, arg_type[0]); ret = -ENOSYS; break; } return ret; }
long do_mach_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8) { extern uint32_t mach_reply_port(); long ret = 0; arg1 = tswap32(arg1); arg2 = tswap32(arg2); arg3 = tswap32(arg3); arg4 = tswap32(arg4); arg5 = tswap32(arg5); arg6 = tswap32(arg6); arg7 = tswap32(arg7); arg8 = tswap32(arg8); DPRINTF("mach syscall %d : " , num); switch(num) { /* see xnu/osfmk/mach/syscall_sw.h */ case -26: DPRINTF("mach_reply_port()\n"); ret = mach_reply_port(); break; case -27: DPRINTF("mach_thread_self()\n"); ret = mach_thread_self(); break; case -28: DPRINTF("mach_task_self()\n"); ret = mach_task_self(); break; case -29: DPRINTF("mach_host_self()\n"); ret = mach_host_self(); break; case -31: DPRINTF("mach_msg_trap(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", arg1, arg2, arg3, arg4, arg5, arg6, arg7); ret = target_mach_msg_trap((mach_msg_header_t *)arg1, arg2, arg3, arg4, arg5, arg6, arg7); break; /* may need more translation if target arch is different from host */ #if (defined(TARGET_I386) && defined(__i386__)) || (defined(TARGET_PPC) && defined(__ppc__)) case -33: DPRINTF("semaphore_signal_trap(0x%x)\n", arg1); ret = semaphore_signal_trap(arg1); break; case -34: DPRINTF("semaphore_signal_all_trap(0x%x)\n", arg1); ret = semaphore_signal_all_trap(arg1); break; case -35: DPRINTF("semaphore_signal_thread_trap(0x%x)\n", arg1, arg2); ret = semaphore_signal_thread_trap(arg1,arg2); break; #endif case -36: DPRINTF("semaphore_wait_trap(0x%x)\n", arg1); extern int semaphore_wait_trap(int); // XXX: is there any header for that? ret = semaphore_wait_trap(arg1); break; /* may need more translation if target arch is different from host */ #if (defined(TARGET_I386) && defined(__i386__)) || (defined(TARGET_PPC) && defined(__ppc__)) case -37: DPRINTF("semaphore_wait_signal_trap(0x%x, 0x%x)\n", arg1, arg2); ret = semaphore_wait_signal_trap(arg1,arg2); break; #endif case -43: DPRINTF("map_fd(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", arg1, arg2, arg3, arg4, arg5); ret = map_fd(arg1, arg2, (void*)arg3, arg4, arg5); tswap32s((uint32_t*)arg3); break; /* may need more translation if target arch is different from host */ #if (defined(TARGET_I386) && defined(__i386__)) || (defined(TARGET_PPC) && defined(__ppc__)) case -61: DPRINTF("syscall_thread_switch(0x%x, 0x%x, 0x%x)\n", arg1, arg2, arg3); ret = syscall_thread_switch(arg1, arg2, arg3); // just a hint to the scheduler; can drop? break; #endif case -89: DPRINTF("mach_timebase_info(0x%x)\n", arg1); struct mach_timebase_info info; ret = mach_timebase_info(&info); if(!is_error(ret)) { struct mach_timebase_info *outInfo = (void*)arg1; outInfo->numer = tswap32(info.numer); outInfo->denom = tswap32(info.denom); } break; case -90: DPRINTF("mach_wait_until()\n"); extern int mach_wait_until(uint64_t); // XXX: is there any header for that? ret = mach_wait_until(((uint64_t)arg2<<32) | (uint64_t)arg1); break; case -91: DPRINTF("mk_timer_create()\n"); extern int mk_timer_create(); // XXX: is there any header for that? ret = mk_timer_create(); break; case -92: DPRINTF("mk_timer_destroy()\n"); extern int mk_timer_destroy(int); // XXX: is there any header for that? ret = mk_timer_destroy(arg1); break; case -93: DPRINTF("mk_timer_create()\n"); extern int mk_timer_arm(int, uint64_t); // XXX: is there any header for that? ret = mk_timer_arm(arg1, ((uint64_t)arg3<<32) | (uint64_t)arg2); break; case -94: DPRINTF("mk_timer_cancel()\n"); extern int mk_timer_cancel(int, uint64_t *); // XXX: is there any header for that? ret = mk_timer_cancel(arg1, (uint64_t *)arg2); if((!is_error(ret)) && arg2) tswap64s((uint64_t *)arg2); break; default: gemu_log("qemu: Unsupported mach syscall: %d(0x%x)\n", num, num); gdb_handlesig (cpu_env, SIGTRAP); exit(0); break; } return ret; }