Patchwork [13/23] bsd-user: add shims for signal related system calls

login
register
mail settings
Submitter Stacey Son
Date June 24, 2013, 2:03 a.m.
Message ID <1372039435-41921-14-git-send-email-sson@FreeBSD.org>
Download mbox | patch
Permalink /patch/253931/
State New
Headers show

Comments

Stacey Son - June 24, 2013, 2:03 a.m.
This change adds support for signal related system calls including sigaction(2),
sigprocmask(2), sigpending(2), sigsuspend(2), and so on.  The older, obsolete,
system calls such as sigvec(2), sigblock(2), sigsetmask(2), and sigstack(2) are
not supported.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/bsd-signal.h        |  232 ++++++++++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/os-signal.h |   43 ++++++++
 bsd-user/netbsd/os-signal.h  |   34 ++++++
 bsd-user/openbsd/os-signal.h |   34 ++++++
 bsd-user/syscall.c           |   57 ++++++++++
 5 files changed, 400 insertions(+), 0 deletions(-)
 create mode 100644 bsd-user/bsd-signal.h
 create mode 100644 bsd-user/freebsd/os-signal.h
 create mode 100644 bsd-user/netbsd/os-signal.h
 create mode 100644 bsd-user/openbsd/os-signal.h

Patch

diff --git a/bsd-user/bsd-signal.h b/bsd-user/bsd-signal.h
new file mode 100644
index 0000000..48a8b56
--- /dev/null
+++ b/bsd-user/bsd-signal.h
@@ -0,0 +1,232 @@ 
+/*
+ *  signal related system call shims
+ *
+ *  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_SIGNAL_H_
+#define __BSD_SIGNAL_H_
+
+/* sigaction(2) */
+static inline abi_long do_bsd_sigaction(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    struct target_sigaction *old_act, act, oact, *pact;
+
+    if (arg2) {
+        if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1)) {
+            return -TARGET_EFAULT;
+        }
+        act._sa_handler = old_act->_sa_handler;
+        act.sa_flags = old_act->sa_flags;
+        memcpy(&act.sa_mask, &old_act->sa_mask, sizeof(target_sigset_t));
+        unlock_user_struct(old_act, arg2, 0);
+        pact = &act;
+    } else {
+        pact = NULL;
+    }
+    ret = get_errno(do_sigaction(arg1, pact, &oact));
+    if (!is_error(ret) && arg3) {
+        if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0)) {
+            return -TARGET_EFAULT;
+        }
+        old_act->_sa_handler = oact._sa_handler;
+        old_act->sa_flags = oact.sa_flags;
+        memcpy(&old_act->sa_mask, &oact.sa_mask, sizeof(target_sigset_t));
+        unlock_user_struct(old_act, arg3, 1);
+    }
+    return ret;
+}
+
+
+/* sigprocmask(2) */
+static inline abi_long do_bsd_sigprocmask(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    sigset_t set, oldset, *set_ptr;
+    int how;
+
+    if (arg2) {
+        switch (arg1) {
+        case TARGET_SIG_BLOCK:
+            how = SIG_BLOCK;
+            break;
+
+        case TARGET_SIG_UNBLOCK:
+            how = SIG_UNBLOCK;
+            break;
+
+        case TARGET_SIG_SETMASK:
+            how = SIG_SETMASK;
+            break;
+
+        default:
+            return -TARGET_EFAULT;
+        }
+        p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        target_to_host_sigset(&set, p);
+        unlock_user(p, arg2, 0);
+        set_ptr = &set;
+    } else {
+        how = 0;
+        set_ptr = NULL;
+    }
+    ret = get_errno(sigprocmask(how, set_ptr, &oldset));
+    if (!is_error(ret) && arg3) {
+        p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        host_to_target_sigset(p, &oldset);
+        unlock_user(p, arg3, sizeof(target_sigset_t));
+    }
+    return ret;
+}
+
+/* sigpending(2) */
+static inline abi_long do_bsd_sigpending(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+    sigset_t set;
+
+    ret = get_errno(sigpending(&set));
+    if (!is_error(ret)) {
+        p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        host_to_target_sigset(p, &set);
+        unlock_user(p, arg1, sizeof(target_sigset_t));
+    }
+    return ret;
+}
+
+/* sigsuspend(2) */
+static inline abi_long do_bsd_sigsuspend(abi_long arg1, abi_long arg2)
+{
+    void *p;
+    sigset_t set;
+
+    p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    target_to_host_sigset(&set, p);
+    unlock_user(p, arg1, 0);
+
+    return get_errno(sigsuspend(&set));
+}
+
+/* sigreturn(2) */
+static inline abi_long do_bsd_sigreturn(void *cpu_env, abi_long arg1)
+{
+
+    return do_sigreturn(cpu_env, arg1);
+}
+
+/* sigvec(2) - not defined */
+/* sigblock(2) - not defined */
+/* sigsetmask(2) - not defined */
+/* sigstack(2) - not defined */
+
+/* sigwait(2) */
+static inline abi_long do_bsd_sigwait(abi_ulong arg1, abi_ulong arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+    sigset_t set;
+    int sig;
+
+    p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    target_to_host_sigset(&set, p);
+    unlock_user(p, arg1, 0);
+    ret = get_errno(sigwait(&set, &sig));
+    if (!is_error(ret) && arg2) {
+        ret = put_user_s32(sig, arg2);
+    }
+    return ret;
+}
+
+/* sigwaitinfo(2) */
+static inline abi_long do_bsd_sigwaitinfo(abi_ulong arg1, abi_ulong arg2)
+{
+    abi_long ret;
+    void *p;
+    sigset_t set;
+    siginfo_t uinfo;
+
+    p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    target_to_host_sigset(&set, p);
+    unlock_user(p, arg1, 0);
+    ret = get_errno(sigwaitinfo(&set, &uinfo));
+    if (!is_error(ret) && arg2) {
+        p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        host_to_target_siginfo(p, &uinfo);
+        unlock_user(p, arg2, sizeof(target_siginfo_t));
+    }
+    return ret;
+}
+
+/* sigqueue(2) */
+static inline abi_long do_bsd_sigqueue(abi_long arg1, abi_long arg2,
+        abi_ulong arg3)
+{
+    union sigval value;
+
+    value.sival_ptr = (void *)(uintptr_t)arg3;
+    return get_errno(sigqueue(arg1, target_to_host_signal(arg2), value));
+}
+
+/* sigaltstck(2) */
+static inline abi_long do_bsd_sigaltstack(void *cpu_env, abi_ulong arg1,
+        abi_ulong arg2)
+{
+
+    return do_sigaltstack(arg1, arg2, get_sp_from_cpustate(cpu_env));
+}
+
+/* kill(2) */
+static inline abi_long do_bsd_kill(abi_long pid, abi_long sig)
+{
+
+    return get_errno(kill(pid, target_to_host_signal(sig)));
+}
+
+/* killpg(2) */
+static inline abi_long do_bsd_killpg(abi_long pg, abi_long sig)
+{
+
+    return get_errno(killpg(pg, target_to_host_signal(sig)));
+}
+
+#endif /* !  __BSD_SIGNAL_H_ */
diff --git a/bsd-user/freebsd/os-signal.h b/bsd-user/freebsd/os-signal.h
new file mode 100644
index 0000000..d4a26da
--- /dev/null
+++ b/bsd-user/freebsd/os-signal.h
@@ -0,0 +1,43 @@ 
+/*
+ *  FreeBSD signal system call shims
+ *
+ *  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_OS_SIGNAL_H_
+#define __FREEBSD_OS_SIGNAL_H_
+
+#include <sys/procdesc.h>
+
+#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
+/* pdkill(2) */
+static inline abi_long do_freebsd_pdkill(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(pdkill(arg1, arg2));
+}
+
+#else
+
+static inline abi_long do_freebsd_pdkill(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall pdkill()\n");
+    return -TARGET_ENOSYS;
+}
+#endif /* ! __FreeBSD_version > 900000 */
+
+#endif /* ! __FREEBSD_OS_SIGNAL_H_ */
diff --git a/bsd-user/netbsd/os-signal.h b/bsd-user/netbsd/os-signal.h
new file mode 100644
index 0000000..3ec4dfe
--- /dev/null
+++ b/bsd-user/netbsd/os-signal.h
@@ -0,0 +1,34 @@ 
+/*
+ *  NetBSD signal system call shims
+ *
+ *
+ *  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 __NETBSD_OS_SIGNAL_H_
+#define __NETBSD_OS_SIGNAL_H_
+
+/*
+ * XXX To support FreeBSD binaries on NetBSD these syscalls will need
+ * to be emulated.
+ */
+
+static inline abi_long do_freebsd_pdkill(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall pdkill()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __NETBSD_OS_SIGNAL_H_ */
diff --git a/bsd-user/openbsd/os-signal.h b/bsd-user/openbsd/os-signal.h
new file mode 100644
index 0000000..5ca80b3
--- /dev/null
+++ b/bsd-user/openbsd/os-signal.h
@@ -0,0 +1,34 @@ 
+/*
+ *  OpenBSD signal system call shims
+ *
+ *
+ *  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 __OPENBSD_OS_SIGNAL_H_
+#define __OPENBSD_OS_SIGNAL_H_
+
+/*
+ * XXX To support FreeBSD binaries on OpenBSD these syscalls will need
+ * to be emulated.
+ */
+
+static inline abi_long do_freebsd_pdkill(abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall pdkill()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* ! __OPENBSD_OS_SIGNAL_H_ */
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index cbdd363..a04c1bf 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -36,8 +36,10 @@ 
 #include "bsd-errno.h"
 #include "bsd-file.h"
 #include "bsd-mem.h"
+#include "bsd-signal.h"
 
 #include "os-time.h"
+#include "os-signal.h"
 
 /* #define DEBUG */
 
@@ -777,6 +779,61 @@  abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         ret = do_freebsd_kevent(arg1, arg2, arg3, arg4, arg5, arg6);
         break;
 
+        /*
+         * signal system calls
+         */
+    case TARGET_FREEBSD_NR_sigtimedwait: /* sigtimedwait(2) */
+        ret = do_freebsd_sigtimedwait(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigaction: /* sigaction(2) */
+        ret = do_bsd_sigaction(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigprocmask: /* sigprocmask(2) */
+        ret = do_bsd_sigprocmask(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigpending: /* sigpending(2) */
+        ret = do_bsd_sigpending(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_sigsuspend: /* sigsuspend(2) */
+        ret = do_bsd_sigsuspend(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_sigreturn: /* sigreturn(2) */
+        ret = do_bsd_sigreturn(cpu_env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_sigwait: /* sigwait(2) */
+        ret = do_bsd_sigwait(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigwaitinfo: /* sigwaitinfo(2) */
+        ret = do_bsd_sigwaitinfo(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_sigqueue: /* sigqueue(2) */
+        ret = do_bsd_sigqueue(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigaltstack: /* sigaltstack(2) */
+        ret = do_bsd_sigaltstack(cpu_env, arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_kill: /* kill(2) */
+        ret = do_bsd_kill(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_killpg: /* killpg(2) */
+        ret = do_bsd_killpg(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_pdkill: /* pdkill(2) */
+        ret = do_freebsd_pdkill(arg1, arg2);
+        break;
+
 
     case TARGET_FREEBSD_NR_break:
         ret = do_obreak(arg1);