[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 04/23] bsd-user: add bsd signal emulation
From: |
Stacey Son |
Subject: |
[Qemu-devel] [PATCH 04/23] bsd-user: add bsd signal emulation |
Date: |
Sun, 23 Jun 2013 21:03:36 -0500 |
Add bsd-user signal emulation code, fix name space confict with sigqueue, add
arch dependent code for mips/mips64, and OS dependent definitions for FreeBSD.
Signed-off-by: Stacey Son <address@hidden>
---
bsd-user/freebsd/target_os_signal.h | 9 +
bsd-user/i386/target_arch_signal.h | 39 ++
bsd-user/i386/target_arch_vmparam.h | 2 -
bsd-user/mips/target_arch_signal.h | 160 ++++++
bsd-user/mips/target_arch_vmparam.h | 6 +-
bsd-user/mips64/target_arch_signal.h | 159 ++++++
bsd-user/qemu.h | 33 +-
bsd-user/signal.c | 922 +++++++++++++++++++++++++++++++++
bsd-user/sparc/target_arch_signal.h | 39 ++
bsd-user/sparc64/target_arch_signal.h | 39 ++
bsd-user/x86_64/target_arch_signal.h | 39 ++
11 files changed, 1429 insertions(+), 18 deletions(-)
diff --git a/bsd-user/freebsd/target_os_signal.h
b/bsd-user/freebsd/target_os_signal.h
index 3421a4e..d7004c8 100644
--- a/bsd-user/freebsd/target_os_signal.h
+++ b/bsd-user/freebsd/target_os_signal.h
@@ -52,6 +52,15 @@
#define TARGET_SIG_IGN ((abi_long)1) /* ignore signal */
#define TARGET_SIG_ERR ((abi_long)-1) /* error return from signal */
+#define TARGET_SA_ONSTACK 0x0001 /* take signal on signal stack */
+#define TARGET_SA_RESTART 0x0002 /* restart system on signal return */
+#define TARGET_SA_RESETHAND 0x0004 /* reset to SIG_DFL when taking signal */
+#define TARGET_SA_NODEFER 0x0010 /* don't mask the signal we're delivering
*/
+#define TARGET_SA_NOCLDWAIT 0x0020 /* don't create zombies (assign to pid 1)
*/
+#define TARGET_SA_USERTRAMP 0x0100 /* do not bounce off kernel's sigtramp */
+#define TARGET_SA_NOCLDSTOP 0x0008 /* do not generate SIGCHLD on child stop */
+#define TARGET_SA_SIGINFO 0x0040 /* generate siginfo_t */
+
/*
* Flags for sigprocmask:
*/
diff --git a/bsd-user/i386/target_arch_signal.h
b/bsd-user/i386/target_arch_signal.h
index ebd83f6..2e89529 100644
--- a/bsd-user/i386/target_arch_signal.h
+++ b/bsd-user/i386/target_arch_signal.h
@@ -20,4 +20,43 @@
#include "cpu.h"
+/* Size of the signal trampolin code placed on the stack. */
+/* #define TARGET_SZSIGCODE (0) */ /* XXX to be added. */
+
+/* compare to x86/include/_limits.h */
+#define TARGET_MINSIGSTKSZ (512 * 4) /* min sig stack size */
+#define TARGET_SIGSTKSZ (MINSIGSTKSZ + 32768) /* recommended size */
+
+struct target_sigcontext {
+ /* to be added */
+};
+
+typedef struct target_mcontext {
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+ target_sigset_t uc_sigmask;
+ target_mcontext_t uc_mcontext;
+ abi_ulong uc_link;
+ target_stack_t uc_stack;
+ int32_t uc_flags;
+ int32_t __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+ abi_ulong sf_signum;
+ abi_ulong sf_siginfo; /* code or pointer to sf_si */
+ abi_ulong sf_ucontext; /* points to sf_uc */
+ abi_ulong sf_addr; /* undocumented 4th arg */
+ target_ucontext_t sf_uc; /* = *sf_uncontext */
+ target_siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+ uint32_t __spare__[2];
+};
+
+static inline abi_long set_mcontext(CPUX86State *regs,
+ target_mcontext_t *mcp, int srflag)
+{
+ return -TARGET_EOPNOTSUPP;
+}
+
#endif /* TARGET_ARCH_SIGNAL_H */
diff --git a/bsd-user/i386/target_arch_vmparam.h
b/bsd-user/i386/target_arch_vmparam.h
index 6687adb..6d3cf4f 100644
--- a/bsd-user/i386/target_arch_vmparam.h
+++ b/bsd-user/i386/target_arch_vmparam.h
@@ -13,8 +13,6 @@
#define TARGET_USRSTACK (0xbfc00000)
-#define TARGET_PS_STRINGS (TARGET_USRSTACK - sizeof(struct target_ps_strings))
-
static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
{
return state->regs[R_ESP];
diff --git a/bsd-user/mips/target_arch_signal.h
b/bsd-user/mips/target_arch_signal.h
index 256c135..cc7e750 100644
--- a/bsd-user/mips/target_arch_signal.h
+++ b/bsd-user/mips/target_arch_signal.h
@@ -22,6 +22,23 @@
#define TARGET_INSN_SIZE 4 /* mips instruction size */
+/* Size of the signal trampolin code placed on the stack. */
+#define TARGET_SZSIGCODE ((abi_ulong)(4 * TARGET_INSN_SIZE))
+
+/* compare to mips/include/_limits.h */
+#define TARGET_MINSIGSTKSZ (512 * 4) /* min sig stack size
*/
+#define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) /* recommended size
*/
+
+/* compare to sys/mips/include/asm.h */
+#define TARGET_SZREG 8
+#define TARGET_CALLFRAME_SIZ (TARGET_SZREG * 4)
+
+/* mips/mips/pm_machdep.c */
+#define TARGET_UCONTEXT_MAGIC 0xACEDBADE
+#define TARGET_MC_GET_CLEAR_RET 0x0001
+#define TARGET_MC_ADD_MAGIC 0x0002
+#define TARGET_MC_SET_ONSTACK 0x0004
+
struct target_sigcontext {
target_sigset_t sc_mask; /* signal mask to retstore */
int32_t sc_onstack; /* sigstack state to restore */
@@ -65,4 +82,147 @@ struct target_sigframe {
uint32_t __spare__[2];
};
+/*
+ * Compare to mips/mips/pm_machdep.c sendsig()
+ * Assumes that target stack frame memory is locked.
+ */
+static inline abi_long
+set_sigtramp_args(CPUMIPSState *regs, int sig, struct target_sigframe *frame,
+ abi_ulong frame_addr, struct target_sigaction *ka)
+{
+
+ /* frame->sf_si.si_addr = regs->CP0_BadVAddr; */
+
+ /* MIPS only struct target_sigframe members: */
+ frame->sf_signum = sig;
+ frame->sf_siginfo = (abi_ulong)&frame->sf_si;
+ frame->sf_ucontext = (abi_ulong)&frame->sf_uc;
+
+ /*
+ * Arguments to signal handler:
+ * a0 ($4) = signal number
+ * a1 ($5) = siginfo pointer
+ * a2 ($6) = ucontext pointer
+ * PC = signal handler pointer
+ * t9 ($25) = signal handler pointer
+ * $29 = point to sigframe struct
+ * ra ($31) = sigtramp at base of user stack
+ */
+ 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;
+
+ return 0;
+}
+
+/*
+ * Compare to mips/mips/pm_machdep.c get_mcontext()
+ * Assumes that the memory is locked if mcp points to user memory.
+ */
+static inline abi_long
+get_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp, int flags)
+{
+ int i, err = 0;
+
+ if (flags & TARGET_MC_ADD_MAGIC) {
+ mcp->mc_regs[0] = tswapal(TARGET_UCONTEXT_MAGIC);
+ } else {
+ mcp->mc_regs[0] = 0;
+ }
+
+ if (flags & TARGET_MC_SET_ONSTACK) {
+ mcp->mc_onstack = tswapal(1);
+ } else {
+ mcp->mc_onstack = 0;
+ }
+
+ for (i = 1; i < 32; i++) {
+ mcp->mc_regs[i] = tswapal(regs->active_tc.gpr[i]);
+ }
+
+#if 0 /* XXX FP is not used right now */
+ abi_ulong used_fp = used_math() ? TARGET_MDTD_FPUSED : 0;
+
+ mcp->mc_fpused = used_fp;
+ if (used_fp) {
+ preempt_disable();
+ if (!is_fpu_owner()) {
+ own_fpu();
+ for (i = 0; i < 33; i++) {
+ mcp->mc_fpregs[i] = tswapal(regs->active_fpu.fpr[i]);
+ }
+ }
+ preempt_enable();
+ }
+#else
+ mcp->mc_fpused = 0;
+#endif
+
+ if (flags & TARGET_MC_GET_CLEAR_RET) {
+ mcp->mc_regs[2] = 0; /* v0 = 0 */
+ mcp->mc_regs[3] = 0; /* v1 = 0 */
+ mcp->mc_regs[7] = 0; /* a3 = 0 */
+ }
+
+ mcp->mc_pc = tswapal(regs->active_tc.PC);
+ mcp->mullo = tswapal(regs->active_tc.LO[0]);
+ mcp->mulhi = tswapal(regs->active_tc.HI[0]);
+ mcp->mc_tls = tswapal(regs->tls_value);
+
+ /* Don't do any of the status and cause registers. */
+
+ return err;
+}
+
+/* Compare to mips/mips/pm_machdep.c set_mcontext() */
+static inline abi_long set_mcontext(CPUMIPSState *regs,
+ target_mcontext_t *mcp, int srflag)
+{
+ int i, err = 0;
+
+ for (i = 1; i < 32; i++) {
+ regs->active_tc.gpr[i] = tswapal(mcp->mc_regs[i]);
+ }
+
+#if 0 /* XXX FP is not used right now */
+ abi_ulong used_fp = 0;
+
+ used_fp = tswapal(mcp->mc_fpused)
+ conditional_used_math(used_fp);
+
+ preempt_disabled();
+ if (used_math()) {
+ /* restore fpu context if we have used it before */
+ own_fpu();
+ for (i = 0; i < 32; i++) {
+ regs->active_fpu.fpr[i] = tswapal(mcp->mc_fpregs[i]);
+ }
+ } else {
+ /* Signal handler may have used FPU. Give it up. */
+ lose_fpu();
+ }
+ preempt_enable();
+#endif
+
+ regs->CP0_EPC = tswapal(mcp->mc_pc);
+ regs->active_tc.LO[0] = tswapal(mcp->mullo);
+ regs->active_tc.HI[0] = tswapal(mcp->mulhi);
+ regs->tls_value = tswapal(mcp->mc_tls);
+
+ if (srflag) {
+ /* doing sigreturn() */
+ regs->active_tc.PC = regs->CP0_EPC;
+ regs->CP0_EPC = 0; /* XXX for nested signals ? */
+ }
+
+ /* Don't do any of the status and cause registers. */
+
+ return err;
+}
+
#endif /* !_TARGET_ARCH_SIGNAL_H_ */
diff --git a/bsd-user/mips/target_arch_vmparam.h
b/bsd-user/mips/target_arch_vmparam.h
index 0480035..8f8bc9e 100644
--- a/bsd-user/mips/target_arch_vmparam.h
+++ b/bsd-user/mips/target_arch_vmparam.h
@@ -1,5 +1,5 @@
/*
- * mips64 VM parameters definitions
+ * mips VM parameters definitions
*
* Copyright (c) 2013 Stacey D. Son
*
@@ -29,8 +29,8 @@
#define TARGET_MAXSSIZ (64UL*1024*1024) /* max stack size */
#define TARGET_SGROWSIZ (128UL*1024) /* amount to grow stack */
-#define TARGET_VM_MINUSER_ADDRESS (0x0000000000000000UL)
-#define TARGET_VM_MAXUSER_ADDRESS (0x0000008000000000UL)
+#define TARGET_VM_MINUSER_ADDRESS (0x00000000)
+#define TARGET_VM_MAXUSER_ADDRESS (0x80000000)
#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE)
diff --git a/bsd-user/mips64/target_arch_signal.h
b/bsd-user/mips64/target_arch_signal.h
index 27aa700..5edcc3a 100644
--- a/bsd-user/mips64/target_arch_signal.h
+++ b/bsd-user/mips64/target_arch_signal.h
@@ -22,6 +22,22 @@
#define TARGET_INSN_SIZE 4 /* mips64 instruction size */
+/* Size of the signal trampolin code placed on the stack. */
+#define TARGET_SZSIGCODE ((abi_ulong)(4 * TARGET_INSN_SIZE))
+
+#define TARGET_MINSIGSTKSZ (512 * 4)
+#define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768)
+
+/* compare to sys/mips/include/asm.h */
+#define TARGET_SZREG 8
+#define TARGET_CALLFRAME_SIZ (TARGET_SZREG * 4)
+
+/* mips/mips/pm_machdep.c */
+#define TARGET_UCONTEXT_MAGIC 0xACEDBADE
+#define TARGET_MC_GET_CLEAR_RET 0x0001
+#define TARGET_MC_ADD_MAGIC 0x0002
+#define TARGET_MC_SET_ONSTACK 0x0004
+
struct target_sigcontext {
target_sigset_t sc_mask; /* signal mask to retstore */
int32_t sc_onstack; /* sigstack state to restore */
@@ -65,4 +81,147 @@ struct target_sigframe {
uint32_t __spare__[2];
};
+/*
+ * Compare to mips/mips/pm_machdep.c sendsig()
+ * Assumes that target stack frame memory is locked.
+ */
+static inline abi_long
+set_sigtramp_args(CPUMIPSState *regs, int sig, struct target_sigframe *frame,
+ abi_ulong frame_addr, struct target_sigaction *ka)
+{
+
+ /* frame->sf_si.si_addr = regs->CP0_BadVAddr; */
+
+ /* MIPS only struct target_sigframe members: */
+ frame->sf_signum = sig;
+ frame->sf_siginfo = (abi_ulong)&frame->sf_si;
+ frame->sf_ucontext = (abi_ulong)&frame->sf_uc;
+
+ /*
+ * Arguments to signal handler:
+ * a0 ($4) = signal number
+ * a1 ($5) = siginfo pointer
+ * a2 ($6) = ucontext pointer
+ * PC = signal handler pointer
+ * t9 ($25) = signal handler pointer
+ * $29 = point to sigframe struct
+ * ra ($31) = sigtramp at base of user stack
+ */
+ 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;
+
+ return 0;
+}
+
+/*
+ * Compare to mips/mips/pm_machdep.c get_mcontext()
+ * Assumes that the memory is locked if mcp points to user memory.
+ */
+static inline abi_long
+get_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp, int flags)
+{
+ int i, err = 0;
+
+ if (flags & TARGET_MC_ADD_MAGIC) {
+ mcp->mc_regs[0] = tswapal(TARGET_UCONTEXT_MAGIC);
+ } else {
+ mcp->mc_regs[0] = 0;
+ }
+
+ if (flags & TARGET_MC_SET_ONSTACK) {
+ mcp->mc_onstack = tswapal(1);
+ } else {
+ mcp->mc_onstack = 0;
+ }
+
+ for (i = 1; i < 32; i++) {
+ mcp->mc_regs[i] = tswapal(regs->active_tc.gpr[i]);
+ }
+
+#if 0 /* XXX FP is not used right now */
+ abi_ulong used_fp = used_math() ? TARGET_MDTD_FPUSED : 0;
+
+ mcp->mc_fpused = used_fp;
+ if (used_fp) {
+ preempt_disable();
+ if (!is_fpu_owner()) {
+ own_fpu();
+ for (i = 0; i < 33; i++) {
+ mcp->mc_fpregs[i] = tswapal(regs->active_fpu.fpr[i]);
+ }
+ }
+ preempt_enable();
+ }
+#else
+ mcp->mc_fpused = 0;
+#endif
+
+ if (flags & TARGET_MC_GET_CLEAR_RET) {
+ mcp->mc_regs[2] = 0; /* v0 = 0 */
+ mcp->mc_regs[3] = 0; /* v1 = 0 */
+ mcp->mc_regs[7] = 0; /* a3 = 0 */
+ }
+
+ mcp->mc_pc = tswapal(regs->active_tc.PC);
+ mcp->mullo = tswapal(regs->active_tc.LO[0]);
+ mcp->mulhi = tswapal(regs->active_tc.HI[0]);
+ mcp->mc_tls = tswapal(regs->tls_value);
+
+ /* Don't do any of the status and cause registers. */
+
+ return err;
+}
+
+/* Compare to mips/mips/pm_machdep.c set_mcontext() */
+static inline abi_long set_mcontext(CPUMIPSState *regs,
+ target_mcontext_t *mcp, int srflag)
+{
+ int i, err = 0;
+
+ for (i = 1; i < 32; i++) {
+ regs->active_tc.gpr[i] = tswapal(mcp->mc_regs[i]);
+ }
+
+#if 0 /* XXX FP is not used right now */
+ abi_ulong used_fp = 0;
+
+ used_fp = tswapal(mcp->mc_fpused)
+ conditional_used_math(used_fp);
+
+ preempt_disabled();
+ if (used_math()) {
+ /* restore fpu context if we have used it before */
+ own_fpu();
+ for (i = 0; i < 32; i++) {
+ regs->active_fpu.fpr[i] = tswapal(mcp->mc_fpregs[i]);
+ }
+ } else {
+ /* Signal handler may have used FPU. Give it up. */
+ lose_fpu();
+ }
+ preempt_enable();
+#endif
+
+ regs->CP0_EPC = tswapal(mcp->mc_pc);
+ regs->active_tc.LO[0] = tswapal(mcp->mullo);
+ regs->active_tc.HI[0] = tswapal(mcp->mulhi);
+ regs->tls_value = tswapal(mcp->mc_tls);
+
+ if (srflag) {
+ /* doing sigreturn() */
+ regs->active_tc.PC = regs->CP0_EPC;
+ regs->CP0_EPC = 0; /* XXX for nested signals ? */
+ }
+
+ /* Don't do any of the status and cause registers. */
+
+ return err;
+}
+
#endif /* !_TARGET_ARCH_SIGNAL_H_ */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index 63a3942..c0cdfcd 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -38,8 +38,8 @@ extern enum BSDType bsd_type;
#include "syscall_defs.h"
#include "syscall.h"
-#include "target_os_signal.h"
#include "target_os_vmparam.h"
+#include "target_os_signal.h"
#include "exec/gdbstub.h"
#if defined(CONFIG_USE_NPTL)
@@ -72,16 +72,16 @@ struct image_info {
#define MAX_SIGQUEUE_SIZE 1024
-struct sigqueue {
- struct sigqueue *next;
- //target_siginfo_t info;
+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
- first signal, we put it here */
+ struct qemu_sigqueue *first;
+ struct qemu_sigqueue info; /* in order to always have memory for the
+ first signal, we put it here */
};
/* NOTE: we force a big alignment so that the stack stored after is
@@ -92,8 +92,8 @@ typedef struct TaskState {
struct image_info *info;
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];
@@ -186,12 +186,19 @@ extern int do_strace;
/* signal.c */
void process_pending_signals(CPUArchState *cpu_env);
void signal_init(void);
-//int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info);
-//void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
-//void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
-long do_sigreturn(CPUArchState *env);
+int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info);
+void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
+void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
+int target_to_host_signal(int sig);
+int host_to_target_signal(int sig);
+void host_to_target_sigset(target_sigset_t *d, const sigset_t *s);
+void target_to_host_sigset(sigset_t *d, const target_sigset_t *s);
+long do_sigreturn(CPUArchState *env, abi_ulong addr);
long do_rt_sigreturn(CPUArchState *env);
abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp);
+int do_sigaction(int sig, const struct target_sigaction *act,
+ struct target_sigaction *oact);
+void QEMU_NORETURN force_sig(int target_sig);
/* mmap.c */
int target_mprotect(abi_ulong start, abi_ulong len, int prot);
diff --git a/bsd-user/signal.c b/bsd-user/signal.c
index e75fd0b..eb452fc 100644
--- a/bsd-user/signal.c
+++ b/bsd-user/signal.c
@@ -2,6 +2,7 @@
* Emulation of BSD signals
*
* Copyright (c) 2003 - 2008 Fabrice Bellard
+ * Copyright (c) 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
@@ -23,15 +24,936 @@
#include <unistd.h>
#include <signal.h>
#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
#include "qemu.h"
//#define DEBUG_SIGNAL
+static target_stack_t target_sigaltstack_used = {
+ .ss_sp = 0,
+ .ss_size = 0,
+ .ss_flags = TARGET_SS_DISABLE,
+};
+
+static uint8_t host_to_target_signal_table[TARGET_NSIG] = {
+ [SIGHUP] = TARGET_SIGHUP,
+ [SIGINT] = TARGET_SIGINT,
+ [SIGQUIT] = TARGET_SIGQUIT,
+ [SIGILL] = TARGET_SIGILL,
+ [SIGTRAP] = TARGET_SIGTRAP,
+ [SIGABRT] = TARGET_SIGABRT,
+ [SIGEMT] = TARGET_SIGEMT,
+ [SIGFPE] = TARGET_SIGFPE,
+ [SIGKILL] = TARGET_SIGKILL,
+ [SIGBUS] = TARGET_SIGBUS,
+ [SIGSEGV] = TARGET_SIGSEGV,
+ [SIGSYS] = TARGET_SIGSYS,
+ [SIGPIPE] = TARGET_SIGPIPE,
+ [SIGALRM] = TARGET_SIGALRM,
+ [SIGTERM] = TARGET_SIGTERM,
+ [SIGURG] = TARGET_SIGURG,
+ [SIGSTOP] = TARGET_SIGSTOP,
+ [SIGTSTP] = TARGET_SIGTSTP,
+ [SIGCONT] = TARGET_SIGCONT,
+ [SIGCHLD] = TARGET_SIGCHLD,
+ [SIGTTIN] = TARGET_SIGTTIN,
+ [SIGTTOU] = TARGET_SIGTTOU,
+ [SIGIO] = TARGET_SIGIO,
+ [SIGXCPU] = TARGET_SIGXCPU,
+ [SIGXFSZ] = TARGET_SIGXFSZ,
+ [SIGVTALRM] = TARGET_SIGVTALRM,
+ [SIGPROF] = TARGET_SIGPROF,
+ [SIGWINCH] = TARGET_SIGWINCH,
+ [SIGINFO] = TARGET_SIGINFO,
+ [SIGUSR1] = TARGET_SIGUSR1,
+ [SIGUSR2] = TARGET_SIGUSR2,
+#ifdef SIGTHR
+ [SIGTHR + 3] = TARGET_SIGTHR,
+#endif
+ /* [SIGLWP] = TARGET_SIGLWP, */
+#ifdef SIGLIBRT
+ [SIGLIBRT] = TARGET_SIGLIBRT,
+#endif
+
+ /*
+ * The following signals stay the same.
+ * Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
+ * host libpthread signals. This assumes no one actually uses
+ * SIGRTMAX. To fix this properly we need to manual signal delivery
+ * multiplexed over a single host signal.
+ */
+ [SIGRTMIN] = SIGRTMAX,
+ [SIGRTMAX] = SIGRTMIN,
+};
+
+static uint8_t target_to_host_signal_table[TARGET_NSIG];
+static struct target_sigaction sigact_table[TARGET_NSIG];
+static void host_signal_handler(int host_signum, siginfo_t *info, void *puc);
+static void target_to_host_sigset_internal(sigset_t *d,
+ const target_sigset_t *s);
+
+static inline int on_sig_stack(unsigned long sp)
+{
+ return sp - target_sigaltstack_used.ss_sp <
target_sigaltstack_used.ss_size;
+}
+
+static inline int sas_ss_flags(unsigned long sp)
+{
+ return target_sigaltstack_used.ss_size == 0 ? SS_DISABLE : on_sig_stack(sp)
+ ? SS_ONSTACK : 0;
+}
+
+int host_to_target_signal(int sig)
+{
+
+ if (sig < 0 || sig >= TARGET_NSIG) {
+ return sig;
+ }
+
+ return host_to_target_signal_table[sig];
+}
+
+int target_to_host_signal(int sig)
+{
+
+ if (sig >= TARGET_NSIG) {
+ return sig;
+ }
+
+ return target_to_host_signal_table[sig];
+}
+
+static inline void target_sigemptyset(target_sigset_t *set)
+{
+
+ memset(set, 0, sizeof(*set));
+}
+
+static inline void target_sigaddset(target_sigset_t *set, int signum)
+{
+
+ signum--;
+ uint32_t mask = (uint32_t)1 << (signum % TARGET_NSIG_BPW);
+ set->__bits[signum / TARGET_NSIG_BPW] |= mask;
+}
+
+static inline int target_sigismember(const target_sigset_t *set, int signum)
+{
+
+ signum--;
+ abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
+ return (set->__bits[signum / TARGET_NSIG_BPW] & mask) != 0;
+}
+
+static void host_to_target_sigset_internal(target_sigset_t *d,
+ const sigset_t *s)
+{
+ int i;
+
+ target_sigemptyset(d);
+ for (i = 1; i <= TARGET_NSIG; i++) {
+ if (sigismember(s, i)) {
+ target_sigaddset(d, host_to_target_signal(i));
+ }
+ }
+}
+
+void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
+{
+ target_sigset_t d1;
+ int i;
+
+ host_to_target_sigset_internal(&d1, s);
+ for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+ d->__bits[i] = tswap32(d1.__bits[i]);
+ }
+}
+
+static void target_to_host_sigset_internal(sigset_t *d,
+ const target_sigset_t *s)
+{
+ int i;
+
+ sigemptyset(d);
+ for (i = 1; i <= TARGET_NSIG; i++) {
+ if (target_sigismember(s, i)) {
+ sigaddset(d, target_to_host_signal(i));
+ }
+ }
+}
+
+void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
+{
+ target_sigset_t s1;
+ int i;
+
+ for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+ s1.__bits[i] = tswap32(s->__bits[i]);
+ }
+ target_to_host_sigset_internal(d, &s1);
+}
+
+/* Siginfo conversion. */
+static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
+ const siginfo_t *info)
+{
+ int sig, code;
+
+ sig = host_to_target_signal(info->si_signo);
+ /* XXX should have host_to_target_si_code() */
+ code = tswap32(info->si_code);
+ tinfo->si_signo = sig;
+ tinfo->si_errno = info->si_errno;
+ tinfo->si_code = info->si_code;
+ tinfo->si_pid = info->si_pid;
+ tinfo->si_uid = info->si_uid;
+ tinfo->si_addr = (abi_ulong)(unsigned long)info->si_addr;
+ /* si_value is opaque to kernel */
+ tinfo->si_value.sival_ptr =
+ (abi_ulong)(unsigned long)info->si_value.sival_ptr;
+ if (SIGILL == sig || SIGFPE == sig || SIGSEGV == sig || SIGBUS == sig ||
+ SIGTRAP == sig) {
+ tinfo->_reason._fault._trapno = info->_reason._fault._trapno;
+ }
+#ifdef SIGPOLL
+ if (SIGPOLL == sig) {
+ tinfo->_reason._poll._band = info->_reason._poll._band;
+ }
+#endif
+ if (SI_TIMER == code) {
+ tinfo->_reason._timer._timerid = info->_reason._timer._timerid;
+ tinfo->_reason._timer._overrun = info->_reason._timer._overrun;
+ }
+}
+
+static void tswap_siginfo(target_siginfo_t *tinfo, const target_siginfo_t
*info)
+{
+ 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);
+ tinfo->si_pid = tswap32(info->si_pid);
+ tinfo->si_uid = tswap32(info->si_uid);
+ tinfo->si_addr = tswapal(info->si_addr);
+ if (SIGILL == sig || SIGFPE == sig || SIGSEGV == sig || SIGBUS == sig ||
+ SIGTRAP == sig) {
+ tinfo->_reason._fault._trapno = tswap32(info->_reason._fault._trapno);
+ }
+#ifdef SIGPOLL
+ if (SIGPOLL == sig) {
+ tinfo->_reason._poll._band = tswap32(info->_reason._poll._band);
+ }
+#endif
+ if (SI_TIMER == code) {
+ tinfo->_reason._timer._timerid =
tswap32(info->_reason._timer._timerid);
+ tinfo->_reason._timer._overrun =
tswap32(info->_reason._timer._overrun);
+ }
+}
+
+void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
+{
+
+ host_to_target_siginfo_noswap(tinfo, info);
+ tswap_siginfo(tinfo, tinfo);
+}
+
+#if 0 /* not yet */
+/* Returns 1 if given signal should dump core if not handled. */
+static int core_dump_signal(int sig)
+{
+ switch (sig) {
+ case TARGET_SIGABRT:
+ case TARGET_SIGFPE:
+ case TARGET_SIGILL:
+ case TARGET_SIGQUIT:
+ case TARGET_SIGSEGV:
+ case TARGET_SIGTRAP:
+ case TARGET_SIGBUS:
+ return 1;
+ default:
+ return 0;
+ }
+}
+#endif /* not yet */
+
+/* Signal queue handling. */
+static inline struct qemu_sigqueue *alloc_sigqueue(CPUArchState *env)
+{
+ TaskState *ts = env->opaque;
+ struct qemu_sigqueue *q = ts->first_free;
+
+ if (!q) {
+ return NULL;
+ }
+ ts->first_free = q->next;
+ return q;
+}
+
+static inline void free_sigqueue(CPUArchState *env, struct qemu_sigqueue *q)
+{
+
+ TaskState *ts = env->opaque;
+ q->next = ts->first_free;
+ ts->first_free = q;
+}
+
+/* Abort execution with signal. */
+void QEMU_NORETURN force_sig(int target_sig)
+{
+#if 0 /* not yet */
+ TaskState *ts = (TaskState *)thread_env->opaque;
+ int core_dumped = 0;
+#endif
+ int host_sig;
+ struct sigaction act;
+
+ host_sig = target_to_host_signal(target_sig);
+ gdb_signalled(thread_env, target_sig);
+
+ /* Dump core if supported by target binary format */
+#if 0 /* net yet */
+ if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
+ stop_all_tasks();
+ core_dumped =
+ ((*ts->bprm->core_dump)(target_sig, thread_env) == 0);
+ }
+ if (core_dumped) {
+ struct rlimit nodump;
+
+ /*
+ * We already dumped the core of target process, we don't want
+ * a coredump of qemu itself.
+ */
+ getrlimit(RLIMIT_CORE, &nodump);
+ nodump.rlim_cur = 0;
+ (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) "
+ "- %s\n", target_sig, strsignal(host_sig), "core dumped");
+ }
+#endif /* not yet */
+
+ /*
+ * The proper exit code for dying from an uncaught signal is
+ * -<signal>. The kernel doesn't allow exit() or _exit() to pass
+ * a negative value. To get the proper exit code we need to
+ * actually die from an uncaught signal. Here the default signal
+ * handler is installed, we send ourself a signal and we wait for
+ * it to arrive.
+ */
+ memset(&act, 0, sizeof(act));
+ sigfillset(&act.sa_mask);
+ act.sa_handler = SIG_DFL;
+ sigaction(host_sig, &act, NULL);
+
+ kill(getpid(), host_sig);
+
+ /*
+ * Make sure the signal isn't masked (just reuse the mask inside
+ * of act).
+ */
+ sigdelset(&act.sa_mask, host_sig);
+ sigsuspend(&act.sa_mask);
+
+ /* unreachable */
+ abort();
+}
+
+/*
+ * Queue a signal so that it will be send to the virtual CPU as soon as
+ * possible.
+ */
+int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
+{
+ TaskState *ts = env->opaque;
+ struct emulated_sigtable *k;
+ struct qemu_sigqueue *q, **pq;
+ abi_ulong handler;
+ int queue;
+
+ k = &ts->sigtab[sig - 1];
+ queue = gdb_queuesig();
+ handler = sigact_table[sig - 1]._sa_handler;
+#ifdef DEBUG_SIGNAL
+ fprintf(stderr, "queue_signal: sig=%d handler=0x%lx flags=0x%x\n", sig,
+ handler, (uint32_t)sigact_table[sig - 1].sa_flags);
+#endif
+ if (!queue && (TARGET_SIG_DFL == handler)) {
+ if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN ||
+ sig == TARGET_SIGTTOU) {
+ kill(getpid(), SIGSTOP);
+ return 0;
+ } else {
+ if (sig != TARGET_SIGCHLD &&
+ sig != TARGET_SIGURG &&
+ sig != TARGET_SIGWINCH &&
+ sig != TARGET_SIGCONT) {
+ force_sig(sig);
+ } else {
+ return 0; /* The signal was ignored. */
+ }
+ }
+ } else if (!queue && (TARGET_SIG_IGN == handler)) {
+ return 0; /* Ignored signal. */
+ } else if (!queue && (TARGET_SIG_ERR == handler)) {
+ force_sig(sig);
+ } else {
+ pq = &k->first;
+
+ /*
+ * FreeBSD signals are always queued.
+ * Linux only queues real time signals.
+ * XXX this code is not thread safe.
+ */
+ if (!k->pending) {
+ /* first signal */
+ q = &k->info;
+ } else {
+ q = alloc_sigqueue(env);
+ if (!q) {
+ return -EAGAIN;
+ }
+ while (*pq != NULL) {
+ pq = &(*pq)->next;
+ }
+ }
+ *pq = q;
+ q->info = *info;
+ q->next = NULL;
+ k->pending = 1;
+ /* Signal that a new signal is pending. */
+ ts->signal_pending = 1;
+ return 1; /* Indicates that the signal was queued. */
+ }
+}
+
+static void host_signal_handler(int host_signum, siginfo_t *info, void *puc)
+{
+ int sig;
+ target_siginfo_t tinfo;
+
+ /*
+ * The CPU emulator uses some host signal to detect exceptions so
+ * we forward to it some signals.
+ */
+ if ((host_signum == SIGSEGV || host_signum == SIGBUS) &&
+ info->si_code < 0x10000) {
+ if (cpu_signal_handler(host_signum, info, puc)) {
+ return;
+ }
+ }
+
+ /* Get the target signal number. */
+ sig = host_to_target_signal(host_signum);
+ if (sig < 1 || sig > TARGET_NSIG) {
+ return;
+ }
+#ifdef DEBUG_SIGNAL
+ fprintf(stderr, "qemu: got signal %d\n", sig);
+#endif
+ host_to_target_siginfo_noswap(&tinfo, info);
+ if (queue_signal(thread_env, sig, &tinfo) == 1) {
+ /* Interrupt the virtual CPU as soon as possible. */
+ cpu_exit(thread_env);
+ }
+}
+
+/* do_sigaltstack() returns target values and errnos. */
+/* compare to kern/kern_sig.c sys_sigaltstack() and kern_sigaltstack() */
+abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
+{
+ int ret = 0;
+ target_stack_t ss, oss, *uss;
+
+ if (uoss_addr) {
+ /* Save current signal stack params */
+ oss.ss_sp = tswapl(target_sigaltstack_used.ss_sp);
+ oss.ss_size = tswapl(target_sigaltstack_used.ss_size);
+ oss.ss_flags = tswapl(sas_ss_flags(sp));
+ }
+
+ if (uss_addr) {
+
+ if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1) ||
+ __get_user(ss.ss_sp, &uss->ss_sp) ||
+ __get_user(ss.ss_size, &uss->ss_size) ||
+ __get_user(ss.ss_flags, &uss->ss_flags)) {
+ ret = -TARGET_EFAULT;
+ goto out;
+ }
+ unlock_user_struct(uss, uss_addr, 0);
+
+ if (on_sig_stack(sp)) {
+ ret = -TARGET_EPERM;
+ goto out;
+ }
+
+ if ((ss.ss_flags & ~TARGET_SS_DISABLE) != 0) {
+ ret = -TARGET_EINVAL;
+ goto out;
+ }
+
+ if (!(ss.ss_flags & ~TARGET_SS_DISABLE)) {
+ if (ss.ss_size < TARGET_MINSIGSTKSZ) {
+ ret = -TARGET_ENOMEM;
+ goto out;
+ }
+ } else {
+ ss.ss_size = 0;
+ ss.ss_sp = 0;
+ }
+
+ target_sigaltstack_used.ss_sp = ss.ss_sp;
+ target_sigaltstack_used.ss_size = ss.ss_size;
+ }
+
+ if (uoss_addr) {
+ /* Copy out to user saved signal stack params */
+ if (copy_to_user(uoss_addr, &oss, sizeof(oss))) {
+ ret = -TARGET_EFAULT;
+ goto out;
+ }
+ }
+
+out:
+ return ret;
+}
+
+static int fatal_signal(int sig)
+{
+
+ switch (sig) {
+ case TARGET_SIGCHLD:
+ case TARGET_SIGURG:
+ case TARGET_SIGWINCH:
+ /* Ignored by default. */
+ return 0;
+ case TARGET_SIGCONT:
+ case TARGET_SIGSTOP:
+ case TARGET_SIGTSTP:
+ case TARGET_SIGTTIN:
+ case TARGET_SIGTTOU:
+ /* Job control signals. */
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+/* do_sigaction() return host values and errnos */
+int do_sigaction(int sig, const struct target_sigaction *act,
+ struct target_sigaction *oact)
+{
+ struct target_sigaction *k;
+ struct sigaction act1;
+ int host_sig;
+ int ret = 0;
+
+ if (sig < 1 || sig > TARGET_NSIG || TARGET_SIGKILL == sig ||
+ TARGET_SIGSTOP == sig) {
+ return -EINVAL;
+ }
+ k = &sigact_table[sig - 1];
+#if defined(DEBUG_SIGNAL)
+ fprintf(stderr, "do_sigaction sig=%d act=%p, oact=%p\n",
+ sig, act, oact);
+#endif
+ if (oact) {
+ oact->_sa_handler = tswapal(k->_sa_handler);
+ oact->sa_flags = tswap32(k->sa_flags);
+ oact->sa_mask = k->sa_mask;
+ }
+ if (act) {
+ /* XXX: this is most likely not threadsafe. */
+ k->_sa_handler = tswapal(act->_sa_handler);
+ k->sa_flags = tswap32(act->sa_flags);
+ k->sa_mask = act->sa_mask;
+
+ /* Update the host signal state. */
+ host_sig = target_to_host_signal(sig);
+ if (host_sig != SIGSEGV && host_sig != SIGBUS) {
+ memset(&act1, 0, sizeof(struct sigaction));
+ sigfillset(&act1.sa_mask);
+ if (k->sa_flags & TARGET_SA_RESTART) {
+ act1.sa_flags |= SA_RESTART;
+ }
+ /*
+ * Note: It is important to update the host kernel signal mask to
+ * avoid getting unexpected interrupted system calls.
+ */
+ if (k->_sa_handler == TARGET_SIG_IGN) {
+ act1.sa_sigaction = (void *)SIG_IGN;
+ } else if (k->_sa_handler == TARGET_SIG_DFL) {
+ if (fatal_signal(sig)) {
+ act1.sa_flags = SA_SIGINFO;
+ act1.sa_sigaction = host_signal_handler;
+ } else {
+ act1.sa_sigaction = (void *)SIG_DFL;
+ }
+ } else {
+ act1.sa_flags = SA_SIGINFO;
+ act1.sa_sigaction = host_signal_handler;
+ }
+ ret = sigaction(host_sig, &act1, NULL);
+#if defined(DEBUG_SIGNAL)
+ fprintf(stderr, "sigaction (action = %p "
+ "(host_signal_handler = %p)) returned: %d\n",
+ act1.sa_sigaction, host_signal_handler, ret);
+#endif
+ }
+ }
+ return ret;
+}
+
+static inline abi_ulong get_sigframe(struct target_sigaction *ka,
+ CPUArchState *regs, size_t frame_size)
+{
+ abi_ulong sp;
+
+ /* Use default user stack */
+ sp = get_sp_from_cpustate(regs);
+
+ if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
+ sp = target_sigaltstack_used.ss_sp +
+ target_sigaltstack_used.ss_size;
+ }
+
+#if defined(TARGET_MIPS) || defined(TARGET_ARM)
+ return (sp - frame_size) & ~7;
+#else
+ return sp - frame_size;
+#endif
+}
+
+#if defined(TARGET_MIPS) || defined(TARGET_ARM)
+/* compare to mips/mips/pm_machdep.c and sparc64/sparc64/machdep.c sendsig() */
+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;
+ int i;
+
+#ifdef DEBUG_SIGNAL
+ fprintf(stderr, "setup_frame()\n");
+#endif
+#if defined(TARGET_SPARC64)
+ if (!sparc_user_sigtramp) {
+ /* No signal trampoline... kill the process. */
+ fprintf(stderr, "setup_frame(): no sigtramp\n");
+ force_sig(TARGET_SIGKILL);
+ }
+#endif
+
+ frame_addr = get_sigframe(ka, regs, sizeof(*frame));
+ 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;
+#else
+ int mflags = 0;
+#endif
+ if (get_mcontext(regs, &frame->sf_uc.uc_mcontext, mflags)) {
+ goto give_sigsegv;
+ }
+
+ for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+ if (__put_user(set->__bits[i], &frame->sf_uc.uc_sigmask.__bits[i])) {
+ 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
+
+ }
+
+ if (set_sigtramp_args(regs, sig, frame, frame_addr, ka)) {
+ goto give_sigsegv;
+ }
+
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+
+give_sigsegv:
+ unlock_user_struct(frame, frame_addr, 1);
+ force_sig(TARGET_SIGSEGV);
+}
+
+#else
+
+static void 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");
+}
+
+#endif /* !TARGET_MIPS */
+
+static int reset_signal_mask(target_ucontext_t *ucontext)
+{
+ int i;
+ sigset_t blocked;
+ target_sigset_t target_set;
+
+ for (i = 0; i < TARGET_NSIG_WORDS; i++)
+ if (__get_user(target_set.__bits[i],
+ &ucontext->uc_sigmask.__bits[i])) {
+ return -TARGET_EFAULT;
+ }
+ target_to_host_sigset_internal(&blocked, &target_set);
+ sigprocmask(SIG_SETMASK, &blocked, NULL);
+
+ return 0;
+}
+
+long do_sigreturn(CPUArchState *regs, abi_ulong addr)
+{
+ target_ucontext_t *ucontext;
+
+ /* Lock the memory and get the ucontext ptr from the stack frame */
+ if (!lock_user_struct(VERIFY_READ, ucontext, addr, 0)) {
+ goto badframe;
+ }
+
+ /* Set the register state back to before the signal. */
+ if (set_mcontext(regs, &ucontext->uc_mcontext, 1)) {
+ goto badframe;
+ }
+
+ /* And reset the signal mask. */
+ if (reset_signal_mask(ucontext)) {
+ goto badframe;
+ }
+
+ unlock_user_struct(ucontext, addr, 0);
+ return -TARGET_EJUSTRETURN;
+
+badframe:
+ if (addr != 0) {
+ unlock_user_struct(ucontext, addr, 0);
+ }
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_EFAULT;
+}
+
void signal_init(void)
{
+ struct sigaction act;
+ struct sigaction oact;
+ int i, j;
+ int host_sig;
+
+ /* Generate the signal conversion tables. */
+ for (i = 1; i < TARGET_NSIG; i++) {
+ if (host_to_target_signal_table[i] == 0) {
+ host_to_target_signal_table[i] = i;
+ }
+ }
+ for (i = 1; i < TARGET_NSIG; i++) {
+ j = host_to_target_signal_table[i];
+ target_to_host_signal_table[j] = i;
+ }
+
+ /*
+ * Set all host signal handlers. ALL signals are blocked during the
+ * handlers to serialize them.
+ */
+ memset(sigact_table, 0, sizeof(sigact_table));
+
+ sigfillset(&act.sa_mask);
+ act.sa_sigaction = host_signal_handler;
+ act.sa_flags = SA_SIGINFO;
+
+ for (i = 1; i <= TARGET_NSIG; i++) {
+ host_sig = target_to_host_signal(i);
+ sigaction(host_sig, NULL, &oact);
+ if (oact.sa_sigaction == (void *)SIG_IGN) {
+ sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
+ } else if (oact.sa_sigaction == (void *)SIG_DFL) {
+ sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
+ }
+ /*
+ * If there's already a handler installed then something has
+ * gone horribly wrong, so don't even try to handle that case.
+ * Install some handlers for our own use. We need at least
+ * SIGSEGV and SIGBUS, to detect exceptions. We can not just
+ * trap all signals because it affects syscall interrupt
+ * behavior. But do trap all default-fatal signals.
+ */
+ if (fatal_signal(i)) {
+ sigaction(host_sig, &act, NULL);
+ }
+ }
}
void process_pending_signals(CPUArchState *cpu_env)
{
+ 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 qemu_sigqueue *q;
+ TaskState *ts = cpu_env->opaque;
+
+ if (!ts->signal_pending) {
+ return;
+ }
+
+ /* FIXME: This is not threadsafe. */
+ k = ts->sigtab;
+ for (sig = 1; sig <= TARGET_NSIG; sig++) {
+ if (k->pending) {
+ goto handle_signal;
+ }
+ k++;
+ }
+#ifdef DEBUG_SIGNAL
+ fprintf(stderr, "qemu: process_pending_signals has no signals\n");
+#endif
+ /* If no signal is pending then just return. */
+ ts->signal_pending = 0;
+ return;
+
+handle_signal:
+#ifdef DEBUG_SIGNAL
+ fprintf(stderr, "qemu: process signal %d\n", sig);
+#endif
+
+ /* Dequeue signal. */
+ q = k->first;
+ k->first = q->next;
+ if (!k->first) {
+ k->pending = 0;
+ }
+
+ sig = gdb_handlesig(cpu_env, sig);
+ if (!sig) {
+ sa = NULL;
+ handler = TARGET_SIG_IGN;
+ } else {
+ sa = &sigact_table[sig - 1];
+ handler = sa->_sa_handler;
+ }
+
+ if (handler == TARGET_SIG_DFL) {
+#ifdef DEBUG_SIGNAL
+ fprintf(stderr, "qemu: TARGET_SIG_DFL\n");
+#endif
+ /*
+ * default handler : ignore some signal. The other are job
+ * control or fatal.
+ */
+ if (TARGET_SIGTSTP == sig || TARGET_SIGTTIN == sig ||
+ TARGET_SIGTTOU == sig) {
+ kill(getpid(), SIGSTOP);
+ } else if (TARGET_SIGCHLD != sig && TARGET_SIGURG != sig &&
+ TARGET_SIGWINCH != sig && TARGET_SIGCONT != sig) {
+ force_sig(sig);
+ }
+ } else if (TARGET_SIG_IGN == handler) {
+ /* ignore sig */
+#ifdef DEBUG_SIGNAL
+ fprintf(stderr, "qemu: TARGET_SIG_IGN\n");
+#endif
+ } else if (TARGET_SIG_ERR == handler) {
+#ifdef DEBUG_SIGNAL
+ fprintf(stderr, "qemu: TARGET_SIG_ERR\n");
+#endif
+ force_sig(sig);
+ } else {
+ /* compute the blocked signals during the handler execution */
+ target_to_host_sigset(&set, &sa->sa_mask);
+ /*
+ * SA_NODEFER indicates that the current signal should not be
+ * blocked during the handler.
+ */
+ if (!(sa->sa_flags & TARGET_SA_NODEFER)) {
+ sigaddset(&set, target_to_host_signal(sig));
+ }
+
+ /* block signals in the handler */
+ sigprocmask(SIG_BLOCK, &set, &old_set);
+
+ /*
+ * Save the previous blocked signal state to restore it at the
+ * end of the signal execution (see do_sigreturn).
+ */
+ host_to_target_sigset_internal(&target_old_set, &old_set);
+
+#if 0 /* not yet */
+#if defined(TARGET_I386) && !defined(TARGET_X86_64)
+ /* if the CPU is in VM86 mode, we restore the 32 bit values */
+ {
+ CPUX86State *env = cpu_env;
+ if (env->eflags & VM_MASK) {
+ save_v86_state(env);
+ }
+ }
+#endif
+#endif /* not yet */
+
+ code = q->info.si_code;
+ /* prepare the stack frame of the virtual CPU */
+ if (sa->sa_flags & TARGET_SA_SIGINFO) {
+ tswap_siginfo(&tinfo, &q->info);
+ setup_frame(sig, code, sa, &target_old_set, &tinfo, 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;
+ }
+ }
+ if (q != &k->info) {
+ free_sigqueue(cpu_env, q);
+ }
}
diff --git a/bsd-user/sparc/target_arch_signal.h
b/bsd-user/sparc/target_arch_signal.h
index 6bef0ad..275d1ef 100644
--- a/bsd-user/sparc/target_arch_signal.h
+++ b/bsd-user/sparc/target_arch_signal.h
@@ -3,4 +3,43 @@
#include "cpu.h"
+/* Size of the signal trampolin code placed on the stack. */
+/* #define TARGET_SZSIGCODE (0) */ /* XXX to be added. */
+
+/* compare to sparc64/include/_limits.h */
+#define TARGET_MINSIGSTKSZ (1024 * 4) /* min sig stack size */
+#define TARGET_SIGSTKSZ (MINSIGSTKSZ + 32768) /* recommended size */
+
+struct target_sigcontext {
+ /* to be added */
+};
+
+typedef struct target_mcontext {
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+ target_sigset_t uc_sigmask;
+ target_mcontext_t uc_mcontext;
+ abi_ulong uc_link;
+ target_stack_t uc_stack;
+ int32_t uc_flags;
+ int32_t __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+ abi_ulong sf_signum;
+ abi_ulong sf_siginfo; /* code or pointer to sf_si */
+ abi_ulong sf_ucontext; /* points to sf_uc */
+ abi_ulong sf_addr; /* undocumented 4th arg */
+ target_ucontext_t sf_uc; /* = *sf_uncontext */
+ target_siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+ uint32_t __spare__[2];
+};
+
+static inline abi_long set_mcontext(CPUSPARCState *regs,
+ target_mcontext_t *mcp, int srflag)
+{
+ return -TARGET_EOPNOTSUPP;
+}
+
#endif /* TARGET_ARCH_SIGNAL_H */
diff --git a/bsd-user/sparc64/target_arch_signal.h
b/bsd-user/sparc64/target_arch_signal.h
index eb7ad2a..8126383 100644
--- a/bsd-user/sparc64/target_arch_signal.h
+++ b/bsd-user/sparc64/target_arch_signal.h
@@ -20,4 +20,43 @@
#include "cpu.h"
+/* Size of the signal trampolin code placed on the stack. */
+/* #define TARGET_SZSIGCODE (0) */ /* XXX to be added. */
+
+/* compare to sparc64/include/_limits.h */
+#define TARGET_MINSIGSTKSZ (1024 * 4) /* min sig stack size */
+#define TARGET_SIGSTKSZ (MINSIGSTKSZ + 32768) /* recommended size */
+
+struct target_sigcontext {
+ /* to be added */
+};
+
+typedef struct target_mcontext {
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+ target_sigset_t uc_sigmask;
+ target_mcontext_t uc_mcontext;
+ abi_ulong uc_link;
+ target_stack_t uc_stack;
+ int32_t uc_flags;
+ int32_t __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+ abi_ulong sf_signum;
+ abi_ulong sf_siginfo; /* code or pointer to sf_si */
+ abi_ulong sf_ucontext; /* points to sf_uc */
+ abi_ulong sf_addr; /* undocumented 4th arg */
+ target_ucontext_t sf_uc; /* = *sf_uncontext */
+ target_siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+ uint32_t __spare__[2];
+};
+
+static inline abi_long set_mcontext(CPUSPARCState *regs,
+ target_mcontext_t *mcp, int srflag)
+{
+ return -TARGET_EOPNOTSUPP;
+}
+
#endif /* !_TARGET_ARCH_SIGNAL_H_ */
diff --git a/bsd-user/x86_64/target_arch_signal.h
b/bsd-user/x86_64/target_arch_signal.h
index 614c11a..d43f5f0 100644
--- a/bsd-user/x86_64/target_arch_signal.h
+++ b/bsd-user/x86_64/target_arch_signal.h
@@ -20,4 +20,43 @@
#include "cpu.h"
+/* Size of the signal trampolin code placed on the stack. */
+/* #define TARGET_SZSIGCODE (0) */ /* XXX to be added */
+
+/* compare to x86/include/_limits.h */
+#define TARGET_MINSIGSTKSZ (512 * 4) /* min sig stack size */
+#define TARGET_SIGSTKSZ (MINSIGSTKSZ + 32768) /* recommended size */
+
+struct target_sigcontext {
+ /* to be added */
+};
+
+typedef struct target_mcontext {
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+ target_sigset_t uc_sigmask;
+ target_mcontext_t uc_mcontext;
+ abi_ulong uc_link;
+ target_stack_t uc_stack;
+ int32_t uc_flags;
+ int32_t __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+ abi_ulong sf_signum;
+ abi_ulong sf_siginfo; /* code or pointer to sf_si */
+ abi_ulong sf_ucontext; /* points to sf_uc */
+ abi_ulong sf_addr; /* undocumented 4th arg */
+ target_ucontext_t sf_uc; /* = *sf_uncontext */
+ target_siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+ uint32_t __spare__[2];
+};
+
+static inline abi_long set_mcontext(CPUX86State *regs,
+ target_mcontext_t *mcp, int srflag)
+{
+ return -TARGET_EOPNOTSUPP;
+}
+
#endif /* !TARGET_ARCH_SIGNAL_H_ */
--
1.7.8
- [Qemu-devel] [PATCH 01/23] bsd-user: initial code clean up, (continued)
- [Qemu-devel] [PATCH 01/23] bsd-user: initial code clean up, Stacey Son, 2013/06/24
- [Qemu-devel] [PATCH 11/23] bsd-user: add shims for file related system calls, Stacey Son, 2013/06/24
- [Qemu-devel] [PATCH 10/23] bsd-user: add shims for memory management related syscalls, Stacey Son, 2013/06/24
- [Qemu-devel] [PATCH 09/23] bsd-user: refresh FreeBSD's system call numbers, Stacey Son, 2013/06/24
- [Qemu-devel] [PATCH 12/23] bsd-user: add shims for time related system calls., Stacey Son, 2013/06/24
- [Qemu-devel] [PATCH 03/23] bsd-user: additional seperation of OS and architecture dependent code, Stacey Son, 2013/06/24
- [Qemu-devel] [PATCH 04/23] bsd-user: add bsd signal emulation,
Stacey Son <=
- [Qemu-devel] [PATCH 22/23] bsd-user: add more strace formating, Stacey Son, 2013/06/24
- [Qemu-devel] [PATCH 20/23] bsd-user: add shims for extended attributes system calls, Stacey Son, 2013/06/24
- [Qemu-devel] [PATCH 18/23] bsd-user: add shim for the ioctl system call, Stacey Son, 2013/06/24
- [Qemu-devel] [PATCH 16/23] bsd-user: add shims for stat and file handle related syscalls, Stacey Son, 2013/06/24
- [Qemu-devel] [PATCH 15/23] bsd-user: add shims for socket related system calls, Stacey Son, 2013/06/24
- [Qemu-devel] [PATCH 14/23] bsd-user: add shims for process related system calls, Stacey Son, 2013/06/24
- [Qemu-devel] [PATCH 21/23] bsd-user: add miscellaneous system call shims, Stacey Son, 2013/06/24
- [Qemu-devel] [PATCH 17/23] bsd-user: add shims for thread related system calls, Stacey Son, 2013/06/24