diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index 4c6acb0..d21ddfa 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,2 +1,3 @@
 obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
-	        uaccess.o bsd-mem.o $(TARGET_OS)/os-time.o
+	        uaccess.o bsd-mem.o bsd-proc.o $(TARGET_OS)/os-time.o \
+			$(TARGET_OS)/os-proc.o
diff --git a/bsd-user/bsd-errno.h b/bsd-user/bsd-errno.h
deleted file mode 100644
index 721bfc0..0000000
--- a/bsd-user/bsd-errno.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- *  errno translation
- *
- *  Copyright (c) 2003 - 2008 Fabrice Bellard
- *  Copyright (c) 2013 Stacey D. 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
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __BSD_ERRNO_H_
-#define __BSD_ERRNO_H_
-
-static inline abi_long get_errno(abi_long ret)
-{
-
-    if (ret == -1) {
-        /* XXX need to translate host -> target errnos here */
-        return -(errno);
-    } else {
-        return ret;
-    }
-}
-
-static inline int is_error(abi_long ret)
-{
-
-    return (abi_ulong)ret >= (abi_ulong)(-4096);
-}
-
-#endif /* !__BSD_ERRNO_H_ */
diff --git a/bsd-user/bsd-proc.c b/bsd-user/bsd-proc.c
new file mode 100644
index 0000000..a4bcdc8
--- /dev/null
+++ b/bsd-user/bsd-proc.c
@@ -0,0 +1,160 @@
+/*
+ *  BSD process related system call helpers
+ *
+ *  Copyright (c) 2013 Stacey D. 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
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+#include "qemu.h"
+#include "qemu-bsd.h"
+
+/*
+ * resource/rusage conversion
+ */
+int target_to_host_resource(int code)
+{
+
+    switch (code) {
+    case TARGET_RLIMIT_AS:
+        return RLIMIT_AS;
+
+    case TARGET_RLIMIT_CORE:
+        return RLIMIT_CORE;
+
+    case TARGET_RLIMIT_CPU:
+        return RLIMIT_CPU;
+
+    case TARGET_RLIMIT_DATA:
+        return RLIMIT_DATA;
+
+    case TARGET_RLIMIT_FSIZE:
+        return RLIMIT_FSIZE;
+
+    case TARGET_RLIMIT_MEMLOCK:
+        return RLIMIT_MEMLOCK;
+
+    case TARGET_RLIMIT_NOFILE:
+        return RLIMIT_NOFILE;
+
+    case TARGET_RLIMIT_NPROC:
+        return RLIMIT_NPROC;
+
+    case TARGET_RLIMIT_RSS:
+        return RLIMIT_RSS;
+
+    case TARGET_RLIMIT_SBSIZE:
+        return RLIMIT_SBSIZE;
+
+    case TARGET_RLIMIT_STACK:
+        return RLIMIT_STACK;
+
+    case TARGET_RLIMIT_SWAP:
+        return RLIMIT_SWAP;
+
+    case TARGET_RLIMIT_NPTS:
+        return RLIMIT_NPTS;
+
+    default:
+        return code;
+    }
+}
+
+rlim_t target_to_host_rlim(abi_ulong target_rlim)
+{
+    abi_ulong target_rlim_swap;
+    rlim_t result;
+
+    target_rlim_swap = tswapal(target_rlim);
+    if (target_rlim_swap == TARGET_RLIM_INFINITY) {
+        return RLIM_INFINITY;
+    }
+
+    result = target_rlim_swap;
+    if (target_rlim_swap != (rlim_t)result) {
+        return RLIM_INFINITY;
+    }
+
+    return result;
+}
+
+abi_ulong host_to_target_rlim(rlim_t rlim)
+{
+    abi_ulong target_rlim_swap;
+    abi_ulong result;
+
+    if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim) {
+        target_rlim_swap = TARGET_RLIM_INFINITY;
+    } else {
+        target_rlim_swap = rlim;
+    }
+    result = tswapal(target_rlim_swap);
+
+    return result;
+}
+
+abi_long host_to_target_rusage(abi_ulong target_addr,
+        const struct rusage *rusage)
+{
+    struct target_freebsd_rusage *target_rusage;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(rusage->ru_utime.tv_sec, &target_rusage->ru_utime.tv_sec);
+    __put_user(rusage->ru_utime.tv_usec, &target_rusage->ru_utime.tv_usec);
+
+    __put_user(rusage->ru_stime.tv_sec, &target_rusage->ru_stime.tv_sec);
+    __put_user(rusage->ru_stime.tv_usec, &target_rusage->ru_stime.tv_usec);
+
+    __put_user(rusage->ru_maxrss, &target_rusage->ru_maxrss);
+    __put_user(rusage->ru_idrss, &target_rusage->ru_idrss);
+    __put_user(rusage->ru_idrss, &target_rusage->ru_idrss);
+    __put_user(rusage->ru_isrss, &target_rusage->ru_isrss);
+    __put_user(rusage->ru_minflt, &target_rusage->ru_minflt);
+    __put_user(rusage->ru_majflt, &target_rusage->ru_majflt);
+    __put_user(rusage->ru_nswap, &target_rusage->ru_nswap);
+    __put_user(rusage->ru_inblock, &target_rusage->ru_inblock);
+    __put_user(rusage->ru_oublock, &target_rusage->ru_oublock);
+    __put_user(rusage->ru_msgsnd, &target_rusage->ru_msgsnd);
+    __put_user(rusage->ru_msgrcv, &target_rusage->ru_msgrcv);
+    __put_user(rusage->ru_nsignals, &target_rusage->ru_nsignals);
+    __put_user(rusage->ru_nvcsw, &target_rusage->ru_nvcsw);
+    __put_user(rusage->ru_nivcsw, &target_rusage->ru_nivcsw);
+    unlock_user_struct(target_rusage, target_addr, 1);
+
+    return 0;
+}
+
+/*
+ * wait status conversion.
+ *
+ * Map host to target signal numbers for the wait family of syscalls.
+ * Assume all other status bits are the same.
+ */
+int host_to_target_waitstatus(int status)
+{
+    if (WIFSIGNALED(status)) {
+        return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
+    }
+    if (WIFSTOPPED(status)) {
+        return (host_to_target_signal(WSTOPSIG(status)) << 8) | (status & 0xff);
+    }
+    return status;
+}
+
diff --git a/bsd-user/bsd-proc.h b/bsd-user/bsd-proc.h
new file mode 100644
index 0000000..d1c732a
--- /dev/null
+++ b/bsd-user/bsd-proc.h
@@ -0,0 +1,434 @@
+/*
+ *  process related system call shims and definitions
+ *
+ *  Copyright (c) 2013 Stacey D. 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
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __BSD_PROC_H_
+#define __BSD_PROC_H_
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+
+#include "qemu-bsd.h"
+
+extern int _getlogin(char*, int);
+
+/* exit(2) */
+static inline abi_long do_bsd_exit(void *cpu_env, abi_long arg1)
+{
+#ifdef TARGET_GPROF
+    _mcleanup();
+#endif
+    gdb_exit(cpu_env, arg1);
+    /* XXX: should free thread stack and CPU env here  */
+    _exit(arg1);
+
+    return 0;
+}
+
+/* getgroups(2) */
+static inline abi_long do_bsd_getgroups(abi_long gidsetsize, abi_long arg2)
+{
+    abi_long ret;
+    uint32_t *target_grouplist;
+    gid_t *grouplist;
+    int i;
+
+    grouplist = alloca(gidsetsize * sizeof(gid_t));
+    ret = get_errno(getgroups(gidsetsize, grouplist));
+    if (gidsetsize != 0) {
+        if (!is_error(ret)) {
+            target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 2, 0);
+            if (!target_grouplist) {
+                return -TARGET_EFAULT;
+            }
+            for (i = 0; i < ret; i++) {
+                target_grouplist[i] = tswap32(grouplist[i]);
+            }
+            unlock_user(target_grouplist, arg2, gidsetsize * 2);
+        }
+    }
+    return ret;
+}
+
+/* setgroups(2) */
+static inline abi_long do_bsd_setgroups(abi_long gidsetsize, abi_long arg2)
+{
+    uint32_t *target_grouplist;
+    gid_t *grouplist;
+    int i;
+
+    grouplist = alloca(gidsetsize * sizeof(gid_t));
+    target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1);
+    if (!target_grouplist) {
+        return -TARGET_EFAULT;
+    }
+    for (i = 0; i < gidsetsize; i++) {
+        grouplist[i] = tswap32(target_grouplist[i]);
+    }
+    unlock_user(target_grouplist, arg2, 0);
+    return get_errno(setgroups(gidsetsize, grouplist));
+}
+
+/* umask(2) */
+static inline abi_long do_bsd_umask(abi_long arg1)
+{
+
+    return get_errno(umask(arg1));
+}
+
+/* setlogin(2) */
+static inline abi_long do_bsd_setlogin(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(setlogin(p));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* getlogin(2) */
+static inline abi_long do_bsd_getlogin(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(_getlogin(p, arg2));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* getrusage(2) */
+static inline abi_long do_bsd_getrusage(abi_long who, abi_ulong target_addr)
+{
+    abi_long ret;
+    struct rusage rusage;
+
+    ret = get_errno(getrusage(who, &rusage));
+    if (!is_error(ret)) {
+        host_to_target_rusage(target_addr, &rusage);
+    }
+    return ret;
+}
+
+/* getrlimit(2) */
+static inline abi_long do_bsd_getrlimit(abi_long arg1, abi_ulong arg2)
+{
+    abi_long ret;
+    int resource = target_to_host_resource(arg1);
+    struct target_rlimit *target_rlim;
+    struct rlimit rlim;
+
+    switch (resource) {
+    case RLIMIT_STACK:
+        rlim.rlim_cur = target_dflssiz;
+        rlim.rlim_max = target_maxssiz;
+        ret = 0;
+        break;
+
+    case RLIMIT_DATA:
+        rlim.rlim_cur = target_dfldsiz;
+        rlim.rlim_max = target_maxdsiz;
+        ret = 0;
+        break;
+
+    default:
+        ret = get_errno(getrlimit(resource, &rlim));
+        break;
+    }
+    if (!is_error(ret)) {
+        if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0)) {
+            return -TARGET_EFAULT;
+        }
+        target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
+        target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
+        unlock_user_struct(target_rlim, arg2, 1);
+    }
+    return ret;
+}
+
+/* setrlimit(2) */
+static inline abi_long do_bsd_setrlimit(abi_long arg1, abi_ulong arg2)
+{
+    abi_long ret;
+    int resource = target_to_host_resource(arg1);
+    struct target_rlimit *target_rlim;
+    struct rlimit rlim;
+
+    if (RLIMIT_STACK == resource) {
+        /* XXX We should, maybe, allow the stack size to shrink */
+        ret = -TARGET_EPERM;
+    } else {
+        if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1)) {
+            return -TARGET_EFAULT;
+        }
+        rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
+        rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
+        unlock_user_struct(target_rlim, arg2, 0);
+        ret = get_errno(setrlimit(resource, &rlim));
+    }
+    return ret;
+}
+
+/* getpid(2) */
+static inline abi_long do_bsd_getpid(void)
+{
+
+    return get_errno(getpid());
+}
+
+/* getppid(2) */
+static inline abi_long do_bsd_getppid(void)
+{
+
+    return get_errno(getppid());
+}
+
+/* getuid(2) */
+static inline abi_long do_bsd_getuid(void)
+{
+
+    return get_errno(getuid());
+}
+
+/* geteuid(2) */
+static inline abi_long do_bsd_geteuid(void)
+{
+
+    return get_errno(geteuid());
+}
+
+/* getgid(2) */
+static inline abi_long do_bsd_getgid(void)
+{
+
+    return get_errno(getgid());
+}
+
+/* getegid(2) */
+static inline abi_long do_bsd_getegid(void)
+{
+
+    return get_errno(getegid());
+}
+
+/* setuid(2) */
+static inline abi_long do_bsd_setuid(abi_long arg1)
+{
+
+    return get_errno(setuid(arg1));
+}
+
+/* seteuid(2) */
+static inline abi_long do_bsd_seteuid(abi_long arg1)
+{
+
+    return get_errno(seteuid(arg1));
+}
+
+/* setgid(2) */
+static inline abi_long do_bsd_setgid(abi_long arg1)
+{
+
+    return get_errno(setgid(arg1));
+}
+
+/* setegid(2) */
+static inline abi_long do_bsd_setegid(abi_long arg1)
+{
+
+    return get_errno(setegid(arg1));
+}
+
+/* getpgrp(2) */
+static inline abi_long do_bsd_getpgrp(void)
+{
+
+    return get_errno(getpgrp());
+}
+
+/* setreuid(2) */
+static inline abi_long do_bsd_setreuid(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(setreuid(arg1, arg2));
+}
+
+/* setregid(2) */
+static inline abi_long do_bsd_setregid(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(setregid(arg1, arg2));
+}
+
+/* setresuid(2) */
+static inline abi_long do_bsd_setresuid(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    return get_errno(setresuid(arg1, arg2, arg3));
+}
+
+/* getresuid(2) */
+static inline abi_long do_bsd_getresuid(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+    abi_long ret;
+    uid_t ruid, euid, suid;
+
+    ret = get_errno(getresuid(&ruid, &euid, &suid));
+    if (is_error(ret)) {
+            return ret;
+    }
+    if (put_user_s32(ruid, arg1)) {
+        return -TARGET_EFAULT;
+    }
+    if (put_user_s32(euid, arg2)) {
+        return -TARGET_EFAULT;
+    }
+    if (put_user_s32(suid, arg3)) {
+        return -TARGET_EFAULT;
+    }
+    return ret;
+}
+
+/* getresgid(2) */
+static inline abi_long do_bsd_getresgid(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+    abi_long ret;
+    uid_t ruid, euid, suid;
+
+    ret = get_errno(getresgid(&ruid, &euid, &suid));
+    if (is_error(ret)) {
+            return ret;
+    }
+    if (put_user_s32(ruid, arg1)) {
+        return -TARGET_EFAULT;
+    }
+    if (put_user_s32(euid, arg2)) {
+        return -TARGET_EFAULT;
+    }
+    if (put_user_s32(suid, arg3)) {
+        return -TARGET_EFAULT;
+    }
+    return ret;
+}
+
+/* getsid(2) */
+static inline abi_long do_bsd_getsid(abi_long arg1)
+{
+
+    return get_errno(getsid(arg1));
+}
+
+/* setsid(2) */
+static inline abi_long do_bsd_setsid(void)
+{
+
+    return get_errno(setsid());
+}
+
+/* issetugid(2) */
+static inline abi_long do_bsd_issetugid(void)
+{
+
+    return get_errno(issetugid());
+}
+
+/* profil(2) */
+static inline abi_long do_bsd_profil(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall profil()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* ktrace(2) */
+static inline abi_long do_bsd_ktrace(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall ktrace()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* utrace(2) */
+static inline abi_long do_bsd_utrace(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall ptrace()\n");
+    return -TARGET_ENOSYS;
+}
+
+
+/* ptrace(2) */
+static inline abi_long do_bsd_ptrace(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall ptrace()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getpriority(2) */
+static inline abi_long do_bsd_getpriority(abi_long which, abi_long who)
+{
+    abi_long ret;
+    /*
+     * Note that negative values are valid for getpriority, so we must
+     * differentiate based on errno settings.
+     */
+    errno = 0;
+    ret = getpriority(which, who);
+    if (ret == -1 && errno != 0) {
+        ret = -host_to_target_errno(errno);
+        return ret;
+    }
+    /* Return value is a biased priority to avoid negative numbers. */
+    ret = 20 - ret;
+
+    return ret;
+}
+
+/* setpriority(2) */
+static inline abi_long do_bsd_setpriority(abi_long which, abi_long who,
+        abi_long prio)
+{
+
+    return get_errno(setpriority(which, who, prio));
+}
+
+
+#endif /* !__BSD_PROC_H_ */
+
diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c
index 0cd5fc4..78a8d98 100644
--- a/bsd-user/elfload.c
+++ b/bsd-user/elfload.c
@@ -111,6 +111,7 @@ enum {
 
 #ifdef TARGET_I386
 
+#ifndef __FreeBSD__
 #define ELF_PLATFORM get_elf_platform()
 
 static const char *get_elf_platform(void)
@@ -130,6 +131,7 @@ static uint32_t get_elf_hwcap(void)
 {
     return thread_env->features[FEAT_1_EDX];
 }
+#endif /* ! __FreeBSD__ */
 
 #ifdef TARGET_X86_64
 #define ELF_START_MMAP 0x2aaaaab000ULL
@@ -211,6 +213,9 @@ static inline void init_thread(struct target_pt_regs *regs,
       regs->ARM_cpsr |= CPSR_T;
     regs->ARM_pc = infop->entry & 0xfffffffe;
     regs->ARM_sp = infop->start_stack;
+    if (bsd_type == target_freebsd) {
+        regs->ARM_lr = infop->entry & 0xfffffffe;
+    }
     /* FIXME - what to for failure of get_user()? */
     get_user_ual(regs->ARM_r2, stack + 8); /* envp */
     get_user_ual(regs->ARM_r1, stack + 4); /* envp */
@@ -803,11 +808,14 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
 {
         abi_ulong sp;
         int size;
+#ifndef __FreeBSD__
         abi_ulong u_platform;
         const char *k_platform;
+#endif
         const int n = sizeof(elf_addr_t);
 
         sp = p;
+#ifndef __FreeBSD__
         u_platform = 0;
         k_platform = ELF_PLATFORM;
         if (k_platform) {
@@ -817,16 +825,19 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
             /* FIXME - check return value of memcpy_to_target() for failure */
             memcpy_to_target(sp, k_platform, len);
         }
+#endif /* !__FreeBSD__ */
         /*
          * Force 16 byte _final_ alignment here for generality.
          */
         sp = sp &~ (abi_ulong)15;
         size = (DLINFO_ITEMS + 1) * 2;
+#ifndef __FreeBSD__
         if (k_platform)
           size += 2;
 #ifdef DLINFO_ARCH_ITEMS
         size += DLINFO_ARCH_ITEMS * 2;
 #endif
+#endif /* ! __FreeBSD__ */
         size += envc + argc + 2;
         size += (!ibcs ? 3 : 1);        /* argc itself */
         size *= n;
@@ -855,10 +866,12 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
         NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
         NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
         NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
+#ifndef __FreeBSD__
         NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
         NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
         if (k_platform)
             NEW_AUX_ENT(AT_PLATFORM, u_platform);
+#endif
 #ifdef ARCH_DLINFO
         /*
          * ARCH_DLINFO must come last so platform specific code can enforce
@@ -1173,6 +1186,30 @@ 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)
 {
diff --git a/bsd-user/freebsd/os-proc.c b/bsd-user/freebsd/os-proc.c
new file mode 100644
index 0000000..b696222
--- /dev/null
+++ b/bsd-user/freebsd/os-proc.c
@@ -0,0 +1,234 @@
+/*
+ *  FreeBSD process related emulation code
+ *
+ *  Copyright (c) 2013 Stacey D. 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
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/sysctl.h>
+#include <sys/unistd.h>
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+#include <libprocstat.h>
+#endif
+
+#include "qemu.h"
+
+/*
+ * 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)
+{
+    char *ret = NULL;
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+    unsigned int cnt;
+    struct procstat *procstat = NULL;
+    struct kinfo_proc *kipp = NULL;
+    struct filestat_list *head = NULL;
+    struct filestat *fst;
+
+    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);
+    }
+#endif
+    return ret;
+}
+
+/*
+ * execve/fexecve
+ */
+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;
+        }
+        *q = lock_user_string(addr);
+        if (*q == NULL) {
+            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;
+        }
+        *q = lock_user_string(addr);
+        if (*q == NULL) {
+            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;
+
+        p = lock_user_string(path_or_fd);
+        if (p == NULL) {
+            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;
+}
+
+
diff --git a/bsd-user/freebsd/os-proc.h b/bsd-user/freebsd/os-proc.h
new file mode 100644
index 0000000..fd2bb42
--- /dev/null
+++ b/bsd-user/freebsd/os-proc.h
@@ -0,0 +1,427 @@
+/*
+ *  process related system call shims and definitions
+ *
+ *  Copyright (c) 2013 Stacey D. 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
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __FREEBSD_PROC_H_
+#define __FREEBSD_PROC_H_
+
+#include <sys/types.h>
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+#include <sys/procdesc.h>
+#endif
+#include <sys/wait.h>
+#include <unistd.h>
+
+
+extern int __setugid(int flag);
+extern int pdwait4(int fd, int *status, int options, struct rusage *rusage);
+
+/* execve(2) */
+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);
+}
+
+/* fexecve(2) */
+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);
+}
+
+/* wait4(2) */
+static inline abi_long do_freebsd_wait4(abi_long arg1, abi_ulong target_status,
+        abi_long arg3, abi_ulong target_rusage)
+{
+    abi_long ret;
+    int status;
+    struct rusage rusage, *rusage_ptr = NULL;
+
+    if (target_rusage) {
+        rusage_ptr = &rusage;
+    }
+    ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
+    if (!is_error(ret)) {
+        status = host_to_target_waitstatus(status);
+        if (put_user_s32(status, target_status) != 0) {
+            return -TARGET_EFAULT;
+        }
+        if (target_rusage != 0) {
+            host_to_target_rusage(target_rusage, &rusage);
+        }
+    }
+    return ret;
+}
+
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+/* setloginclass(2) */
+static inline abi_long do_freebsd_setloginclass(abi_ulong arg1)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(setloginclass(p));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* getloginclass(2) */
+static inline abi_long do_freebsd_getloginclass(abi_ulong arg1, abi_ulong arg2)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(getloginclass(p, arg2));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* pdwait4(2) */
+static inline abi_long do_freebsd_pdwait4(abi_long arg1,
+        abi_ulong target_status, abi_long arg3, abi_ulong target_rusage)
+{
+    abi_long ret;
+    int status;
+    struct rusage rusage, *rusage_ptr = NULL;
+
+    if (target_rusage) {
+        rusage_ptr = &rusage;
+    }
+    ret = get_errno(pdwait4(arg1, &status, arg3, rusage_ptr));
+    if (!is_error(ret)) {
+        status = host_to_target_waitstatus(status);
+        if (put_user_s32(status, target_status) != 0) {
+            return -TARGET_EFAULT;
+        }
+        if (target_rusage != 0) {
+            host_to_target_rusage(target_rusage, &rusage);
+        }
+    }
+    return ret;
+}
+
+/* pdgetpid(2) */
+static inline abi_long do_freebsd_pdgetpid(abi_long fd, abi_ulong target_pidp)
+{
+    abi_long ret;
+    pid_t pid;
+
+    ret = get_errno(pdgetpid(fd, &pid));
+    if (!is_error(ret)) {
+        if (put_user_u32(pid, target_pidp)) {
+            return -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+#else
+
+/* setloginclass(2) */
+static inline abi_long do_freebsd_setloginclass(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setloginclass()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getloginclass(2) */
+static inline abi_long do_freebsd_getloginclass(abi_ulong arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getloginclass()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdwait4(2) */
+static inline abi_long do_freebsd_pdwait4(abi_long arg1,
+        abi_ulong target_status, abi_long arg3, abi_ulong target_rusage)
+{
+
+    qemu_log("qemu: Unsupported syscall pdwait4()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdgetpid(2) */
+static inline abi_long do_freebsd_pdgetpid(abi_long fd, abi_ulong target_pidp)
+{
+
+    qemu_log("qemu: Unsupported syscall pdgetpid()\n");
+    return -TARGET_ENOSYS;
+}
+#endif /* !  __FreeBSD_version > 900000 */
+
+/* undocumented __setugid */
+static inline abi_long do_freebsd___setugid(abi_long arg1)
+{
+
+    return get_errno(__setugid(arg1));
+}
+
+/* fork(2) */
+static inline abi_long do_freebsd_fork(void *cpu_env)
+{
+    abi_long ret;
+    abi_ulong child_flag = 0;
+
+    fork_start();
+    ret = fork();
+    if (ret == 0) {
+        /* child */
+        child_flag = 1;
+        cpu_clone_regs(cpu_env, 0);
+    } else {
+        /* parent */
+        fork_end(0);
+    }
+
+    /*
+     * The fork system call sets a child flag in the second return
+     * value: 0 for parent process, 1 for child process.
+     */
+    set_second_rval(cpu_env, child_flag);
+
+    return ret;
+}
+
+/* vfork(2) */
+static inline abi_long do_freebsd_vfork(void *cpu_env)
+{
+
+    return do_freebsd_fork(cpu_env);
+}
+
+/* rfork(2) */
+static inline abi_long do_freebsd_rfork(void *cpu_env, abi_long flags)
+{
+    abi_long ret;
+    abi_ulong child_flag = 0;
+
+    fork_start();
+    ret = rfork(flags);
+    if (ret == 0) {
+        /* child */
+        child_flag = 1;
+        cpu_clone_regs(cpu_env, 0);
+    } else {
+        /* parent */
+        fork_end(0);
+    }
+
+    /*
+     * The fork system call sets a child flag in the second return
+     * value: 0 for parent process, 1 for child process.
+     */
+    set_second_rval(cpu_env, child_flag);
+
+    return ret;
+
+}
+
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+/* pdfork(2) */
+static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong target_fdp,
+        abi_long flags)
+{
+    abi_long ret;
+    abi_ulong child_flag = 0;
+    int fd;
+
+    fork_start();
+    ret = pdfork(&fd, flags);
+    if (ret == 0) {
+        /* child */
+        child_flag = 1;
+        cpu_clone_regs(cpu_env, 0);
+    } else {
+        /* parent */
+        fork_end(0);
+    }
+    if (put_user_s32(fd, target_fdp)) {
+        return -TARGET_EFAULT;
+    }
+
+    /*
+     * The fork system call sets a child flag in the second return
+     * value: 0 for parent process, 1 for child process.
+     */
+    set_second_rval(cpu_env, child_flag);
+
+    return ret;
+}
+
+#else
+
+/* pdfork(2) */
+static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong arg1,
+        abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall pdfork()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* __FreeBSD_version > 900000 */
+
+/* jail(2) */
+static inline abi_long do_freebsd_jail(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_attach(2) */
+static inline abi_long do_freebsd_jail_attach(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_attach()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_remove(2) */
+static inline abi_long do_freebsd_jail_remove(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_remove()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_get(2) */
+static inline abi_long do_freebsd_jail_get(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_get()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_set(2) */
+static inline abi_long do_freebsd_jail_set(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_set()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_enter(2) */
+static inline abi_long do_freebsd_cap_enter(void)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_enter()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_new(2) */
+static inline abi_long do_freebsd_cap_new(abi_long arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_new()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_getrights(2) */
+static inline abi_long do_freebsd_cap_getrights(abi_long arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_getrights()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_getmode(2) */
+static inline abi_long do_freebsd_cap_getmode(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_getmode()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* audit(2) */
+static inline abi_long do_freebsd_audit(abi_ulong arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall audit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* auditon(2) */
+static inline abi_long do_freebsd_auditon(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall auditon()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getaudit(2) */
+static inline abi_long do_freebsd_getaudit(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall getaudit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setaudit(2) */
+static inline abi_long do_freebsd_setaudit(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setaudit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getaudit_addr(2) */
+static inline abi_long do_freebsd_getaudit_addr(abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getaudit_addr()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setaudit_addr(2) */
+static inline abi_long do_freebsd_setaudit_addr(abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall setaudit_addr()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* auditctl(2) */
+static inline abi_long do_freebsd_auditctl(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall auditctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __FREEBSD_PROC_H_ */
diff --git a/bsd-user/main.c b/bsd-user/main.c
index 0442dbe..1fa5e7f 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -27,6 +27,7 @@
 #include <sys/syscall.h>
 #include <sys/types.h>
 #include <sys/mman.h>
+#include <sys/sysctl.h>
 
 #include "qemu.h"
 #include "qemu-common.h"
@@ -56,6 +57,32 @@ unsigned long target_dflssiz = TARGET_DFLSSIZ;   /* initial data size limit */
 unsigned long target_maxssiz = TARGET_MAXSSIZ;   /* max stack size */
 unsigned long target_sgrowsiz = TARGET_SGROWSIZ; /* amount to grow stack */
 
+#ifdef __FreeBSD__
+char qemu_proc_pathname[PATH_MAX];
+
+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_prov_pathname(void)
+{
+}
+#endif /* !__FreeBSD__ */
+
 void gemu_log(const char *fmt, ...)
 {
     va_list ap;
@@ -931,6 +958,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/netbsd/os-proc.c b/bsd-user/netbsd/os-proc.c
new file mode 100644
index 0000000..bc11d29
--- /dev/null
+++ b/bsd-user/netbsd/os-proc.c
@@ -0,0 +1,11 @@
+/*
+ * XXX To support FreeBSD binaries on NetBSD the following will need to be
+ * emulated.
+ */
+abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
+        abi_ulong guest_envp, int do_fexec)
+{
+
+    qemu_log("qemu: Unsupported %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
diff --git a/bsd-user/netbsd/os-proc.h b/bsd-user/netbsd/os-proc.h
new file mode 100644
index 0000000..f34d616
--- /dev/null
+++ b/bsd-user/netbsd/os-proc.h
@@ -0,0 +1,243 @@
+#ifndef __NETBSD_PROC_H_
+#define __NETBSD_PROC_H_
+
+/*
+ * XXX To support FreeBSD binaries on NetBSD these syscalls will need
+ * to be emulated.
+ */
+
+/* execve(2) */
+static inline abi_long do_freebsd_execve(abi_ulong path_or_fd, abi_ulong argp,
+        abi_ulong envp)
+{
+
+    qemu_log("qemu: Unsupported syscall execve()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fexecve(2) */
+static inline abi_long do_freebsd_fexecve(abi_ulong path_or_fd, abi_ulong argp,
+        abi_ulong envp)
+{
+
+    qemu_log("qemu: Unsupported syscall fexecve()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* wait4(2) */
+static inline abi_long do_freebsd_wait4(abi_long arg1, abi_ulong target_status,
+        abi_long arg3, abi_ulong target_rusage)
+{
+
+    qemu_log("qemu: Unsupported syscall wait4()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setloginclass(2) */
+static inline abi_long do_freebsd_setloginclass(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setloginclass()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getloginclass(2) */
+static inline abi_long do_freebsd_getloginclass(abi_ulong arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getloginclass()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdwait4(2) */
+static inline abi_long do_freebsd_pdwait4(abi_long arg1,
+        abi_ulong target_status, abi_long arg3, abi_ulong target_rusage)
+{
+
+    qemu_log("qemu: Unsupported syscall pdwait4()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdgetpid(2) */
+static inline abi_long do_freebsd_pdgetpid(abi_long fd, abi_ulong target_pidp)
+{
+
+    qemu_log("qemu: Unsupported syscall pdgetpid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* undocumented __setugid */
+static inline abi_long do_freebsd___setugid(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall __setugid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fork(2) */
+static inline abi_long do_freebsd_fork(void *cpu_env)
+{
+
+    qemu_log("qemu: Unsupported syscall fork()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* vfork(2) */
+static inline abi_long do_freebsd_vfork(void *cpu_env)
+{
+
+    qemu_log("qemu: Unsupported syscall vfork()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rfork(2) */
+static inline abi_long do_freebsd_rfork(void *cpu_env, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall rfork()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdfork(2) */
+static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong arg1,
+        abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall pdfork()\n");
+    return -TARGET_ENOSYS
+}
+
+/* jail(2) */
+static inline abi_long do_freebsd_jail(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_attach(2) */
+static inline abi_long do_freebsd_jail_attach(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_attach()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_remove(2) */
+static inline abi_long do_freebsd_jail_remove(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_remove()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_get(2) */
+static inline abi_long do_freebsd_jail_get(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_get()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_set(2) */
+static inline abi_long do_freebsd_jail_set(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_set()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_enter(2) */
+static inline abi_long do_freebsd_cap_enter(void)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_enter()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_new(2) */
+static inline abi_long do_freebsd_cap_new(abi_long arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_new()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_getrights(2) */
+static inline abi_long do_freebsd_cap_getrights(abi_long arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_getrights()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_getmode(2) */
+static inline abi_long do_freebsd_cap_getmode(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_getmode()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* audit(2) */
+static inline abi_long do_freebsd_audit(abi_ulong arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall audit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* auditon(2) */
+static inline abi_long do_freebsd_auditon(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall auditon()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getaudit(2) */
+static inline abi_long do_freebsd_getaudit(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall getaudit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setaudit(2) */
+static inline abi_long do_freebsd_setaudit(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setaudit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getaudit_addr(2) */
+static inline abi_long do_freebsd_getaudit_addr(abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getaudit_addr()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setaudit_addr(2) */
+static inline abi_long do_freebsd_setaudit_addr(abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall setaudit_addr()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* auditctl(2) */
+static inline abi_long do_freebsd_auditctl(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall auditctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __NETBSD_PROC_H_ */
diff --git a/bsd-user/openbsd/os-proc.c b/bsd-user/openbsd/os-proc.c
new file mode 100644
index 0000000..bc11d29
--- /dev/null
+++ b/bsd-user/openbsd/os-proc.c
@@ -0,0 +1,11 @@
+/*
+ * XXX To support FreeBSD binaries on NetBSD the following will need to be
+ * emulated.
+ */
+abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
+        abi_ulong guest_envp, int do_fexec)
+{
+
+    qemu_log("qemu: Unsupported %s\n", __func__);
+    return -TARGET_ENOSYS;
+}
diff --git a/bsd-user/openbsd/os-proc.h b/bsd-user/openbsd/os-proc.h
new file mode 100644
index 0000000..9cce719
--- /dev/null
+++ b/bsd-user/openbsd/os-proc.h
@@ -0,0 +1,243 @@
+#ifndef __OPENBSD_PROC_H_
+#define __OPENBSD_PROC_H_
+
+/*
+ * XXX To support FreeBSD binaries on OpenBSD these syscalls will need
+ * to be emulated.
+ */
+
+/* execve(2) */
+static inline abi_long do_freebsd_execve(abi_ulong path_or_fd, abi_ulong argp,
+        abi_ulong envp)
+{
+
+    qemu_log("qemu: Unsupported syscall execve()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fexecve(2) */
+static inline abi_long do_freebsd_fexecve(abi_ulong path_or_fd, abi_ulong argp,
+        abi_ulong envp)
+{
+
+    qemu_log("qemu: Unsupported syscall fexecve()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* wait4(2) */
+static inline abi_long do_freebsd_wait4(abi_long arg1, abi_ulong target_status,
+        abi_long arg3, abi_ulong target_rusage)
+{
+
+    qemu_log("qemu: Unsupported syscall wait4()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setloginclass(2) */
+static inline abi_long do_freebsd_setloginclass(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setloginclass()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getloginclass(2) */
+static inline abi_long do_freebsd_getloginclass(abi_ulong arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getloginclass()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdwait4(2) */
+static inline abi_long do_freebsd_pdwait4(abi_long arg1,
+        abi_ulong target_status, abi_long arg3, abi_ulong target_rusage)
+{
+
+    qemu_log("qemu: Unsupported syscall pdwait4()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdgetpid(2) */
+static inline abi_long do_freebsd_pdgetpid(abi_long fd, abi_ulong target_pidp)
+{
+
+    qemu_log("qemu: Unsupported syscall pdgetpid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* undocumented __setugid */
+static inline abi_long do_freebsd___setugid(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall __setugid()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* fork(2) */
+static inline abi_long do_freebsd_fork(void *cpu_env)
+{
+
+    qemu_log("qemu: Unsupported syscall fork()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* vfork(2) */
+static inline abi_long do_freebsd_vfork(void *cpu_env)
+{
+
+    qemu_log("qemu: Unsupported syscall vfork()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* rfork(2) */
+static inline abi_long do_freebsd_rfork(void *cpu_env, abi_long flags)
+{
+
+    qemu_log("qemu: Unsupported syscall rfork()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* pdfork(2) */
+static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong arg1,
+        abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall pdfork()\n");
+    return -TARGET_ENOSYS
+}
+
+/* jail(2) */
+static inline abi_long do_freebsd_jail(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_attach(2) */
+static inline abi_long do_freebsd_jail_attach(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_attach()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_remove(2) */
+static inline abi_long do_freebsd_jail_remove(abi_long arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_remove()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_get(2) */
+static inline abi_long do_freebsd_jail_get(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_get()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* jail_set(2) */
+static inline abi_long do_freebsd_jail_set(abi_ulong arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall jail_set()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_enter(2) */
+static inline abi_long do_freebsd_cap_enter(void)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_enter()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* cap_new(2) */
+static inline abi_long do_freebsd_cap_new(abi_long arg1, abi_ulong arg2)
+{
+
+        qemu_log("qemu: Unsupported syscall cap_new()\n");
+            return -TARGET_ENOSYS;
+}
+
+/* cap_getrights(2) */
+static inline abi_long do_freebsd_cap_getrights(abi_long arg1, abi_ulong arg2)
+{
+
+        qemu_log("qemu: Unsupported syscall cap_getrights()\n");
+            return -TARGET_ENOSYS;
+}
+
+/* cap_getmode(2) */
+static inline abi_long do_freebsd_cap_getmode(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall cap_getmode()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* audit(2) */
+static inline abi_long do_freebsd_audit(abi_ulong arg1, abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall audit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* auditon(2) */
+static inline abi_long do_freebsd_auditon(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall auditon()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getaudit(2) */
+static inline abi_long do_freebsd_getaudit(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall getaudit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setaudit(2) */
+static inline abi_long do_freebsd_setaudit(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall setaudit()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* getaudit_addr(2) */
+static inline abi_long do_freebsd_getaudit_addr(abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall getaudit_addr()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* setaudit_addr(2) */
+static inline abi_long do_freebsd_setaudit_addr(abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall setaudit_addr()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* auditctl(2) */
+static inline abi_long do_freebsd_auditctl(abi_ulong arg1)
+{
+
+    qemu_log("qemu: Unsupported syscall auditctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __OPENBSD_PROC_H_ */
diff --git a/bsd-user/qemu-bsd.h b/bsd-user/qemu-bsd.h
index 0add0b3..893a475 100644
--- a/bsd-user/qemu-bsd.h
+++ b/bsd-user/qemu-bsd.h
@@ -20,6 +20,12 @@
 #ifndef _QEMU_BSD_H_
 #define _QEMU_BSD_H_
 
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/resource.h>
+#include <sys/shm.h>
+#include <sys/wait.h>
+
 /* bsd-mem.c */
 abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
         abi_ulong target_addr);
@@ -30,5 +36,12 @@ abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
 abi_long host_to_target_shmid_ds(abi_ulong target_addr,
         struct shmid_ds *host_sd);
 
+/* bsd-proc.c */
+int target_to_host_resource(int code);
+rlim_t target_to_host_rlim(abi_ulong target_rlim);
+abi_ulong host_to_target_rlim(rlim_t rlim);
+abi_long host_to_target_rusage(abi_ulong target_addr,
+        const struct rusage *rusage);
+int host_to_target_waitstatus(int status);
 
 #endif /* !_QEMU_BSD_H_ */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index da69073..7ded869 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -144,6 +144,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);
 
 abi_long memcpy_to_target(abi_ulong dest, const void *src,
                           unsigned long len);
@@ -232,6 +233,15 @@ extern unsigned long target_maxdsiz;
 extern unsigned long target_dflssiz;
 extern unsigned long target_maxssiz;
 extern unsigned long target_sgrowsiz;
+extern char qemu_proc_pathname[];
+
+/* syscall.c */
+abi_long get_errno(abi_long ret);
+int is_error(abi_long ret);
+
+/* os-proc.c */
+abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
+        abi_ulong guest_envp, int do_fexec);
 
 /* user access */
 
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index a04c1bf..e8fe25c 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -32,17 +32,45 @@
 #include "qemu-common.h"
 
 #define target_to_host_bitmask(x, tbl) (x)
+static int host_to_target_errno(int err);
 
-#include "bsd-errno.h"
 #include "bsd-file.h"
 #include "bsd-mem.h"
 #include "bsd-signal.h"
+#include "bsd-proc.h"
 
 #include "os-time.h"
 #include "os-signal.h"
+#include "os-proc.h"
 
 /* #define DEBUG */
 
+/*
+ * errno conversion.
+ */
+abi_long get_errno(abi_long ret)
+{
+
+    if (ret == -1) {
+        /* XXX need to translate host -> target errnos here */
+        return -(errno);
+    } else {
+        return ret;
+    }
+}
+
+static int host_to_target_errno(int err)
+{
+    /* XXX need to translate host errnos here */
+    return err;
+}
+
+int is_error(abi_long ret)
+{
+
+    return (abi_ulong)ret >= (abi_ulong)(-4096);
+}
+
 #if defined(TARGET_I386)
 static abi_long do_freebsd_sysarch(CPUX86State *env, int op, abi_ulong parms)
 {
@@ -140,7 +168,7 @@ oidfmt(int *oid, int len, char *fmt, uint32_t *kind)
 
     if (fmt)
         strcpy(fmt, (char *)(buf + sizeof(uint32_t)));
-    return (0);
+    return 0;
 }
 
 /*
@@ -291,16 +319,257 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
 
     switch (num) {
-    case TARGET_FREEBSD_NR_exit:
-#ifdef TARGET_GPROF
-        _mcleanup();
+        /*
+         * process system calls
+         */
+    case TARGET_FREEBSD_NR_fork: /* fork(2) */
+        ret = do_freebsd_fork(cpu_env);
+        break;
+
+    case TARGET_FREEBSD_NR_vfork: /* vfork(2) */
+        ret = do_freebsd_vfork(cpu_env);
+        break;
+
+    case TARGET_FREEBSD_NR_rfork: /* rfork(2) */
+        ret = do_freebsd_rfork(cpu_env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_pdfork: /* pdfork(2) */
+        ret = do_freebsd_pdfork(cpu_env, arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_execve: /* execve(2) */
+        ret = do_freebsd_execve(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_fexecve: /* fexecve(2) */
+        ret = do_freebsd_fexecve(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_wait4: /* wait4(2) */
+        ret = do_freebsd_wait4(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_exit: /* exit(2) */
+        ret = do_bsd_exit(cpu_env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_getgroups: /* getgroups(2) */
+        ret = do_bsd_getgroups(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_setgroups: /* setgroups(2) */
+        ret = do_bsd_setgroups(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_umask: /* umask(2) */
+        ret = do_bsd_umask(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_setlogin: /* setlogin(2) */
+        ret = do_bsd_setlogin(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_getlogin: /* getlogin(2) */
+        ret = do_bsd_getlogin(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getrusage: /* getrusage(2) */
+        ret = do_bsd_getrusage(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getrlimit: /* getrlimit(2) */
+        ret = do_bsd_getrlimit(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_setrlimit: /* setrlimit(2) */
+        ret = do_bsd_setrlimit(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getpid: /* getpid(2) */
+        ret = do_bsd_getpid();
+        break;
+
+    case TARGET_FREEBSD_NR_getppid: /* getppid(2) */
+        ret = do_bsd_getppid();
+        break;
+
+    case TARGET_FREEBSD_NR_getuid: /* getuid(2) */
+        ret = do_bsd_getuid();
+        break;
+
+    case TARGET_FREEBSD_NR_geteuid: /* geteuid(2) */
+        ret = do_bsd_geteuid();
+        break;
+
+    case TARGET_FREEBSD_NR_getgid: /* getgid(2) */
+        ret = do_bsd_getgid();
+        break;
+
+    case TARGET_FREEBSD_NR_getegid: /* getegid(2) */
+        ret = do_bsd_getegid();
+        break;
+
+    case TARGET_FREEBSD_NR_setuid: /* setuid(2) */
+        ret = do_bsd_setuid(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_seteuid: /* seteuid(2) */
+        ret = do_bsd_seteuid(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_setgid: /* setgid(2) */
+        ret = do_bsd_setgid(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_setegid: /* setegid(2) */
+        ret = do_bsd_setegid(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_getpgrp: /* getpgrp(2) */
+        ret = do_bsd_getpgrp();
+        break;
+
+    case TARGET_FREEBSD_NR_setreuid: /* setreuid(2) */
+        ret = do_bsd_setreuid(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_setregid: /* setregid(2) */
+        ret = do_bsd_setregid(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getresuid: /* getresuid(2) */
+        ret = do_bsd_getresuid(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getresgid: /* getresgid(2) */
+        ret = do_bsd_getresgid(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getsid: /* getsid(2) */
+        ret = do_bsd_getsid(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_setsid: /* setsid(2) */
+        ret = do_bsd_setsid();
+        break;
+
+    case TARGET_FREEBSD_NR_issetugid: /* issetugid(2) */
+        ret = do_bsd_issetugid();
+        break;
+
+    case TARGET_FREEBSD_NR_profil: /* profil(2) */
+        ret = do_bsd_profil(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_ktrace: /* ktrace(2) */
+        ret = do_bsd_ktrace(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_setloginclass: /* setloginclass(2) */
+        ret = do_freebsd_setloginclass(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_getloginclass: /* getloginclass(2) */
+        ret = do_freebsd_getloginclass(arg1, arg2);
+        break;
+
+#if 0
+    case TARGET_FREEBSD_NR_pdwait4: /* pdwait4(2) */
+        ret = do_freebsd_pdwait4(arg1, arg2, arg3, arg4);
+        break;
 #endif
-        gdb_exit(cpu_env, arg1);
-        /* XXX: should free thread stack and CPU env */
-        _exit(arg1);
-        ret = 0; /* avoid warning */
+
+    case TARGET_FREEBSD_NR_pdgetpid: /* pdgetpid(2) */
+        ret = do_freebsd_pdgetpid(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___setugid: /* undocumented */
+        ret = do_freebsd___setugid(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_jail: /* jail(2) */
+        ret = do_freebsd_jail(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_jail_attach: /* jail_attach(2) */
+        ret = do_freebsd_jail_attach(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_jail_remove: /* jail_remove(2) */
+        ret = do_freebsd_jail_remove(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_jail_get: /* jail_get(2) */
+        ret = do_freebsd_jail_get(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_jail_set: /* jail_set(2) */
+        ret = do_freebsd_jail_set(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_cap_enter: /* cap_enter(2) */
+        ret = do_freebsd_cap_enter();
+        break;
+
+    case TARGET_FREEBSD_NR_cap_new: /* cap_new(2) */
+        ret = do_freebsd_cap_new(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_cap_getrights: /* cap_getrights(2) */
+        ret = do_freebsd_cap_getrights(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_cap_getmode: /* cap_getmode(2) */
+        ret = do_freebsd_cap_getmode(arg1);
         break;
 
+    case TARGET_FREEBSD_NR_audit: /* audit(2) */
+        ret = do_freebsd_audit(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_auditon: /* auditon(2) */
+        ret = do_freebsd_auditon(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getaudit: /* getaudit(2) */
+        ret = do_freebsd_getaudit(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_setaudit: /* setaudit(2) */
+        ret = do_freebsd_setaudit(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_getaudit_addr: /* getaudit_addr(2) */
+        ret = do_freebsd_getaudit_addr(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_setaudit_addr: /* setaudit_addr(2) */
+        ret = do_freebsd_setaudit_addr(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_auditctl: /* auditctl(2) */
+        ret = do_freebsd_auditctl(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_utrace: /* utrace(2) */
+        ret = do_bsd_utrace(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_ptrace: /* ptrace(2) */
+        ret = do_bsd_ptrace(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_getpriority: /* getpriority(2) */
+        ret = do_bsd_getpriority(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_setpriority: /* setpriority(2) */
+        ret = do_bsd_setpriority(arg1, arg2, arg3);
+        break;
+
+
+
         /*
          * File system calls.
          */
@@ -877,13 +1146,7 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
 
     switch (num) {
     case TARGET_NETBSD_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 */
+        ret = do_bsd_exit(cpu_env, arg1);
         break;
 
     case TARGET_NETBSD_NR_read:
@@ -933,13 +1196,7 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
 
     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 */
+        ret = do_bsd_exit(cpu_env, arg1);
         break;
 
     case TARGET_OPENBSD_NR_read:
diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h
index 7b85835..a69b31b 100644
--- a/bsd-user/syscall_defs.h
+++ b/bsd-user/syscall_defs.h
@@ -159,4 +159,54 @@ struct target_freebsd_kevent {
     abi_ulong  udata;
 } __packed;
 
+/*
+ *  sys/resource.h
+ */
+#if defined(__FreeBSD__) && defined(TARGET_ALPHA)
+#define TARGET_RLIM_INFINITY    0x7fffffffffffffffull
+#elif defined(__FreeBSD__) && (defined(TARGET_MIPS) || \
+        (defined(TARGET_SPARC) && TARGET_ABI_BITS == 32))
+#define TARGET_RLIM_INFINITY    0x7fffffffUL
+#else
+#define TARGET_RLIM_INFINITY    ((abi_ulong)-1)
+#endif
+
+#define TARGET_RLIMIT_CPU       0
+#define TARGET_RLIMIT_FSIZE     1
+#define TARGET_RLIMIT_DATA      2
+#define TARGET_RLIMIT_STACK     3
+#define TARGET_RLIMIT_CORE      4
+#define TARGET_RLIMIT_RSS       5
+#define TARGET_RLIMIT_MEMLOCK   6
+#define TARGET_RLIMIT_NPROC     7
+#define TARGET_RLIMIT_NOFILE    8
+#define TARGET_RLIMIT_SBSIZE    9
+#define TARGET_RLIMIT_AS        10
+#define TARGET_RLIMIT_NPTS      11
+#define TARGET_RLIMIT_SWAP      12
+
+struct target_rlimit {
+    uint64_t rlim_cur;
+    uint64_t rlim_max;
+};
+
+struct target_freebsd_rusage {
+    struct target_freebsd_timeval ru_utime; /* user time used */
+    struct target_freebsd_timeval ru_stime; /* system time used */
+    abi_long    ru_maxrss;      /* maximum resident set size */
+    abi_long    ru_ixrss;       /* integral shared memory size */
+    abi_long    ru_idrss;       /* integral unshared data size */
+    abi_long    ru_isrss;       /* integral unshared stack size */
+    abi_long    ru_minflt;      /* page reclaims */
+    abi_long    ru_majflt;      /* page faults */
+    abi_long    ru_nswap;       /* swaps */
+    abi_long    ru_inblock;     /* block input operations */
+    abi_long    ru_oublock;     /* block output operations */
+    abi_long    ru_msgsnd;      /* messages sent */
+    abi_long    ru_msgrcv;      /* messages received */
+    abi_long    ru_nsignals;    /* signals received */
+    abi_long    ru_nvcsw;       /* voluntary context switches */
+    abi_long    ru_nivcsw;      /* involuntary context switches */
+};
+
 #endif /* ! _SYSCALL_DEFS_H_ */
diff --git a/configure b/configure
index 749eba8..ba90975 100755
--- a/configure
+++ b/configure
@@ -457,7 +457,8 @@ FreeBSD)
   audio_drv_list="oss"
   audio_possible_drivers="oss sdl esd pa"
   # needed for kinfo_getvmmap(3) in libutil.h
-  LIBS="-lutil $LIBS"
+  # -lprocstat needed for procstat_*(3) in bsd-user/main.c
+  LIBS="-lprocstat -lutil $LIBS"
   TARGET_OS="freebsd"
 ;;
 DragonFly)
