aboutsummaryrefslogtreecommitdiff
path: root/linux-user/signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux-user/signal.c')
-rw-r--r--linux-user/signal.c211
1 files changed, 130 insertions, 81 deletions
diff --git a/linux-user/signal.c b/linux-user/signal.c
index d3ac0e2..e4eea69 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -512,9 +512,43 @@ void signal_init(void)
}
}
+#if !(defined(TARGET_X86_64) || defined(TARGET_UNICORE32))
+/* Force a synchronously taken signal. The kernel force_sig() function
+ * also forces the signal to "not blocked, not ignored", but for QEMU
+ * that work is done in process_pending_signals().
+ */
+static void force_sig(int sig)
+{
+ CPUState *cpu = thread_cpu;
+ CPUArchState *env = cpu->env_ptr;
+ target_siginfo_t info;
+
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = TARGET_SI_KERNEL;
+ info._sifields._kill._pid = 0;
+ info._sifields._kill._uid = 0;
+ queue_signal(env, info.si_signo, QEMU_SI_KILL, &info);
+}
+
+/* Force a SIGSEGV if we couldn't write to memory trying to set
+ * up the signal frame. oldsig is the signal we were trying to handle
+ * at the point of failure.
+ */
+static void force_sigsegv(int oldsig)
+{
+ if (oldsig == SIGSEGV) {
+ /* Make sure we don't try to deliver the signal again; this will
+ * end up with handle_pending_signal() calling dump_core_and_abort().
+ */
+ sigact_table[oldsig - 1]._sa_handler = TARGET_SIG_DFL;
+ }
+ force_sig(TARGET_SIGSEGV);
+}
+#endif
/* abort execution with signal */
-static void QEMU_NORETURN force_sig(int target_sig)
+static void QEMU_NORETURN dump_core_and_abort(int target_sig)
{
CPUState *cpu = thread_cpu;
CPUArchState *env = cpu->env_ptr;
@@ -569,19 +603,15 @@ static void QEMU_NORETURN force_sig(int target_sig)
/* 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)
+int queue_signal(CPUArchState *env, int sig, int si_type,
+ target_siginfo_t *info)
{
CPUState *cpu = ENV_GET_CPU(env);
TaskState *ts = cpu->opaque;
trace_user_queue_signal(env, sig);
- /* Currently all callers define siginfo structures which
- * use the _sifields._sigfault union member, so we can
- * set the type here. If that changes we should push this
- * out so the si_type is passed in by callers.
- */
- info->si_code = deposit32(info->si_code, 16, 16, QEMU_SI_FAULT);
+ info->si_code = deposit32(info->si_code, 16, 16, si_type);
ts->sync_signal.info = *info;
ts->sync_signal.pending = sig;
@@ -1015,10 +1045,7 @@ static void setup_frame(int sig, struct target_sigaction *ka,
return;
give_sigsegv:
- if (sig == TARGET_SIGSEGV) {
- ka->_sa_handler = TARGET_SIG_DFL;
- }
- force_sig(TARGET_SIGSEGV /* , current */);
+ force_sigsegv(sig);
}
/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
@@ -1088,10 +1115,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
return;
give_sigsegv:
- if (sig == TARGET_SIGSEGV) {
- ka->_sa_handler = TARGET_SIG_DFL;
- }
- force_sig(TARGET_SIGSEGV /* , current */);
+ force_sigsegv(sig);
}
static int
@@ -1165,7 +1189,7 @@ long do_sigreturn(CPUX86State *env)
badframe:
unlock_user_struct(frame, frame_addr, 0);
force_sig(TARGET_SIGSEGV);
- return 0;
+ return -TARGET_QEMU_ESIGRETURN;
}
long do_rt_sigreturn(CPUX86State *env)
@@ -1196,7 +1220,7 @@ long do_rt_sigreturn(CPUX86State *env)
badframe:
unlock_user_struct(frame, frame_addr, 0);
force_sig(TARGET_SIGSEGV);
- return 0;
+ return -TARGET_QEMU_ESIGRETURN;
}
#elif defined(TARGET_AARCH64)
@@ -1420,7 +1444,7 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
give_sigsegv:
unlock_user_struct(frame, frame_addr, 1);
- force_sig(TARGET_SIGSEGV);
+ force_sigsegv(usig);
}
static void setup_rt_frame(int sig, struct target_sigaction *ka,
@@ -1466,7 +1490,7 @@ long do_rt_sigreturn(CPUARMState *env)
badframe:
unlock_user_struct(frame, frame_addr, 0);
force_sig(TARGET_SIGSEGV);
- return 0;
+ return -TARGET_QEMU_ESIGRETURN;
}
long do_sigreturn(CPUARMState *env)
@@ -1772,7 +1796,7 @@ static void setup_frame_v1(int usig, struct target_sigaction *ka,
trace_user_setup_frame(regs, frame_addr);
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- return;
+ goto sigsegv;
}
setup_sigcontext(&frame->sc, regs, set->sig[0]);
@@ -1785,6 +1809,9 @@ static void setup_frame_v1(int usig, struct target_sigaction *ka,
frame_addr + offsetof(struct sigframe_v1, retcode));
unlock_user_struct(frame, frame_addr, 1);
+ return;
+sigsegv:
+ force_sigsegv(usig);
}
static void setup_frame_v2(int usig, struct target_sigaction *ka,
@@ -1795,7 +1822,7 @@ static void setup_frame_v2(int usig, struct target_sigaction *ka,
trace_user_setup_frame(regs, frame_addr);
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- return;
+ goto sigsegv;
}
setup_sigframe_v2(&frame->uc, set, regs);
@@ -1804,6 +1831,9 @@ static void setup_frame_v2(int usig, struct target_sigaction *ka,
frame_addr + offsetof(struct sigframe_v2, retcode));
unlock_user_struct(frame, frame_addr, 1);
+ return;
+sigsegv:
+ force_sigsegv(usig);
}
static void setup_frame(int usig, struct target_sigaction *ka,
@@ -1829,7 +1859,7 @@ static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
trace_user_setup_rt_frame(env, frame_addr);
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- return /* 1 */;
+ goto sigsegv;
}
info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
@@ -1859,6 +1889,9 @@ static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
env->regs[2] = uc_addr;
unlock_user_struct(frame, frame_addr, 1);
+ return;
+sigsegv:
+ force_sigsegv(usig);
}
static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
@@ -1871,7 +1904,7 @@ static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
trace_user_setup_rt_frame(env, frame_addr);
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- return /* 1 */;
+ goto sigsegv;
}
info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
@@ -1887,6 +1920,9 @@ static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
env->regs[2] = uc_addr;
unlock_user_struct(frame, frame_addr, 1);
+ return;
+sigsegv:
+ force_sigsegv(usig);
}
static void setup_rt_frame(int usig, struct target_sigaction *ka,
@@ -1976,8 +2012,8 @@ static long do_sigreturn_v1(CPUARMState *env)
return -TARGET_QEMU_ESIGRETURN;
badframe:
- force_sig(TARGET_SIGSEGV /* , current */);
- return 0;
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
}
static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
@@ -2035,7 +2071,8 @@ static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
return (abi_ulong*)(iwmmxtframe + 1);
}
-static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
+static int do_sigframe_return_v2(CPUARMState *env,
+ target_ulong context_addr,
struct target_ucontext_v2 *uc)
{
sigset_t host_set;
@@ -2062,8 +2099,11 @@ static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
}
}
- if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
+ if (do_sigaltstack(context_addr
+ + offsetof(struct target_ucontext_v2, tuc_stack),
+ 0, get_sp_from_cpustate(env)) == -EFAULT) {
return 1;
+ }
#if 0
/* Send SIGTRAP if we're single-stepping */
@@ -2094,7 +2134,10 @@ static long do_sigreturn_v2(CPUARMState *env)
goto badframe;
}
- if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) {
+ if (do_sigframe_return_v2(env,
+ frame_addr
+ + offsetof(struct sigframe_v2, uc),
+ &frame->uc)) {
goto badframe;
}
@@ -2103,8 +2146,8 @@ static long do_sigreturn_v2(CPUARMState *env)
badframe:
unlock_user_struct(frame, frame_addr, 0);
- force_sig(TARGET_SIGSEGV /* , current */);
- return 0;
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
}
long do_sigreturn(CPUARMState *env)
@@ -2157,8 +2200,8 @@ static long do_rt_sigreturn_v1(CPUARMState *env)
badframe:
unlock_user_struct(frame, frame_addr, 0);
- force_sig(TARGET_SIGSEGV /* , current */);
- return 0;
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
}
static long do_rt_sigreturn_v2(CPUARMState *env)
@@ -2181,7 +2224,10 @@ static long do_rt_sigreturn_v2(CPUARMState *env)
goto badframe;
}
- if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) {
+ if (do_sigframe_return_v2(env,
+ frame_addr
+ + offsetof(struct rt_sigframe_v2, uc),
+ &frame->uc)) {
goto badframe;
}
@@ -2190,8 +2236,8 @@ static long do_rt_sigreturn_v2(CPUARMState *env)
badframe:
unlock_user_struct(frame, frame_addr, 0);
- force_sig(TARGET_SIGSEGV /* , current */);
- return 0;
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
}
long do_rt_sigreturn(CPUARMState *env)
@@ -2445,7 +2491,7 @@ sigill_and_return:
#endif
sigsegv:
unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
- force_sig(TARGET_SIGSEGV);
+ force_sigsegv(sig);
}
static void setup_rt_frame(int sig, struct target_sigaction *ka,
@@ -2525,6 +2571,7 @@ long do_sigreturn(CPUSPARCState *env)
segv_and_exit:
unlock_user_struct(sf, sf_addr, 0);
force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
}
long do_rt_sigreturn(CPUSPARCState *env)
@@ -3037,7 +3084,7 @@ static void setup_frame(int sig, struct target_sigaction * ka,
return;
give_sigsegv:
- force_sig(TARGET_SIGSEGV/*, current*/);
+ force_sigsegv(sig);
}
long do_sigreturn(CPUMIPSState *regs)
@@ -3082,8 +3129,8 @@ long do_sigreturn(CPUMIPSState *regs)
return -TARGET_QEMU_ESIGRETURN;
badframe:
- force_sig(TARGET_SIGSEGV/*, current*/);
- return 0;
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
}
# endif /* O32 */
@@ -3146,7 +3193,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
give_sigsegv:
unlock_user_struct(frame, frame_addr, 1);
- force_sig(TARGET_SIGSEGV/*, current*/);
+ force_sigsegv(sig);
}
long do_rt_sigreturn(CPUMIPSState *env)
@@ -3179,8 +3226,8 @@ long do_rt_sigreturn(CPUMIPSState *env)
return -TARGET_QEMU_ESIGRETURN;
badframe:
- force_sig(TARGET_SIGSEGV/*, current*/);
- return 0;
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
}
#elif defined(TARGET_SH4)
@@ -3349,7 +3396,7 @@ static void setup_frame(int sig, struct target_sigaction *ka,
give_sigsegv:
unlock_user_struct(frame, frame_addr, 1);
- force_sig(TARGET_SIGSEGV);
+ force_sigsegv(sig);
}
static void setup_rt_frame(int sig, struct target_sigaction *ka,
@@ -3409,7 +3456,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
give_sigsegv:
unlock_user_struct(frame, frame_addr, 1);
- force_sig(TARGET_SIGSEGV);
+ force_sigsegv(sig);
}
long do_sigreturn(CPUSH4State *regs)
@@ -3446,7 +3493,7 @@ long do_sigreturn(CPUSH4State *regs)
badframe:
unlock_user_struct(frame, frame_addr, 0);
force_sig(TARGET_SIGSEGV);
- return 0;
+ return -TARGET_QEMU_ESIGRETURN;
}
long do_rt_sigreturn(CPUSH4State *regs)
@@ -3478,7 +3525,7 @@ long do_rt_sigreturn(CPUSH4State *regs)
badframe:
unlock_user_struct(frame, frame_addr, 0);
force_sig(TARGET_SIGSEGV);
- return 0;
+ return -TARGET_QEMU_ESIGRETURN;
}
#elif defined(TARGET_MICROBLAZE)
@@ -3656,7 +3703,7 @@ static void setup_frame(int sig, struct target_sigaction *ka,
unlock_user_struct(frame, frame_addr, 1);
return;
badframe:
- force_sig(TARGET_SIGSEGV);
+ force_sigsegv(sig);
}
static void setup_rt_frame(int sig, struct target_sigaction *ka,
@@ -3697,6 +3744,7 @@ long do_sigreturn(CPUMBState *env)
return -TARGET_QEMU_ESIGRETURN;
badframe:
force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
}
long do_rt_sigreturn(CPUMBState *env)
@@ -3826,7 +3874,7 @@ static void setup_frame(int sig, struct target_sigaction *ka,
unlock_user_struct(frame, frame_addr, 1);
return;
badframe:
- force_sig(TARGET_SIGSEGV);
+ force_sigsegv(sig);
}
static void setup_rt_frame(int sig, struct target_sigaction *ka,
@@ -3864,6 +3912,7 @@ long do_sigreturn(CPUCRISState *env)
return -TARGET_QEMU_ESIGRETURN;
badframe:
force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
}
long do_rt_sigreturn(CPUCRISState *env)
@@ -4065,10 +4114,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
give_sigsegv:
unlock_user_struct(frame, frame_addr, 1);
- if (sig == TARGET_SIGSEGV) {
- ka->_sa_handler = TARGET_SIG_DFL;
- }
- force_sig(TARGET_SIGSEGV);
+ force_sigsegv(sig);
}
long do_sigreturn(CPUOpenRISCState *env)
@@ -4249,7 +4295,7 @@ static void setup_frame(int sig, struct target_sigaction *ka,
return;
give_sigsegv:
- force_sig(TARGET_SIGSEGV);
+ force_sigsegv(sig);
}
static void setup_rt_frame(int sig, struct target_sigaction *ka,
@@ -4304,7 +4350,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
return;
give_sigsegv:
- force_sig(TARGET_SIGSEGV);
+ force_sigsegv(sig);
}
static int
@@ -4358,7 +4404,7 @@ long do_sigreturn(CPUS390XState *env)
badframe:
force_sig(TARGET_SIGSEGV);
- return 0;
+ return -TARGET_QEMU_ESIGRETURN;
}
long do_rt_sigreturn(CPUS390XState *env)
@@ -4389,7 +4435,7 @@ long do_rt_sigreturn(CPUS390XState *env)
badframe:
unlock_user_struct(frame, frame_addr, 0);
force_sig(TARGET_SIGSEGV);
- return 0;
+ return -TARGET_QEMU_ESIGRETURN;
}
#elif defined(TARGET_PPC)
@@ -4815,7 +4861,7 @@ static void setup_frame(int sig, struct target_sigaction *ka,
sigsegv:
unlock_user_struct(frame, frame_addr, 1);
- force_sig(TARGET_SIGSEGV);
+ force_sigsegv(sig);
}
static void setup_rt_frame(int sig, struct target_sigaction *ka,
@@ -4910,7 +4956,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
sigsegv:
unlock_user_struct(rt_sf, rt_sf_addr, 1);
- force_sig(TARGET_SIGSEGV);
+ force_sigsegv(sig);
}
@@ -4948,7 +4994,7 @@ sigsegv:
unlock_user_struct(sr, sr_addr, 1);
unlock_user_struct(sc, sc_addr, 1);
force_sig(TARGET_SIGSEGV);
- return 0;
+ return -TARGET_QEMU_ESIGRETURN;
}
/* See arch/powerpc/kernel/signal_32.c. */
@@ -5003,7 +5049,7 @@ long do_rt_sigreturn(CPUPPCState *env)
sigsegv:
unlock_user_struct(rt_sf, rt_sf_addr, 1);
force_sig(TARGET_SIGSEGV);
- return 0;
+ return -TARGET_QEMU_ESIGRETURN;
}
#elif defined(TARGET_M68K)
@@ -5159,7 +5205,7 @@ static void setup_frame(int sig, struct target_sigaction *ka,
return;
give_sigsegv:
- force_sig(TARGET_SIGSEGV);
+ force_sigsegv(sig);
}
static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
@@ -5298,7 +5344,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
give_sigsegv:
unlock_user_struct(frame, frame_addr, 1);
- force_sig(TARGET_SIGSEGV);
+ force_sigsegv(sig);
}
long do_sigreturn(CPUM68KState *env)
@@ -5333,7 +5379,7 @@ long do_sigreturn(CPUM68KState *env)
badframe:
force_sig(TARGET_SIGSEGV);
- return 0;
+ return -TARGET_QEMU_ESIGRETURN;
}
long do_rt_sigreturn(CPUM68KState *env)
@@ -5366,7 +5412,7 @@ long do_rt_sigreturn(CPUM68KState *env)
badframe:
unlock_user_struct(frame, frame_addr, 0);
force_sig(TARGET_SIGSEGV);
- return 0;
+ return -TARGET_QEMU_ESIGRETURN;
}
#elif defined(TARGET_ALPHA)
@@ -5505,10 +5551,8 @@ static void setup_frame(int sig, struct target_sigaction *ka,
if (err) {
give_sigsegv:
- if (sig == TARGET_SIGSEGV) {
- ka->_sa_handler = TARGET_SIG_DFL;
- }
- force_sig(TARGET_SIGSEGV);
+ force_sigsegv(sig);
+ return;
}
env->ir[IR_RA] = r26;
@@ -5562,10 +5606,8 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
if (err) {
give_sigsegv:
- if (sig == TARGET_SIGSEGV) {
- ka->_sa_handler = TARGET_SIG_DFL;
- }
- force_sig(TARGET_SIGSEGV);
+ force_sigsegv(sig);
+ return;
}
env->ir[IR_RA] = r26;
@@ -5599,6 +5641,7 @@ long do_sigreturn(CPUAlphaState *env)
badframe:
force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
}
long do_rt_sigreturn(CPUAlphaState *env)
@@ -5628,6 +5671,7 @@ long do_rt_sigreturn(CPUAlphaState *env)
badframe:
unlock_user_struct(frame, frame_addr, 0);
force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
}
#elif defined(TARGET_TILEGX)
@@ -5762,10 +5806,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
return;
give_sigsegv:
- if (sig == TARGET_SIGSEGV) {
- ka->_sa_handler = TARGET_SIG_DFL;
- }
- force_sig(TARGET_SIGSEGV /* , current */);
+ force_sigsegv(sig);
}
long do_rt_sigreturn(CPUTLGState *env)
@@ -5795,6 +5836,7 @@ long do_rt_sigreturn(CPUTLGState *env)
badframe:
unlock_user_struct(frame, frame_addr, 0);
force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
}
#else
@@ -5849,6 +5891,10 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig,
handler = sa->_sa_handler;
}
+ if (do_strace) {
+ print_taken_signal(sig, &k->info);
+ }
+
if (handler == TARGET_SIG_DFL) {
/* default handler : ignore some signal. The other are job control or fatal */
if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
@@ -5857,12 +5903,12 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig,
sig != TARGET_SIGURG &&
sig != TARGET_SIGWINCH &&
sig != TARGET_SIGCONT) {
- force_sig(sig);
+ dump_core_and_abort(sig);
}
} else if (handler == TARGET_SIG_IGN) {
/* ignore sig */
} else if (handler == TARGET_SIG_ERR) {
- force_sig(sig);
+ dump_core_and_abort(sig);
} else {
/* compute the blocked signals during the handler execution */
sigset_t *blocked_set;
@@ -5921,6 +5967,7 @@ void process_pending_signals(CPUArchState *cpu_env)
sigfillset(&set);
sigprocmask(SIG_SETMASK, &set, 0);
+ restart_scan:
sig = ts->sync_signal.pending;
if (sig) {
/* Synchronous signals are forced,
@@ -5948,8 +5995,10 @@ void process_pending_signals(CPUArchState *cpu_env)
(!sigismember(blocked_set,
target_to_host_signal_table[sig]))) {
handle_pending_signal(cpu_env, sig, &ts->sigtab[sig - 1]);
- /* Restart scan from the beginning */
- sig = 1;
+ /* Restart scan from the beginning, as handle_pending_signal
+ * might have resulted in a new synchronous signal (eg SIGSEGV).
+ */
+ goto restart_scan;
}
}