From ee4b4be9a1f589f8def271565b47125a1a96038a Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Sun, 26 May 2013 07:56:02 -0500 Subject: [PATCH 04/23] bsd-user: add bsd signal emulation To: Cc: 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 --- 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 #include #include +#include +#include +#include #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 + * -. 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