diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c index f5f652f..8abb1dd 100644 --- a/bsd-user/elfload.c +++ b/bsd-user/elfload.c @@ -403,8 +403,11 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i { regs->cp0_status = 2 << CP0St_KSU; - regs->regs[25] = regs->cp0_epc = infop->entry; /* t9 = pc = entry */ + regs->regs[25] = regs->cp0_epc = infop->entry & ~3; /* t9 = pc = entry */ regs->regs[4] = regs->regs[29] = infop->start_stack; /* a0 = sp = start_stack */ + regs->regs[5] = 0; /* a1 = 0 */ + regs->regs[6] = 0; /* a2 = 0 */ + regs->regs[7] = TARGET_PS_STRINGS; /* a3 = ps_strings */ } #define USE_ELF_CORE_DUMP @@ -765,7 +768,7 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct bsd_binprm *bprm, { abi_ulong stack_hi_addr; size_t execpath_len; - abi_ulong destp; + abi_ulong destp, argvp, envp; struct target_ps_strings ps_strs; char canary[sizeof(abi_long) * 8]; char execpath[PATH_MAX]; @@ -808,6 +811,7 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct bsd_binprm *bprm, /* XXX - check return value of put_user_ual(). */ put_user_ual(TARGET_PAGE_SIZE, p); + argvp = p - TARGET_SPACE_USRSPACE; p = destp = p - TARGET_SPACE_USRSPACE - TARGET_ARG_MAX; /* XXX should check strlen(argv and envp strings) < TARGET_ARG_MAX */ @@ -816,31 +820,38 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct bsd_binprm *bprm, * Add argv strings. Note that the argv[] vectors are added by * loader_build_argptr() */ + envp = argvp + (bprm->argc + 2) * sizeof(abi_ulong); + ps_strs.ps_argvstr = tswapl(argvp); + ps_strs.ps_nargvstr = tswap32(bprm->argc); // i = bprm->argc; // while (i-- > 0) { for (i = 0; i < bprm->argc; ++i) { size_t len = strlen(bprm->argv[i]) + 1; /* XXX - check return value of memcpy_to_target(). */ memcpy_to_target(destp, bprm->argv[i], len); + put_user_ual(destp, argvp); + argvp += sizeof(abi_ulong); destp += len; } - ps_strs.ps_argvstr = tswapl(destp); - ps_strs.ps_nargvstr = tswap32(bprm->argc); + put_user_ual(0, argvp); /* * Add env strings. Note that the envp[] vectors are added by * loader_build_argptr(). */ + ps_strs.ps_envstr = tswapl(envp); + ps_strs.ps_nenvstr = tswap32(bprm->envc); // i = bprm->envc; // while(i-- > 0) { for (i = 0; i < bprm->envc; ++i) { size_t len = strlen(bprm->envp[i]) + 1; /* XXX - check return value of memcpy_to_target(). */ memcpy_to_target(destp, bprm->envp[i], len); + put_user_ual(destp, envp); + envp += sizeof(abi_ulong); destp += len; } - ps_strs.ps_envstr = tswapl(destp); - ps_strs.ps_nenvstr = tswap32(bprm->envc); + put_user_ual(0, envp); /* XXX - check return value of memcpy_to_target(). */ memcpy_to_target(stack_hi_addr - sizeof(ps_strs), &ps_strs, @@ -1304,6 +1315,27 @@ static void load_symbols(struct elfhdr *hdr, int fd) syminfos = s; } +/* Check the elf header and see if this a target elf binary. */ +int is_target_elf_binary(int fd) +{ + uint8_t buf[128]; + struct elfhdr elf_ex; + + if (lseek(fd, 0L, SEEK_SET) < 0) + return (0); + if (read(fd, buf, sizeof(buf)) < 0) + return (0); + + elf_ex = *((struct elfhdr *)buf); + bswap_ehdr(&elf_ex); + + if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) || + (! elf_check_arch(elf_ex.e_machine))) + return (0); + else + return (1); +} + int load_elf_binary(struct bsd_binprm * bprm, struct target_pt_regs * regs, struct image_info * info) { @@ -1424,13 +1456,10 @@ int load_elf_binary(struct bsd_binprm * bprm, struct target_pt_regs * regs, /* JRP - Need to add X86 lib dir stuff here... */ if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 || - strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) { + strcmp(elf_interpreter,"/libexec/ld-elf.so.1") == 0) { ibcs2_interpreter = 1; } -#if 0 - printf("Using ELF interpreter %s\n", path(elf_interpreter)); -#endif if (retval >= 0) { retval = open(path(elf_interpreter), O_RDONLY); if(retval >= 0) { diff --git a/bsd-user/freebsd/filio.h b/bsd-user/freebsd/filio.h new file mode 100644 index 0000000..2269484 --- /dev/null +++ b/bsd-user/freebsd/filio.h @@ -0,0 +1,27 @@ +#ifndef _FREEBSD_FILIO_H_ +#define _FREEBSD_FILIO_H_ + +/* see sys/filio.h */ +#define TARGET_FIOCLEX TARGET_IO('f', 1) +#define TARGET_FIONCLEX TARGET_IO('f', 2) +#define TARGET_FIONREAD TARGET_IOR('f', 127, int) +#define TARGET_FIONBIO TARGET_IOW('f', 126, int) +#define TARGET_FIOASYNC TARGET_IOW('f', 125, int) +#define TARGET_FIOSETOWN TARGET_IOW('f', 124, int) +#define TARGET_FIOGETOWN TARGET_IOR('f', 123, int) +#define TARGET_FIODTYPE TARGET_IOR('f', 122, int) +#define TARGET_FIOGETLBA TARGET_IOR('f', 121, int) + +struct target_fiodgname_arg { + int32_t len; + abi_ulong buf; +}; + +#define TARGET_FIODGNAME TARGET_IOW('f', 120, \ + struct target_fiodgname_arg) +#define TARGET_FIONWRITE TARGET_IOR('f', 119, int) +#define TARGET_FIONSPACE TARGET_IOR('f', 118, int) +#define TARGET_FIOSEEKDATA TARGET_IOWR('f', 97, off_t) +#define TARGET_FIOSEEKHOLE TARGET_IOWR('f', 98, off_t) + +#endif /* !_FREEBSD_FILIO_H_ */ diff --git a/bsd-user/freebsd/ioctl.h b/bsd-user/freebsd/ioctl.h deleted file mode 100644 index f83f6c1..0000000 --- a/bsd-user/freebsd/ioctl.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _FREEBSD_IOCTL_H_ -#define _FREEBSD_IOCTL_H_ - -/* sys/ttycom.h tty(4) */ -IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT)) -IOCTL(TIOCGETD, IOC_R, MK_PTR(TYPE_INT)) -IOCTL(TIOCSBRK, IOC_, TYPE_NULL) -IOCTL(TIOCCBRK, IOC_, TYPE_NULL) -IOCTL(TIOCSDTR, IOC_, TYPE_NULL) -IOCTL(TIOCCDTR, IOC_, TYPE_NULL) -IOCTL(TIOCGPGRP, IOC_R, MK_PTR(TYPE_INT)) -IOCTL(TIOCSPGRP, IOC_W, MK_PTR(TYPE_INT)) -IOCTL(TIOCGETA, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios))) -IOCTL(TIOCSETA, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios))) -IOCTL(TIOCSETAW, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios))) -IOCTL(TIOCSETAF, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios))) -IOCTL(TIOCOUTQ, IOC_R, MK_PTR(TYPE_INT)) -IOCTL(TIOCSTI, IOC_W, MK_PTR(TYPE_CHAR)) -IOCTL(TIOCNOTTY, IOC_, TYPE_NULL) -IOCTL(TIOCSTOP, IOC_, TYPE_NULL) -IOCTL(TIOCSTART, IOC_, TYPE_NULL) -IOCTL(TIOCSCTTY, IOC_, TYPE_NULL) -IOCTL(TIOCDRAIN, IOC_, TYPE_NULL) -IOCTL(TIOCEXCL, IOC_, TYPE_NULL) -IOCTL(TIOCNXCL, IOC_, TYPE_NULL) -IOCTL(TIOCFLUSH, IOC_W, MK_PTR(TYPE_INT)) -IOCTL(TIOCGWINSZ, IOC_R, MK_PTR(MK_STRUCT(STRUCT_winsize))) -IOCTL(TIOCSWINSZ, IOC_W, MK_PTR(MK_STRUCT(STRUCT_winsize))) -IOCTL(TIOCCONS, IOC_W, MK_PTR(TYPE_INT)) -IOCTL(TIOCMSET, IOC_W, MK_PTR(TYPE_INT)) -IOCTL(TIOCMGET, IOC_R, MK_PTR(TYPE_INT)) -IOCTL(TIOCMBIS, IOC_W, MK_PTR(TYPE_INT)) -IOCTL(TIOCMBIC, IOC_W, MK_PTR(TYPE_INT)) - -#endif diff --git a/bsd-user/freebsd/ioctls.h b/bsd-user/freebsd/ioctls.h new file mode 100644 index 0000000..85d3c41 --- /dev/null +++ b/bsd-user/freebsd/ioctls.h @@ -0,0 +1,47 @@ + +/* sys/ttycom.h tty(4) */ +IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT)) +IOCTL(TIOCGETD, IOC_R, MK_PTR(TYPE_INT)) +IOCTL(TIOCSBRK, IOC_, TYPE_NULL) +IOCTL(TIOCCBRK, IOC_, TYPE_NULL) +IOCTL(TIOCSDTR, IOC_, TYPE_NULL) +IOCTL(TIOCCDTR, IOC_, TYPE_NULL) +IOCTL(TIOCGPGRP, IOC_R, MK_PTR(TYPE_INT)) +IOCTL(TIOCSPGRP, IOC_W, MK_PTR(TYPE_INT)) +IOCTL(TIOCGETA, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios))) +IOCTL(TIOCSETA, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios))) +IOCTL(TIOCSETAW, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios))) +IOCTL(TIOCSETAF, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios))) +IOCTL(TIOCOUTQ, IOC_R, MK_PTR(TYPE_INT)) +IOCTL(TIOCSTI, IOC_W, MK_PTR(TYPE_CHAR)) +IOCTL(TIOCNOTTY, IOC_, TYPE_NULL) +IOCTL(TIOCSTOP, IOC_, TYPE_NULL) +IOCTL(TIOCSTART, IOC_, TYPE_NULL) +IOCTL(TIOCSCTTY, IOC_, TYPE_NULL) +IOCTL(TIOCDRAIN, IOC_, TYPE_NULL) +IOCTL(TIOCEXCL, IOC_, TYPE_NULL) +IOCTL(TIOCNXCL, IOC_, TYPE_NULL) +IOCTL(TIOCFLUSH, IOC_W, MK_PTR(TYPE_INT)) +IOCTL(TIOCGWINSZ, IOC_R, MK_PTR(MK_STRUCT(STRUCT_winsize))) +IOCTL(TIOCSWINSZ, IOC_W, MK_PTR(MK_STRUCT(STRUCT_winsize))) +IOCTL(TIOCCONS, IOC_W, MK_PTR(TYPE_INT)) +IOCTL(TIOCMSET, IOC_W, MK_PTR(TYPE_INT)) +IOCTL(TIOCMGET, IOC_R, MK_PTR(TYPE_INT)) +IOCTL(TIOCMBIS, IOC_W, MK_PTR(TYPE_INT)) +IOCTL(TIOCMBIC, IOC_W, MK_PTR(TYPE_INT)) + +/* sys/filio.h */ +IOCTL(FIOCLEX, IOC_, TYPE_NULL) +IOCTL(FIONCLEX, IOC_, TYPE_NULL) +IOCTL(FIONREAD, IOC_R, MK_PTR(TYPE_INT)) +IOCTL(FIONBIO, IOC_W, MK_PTR(TYPE_INT)) +IOCTL(FIOASYNC, IOC_W, MK_PTR(TYPE_INT)) +IOCTL(FIOSETOWN, IOC_W, MK_PTR(TYPE_INT)) +IOCTL(FIOGETOWN, IOC_R, MK_PTR(TYPE_INT)) +IOCTL(FIODTYPE, IOC_R, MK_PTR(TYPE_INT)) +IOCTL(FIOGETLBA, IOC_R, MK_PTR(TYPE_INT)) +IOCTL(FIODGNAME, IOC_R, MK_PTR(STRUCT_fiodgname_arg)) +IOCTL(FIONWRITE, IOC_R, MK_PTR(TYPE_INT)) +IOCTL(FIONSPACE, IOC_R, MK_PTR(TYPE_INT)) +IOCTL(FIOSEEKDATA, IOC_RW, MK_PTR(TYPE_ULONG)) +IOCTL(FIOSEEKHOLE, IOC_RW, MK_PTR(TYPE_ULONG)) diff --git a/bsd-user/freebsd/strace.list b/bsd-user/freebsd/strace.list index c66dcfa..8270c37 100644 --- a/bsd-user/freebsd/strace.list +++ b/bsd-user/freebsd/strace.list @@ -1,7 +1,19 @@ +{ TARGET_FREEBSD_NR___acl_aclcheck_fd, "__acl_get_fd", "%s(%d, %d, %#x)", NULL, NULL }, +{ TARGET_FREEBSD_NR___acl_aclcheck_file, "__acl_get_file", "%s(\"%s\", %d, %#x)", NULL, NULL }, +{ TARGET_FREEBSD_NR___acl_aclcheck_link, "__acl_get_link", "%s(\"%s\", %d, %#x)", NULL, NULL }, +{ TARGET_FREEBSD_NR___acl_delete_fd, "__acl_delete_fd", "%s(%d, %d)", NULL, NULL }, +{ TARGET_FREEBSD_NR___acl_delete_file, "__acl_delete_file", "%s(\"%s\", %d)", NULL, NULL }, +{ TARGET_FREEBSD_NR___acl_delete_link, "__acl_delete_link", "%s(\"%s\", %d)", NULL, NULL }, +{ TARGET_FREEBSD_NR___acl_get_fd, "__acl_get_fd", "%s(\"%s\", %d, %#x)", NULL, NULL }, +{ TARGET_FREEBSD_NR___acl_get_file, "__acl_get_file", "%s(\"%s\", %d, %#x)", NULL, NULL }, +{ TARGET_FREEBSD_NR___acl_get_link, "__acl_get_link", "%s(\"%s\", %d, %#x)", NULL, NULL }, +{ TARGET_FREEBSD_NR___acl_set_fd, "__acl_get_fd", "%s(\"%s\", %d, %#x)", NULL, NULL }, +{ TARGET_FREEBSD_NR___acl_set_file, "__acl_get_file", "%s(\"%s\", %d, %#x)", NULL, NULL }, +{ TARGET_FREEBSD_NR___acl_set_link, "__acl_get_link", "%s(\"%s\", %d, %#x)", NULL, NULL }, { TARGET_FREEBSD_NR___getcwd, "__getcwd", NULL, NULL, NULL }, { TARGET_FREEBSD_NR___semctl, "__semctl", NULL, NULL, NULL }, { TARGET_FREEBSD_NR___syscall, "__syscall", NULL, NULL, NULL }, -{ TARGET_FREEBSD_NR___sysctl, "__sysctl", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR___sysctl, "__sysctl", NULL, print_sysctl, NULL }, { TARGET_FREEBSD_NR__umtx_op, "_umtx_op", "%s(%#x, %d, %d, %#x, %#x)", NULL, NULL }, { TARGET_FREEBSD_NR_accept, "accept", "%s(%d,%#x,%#x)", NULL, NULL }, { TARGET_FREEBSD_NR_access, "access", "%s(\"%s\",%#o)", NULL, NULL }, @@ -23,19 +35,34 @@ { TARGET_FREEBSD_NR_dup2, "dup2", NULL, NULL, NULL }, { TARGET_FREEBSD_NR_execve, "execve", NULL, print_execve, NULL }, { TARGET_FREEBSD_NR_exit, "exit", "%s(%d)\n", NULL, NULL }, +{ TARGET_FREEBSD_NR_extattrctl, "extattrctl", "%s(\"%s\", %d, \"%s\", %d, \"%s\"", NULL, NULL }, +{ TARGET_FREEBSD_NR_extattr_delete_fd, "extattr_delete_fd", "%s(%d, %d, \"%s\")", NULL, NULL }, +{ TARGET_FREEBSD_NR_extattr_delete_file, "extattr_delete_file", "%s(\"%s\", %d, \"%s\")", NULL, NULL }, +{ TARGET_FREEBSD_NR_extattr_delete_link, "extattr_delete_link", "%s(\"%s\", %d, \"%s\")", NULL, NULL }, +{ TARGET_FREEBSD_NR_extattr_get_fd, "extattr_get_fd", "%s(%d, %d, \"%s\", %#x, %d)", NULL, NULL }, +{ TARGET_FREEBSD_NR_extattr_get_file, "extattr_get_file", "%s(\"%s\", %d, \"%s\", %#x, %d)", NULL, NULL }, +{ TARGET_FREEBSD_NR_extattr_get_file, "extattr_get_link", "%s(\"%s\", %d, \"%s\", %#x, %d)", NULL, NULL }, +{ TARGET_FREEBSD_NR_extattr_list_fd, "extattr_list_fd", "%s(%d, %d, %#x, %d)", NULL, NULL }, +{ TARGET_FREEBSD_NR_extattr_list_file, "extattr_list_file", "%s(\"%s\", %#x, %d)", NULL, NULL }, +{ TARGET_FREEBSD_NR_extattr_list_link, "extattr_list_link", "%s(\"%s\", %d, %#x, %d)", NULL, NULL }, +{ TARGET_FREEBSD_NR_extattr_set_fd, "extattr_set_fd", "%s(%d, %d, \"%s\", %#x, %d)", NULL, NULL }, +{ TARGET_FREEBSD_NR_extattr_set_file, "extattr_set_file", "%s(\"%s\", %d, \"%s\", %#x, %d)", NULL, NULL }, +{ TARGET_FREEBSD_NR_extattr_set_link, "extattr_set_link", "%s(\"%s\", %d, \"%s\", %#x, %d)", NULL, NULL }, { TARGET_FREEBSD_NR_fchdir, "fchdir", NULL, NULL, NULL }, { TARGET_FREEBSD_NR_fchflags, "fchflags", NULL, NULL, NULL }, { TARGET_FREEBSD_NR_fchmod, "fchmod", "%s(%d,%#o)", NULL, NULL }, { TARGET_FREEBSD_NR_fchown, "fchown", "%s(\"%s\",%d,%d)", NULL, NULL }, { TARGET_FREEBSD_NR_fcntl, "fcntl", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_fexecve, "fexecve", NULL, print_execve, NULL }, { TARGET_FREEBSD_NR_fhopen, "fhopen", NULL, NULL, NULL }, { TARGET_FREEBSD_NR_fhstat, "fhstat", NULL, NULL, NULL }, { TARGET_FREEBSD_NR_fhstatfs, "fhstatfs", NULL, NULL, NULL }, { TARGET_FREEBSD_NR_flock, "flock", NULL, NULL, NULL }, { TARGET_FREEBSD_NR_fork, "fork", "%s()", NULL, NULL }, { TARGET_FREEBSD_NR_fpathconf, "fpathconf", NULL, NULL, NULL }, -{ TARGET_FREEBSD_NR_fstat, "fstat", "%s(%d,%p)", NULL, NULL }, -{ TARGET_FREEBSD_NR_fstatfs, "fstatfs", "%s(%d,%p)", NULL, NULL }, +{ TARGET_FREEBSD_NR_fstat, "fstat", "%s(%d,%#x)", NULL, NULL }, +{ TARGET_FREEBSD_NR_fstatat, "fstatat", "%s(%d,\"%s\", %#x)", NULL, NULL }, +{ TARGET_FREEBSD_NR_fstatfs, "fstatfs", "%s(%d,%#x)", NULL, NULL }, { TARGET_FREEBSD_NR_fsync, "fsync", NULL, NULL, NULL }, { TARGET_FREEBSD_NR_ftruncate, "ftruncate", NULL, NULL, NULL }, { TARGET_FREEBSD_NR_futimes, "futimes", NULL, NULL, NULL }, @@ -65,7 +92,7 @@ { TARGET_FREEBSD_NR_getsockopt, "getsockopt", NULL, NULL, NULL }, { TARGET_FREEBSD_NR_gettimeofday, "gettimeofday", NULL, NULL, NULL }, { TARGET_FREEBSD_NR_getuid, "getuid", "%s()", NULL, NULL }, -{ TARGET_FREEBSD_NR_ioctl, "ioctl", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_ioctl, "ioctl", NULL, print_ioctl, NULL }, { TARGET_FREEBSD_NR_issetugid, "issetugid", "%s()", NULL, NULL }, { TARGET_FREEBSD_NR_kevent, "kevent", NULL, NULL, NULL }, { TARGET_FREEBSD_NR_kill, "kill", NULL, NULL, NULL }, @@ -74,6 +101,7 @@ { TARGET_FREEBSD_NR_lchown, "lchown", NULL, NULL, NULL }, { TARGET_FREEBSD_NR_link, "link", "%s(\"%s\",\"%s\")", NULL, NULL }, { TARGET_FREEBSD_NR_listen, "listen", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_lpathconf, "lpathconf", "%s(\"%s\", %d)", NULL, NULL }, { TARGET_FREEBSD_NR_lseek, "lseek", NULL, NULL, NULL }, { TARGET_FREEBSD_NR_lstat, "lstat", "%s(\"%s\",%p)", NULL, NULL }, { TARGET_FREEBSD_NR_madvise, "madvise", NULL, NULL, NULL }, @@ -98,7 +126,9 @@ { TARGET_FREEBSD_NR_nanosleep, "nanosleep", NULL, NULL, NULL }, { TARGET_FREEBSD_NR_nfssvc, "nfssvc", NULL, NULL, NULL }, { TARGET_FREEBSD_NR_open, "open", "%s(\"%s\",%#x,%#o)", NULL, NULL }, +{ TARGET_FREEBSD_NR_openat, "openat", "%s(%d, \"%s\",%#x,%#o)", NULL, NULL }, { TARGET_FREEBSD_NR_pathconf, "pathconf", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_pathconf, "pathconf", "%s(\"%s\", %d)", NULL, NULL }, { TARGET_FREEBSD_NR_pipe, "pipe", NULL, NULL, NULL }, { TARGET_FREEBSD_NR_poll, "poll", NULL, NULL, NULL }, { TARGET_FREEBSD_NR_pread, "pread", NULL, NULL, NULL }, @@ -162,7 +192,7 @@ { TARGET_FREEBSD_NR_statfs, "statfs", "%s(\"%s\",%p)", NULL, NULL }, { TARGET_FREEBSD_NR_symlink, "symlink", "%s(\"%s\",\"%s\")", NULL, NULL }, { TARGET_FREEBSD_NR_sync, "sync", NULL, NULL, NULL }, -{ TARGET_FREEBSD_NR_sysarch, "sysarch", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_sysarch, "sysarch", NULL, print_sysarch, NULL }, { TARGET_FREEBSD_NR_syscall, "syscall", NULL, NULL, NULL }, { TARGET_FREEBSD_NR_thr_create, "thr_create", NULL, NULL, NULL }, { TARGET_FREEBSD_NR_thr_exit, "thr_exit", NULL, NULL, NULL }, diff --git a/bsd-user/freebsd/syscall_types.h b/bsd-user/freebsd/syscall_types.h index 6e43400..60b9288 100644 --- a/bsd-user/freebsd/syscall_types.h +++ b/bsd-user/freebsd/syscall_types.h @@ -1,8 +1,7 @@ -#ifndef _FREEBSD_SYSCALL_TYPES_H_ -#define _FREEBSD_SYSCALL_TYPES_H_ STRUCT_SPECIAL(termios) STRUCT(winsize, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT) -#endif +STRUCT(fiodgname_arg, TYPE_INT, TYPE_PTRVOID) + diff --git a/bsd-user/main.c b/bsd-user/main.c index 32bd3e5..bb614de 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -2,6 +2,7 @@ * qemu user main * * Copyright (c) 2003-2008 Fabrice Bellard + * Copyright (c) 2012-2013 Stacey Son * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,6 +26,7 @@ #include #include #include +#include #include "qemu.h" #include "qemu-common.h" @@ -58,6 +60,36 @@ enum BSDType bsd_type; by remapping the process stack directly at the right place */ unsigned long x86_stack_size = 512 * 1024; +static void save_proc_pathname(void); +char qemu_proc_pathname[PATH_MAX]; + +#ifdef __FreeBSD__ +static void +save_proc_pathname(void) +{ + int mib[4]; + size_t len; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = -1; + + len = sizeof(qemu_proc_pathname); + + if (sysctl(mib, 4, qemu_proc_pathname, &len, NULL, 0)) + perror("sysctl"); +} + +#else + +static void +save_proc_pathname(void) +{ +} + +#endif /* !__FreeBSD__ */ + void gemu_log(const char *fmt, ...) { va_list ap; @@ -1496,6 +1528,8 @@ int main(int argc, char **argv) if (argc <= 1) usage(); + save_proc_pathname(); + module_call_init(MODULE_INIT_QOM); if ((envlist = envlist_create()) == NULL) { diff --git a/bsd-user/mips64/target_signal.h b/bsd-user/mips64/target_signal.h index e9c8a9f..c592136 100644 --- a/bsd-user/mips64/target_signal.h +++ b/bsd-user/mips64/target_signal.h @@ -65,13 +65,7 @@ set_sigtramp_args(CPUMIPSState *regs, int sig, struct target_sigframe *frame, abi_ulong frame_addr, struct target_sigaction *ka) { - frame->sf_signum = sig; - frame->sf_siginfo = 0; - frame->sf_ucontext = 0; - - frame->sf_si.si_signo = sig; - frame->sf_si.si_code = TARGET_SA_SIGINFO; - frame->sf_si.si_addr = regs->CP0_BadVAddr; + /* frame->sf_si.si_addr = regs->CP0_BadVAddr; */ /* * Arguments to signal handler: @@ -86,6 +80,8 @@ set_sigtramp_args(CPUMIPSState *regs, int sig, struct target_sigframe *frame, regs->active_tc.gpr[ 4] = sig; regs->active_tc.gpr[ 5] = frame_addr + offsetof(struct target_sigframe, sf_si); + regs->active_tc.gpr[ 6] = frame_addr + + offsetof(struct target_sigframe, sf_uc); regs->active_tc.gpr[25] = regs->active_tc.PC = ka->_sa_handler; regs->active_tc.gpr[29] = frame_addr; regs->active_tc.gpr[31] = TARGET_PS_STRINGS - TARGET_SZSIGCODE; diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index d9c9934..110b54e 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -64,15 +64,15 @@ struct image_info { #define MAX_SIGQUEUE_SIZE 1024 -struct sigqueue { - struct sigqueue *next; +struct qemu_sigqueue { + struct qemu_sigqueue *next; target_siginfo_t info; }; struct emulated_sigtable { int pending; /* true if signal is pending */ - struct sigqueue *first; - struct sigqueue info; /* in order to always have memory for the + struct qemu_sigqueue *first; + struct qemu_sigqueue info; /* in order to always have memory for the first signal, we put it here */ }; @@ -95,8 +95,8 @@ typedef struct TaskState { struct bsd_binprm *bprm; struct emulated_sigtable sigtab[TARGET_NSIG]; - struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */ - struct sigqueue *first_free; /* first free siginfo queue entry */ + struct qemu_sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */ + struct qemu_sigqueue *first_free; /* first free siginfo queue entry */ int signal_pending; /* non zero if a signal may be pending */ uint8_t stack[0]; @@ -146,6 +146,7 @@ int load_elf_binary(struct bsd_binprm * bprm, struct target_pt_regs * regs, struct image_info * info); int load_flt_binary(struct bsd_binprm * bprm, struct target_pt_regs * regs, struct image_info * info); +int is_target_elf_binary(int fd); void target_set_brk(abi_ulong new_brk); abi_long do_brk(abi_ulong new_brk); @@ -222,6 +223,7 @@ void mmap_fork_end(int child); /* main.c */ extern unsigned long x86_stack_size; +extern char qemu_proc_pathname[]; /* user access */ diff --git a/bsd-user/signal.c b/bsd-user/signal.c index d56837b..29e8e12 100644 --- a/bsd-user/signal.c +++ b/bsd-user/signal.c @@ -77,7 +77,7 @@ static uint8_t host_to_target_signal_table[_NSIG] = { [SIGUSR1] = TARGET_SIGUSR1, [SIGUSR2] = TARGET_SIGUSR2, #ifdef SIGTHR - [SIGTHR] = TARGET_SIGTHR, + [SIGTHR + 3] = TARGET_SIGTHR, #endif /* [SIGLWP] = TARGET_SIGLWP, */ #ifdef SIGLIBRT @@ -207,9 +207,10 @@ target_to_host_sigset(sigset_t *d, const target_sigset_t *s) static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo, const siginfo_t *info) { - int sig; + int sig, code; sig = host_to_target_signal(info->si_signo); + code = tswap32(info->si_code); /* XXX should have host_to_target_si_code() */ tinfo->si_signo = sig; tinfo->si_errno = info->si_errno; tinfo->si_code = info->si_code; @@ -222,11 +223,13 @@ host_to_target_siginfo_noswap(target_siginfo_t *tinfo, const siginfo_t *info) if (SIGILL == sig || SIGFPE == sig || SIGSEGV == sig || SIGBUS == sig || SIGTRAP == sig) { tinfo->_reason._fault._trapno = info->_reason._fault._trapno; + } #ifdef SIGPOLL - } else if (SIGPOLL == sig) { + if (SIGPOLL == sig) { tinfo->_reason._poll._band = info->_reason._poll._band; + } #endif - } else { + if (SI_TIMER == code) { tinfo->_reason._timer._timerid = info->_reason._timer._timerid; tinfo->_reason._timer._overrun = info->_reason._timer._overrun; } @@ -235,8 +238,10 @@ host_to_target_siginfo_noswap(target_siginfo_t *tinfo, const siginfo_t *info) static void tswap_siginfo(target_siginfo_t *tinfo, const target_siginfo_t *info) { - int sig; + int sig, code; + sig = info->si_signo; + code = info->si_code; tinfo->si_signo = tswap32(sig); tinfo->si_errno = tswap32(info->si_errno); tinfo->si_code = tswap32(info->si_code); @@ -247,11 +252,13 @@ tswap_siginfo(target_siginfo_t *tinfo, const target_siginfo_t *info) SIGBUS == sig || SIGTRAP == sig) { tinfo->_reason._fault._trapno = tswap32(info->_reason._fault._trapno); + } #ifdef SIGPOLL - } else if (SIGPOLL == sig) { + if (SIGPOLL == sig) { tinfo->_reason._poll._band = tswap32(info->_reason._poll._band); + } #endif - } else { + if (SI_TIMER == code) { tinfo->_reason._timer._timerid = tswap32(info->_reason._timer._timerid); tinfo->_reason._timer._overrun = @@ -286,11 +293,11 @@ core_dump_signal(int sig) } /* Signal queue handling. */ -static inline struct sigqueue * +static inline struct qemu_sigqueue * alloc_sigqueue(CPUArchState *env) { TaskState *ts = env->opaque; - struct sigqueue *q = ts->first_free; + struct qemu_sigqueue *q = ts->first_free; if (!q) return (NULL); @@ -299,7 +306,7 @@ alloc_sigqueue(CPUArchState *env) } static inline void -free_sigqueue(CPUArchState *env, struct sigqueue *q) +free_sigqueue(CPUArchState *env, struct qemu_sigqueue *q) { TaskState *ts = env->opaque; @@ -372,7 +379,7 @@ queue_signal(CPUArchState *env, int sig, target_siginfo_t *info) { TaskState *ts = env->opaque; struct emulated_sigtable *k; - struct sigqueue *q, **pq; + struct qemu_sigqueue *q, **pq; abi_ulong handler; int queue; @@ -606,7 +613,7 @@ do_sigaction(int sig, const struct target_sigaction *act, return (ret); } -#if defined(TARGET_MIPS) || defined(TARGET_SPARC64) +#if defined(TARGET_MIPS64) /* || defined(TARGET_SPARC64) */ static inline abi_ulong get_sigframe(struct target_sigaction *ka, CPUArchState *regs, size_t frame_size) @@ -629,8 +636,8 @@ get_sigframe(struct target_sigaction *ka, CPUArchState *regs, size_t frame_size) } /* compare to mips/mips/pm_machdep.c and sparc64/sparc64/machdep.c sendsig() */ -static void setup_frame(int sig, struct target_sigaction *ka, - target_sigset_t *set, CPUArchState *regs) +static void setup_frame(int sig, int code, struct target_sigaction *ka, + target_sigset_t *set, target_siginfo_t *tinfo, CPUArchState *regs) { struct target_sigframe *frame; abi_ulong frame_addr; @@ -651,6 +658,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) goto give_sigsegv; + memset(frame, 0, sizeof(*frame)); #if defined(TARGET_MIPS) int mflags = on_sig_stack(frame_addr) ? TARGET_MC_ADD_MAGIC : TARGET_MC_SET_ONSTACK | TARGET_MC_ADD_MAGIC; @@ -666,6 +674,58 @@ static void setup_frame(int sig, struct target_sigaction *ka, goto give_sigsegv; } + if (tinfo) { + frame->sf_si.si_signo = tinfo->si_signo; + frame->sf_si.si_errno = tinfo->si_errno; + frame->sf_si.si_code = tinfo->si_code; + frame->sf_si.si_pid = tinfo->si_pid; + frame->sf_si.si_uid = tinfo->si_uid; + frame->sf_si.si_status = tinfo->si_status; + frame->sf_si.si_addr = tinfo->si_addr; + + if (TARGET_SIGILL == sig || TARGET_SIGFPE == sig || + TARGET_SIGSEGV == sig || TARGET_SIGBUS == sig || + TARGET_SIGTRAP == sig) + frame->sf_si._reason._fault._trapno = + tinfo->_reason._fault._trapno; + + /* + * If si_code is one of SI_QUEUE, SI_TIMER, SI_ASYNCIO, or + * SI_MESGQ, then si_value contains the application-specified + * signal value. Otherwise, the contents of si_value are + * undefined. + */ + if (SI_QUEUE == code || SI_TIMER == code || + SI_ASYNCIO == code || SI_MESGQ == code) { + frame->sf_si.si_value.sival_int = + tinfo->si_value.sival_int; + } + + if (SI_TIMER == code) { + frame->sf_si._reason._timer._timerid = + tinfo->_reason._timer._timerid; + frame->sf_si._reason._timer._overrun = + tinfo->_reason._timer._overrun; + } + +#ifdef SIGPOLL + if (SIGPOLL == sig) { + frame->sf_si._reason._band = + tinfo->_reason._band; + } +#endif + + frame->sf_signum = sig; + frame->sf_siginfo = (abi_ulong)&frame->sf_si; + frame->sf_ucontext = (abi_ulong)&frame->sf_uc; + + } else { + frame->sf_signum = sig; + frame->sf_siginfo = 0; + frame->sf_ucontext = 0; + } + + if (set_sigtramp_args(regs, sig, frame, frame_addr, ka)) goto give_sigsegv; @@ -866,8 +926,8 @@ get_sigframe(struct target_sigaction *ka, CPUSPARCState *regs, size_t frame_size } /* compare to sparc64/sparc64/machdep.c sendsig() */ -static void setup_frame(int sig, struct target_sigaction *ka, - target_sigset_t *set, CPUSPARCState *regs) +static void setup_frame(int sig, int code, struct target_sigaction *ka, + target_sigset_t *set, target_siginfo_t *tinfo, CPUSPARCState *regs) { struct target_sigframe *frame; abi_ulong frame_addr; @@ -960,21 +1020,12 @@ badframe: #else static void -setup_frame(int sig, struct target_sigaction *ka, target_sigset_t *set, - CPUArchState *env) +setup_frame(int sig, int code, struct target_sigaction *ka, target_sigset_t *set, + target_siginfo_t *tinfo, CPUArchState *env) { fprintf(stderr, "setup_frame: not implemented\n"); } -#if 0 -static void -setup_rt_frame(int sig, struct target_sigaction *ka, target_siginfo_t *info, - target_sigset_t *set, CPUArchState *env) -{ - fprintf(stderr, "setup_rt_frame: not implemented\n"); -} -#endif - long do_sigreturn(CPUArchState *env, abi_ulong uc_addr) { @@ -1043,13 +1094,14 @@ signal_init(void) void process_pending_signals(CPUArchState *cpu_env) { - int sig; + int sig, code; abi_ulong handler; sigset_t set, old_set; target_sigset_t target_old_set; + target_siginfo_t tinfo; struct emulated_sigtable *k; struct target_sigaction *sa; - struct sigqueue *q; + struct qemu_sigqueue *q; TaskState *ts = cpu_env->opaque; if (!ts->signal_pending) @@ -1143,14 +1195,16 @@ handle_signal: } #endif #endif + code = q->info.si_code; /* prepare the stack frame of the virtual CPU */ -#if 0 /* XXX no rt for fbsd */ - if (sa->sa_flags & TARGET_SA_SIGINFO) - setup_rt_frame(sig, sa, &q->info, &target_old_set, + if (sa->sa_flags & TARGET_SA_SIGINFO) { + tswap_siginfo(&tinfo, &q->info); + setup_frame(sig, code, sa, &target_old_set, &tinfo, cpu_env); - else -#endif - setup_frame(sig, sa, &target_old_set, cpu_env); + } else { + setup_frame(sig, code, sa, &target_old_set, NULL, + cpu_env); + } if (sa->sa_flags & TARGET_SA_RESETHAND) sa->_sa_handler = TARGET_SIG_DFL; } diff --git a/bsd-user/strace.c b/bsd-user/strace.c index d73bbca..7f0f7bd 100644 --- a/bsd-user/strace.c +++ b/bsd-user/strace.c @@ -4,7 +4,12 @@ #include #include #include +#include +#include #include "qemu.h" +#ifdef __FreeBSD__ +#include "freebsd/syscall_nr.h" +#endif int do_strace=0; @@ -23,6 +28,29 @@ struct syscallname { */ static void +print_sysctl(const struct syscallname *name, + abi_long arg1, abi_long arg2, abi_long arg3, + abi_long arg4, abi_long arg5, abi_long arg6) +{ + uint32_t i; + int32_t *namep; + + + gemu_log("%s({ ", name->name); + namep = lock_user(VERIFY_READ, arg1, sizeof(int32_t) * arg2, 1); + if (namep) { + int32_t *p = namep; + + for(i = 0; i < (uint32_t)arg2; i++) + gemu_log("%d ", tswap32(*p++)); + unlock_user(namep, arg1, 0); + } + gemu_log("}, %u, 0x" TARGET_ABI_FMT_lx ", 0x" TARGET_ABI_FMT_lx ", 0x" + TARGET_ABI_FMT_lx ", 0x" TARGET_ABI_FMT_lx ")", + (uint32_t)arg2, arg3, arg4, arg5, arg6); +} + +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) @@ -30,10 +58,18 @@ print_execve(const struct syscallname *name, 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); +#ifdef __FreeBSD__ + if (TARGET_FREEBSD_NR_fexecve == name->nr) { + gemu_log("%s(%d,{", name->name, (int)arg1); + + } else +#endif + { + 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; @@ -54,6 +90,54 @@ print_execve(const struct syscallname *name, gemu_log("NULL})"); } +static void +print_ioctl(const struct syscallname *name, + abi_long arg1, abi_long arg2, abi_long arg3, + abi_long arg4, abi_long arg5, abi_long arg6) +{ + /* Decode the ioctl request */ + gemu_log("%s(%d, 0x%0lx { IO%s%s GRP:0x%x('%c') CMD:%d LEN:%d }, 0x" + TARGET_ABI_FMT_lx ", ...)", + + name->name, + (int)arg1, + (unsigned long)arg2, + arg2 & IOC_OUT ? "R" : "", + arg2 & IOC_IN ? "W" : "", + (unsigned)IOCGROUP(arg2), + isprint(IOCGROUP(arg2)) ? (char)IOCGROUP(arg2) : '?', + (int)arg2 & 0xFF, + (int)IOCPARM_LEN(arg2), + arg3); +} + +static void +print_sysarch(const struct syscallname *name, + abi_long arg1, abi_long arg2, abi_long arg3, + abi_long arg4, abi_long arg5, abi_long arg6) +{ +#ifdef TARGET_MIPS + switch(arg1) { + case 1: + gemu_log("%s(SET_TLS, 0x" TARGET_ABI_FMT_lx ")", + name->name, arg2); + break; + + case 2: + gemu_log("%s(GET_TLS, 0x" TARGET_ABI_FMT_lx ")", + name->name, arg2); + break; + + default: + gemu_log("UNKNOWN OP: %d, " TARGET_ABI_FMT_lx ")", + (int)arg1, arg2); + } +#else + gemu_log("%s(%d, " TARGET_ABI_FMT_lx ", " TARGET_ABI_FMT_lx ", " + TARGET_ABI_FMT_lx ")", name->name, (int)arg1, arg2, arg3, arg4); +#endif +} + /* * Variants for the return value output function */ diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c index 8565ae8..74b5c86 100644 --- a/bsd-user/syscall.c +++ b/bsd-user/syscall.c @@ -2,7 +2,7 @@ * BSD syscalls * * Copyright (c) 2003 - 2008 Fabrice Bellard - * Copyright (c) 2012 Stacey Son + * Copyright (c) 2012 - 2013 Stacey Son * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -68,8 +69,12 @@ #include #endif #include +#include #include #include +#define _ACL_PRIVATE +#include +#include #include #include #include @@ -87,6 +92,7 @@ #include "qemu-common.h" #ifdef __FreeBSD__ #include "freebsd/ttycom.h" +#include "freebsd/filio.h" #endif @@ -95,6 +101,70 @@ static abi_ulong target_brk; static abi_ulong target_original_brk; +static char *get_filename_from_fd(pid_t pid, int fd, char *filename, size_t len); + +#ifdef __FreeBSD__ +#include +#include +#include + + +/* + * Get the filename for the given file descriptor. + * Note that this may return NULL (fail) if no longer cached in the kernel. + */ +static char * +get_filename_from_fd(pid_t pid, int fd, char *filename, size_t len) +{ + unsigned int cnt; + struct procstat *procstat = NULL; + struct kinfo_proc *kipp = NULL; + struct filestat_list *head = NULL; + struct filestat *fst; + char *ret = NULL; + + procstat = procstat_open_sysctl(); + if (NULL == procstat) + goto out; + + kipp = procstat_getprocs(procstat, KERN_PROC_PID, pid, &cnt); + if (NULL == kipp) + goto out; + + head = procstat_getfiles(procstat, kipp, 0); + if (NULL == head) + goto out; + + STAILQ_FOREACH(fst, head, next) { + if (fd == fst->fs_fd) { + if (fst->fs_path != NULL) { + (void)strlcpy(filename, fst->fs_path, len); + ret = filename; + } + break; + } + } + +out: + if (head != NULL) + procstat_freefiles(procstat, head); + if (kipp != NULL) + procstat_freeprocs(procstat, kipp); + if (procstat != NULL) + procstat_close(procstat); + return (ret); +} + +#else + +static char * +get_filename_from_fd(pid_t pid, int fd, char *filename, size_t len) +{ + return (NULL); +} + +#endif /* ! __FreeBSD__ */ + static inline abi_long get_errno(abi_long ret) { if (ret == -1) @@ -297,9 +367,9 @@ static abi_long do_freebsd_sysarch(void *env, int op, abi_ulong parms) switch(op) { case TARGET_MIPS_SET_TLS: - if (get_user(mips_env->tls_value, parms, abi_ulong)) - ret = -TARGET_EFAULT; + mips_env->tls_value = parms; break; + case TARGET_MIPS_GET_TLS: if (put_user(mips_env->tls_value, parms, abi_ulong)) ret = -TARGET_EFAULT; @@ -386,24 +456,46 @@ static int sysctl_oldcvt(void *holdp, size_t holdlen, uint32_t kind) return 0; } +/* + * Convert the undocmented name2oid sysctl data for the target. + */ +static inline void +sysctl_name2oid(uint32_t *holdp, size_t holdlen) +{ + size_t i; + + for(i = 0; i < holdlen; i++) + holdp[i] = tswap32(holdp[i]); +} + +static inline void +sysctl_oidfmt(uint32_t *holdp) +{ + /* byte swap the kind */ + holdp[0] = tswap32(holdp[0]); +} + /* XXX this needs to be emulated on non-FreeBSD hosts... */ static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen) { abi_long ret; - void *hnamep, *holdp, *hnewp = NULL; + void *hnamep, *holdp = NULL, *hnewp = NULL; size_t holdlen; abi_ulong oldlen = 0; int32_t *snamep = g_malloc(sizeof(int32_t) * namelen), *p, *q, i; uint32_t kind = 0; + abi_ulong argv, argv0; + char *fullpath = NULL; if (oldlenp) - get_user_ual(oldlen, oldlenp); + if (get_user_ual(oldlen, oldlenp)) + return -TARGET_EFAULT; if (!(hnamep = lock_user(VERIFY_READ, namep, namelen, 1))) return -TARGET_EFAULT; if (newp && !(hnewp = lock_user(VERIFY_READ, newp, newlen, 1))) return -TARGET_EFAULT; - if (!(holdp = lock_user(VERIFY_WRITE, oldp, oldlen, 0))) + if (oldp && !(holdp = lock_user(VERIFY_WRITE, oldp, oldlen, 0))) return -TARGET_EFAULT; holdlen = oldlen; for (p = hnamep, q = snamep, i = 0; i < namelen; p++, i++) @@ -411,7 +503,8 @@ static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong ol oidfmt(snamep, namelen, NULL, &kind); /* Handle some arch/emulator dependent sysctl()'s here. */ - if (CTL_KERN == snamep[0]) { + switch(snamep[0]) { + case CTL_KERN: switch(snamep[1]) { case KERN_USRSTACK: #if defined(TARGET_ARM) && HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32 @@ -437,17 +530,77 @@ static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong ol #endif goto out; + case KERN_PROC: + switch(snamep[2]) { + case KERN_PROC_PATHNAME: + if (get_user_ual(argv, TARGET_PS_STRINGS)) { + ret = -TARGET_EFAULT; + goto out; + } + if (get_user_ual(argv0, argv)) { + ret = -TARGET_EFAULT; + goto out; + } + + fullpath = realpath(g2h(argv0), NULL); + if (NULL == fullpath) + fullpath = (char *)g2h(argv0); + holdlen = strlen(fullpath) + 1; + if (holdp) { + if (oldlen < holdlen) { + ret = -TARGET_EINVAL; + goto out; + } + if (!access_ok(VERIFY_WRITE, argv0, + holdlen)) { + ret = -TARGET_EFAULT; + goto out; + } + strlcpy(holdp, fullpath, oldlen); + } + ret = 0; + goto out; + + default: + break; + } + break; + default: break; } + break; + + default: + break; } ret = get_errno(sysctl(snamep, namelen, holdp, &holdlen, hnewp, newlen)); - if (!ret) - sysctl_oldcvt(holdp, holdlen, kind); + if (!ret && (holdp != 0 && holdlen != 0)) { + if (0 == snamep[0] && (3 == snamep[1] || 4 == snamep[1])) { + if (3 == snamep[1]) { + /* Handle the undocumented name2oid special case. */ + sysctl_name2oid(holdp, holdlen); + } else { + /* Handle oidfmt */ + sysctl_oidfmt(holdp); + } + } else { + sysctl_oldcvt(holdp, holdlen, kind); + } + } +#ifdef DEBUG + else { + printf("sysctl(mib[0]=%d, mib[1]=%d, mib[3]=%d...) returned %d\n", + snamep[0], snamep[1], snamep[2], (int)ret); + } +#endif out: - put_user_ual(holdlen, oldlenp); + if (fullpath) + free(fullpath); + if (oldlenp) + put_user_ual(holdlen, oldlenp); unlock_user(hnamep, namep, 0); unlock_user(holdp, oldp, holdlen); if (hnewp) @@ -509,6 +662,24 @@ static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr, } static inline abi_long +target_to_host_ip_mreq(struct ip_mreqn *mreqn, abi_ulong target_addr, + socklen_t len) +{ + struct target_ip_mreqn *target_smreqn; + + target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1); + if (!target_smreqn) + return -TARGET_EFAULT; + mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr; + mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr; + if (len == sizeof(struct target_ip_mreqn)) + mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex); + unlock_user(target_smreqn, target_addr, 0); + + return (0); +} + +static inline abi_long target_to_host_sockaddr(struct sockaddr *addr, abi_ulong target_addr, socklen_t len) { @@ -1554,11 +1725,62 @@ int_case: } break; + case IPPROTO_TCP: + /* TCP options all take an 'int' value. */ + goto int_case; + + case IPPROTO_IP: + switch(optname) { + case IP_HDRINCL: + case IP_TOS: + case IP_TTL: + case IP_RECVOPTS: + case IP_RECVRETOPTS: + case IP_RECVDSTADDR: + + case IP_RETOPTS: + case IP_RECVTOS: + case IP_MULTICAST_TTL: + case IP_MULTICAST_LOOP: + case IP_PORTRANGE: + case IP_IPSEC_POLICY: + case IP_FAITH: + case IP_ONESBCAST: + case IP_BINDANY: + if (get_user_u32(len, optlen)) + return (-TARGET_EFAULT); + if (len < 0) + return (-TARGET_EINVAL); + lv = sizeof(lv); + ret = get_errno(getsockopt(sockfd, level, optname, + &val, &lv)); + if (ret < 0) + return (ret); + if (len < sizeof(int) && len > 0 && val >= 0 && + val < 255) { + len = 1; + if (put_user_u32(len, optlen) + || put_user_u8(val, optval_addr)) + return (-TARGET_EFAULT); + } else { + if (len > sizeof(int)) + len = sizeof(int); + if (put_user_u32(len, optlen) + || put_user_u32(val, optval_addr)) + return (-TARGET_EFAULT); + } + break; + + default: + goto unimplemented; + } + break; + default: unimplemented: gemu_log("getsockopt level=%d optname=%d not yet supported\n", level, optname); - ret = -TARGET_EOPNOTSUPP; + ret = (-TARGET_EOPNOTSUPP); break; } return (ret); @@ -1569,10 +1791,67 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, abi_ulong optval_addr, socklen_t optlen) { - int val; abi_long ret; + int val; + struct ip_mreqn *ip_mreq; switch(level) { + case IPPROTO_TCP: + /* TCP options all take an 'int' value. */ + if (optlen < sizeof(uint32_t)) + return (-TARGET_EINVAL); + + if (get_user_u32(val, optval_addr)) + return (-TARGET_EFAULT); + ret = get_errno(setsockopt(sockfd, level, optname, &val, + sizeof(val))); + break; + + case IPPROTO_IP: + switch (optname) { + case IP_HDRINCL:/* int; header is included with data */ + case IP_TOS: /* int; IP type of service and preced. */ + case IP_TTL: /* int; IP time to live */ + case IP_RECVOPTS: /* bool; receive all IP opts w/dgram */ + case IP_RECVRETOPTS: /* bool; receive IP opts for response */ + case IP_RECVDSTADDR: /* bool; receive IP dst addr w/dgram */ + case IP_MULTICAST_IF:/* u_char; set/get IP multicast i/f */ + case IP_MULTICAST_TTL:/* u_char; set/get IP multicast ttl */ + case IP_MULTICAST_LOOP:/*u_char;set/get IP multicast loopback */ + case IP_PORTRANGE: /* int; range to choose for unspec port */ + case IP_RECVIF: /* bool; receive reception if w/dgram */ + case IP_IPSEC_POLICY: /* int; set/get security policy */ + case IP_FAITH: /* bool; accept FAITH'ed connections */ + case IP_RECVTTL: /* bool; receive reception TTL w/dgram */ + val = 0; + if (optlen >= sizeof(uint32_t)) { + if (get_user_u32(val, optval_addr)) + return (-TARGET_EFAULT); + } else if (optlen >= 1) { + if (get_user_u8(val, optval_addr)) + return (-TARGET_EFAULT); + } + ret = get_errno(setsockopt(sockfd, level, optname, + &val, sizeof(val))); + break; + + case IP_ADD_MEMBERSHIP: /*ip_mreq; add an IP group membership */ + case IP_DROP_MEMBERSHIP:/*ip_mreq; drop an IP group membership*/ + if (optlen < sizeof (struct target_ip_mreq) || + optlen > sizeof (struct target_ip_mreqn)) + return (-TARGET_EINVAL); + ip_mreq = (struct ip_mreqn *) alloca(optlen); + target_to_host_ip_mreq(ip_mreq, optval_addr, optlen); + ret = get_errno(setsockopt(sockfd, level, optname, + ip_mreq, optlen)); + break; + + default: + goto unimplemented; + } + break; + + case TARGET_SOL_SOCKET: switch (optname) { /* Options with 'int' argument. */ @@ -1730,13 +2009,15 @@ target_to_host_semarray(int semid, unsigned short **host_array, if (ret == -1) return (get_errno(ret)); nsems = semid_ds.sem_nsems; - *host_array = malloc(nsems * sizeof(unsigned short)); + *host_array = (unsigned short *)malloc(nsems * sizeof(unsigned short)); array = lock_user(VERIFY_READ, target_addr, nsems*sizeof(unsigned short), 1); - if (!array) + if (!array) { + free(*host_array); return (-TARGET_EFAULT); + } for(i=0; isem_perm); - host_ip->cuid = tswapal(target_ip->cuid); - host_ip->cgid = tswapal(target_ip->cgid); - host_ip->uid = tswapal(target_ip->uid); - host_ip->gid = tswapal(target_ip->gid); + host_ip->cuid = tswap32(target_ip->cuid); + host_ip->cgid = tswap32(target_ip->cgid); + host_ip->uid = tswap32(target_ip->uid); + host_ip->gid = tswap32(target_ip->gid); host_ip->mode = tswap16(target_ip->mode); host_ip->seq = tswap16(target_ip->seq); host_ip->key = tswapal(target_ip->key); - unlock_user_struct(target_sd, target_addr, 0); + unlock_user_struct(target_ip, target_addr, 0); return (0); } @@ -1800,18 +2082,17 @@ static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr, struct ipc_perm *host_ip) { struct target_ipc_perm *target_ip; - struct target_semid_ds *target_sd; - if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) + + if (!lock_user_struct(VERIFY_WRITE, target_ip, target_addr, 0)) return (-TARGET_EFAULT); - target_ip = &(target_sd->sem_perm); - target_ip->cuid = tswapal(host_ip->cuid); - target_ip->cgid = tswapal(host_ip->cgid); - target_ip->uid = tswapal(host_ip->uid); - target_ip->gid = tswapal(host_ip->gid); + target_ip->cuid = tswap32(host_ip->cuid); + target_ip->cgid = tswap32(host_ip->cgid); + target_ip->uid = tswap32(host_ip->uid); + target_ip->gid = tswap32(host_ip->gid); target_ip->mode = tswap16(host_ip->mode); target_ip->seq = tswap16(host_ip->seq); target_ip->key = tswapal(host_ip->key); - unlock_user_struct(target_sd, target_addr, 1); + unlock_user_struct(target_ip, target_addr, 1); return (0); } @@ -1822,11 +2103,12 @@ target_to_host_semid_ds(struct semid_ds *host_sd, abi_ulong target_addr) if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) return (-TARGET_EFAULT); - if (target_to_host_ipc_perm(&(host_sd->sem_perm), target_addr)) + if (target_to_host_ipc_perm(&(host_sd->sem_perm), (target_addr + + offsetof(struct target_semid_ds, sem_perm)) )) return (-TARGET_EFAULT); /* sem_base is not used by kernel for IPC_STAT/IPC_SET */ - host_sd->sem_base = NULL; - host_sd->sem_nsems = tswapal(target_sd->sem_nsems); + /* host_sd->sem_base = g2h(target_sd->sem_base); */ + host_sd->sem_nsems = tswap16(target_sd->sem_nsems); host_sd->sem_otime = tswapal(target_sd->sem_otime); host_sd->sem_ctime = tswapal(target_sd->sem_ctime); unlock_user_struct(target_sd, target_addr, 0); @@ -1840,10 +2122,13 @@ host_to_target_semid_ds(abi_ulong target_addr, struct semid_ds *host_sd) if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) return (-TARGET_EFAULT); - if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm))) + if (host_to_target_ipc_perm((target_addr + + offsetof(struct target_semid_ds, sem_perm)), + &(host_sd->sem_perm))) return (-TARGET_EFAULT); /* sem_base is not used by kernel for IPC_STAT/IPC_SET */ - target_sd->sem_nsems = tswapal(host_sd->sem_nsems); + /* target_sd->sem_base = h2g((void *)host_sd->sem_base); */ + target_sd->sem_nsems = tswap16(host_sd->sem_nsems); target_sd->sem_otime = tswapal(host_sd->sem_otime); target_sd->sem_ctime = tswapal(host_sd->sem_ctime); unlock_user_struct(target_sd, target_addr, 1); @@ -1859,6 +2144,7 @@ do_semctl(int semid, int semnum, int cmd, union target_semun target_su) unsigned short *array = NULL; abi_long ret = -TARGET_EINVAL; abi_long err; + abi_ulong target_addr; cmd &= 0xff; @@ -1872,24 +2158,28 @@ do_semctl(int semid, int semnum, int cmd, union target_semun target_su) case GETALL: case SETALL: - err = target_to_host_semarray(semid, &array, target_su.array); + if (get_user_ual(target_addr, (abi_ulong)target_su.array)) + return (-TARGET_EFAULT); + err = target_to_host_semarray(semid, &array, target_addr); if (err) return (err); arg.array = array; ret = get_errno(semctl(semid, semnum, cmd, arg)); - err = host_to_target_semarray(semid, target_su.array, &array); + err = host_to_target_semarray(semid, target_addr, &array); if (err) return (err); break; case IPC_STAT: case IPC_SET: - err = target_to_host_semid_ds(&dsarg, target_su.buf); + if (get_user_ual(target_addr, (abi_ulong)target_su.buf)) + return (-TARGET_EFAULT); + err = target_to_host_semid_ds(&dsarg, target_addr); if (err) return (err); arg.buf = &dsarg; ret = get_errno(semctl(semid, semnum, cmd, arg)); - err = host_to_target_semid_ds(target_su.buf, &dsarg); + err = host_to_target_semid_ds(target_addr, &dsarg); if (err) return (err); break; @@ -3383,6 +3673,64 @@ host_to_target_sched_param(abi_ulong target_addr, struct sched_param *host_sp) } static inline abi_long +target_to_host_acl(struct acl *host_acl, abi_ulong target_addr) +{ + uint32_t i; + struct target_acl *target_acl; + + if (!lock_user_struct(VERIFY_READ, target_acl, target_addr, 1)) + return (-TARGET_EFAULT); + + __get_user(host_acl->acl_maxcnt, &target_acl->acl_maxcnt); + __get_user(host_acl->acl_cnt, &target_acl->acl_cnt); + + for(i = 0; i < host_acl->acl_maxcnt; i++) { + __get_user(host_acl->acl_entry[i].ae_tag, + &target_acl->acl_entry[i].ae_tag); + __get_user(host_acl->acl_entry[i].ae_id, + &target_acl->acl_entry[i].ae_id); + __get_user(host_acl->acl_entry[i].ae_perm, + &target_acl->acl_entry[i].ae_perm); + __get_user(host_acl->acl_entry[i].ae_entry_type, + &target_acl->acl_entry[i].ae_entry_type); + __get_user(host_acl->acl_entry[i].ae_flags, + &target_acl->acl_entry[i].ae_flags); + } + + unlock_user_struct(target_acl, target_addr, 0); + return (0); +} + +static inline abi_long +host_to_target_acl(abi_ulong target_addr, struct acl *host_acl) +{ + uint32_t i; + struct target_acl *target_acl; + + if (!lock_user_struct(VERIFY_WRITE, target_acl, target_addr, 0)) + return (-TARGET_EFAULT); + + __put_user(host_acl->acl_maxcnt, &target_acl->acl_maxcnt); + __put_user(host_acl->acl_cnt, &target_acl->acl_cnt); + + for(i = 0; i < host_acl->acl_maxcnt; i++) { + __put_user(host_acl->acl_entry[i].ae_tag, + &target_acl->acl_entry[i].ae_tag); + __put_user(host_acl->acl_entry[i].ae_id, + &target_acl->acl_entry[i].ae_id); + __put_user(host_acl->acl_entry[i].ae_perm, + &target_acl->acl_entry[i].ae_perm); + __get_user(host_acl->acl_entry[i].ae_entry_type, + &target_acl->acl_entry[i].ae_entry_type); + __get_user(host_acl->acl_entry[i].ae_flags, + &target_acl->acl_entry[i].ae_flags); + } + + unlock_user_struct(target_acl, target_addr, 1); + return (0); +} + +static inline abi_long do_sched_setparam(pid_t pid, abi_ulong target_sp_addr) { int ret; @@ -3993,10 +4341,10 @@ static IOCTLEntry ioctl_entries[] = { { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } }, #define IOCTL_SPECIAL(cmd, access, dofn, ...) \ { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } }, -#ifdef __FreeBSD__ -#include "freebsd/ioctl.h" +#if defined(__FreeBSD__) +#include "freebsd/ioctls.h" #else -#warning No ioctl.h +#warning No *bsd/ioctls.h #endif { 0, 0 }, }; @@ -4096,6 +4444,158 @@ do_ioctl(int fd, abi_long cmd, abi_long arg) return (ret); } +static inline abi_long +freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp, + abi_ulong guest_envp, int do_fexec) +{ + char **argp, **envp, **qargp, **qarg1; + int argc, envc; + abi_ulong gp; + abi_ulong addr; + char **q; + int total_size = 0; + void *p; + abi_long ret; + + argc = 0; + for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) { + if (get_user_ual(addr, gp)) + return (-TARGET_EFAULT); + if (!addr) + break; + argc++; + } + envc = 0; + for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) { + if (get_user_ual(addr, gp)) + return (-TARGET_EFAULT); + if (!addr) + break; + envc++; + } + + qargp = argp = alloca((argc + 3) * sizeof(void *)); + /* save the first agrument for the emulator */ + *argp++ = (char *)getprogname(); + qarg1 = argp; + envp = alloca((envc + 1) * sizeof(void *)); + for (gp = guest_argp, q = argp; gp; gp += sizeof(abi_ulong), q++) { + if (get_user_ual(addr, gp)) { + ret = -TARGET_EFAULT; + goto execve_end; + } + if (!addr) + break; + if (!(*q = lock_user_string(addr))) { + ret = -TARGET_EFAULT; + goto execve_end; + } + total_size += strlen(*q) + 1; + } + *q = NULL; + + for (gp = guest_envp, q = envp; gp; gp += sizeof(abi_ulong), q++) { + if (get_user_ual(addr, gp)) { + ret = -TARGET_EFAULT; + goto execve_end; + } + if (!addr) + break; + if (!(*q = lock_user_string(addr))) { + ret = -TARGET_EFAULT; + goto execve_end; + } + total_size += strlen(*q) + 1; + } + *q = NULL; + + /* + * This case will not be caught by the host's execve() if its + * page size is bigger than the target's. + */ + if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) { + ret = -TARGET_E2BIG; + goto execve_end; + } + + if (do_fexec) { + if (((int)path_or_fd > 0 && + is_target_elf_binary((int)path_or_fd)) == 1) { + char execpath[PATH_MAX]; + + /* + * The executable is an elf binary for the target + * arch. execve() it using the emulator if we can + * determine the filename path from the fd. + */ + if (get_filename_from_fd(getpid(), (int)path_or_fd, + execpath, sizeof(execpath)) != NULL) { + *qarg1 = execpath; + ret = get_errno(execve(qemu_proc_pathname, + qargp, envp)); + } else { + /* Getting the filename path failed. */ + ret = -TARGET_EBADF; + goto execve_end; + } + } else { + ret = get_errno(fexecve((int)path_or_fd, argp, envp)); + } + } else { + int fd; + + if (!(p = lock_user_string(path_or_fd))) { + ret = -TARGET_EFAULT; + goto execve_end; + } + + /* + * Check the header and see if it a target elf binary. If so + * then execute using qemu user mode emulator. + */ + fd = open(p, O_RDONLY | O_CLOEXEC); + if (fd > 0 && is_target_elf_binary(fd) == 1) { + close(fd); + /* Execve() as a target binary using emulator. */ + *qarg1 = (char *)p; + ret = get_errno(execve(qemu_proc_pathname, qargp, envp)); + } else { + close(fd); + /* Execve() as a host native binary. */ + ret = get_errno(execve(p, argp, envp)); + } + unlock_user(p, path_or_fd, 0); + } + +execve_end: + for (gp = guest_argp, q = argp; *q; gp += sizeof(abi_ulong), q++) { + if (get_user_ual(addr, gp) || !addr) + break; + unlock_user(*q, addr, 0); + } + + for (gp = guest_envp, q = envp; *q; gp += sizeof(abi_ulong), q++) { + if (get_user_ual(addr, gp) || !addr) + break; + unlock_user(*q, addr, 0); + } + return (ret); +} + +static inline abi_long +do_freebsd_execve(abi_ulong path_or_fd, abi_ulong argp, abi_ulong envp) +{ + + return (freebsd_exec_common(path_or_fd, argp, envp, 0)); +} + +static inline abi_long +do_freebsd_fexecve(abi_ulong path_or_fd, abi_ulong argp, abi_ulong envp) +{ + + return (freebsd_exec_common(path_or_fd, argp, envp, 1)); +} + /* 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_. */ @@ -4515,96 +5015,14 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, #endif case TARGET_FREEBSD_NR_execve: - { - char **argp, **envp; - int argc, envc; - abi_ulong gp; - abi_ulong guest_argp; - abi_ulong guest_envp; - abi_ulong addr; - char **q; - int total_size = 0; - - argc = 0; - guest_argp = arg2; - for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) { - if (get_user_ual(addr, gp)) - goto efault; - if (!addr) - break; - argc++; - } - envc = 0; - guest_envp = arg3; - for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) { - if (get_user_ual(addr, gp)) - goto efault; - if (!addr) - break; - envc++; - } - - argp = alloca((argc + 1) * sizeof(void *)); - envp = alloca((envc + 1) * sizeof(void *)); - - for (gp = guest_argp, q = argp; gp; - gp += sizeof(abi_ulong), q++) { - if (get_user_ual(addr, gp)) - goto execve_efault; - if (!addr) - break; - if (!(*q = lock_user_string(addr))) - goto execve_efault; - total_size += strlen(*q) + 1; - } - *q = NULL; - - for (gp = guest_envp, q = envp; gp; - gp += sizeof(abi_ulong), q++) { - if (get_user_ual(addr, gp)) - goto execve_efault; - if (!addr) - break; - if (!(*q = lock_user_string(addr))) - goto execve_efault; - total_size += strlen(*q) + 1; - } - *q = NULL; - - /* This case will not be caught by the host's execve() if its - page size is bigger than the target's. */ - if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) { - ret = -TARGET_E2BIG; - goto execve_end; - } - if (!(p = lock_user_string(arg1))) - goto execve_efault; - ret = get_errno(execve(p, argp, envp)); - unlock_user(p, arg1, 0); - - goto execve_end; - - execve_efault: - ret = -TARGET_EFAULT; + ret = do_freebsd_execve(arg1, arg2, arg3); + break; - execve_end: - for (gp = guest_argp, q = argp; *q; - gp += sizeof(abi_ulong), q++) { - if (get_user_ual(addr, gp) - || !addr) - break; - unlock_user(*q, addr, 0); - } - for (gp = guest_envp, q = envp; *q; - gp += sizeof(abi_ulong), q++) { - if (get_user_ual(addr, gp) - || !addr) - break; - unlock_user(*q, addr, 0); - } - } + case TARGET_FREEBSD_NR_fexecve: + ret = do_freebsd_fexecve(arg1, arg2, arg3); break; + case TARGET_FREEBSD_NR_pipe: { int host_pipe[2]; @@ -5296,11 +5714,11 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_F_SETLKW: if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) return (-TARGET_EFAULT); - fl.l_type = tswap16(target_fl->l_type); - fl.l_whence = tswap16(target_fl->l_whence); fl.l_start = tswapal(target_fl->l_start); fl.l_len = tswapal(target_fl->l_len); fl.l_pid = tswap32(target_fl->l_pid); + fl.l_type = tswap16(target_fl->l_type); + fl.l_whence = tswap16(target_fl->l_whence); fl.l_sysid = tswap32(target_fl->l_sysid); unlock_user_struct(target_fl, arg3, 0); ret = get_errno(fcntl(arg1, host_cmd, &fl)); @@ -5370,13 +5788,16 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, if (reclen > len) break; de->d_reclen = tswap16(reclen); + de->d_fileno = tswap32(de->d_fileno); len -= reclen; + de = (struct dirent *)((void *)de + reclen); } } unlock_user(dirp, arg2, ret); - if (arg4) - if (put_user(nbytes, arg4, abi_ulong)) + if (arg4) { + if (put_user(basep, arg4, abi_ulong)) ret = -TARGET_EFAULT; + } } break; @@ -5431,32 +5852,406 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, break; - case TARGET_FREEBSD_NR___acl_get_file: - case TARGET_FREEBSD_NR___acl_set_file: - case TARGET_FREEBSD_NR___acl_get_fd: - case TARGET_FREEBSD_NR___acl_set_fd: - case TARGET_FREEBSD_NR___acl_delete_file: - case TARGET_FREEBSD_NR___acl_delete_fd: - case TARGET_FREEBSD_NR___acl_aclcheck_file: case TARGET_FREEBSD_NR___acl_aclcheck_fd: + { + struct acl host_acl; + + ret = target_to_host_acl(&host_acl, arg3); + if (!is_error(ret)) + ret = get_errno(__acl_aclcheck_fd(arg1, arg2, + &host_acl)); + } + break; + + case TARGET_FREEBSD_NR___acl_aclcheck_file: + { + struct acl host_acl; + + if (!(p = lock_user_string(arg1))) + goto efault; + + ret = target_to_host_acl(&host_acl, arg3); + if (!is_error(ret)) + ret = get_errno(__acl_aclcheck_file(path(p) , arg2, + &host_acl)); + + unlock_user(p, arg1, 0); + } + break; + + case TARGET_FREEBSD_NR___acl_aclcheck_link: + { + struct acl host_acl; + + if (!(p = lock_user_string(arg1))) + goto efault; + + ret = target_to_host_acl(&host_acl, arg3); + if (!is_error(ret)) + ret = get_errno(__acl_aclcheck_link(path(p), arg2, + &host_acl)); + + unlock_user(p, arg1, 0); + } + break; + + case TARGET_FREEBSD_NR___acl_delete_fd: + ret = get_errno(__acl_delete_fd(arg1, arg2)); + break; + + case TARGET_FREEBSD_NR___acl_delete_file: + if (!(p = lock_user_string(arg1))) + goto efault; + + ret = get_errno(__acl_delete_file(path(p), arg2)); + + unlock_user(p, arg1, 0); + break; + + case TARGET_FREEBSD_NR___acl_delete_link: + if (!(p = lock_user_string(arg1))) + goto efault; + + ret = get_errno(__acl_delete_link(path(p), arg2)); + + unlock_user(p, arg1, 0); + break; + + case TARGET_FREEBSD_NR___acl_get_fd: + { + struct acl host_acl; + + ret = get_errno(__acl_get_fd(arg1, arg2, &host_acl)); + + if (!is_error(ret)) + ret = host_to_target_acl(arg3, &host_acl); + } + break; + + case TARGET_FREEBSD_NR___acl_get_file: + { + struct acl host_acl; + + if (!(p = lock_user_string(arg1))) + goto efault; + + ret = get_errno(__acl_get_file(path(p), arg2, &host_acl)); + + if (!is_error(ret)) + ret = host_to_target_acl(arg3, &host_acl); + + unlock_user(p, arg1, 0); + } + break; + case TARGET_FREEBSD_NR___acl_get_link: + { + struct acl host_acl; + + if (!(p = lock_user_string(arg1))) + goto efault; + + ret = get_errno(__acl_get_link(path(p), arg2, &host_acl)); + + if (!is_error(ret)) + ret = host_to_target_acl(arg3, &host_acl); + + unlock_user(p, arg1, 0); + } + break; + + case TARGET_FREEBSD_NR___acl_set_fd: + { + struct acl host_acl; + + if (!(p = lock_user_string(arg1))) + goto efault; + + ret = target_to_host_acl(&host_acl, arg3); + if (!is_error(ret)) + ret = get_errno(__acl_set_fd(arg1, arg2, &host_acl)); + + unlock_user(p, arg1, 0); + } + break; + + case TARGET_FREEBSD_NR___acl_set_file: + { + struct acl host_acl; + + if (!(p = lock_user_string(arg1))) + goto efault; + + ret = target_to_host_acl(&host_acl, arg3); + if (!is_error(ret)) + ret = get_errno(__acl_set_file(path(p), arg2, + &host_acl)); + + unlock_user(p, arg1, 0); + } + break; + case TARGET_FREEBSD_NR___acl_set_link: - case TARGET_FREEBSD_NR___acl_delete_link: - case TARGET_FREEBSD_NR___acl_aclcheck_link: + { + struct acl host_acl; + + if (!(p = lock_user_string(arg1))) + goto efault; + + ret = target_to_host_acl(&host_acl, arg3); + if (!is_error(ret)) + ret = get_errno(__acl_set_link(path(p), arg2, + &host_acl)); + + unlock_user(p, arg1, 0); + } + break; + case TARGET_FREEBSD_NR_extattrctl: + { + void *a, *f; + + if (!(p = lock_user_string(arg1))) + goto efault; + if (!(f = lock_user_string(arg3))) + goto efault; + if (!(a = lock_user_string(arg5))) + goto efault; + + ret = get_errno(extattrctl(path(p), arg2, f, arg4, a)); + + unlock_user(a, arg5, 0); + unlock_user(f, arg3, 0); + unlock_user(p, arg1, 0); + } + break; + case TARGET_FREEBSD_NR_extattr_set_file: + { + void *a, *d; + + if (!(p = lock_user_string(arg1))) + goto efault; + if (!(a = lock_user_string(arg3))) + goto efault; + if (!(d = lock_user(VERIFY_READ, arg4, arg5, 1))) + goto efault; + + ret = get_errno(extattr_set_file(path(p), arg2, a, d, arg5)); + + unlock_user(d, arg4, arg5); + unlock_user(a, arg3, 0); + unlock_user(p, arg1, 0); + } + break; + case TARGET_FREEBSD_NR_extattr_get_file: + { + void *a, *d; + + if (!(p = lock_user_string(arg1))) + goto efault; + if (!(a = lock_user_string(arg3))) + goto efault; + + if (arg4 && arg5 > 0) { + if (!(d = lock_user(VERIFY_WRITE, arg4, arg5, 0))) + goto efault; + ret = get_errno(extattr_get_file(path(p), arg2, a, d, + arg5)); + unlock_user(d, arg4, arg5); + } else { + ret = get_errno(extattr_get_file(path(p), arg2, a, + NULL, arg5)); + } + unlock_user(a, arg3, 0); + unlock_user(p, arg1, 0); + } + break; + case TARGET_FREEBSD_NR_extattr_delete_file: + { + void *a; + + if (!(p = lock_user_string(arg1))) + goto efault; + if (!(a = lock_user_string(arg3))) + goto efault; + + ret = get_errno(extattr_delete_file(path(p), arg2, a)); + + unlock_user(a, arg3, 0); + unlock_user(p, arg1, 0); + } + break; + case TARGET_FREEBSD_NR_extattr_set_fd: + { + void *a, *d; + + if (!(a = lock_user_string(arg3))) + goto efault; + if (!(d = lock_user(VERIFY_READ, arg4, arg5, 1))) + goto efault; + + ret = get_errno(extattr_set_fd(arg1, arg2, a, d, arg5)); + + unlock_user(d, arg4, arg5); + unlock_user(a, arg3, 0); + } + break; + case TARGET_FREEBSD_NR_extattr_get_fd: + { + void *a, *d; + + if (!(a = lock_user_string(arg3))) + goto efault; + + if (arg4 && arg5 > 0) { + if (!(d = lock_user(VERIFY_WRITE, arg4, arg5, 0))) + goto efault; + ret = get_errno(extattr_get_fd(arg1, arg2, a, d, + arg5)); + unlock_user(d, arg4, arg5); + } else { + ret = get_errno(extattr_get_fd(arg1, arg2, a, + NULL, arg5)); + } + unlock_user(a, arg3, 0); + } + break; + case TARGET_FREEBSD_NR_extattr_delete_fd: + { + void *a; + + if (!(a = lock_user_string(arg3))) + goto efault; + + ret = get_errno(extattr_delete_fd(arg1, arg2, a)); + + unlock_user(a, arg3, 0); + } + break; + case TARGET_FREEBSD_NR_extattr_get_link: + { + void *a, *d; + + if (!(p = lock_user_string(arg1))) + goto efault; + if (!(a = lock_user_string(arg3))) + goto efault; + + if (arg4 && arg5 > 0) { + if (!(d = lock_user(VERIFY_WRITE, arg4, arg5, 0))) + goto efault; + ret = get_errno(extattr_get_link(path(p), arg2, a, d, + arg5)); + unlock_user(d, arg4, arg5); + } else { + ret = get_errno(extattr_get_link(path(p), arg2, a, + NULL, arg5)); + } + unlock_user(a, arg3, 0); + unlock_user(p, arg1, 0); + } + break; + case TARGET_FREEBSD_NR_extattr_set_link: + { + void *a, *d; + + if (!(p = lock_user_string(arg1))) + goto efault; + if (!(a = lock_user_string(arg3))) + goto efault; + if (!(d = lock_user(VERIFY_READ, arg4, arg5, 1))) + goto efault; + + ret = get_errno(extattr_set_link(path(p), arg2, a, d, arg5)); + + unlock_user(d, arg4, arg5); + unlock_user(a, arg3, 0); + unlock_user(p, arg1, 0); + } + break; + case TARGET_FREEBSD_NR_extattr_delete_link: + { + void *a; + + if (!(p = lock_user_string(arg1))) + goto efault; + if (!(a = lock_user_string(arg3))) + goto efault; + + ret = get_errno(extattr_delete_link(path(p), arg2, a)); + + unlock_user(a, arg3, 0); + unlock_user(p, arg1, 0); + } + break; + case TARGET_FREEBSD_NR_extattr_list_fd: + { + void *d; + + if (arg3 && arg4 > 0) { + if (!(d = lock_user(VERIFY_WRITE, arg3, arg4, 0))) + goto efault; + ret = get_errno(extattr_list_fd(arg1, arg2, d, + arg4)); + unlock_user(d, arg3, arg4); + } else { + ret = get_errno(extattr_list_fd(arg1, arg2, + NULL, arg4)); + } + } + break; + case TARGET_FREEBSD_NR_extattr_list_file: + { + void *d; + + if (!(p = lock_user_string(arg1))) + goto efault; + + if (arg3 && arg4 > 0) { + if (!(d = lock_user(VERIFY_WRITE, arg3, arg4, 0))) + goto efault; + ret = get_errno(extattr_list_file(path(p), arg2, d, + arg4)); + unlock_user(d, arg3, arg4); + } else { + ret = get_errno(extattr_list_file(path(p), arg2, + NULL, arg4)); + } + unlock_user(p, arg1, 0); + } + break; + case TARGET_FREEBSD_NR_extattr_list_link: - ret = unimplemented(num); + { + void *d; + + if (!(p = lock_user_string(arg1))) + goto efault; + + if (arg3 && arg4 > 0) { + if (!(d = lock_user(VERIFY_WRITE, arg3, arg4, 0))) + goto efault; + ret = get_errno(extattr_list_link(path(p), arg2, d, + arg4)); + unlock_user(d, arg3, arg4); + } else { + ret = get_errno(extattr_list_link(path(p), arg2, + NULL, arg4)); + } + + unlock_user(p, arg1, 0); + } break; case TARGET_FREEBSD_NR_setlogin: @@ -5635,6 +6430,10 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4); break; + case TARGET_FREEBSD_NR_freebsd7___semctl: + ret = unimplemented(num); + break; + case TARGET_FREEBSD_NR_msgctl: ret = do_msgctl(arg1, arg2, arg3); break; @@ -5715,7 +6514,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, break; case TARGET_FREEBSD_NR_seteuid: - ret = get_errno(setegid(arg1)); + ret = get_errno(seteuid(arg1)); break; case TARGET_FREEBSD_NR_getpgrp: @@ -6953,7 +7752,7 @@ void syscall_init(void) #define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def); #define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def); -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) #include "freebsd/syscall_types.h" #else #warning No syscall_types.h diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h index 3eb760b..8a92403 100644 --- a/bsd-user/syscall_defs.h +++ b/bsd-user/syscall_defs.h @@ -203,12 +203,12 @@ struct target_pollfd { #include "openbsd/syscall_nr.h" struct target_flock { - unsigned long long l_start; - unsigned long long l_len; - int l_pid; - int l_sysid; - short l_type; - short l_whence; + abi_long l_start; + abi_long l_len; + int32_t l_pid; + int16_t l_type; + int16_t l_whence; + int32_t l_sysid; } QEMU_PACKED; struct target_iovec { @@ -451,6 +451,7 @@ typedef struct target_siginfo { int32_t si_code; /* signal code */ int32_t si_pid; /* sending process */ int32_t si_uid; /* sender's ruid */ + int32_t si_status; /* exit value */ abi_ulong si_addr; /* faulting instruction */ union target_sigval si_value; /* signal value */ @@ -756,3 +757,41 @@ struct target_timex { struct target_sched_param { int32_t sched_priority; }; + + +/* + * sys/acl.h + */ + +#define TARGET_ACL_MAX_ENTRIES 254 + +struct target_acl_entry { + int32_t ae_tag; + uint32_t ae_id; + uint16_t ae_perm; + uint16_t ae_entry_type; + uint16_t ae_flags; +}; + +struct target_acl { + uint32_t acl_maxcnt; + uint32_t acl_cnt; + int32_t acl_space[4]; + struct target_acl_entry acl_entry[TARGET_ACL_MAX_ENTRIES]; +}; + + +/* + * netinet/in.h + */ + +struct target_ip_mreq { + struct target_in_addr imr_multiaddr; + struct target_in_addr imr_interface; +}; + +struct target_ip_mreqn { + struct target_in_addr imr_multiaddr; + struct target_in_addr imr_address; + int32_t imr_ifindex; +}; diff --git a/configure b/configure index d99584d..6d17c97 100755 --- a/configure +++ b/configure @@ -434,8 +434,9 @@ FreeBSD) make="${MAKE-gmake}" audio_drv_list="oss" audio_possible_drivers="oss sdl esd pa" - # needed for kinfo_getvmmap(3) in libutil.h - LIBS="-lutil $LIBS" + # -lutil needed for kinfo_getvmmap(3) in libutil.h + # -lprocstat needed for procstat_*(3) in main.c + LIBS="-lprocstat -lutil $LIBS" ;; DragonFly) bsd="yes" @@ -1237,6 +1238,11 @@ if test "$static" = "yes" ; then else pie="no" fi + if test "$bsd" = "yes" ; then + # Missing libs when linking statically + LIBS="$LIBS -lintl -lkvm" + libs_qga="-lintl $libs_qga" + fi fi if test "$pie" = ""; then diff --git a/util/aes.c b/util/aes.c index 1da7bff..30a6608 100644 --- a/util/aes.c +++ b/util/aes.c @@ -877,6 +877,7 @@ int AES_set_decrypt_key(const unsigned char *userKey, const int bits, return 0; } +#if defined(CONFIG_STATIC) && ! defined(__FreeBSD__) #ifndef AES_ASM /* * Encrypt a single block @@ -1312,3 +1313,4 @@ void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, } } } +#endif /* CONFIG_STATIC && ! __FreeBSD__ */