new file mode 100644
@@ -0,0 +1,151 @@
+/*
+ * signal related system call shims
+ *
+ * Copyright (c) 2013 Stacey D. Son
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef BSD_SIGNAL_H
+#define BSD_SIGNAL_H
+
+#include <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;
+
+ ret = 0;
+ if (arg2) {
+ 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;
+ 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_EINVAL;
+ }
+ } else {
+ how = 0;
+ set_ptr = NULL;
+ }
+ ret = do_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(CPUArchState *env, abi_long arg1,
+ abi_long arg2)
+{
+ CPUState *cpu = env_cpu(env);
+ TaskState *ts = cpu->opaque;
+ void *p;
+ abi_long ret;
+
+ p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
+ if (p == NULL) {
+ return -TARGET_EFAULT;
+ }
+ target_to_host_sigset(&ts->sigsuspend_mask, p);
+ unlock_user(p, arg1, 0);
+
+ ret = get_errno(sigsuspend(&ts->sigsuspend_mask));
+ /* XXX Trivially true until safe_syscall */
+ if (ret != -TARGET_ERESTART) {
+ ts->in_sigsuspend = true;
+ }
+
+ return ret;
+}
+
+/* sigreturn(2) */
+static inline abi_long do_bsd_sigreturn(CPUArchState *env, abi_long arg1)
+{
+ if (block_signals()) {
+ return -TARGET_ERESTART;
+ }
+ return do_sigreturn(env, arg1);
+}
+
+/* sigvec(2) - not defined */
+/* sigblock(2) - not defined */
+/* sigsetmask(2) - not defined */
+/* sigstack(2) - not defined */
+
+#endif /* BSD_SIGNAL_H */
@@ -38,6 +38,7 @@
#include "bsd-mem.h"
#include "bsd-proc.h"
#include "bsd-misc.h"
+#include "bsd-signal.h"
/* BSD dependent syscall shims */
#include "os-stat.h"
@@ -32,6 +32,7 @@ int block_signals(void); /* Returns non zero if signal pending */
long do_rt_sigreturn(CPUArchState *env);
int do_sigaction(int sig, const struct target_sigaction *act,
struct target_sigaction *oact);
+int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp);
long do_sigreturn(CPUArchState *env, abi_ulong addr);
void force_sig_fault(int sig, int code, abi_ulong addr);
@@ -42,6 +43,9 @@ void process_pending_signals(CPUArchState *env);
void queue_signal(CPUArchState *env, int sig, int si_type,
target_siginfo_t *info);
void signal_init(void);
+abi_long target_to_host_sigevent(struct sigevent *host_sevp,
+ abi_ulong target_addr);
+int target_to_host_signal(int sig);
void target_to_host_sigset(sigset_t *d, const target_sigset_t *s);
/*
@@ -346,6 +346,33 @@ int block_signals(void)
return qatomic_xchg(&ts->signal_pending, 1);
}
+abi_long target_to_host_sigevent(struct sigevent *host_sevp,
+ abi_ulong target_addr)
+{
+ struct target_sigevent *target_sevp;
+
+ if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
+ return -TARGET_EFAULT;
+ }
+
+ /*
+ * This union is awkward on 64 bit systems because it has a 32 bit
+ * integer and a pointer in it; we follow the conversion approach
+ * used for handling sigval types in signal.c so the guest should get
+ * the correct value back even if we did a 64 bit byteswap and it's
+ * using the 32 bit integer.
+ */
+ host_sevp->sigev_value.sival_ptr =
+ (void *)(uintptr_t)target_sevp->sigev_value.sival_ptr;
+ host_sevp->sigev_signo =
+ target_to_host_signal(tswap32(target_sevp->sigev_signo));
+ host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
+ host_sevp->_sigev_un._threadid = tswap32(target_sevp->_sigev_un._threadid);
+
+ unlock_user_struct(target_sevp, target_addr, 0);
+ return 0;
+}
+
/* Returns 1 if given signal should dump core if not handled. */
static int core_dump_signal(int sig)
{
@@ -725,6 +752,46 @@ int do_sigaction(int sig, const struct target_sigaction *act,
return ret;
}
+int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
+{
+ TaskState *ts = get_task_state(thread_cpu);
+
+ if (oldset) {
+ *oldset = ts->signal_mask;
+ }
+
+ if (set) {
+ int i;
+
+ if (block_signals()) {
+ return -TARGET_ERESTART;
+ }
+
+ switch (how) {
+ case SIG_BLOCK:
+ sigorset(&ts->signal_mask, &ts->signal_mask, set);
+ break;
+ case SIG_UNBLOCK:
+ for (i = 1; i <= NSIG; ++i) {
+ if (sigismember(set, i)) {
+ sigdelset(&ts->signal_mask, i);
+ }
+ }
+ break;
+ case SIG_SETMASK:
+ ts->signal_mask = *set;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ /* Silently ignore attempts to change blocking status of KILL or STOP */
+ sigdelset(&ts->signal_mask, SIGKILL);
+ sigdelset(&ts->signal_mask, SIGSTOP);
+ }
+ return 0;
+}
+
static inline abi_ulong get_sigframe(struct target_sigaction *ka,
CPUArchState *env, size_t frame_size)
{