Commit 6ac03437 authored by Paul Mundt's avatar Paul Mundt

sh: Handle cases where setup{_rt,}_frame() fail on SH-5 signal delivery.

Presently these cases are not handled properly due to the return value
not being passed back. This needs to be correct to get proper behaviour
out of things like the tracehook signal notifier, amongst others.
Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent f15b2dc0
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* arch/sh/kernel/signal_64.c * arch/sh/kernel/signal_64.c
* *
* Copyright (C) 2000, 2001 Paolo Alberelli * Copyright (C) 2000, 2001 Paolo Alberelli
* Copyright (C) 2003 Paul Mundt * Copyright (C) 2003 - 2008 Paul Mundt
* Copyright (C) 2004 Richard Curnow * Copyright (C) 2004 Richard Curnow
* *
* This file is subject to the terms and conditions of the GNU General Public * This file is subject to the terms and conditions of the GNU General Public
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
static void static int
handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
sigset_t *oldset, struct pt_regs * regs); sigset_t *oldset, struct pt_regs * regs);
...@@ -80,21 +80,20 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset) ...@@ -80,21 +80,20 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset)
oldset = &current->blocked; oldset = &current->blocked;
signr = get_signal_to_deliver(&info, &ka, regs, 0); signr = get_signal_to_deliver(&info, &ka, regs, 0);
if (signr > 0) { if (signr > 0) {
/* Whee! Actually deliver the signal. */ /* Whee! Actually deliver the signal. */
handle_signal(signr, &info, &ka, oldset, regs); if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
/*
/* * If a signal was successfully delivered, the
* If a signal was successfully delivered, the saved sigmask * saved sigmask is in its frame, and we can
* is in its frame, and we can clear the TIF_RESTORE_SIGMASK * clear the TIF_RESTORE_SIGMASK flag.
* flag. */
*/ if (test_thread_flag(TIF_RESTORE_SIGMASK))
if (test_thread_flag(TIF_RESTORE_SIGMASK)) clear_thread_flag(TIF_RESTORE_SIGMASK);
clear_thread_flag(TIF_RESTORE_SIGMASK);
tracehook_signal_handler(signr, &info, &ka, regs, 0);
tracehook_signal_handler(signr, &info, &ka, regs, 0); return 1;
return 1; }
} }
no_signal: no_signal:
...@@ -504,8 +503,8 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) ...@@ -504,8 +503,8 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
void sa_default_restorer(void); /* See comments below */ void sa_default_restorer(void); /* See comments below */
void sa_default_rt_restorer(void); /* See comments below */ void sa_default_rt_restorer(void); /* See comments below */
static void setup_frame(int sig, struct k_sigaction *ka, static int setup_frame(int sig, struct k_sigaction *ka,
sigset_t *set, struct pt_regs *regs) sigset_t *set, struct pt_regs *regs)
{ {
struct sigframe __user *frame; struct sigframe __user *frame;
int err = 0; int err = 0;
...@@ -596,23 +595,21 @@ static void setup_frame(int sig, struct k_sigaction *ka, ...@@ -596,23 +595,21 @@ static void setup_frame(int sig, struct k_sigaction *ka,
set_fs(USER_DS); set_fs(USER_DS);
#if DEBUG_SIG
/* Broken %016Lx */ /* Broken %016Lx */
printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n", pr_debug("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
signal, signal, current->comm, current->pid, frame,
current->comm, current->pid, frame, regs->pc >> 32, regs->pc & 0xffffffff,
regs->pc >> 32, regs->pc & 0xffffffff, DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
#endif
return; return 0;
give_sigsegv: give_sigsegv:
force_sigsegv(sig, current); force_sigsegv(sig, current);
return -EFAULT;
} }
static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs *regs) sigset_t *set, struct pt_regs *regs)
{ {
struct rt_sigframe __user *frame; struct rt_sigframe __user *frame;
int err = 0; int err = 0;
...@@ -702,29 +699,28 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, ...@@ -702,29 +699,28 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
set_fs(USER_DS); set_fs(USER_DS);
#if DEBUG_SIG pr_debug("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
/* Broken %016Lx */ signal, current->comm, current->pid, frame,
printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n", regs->pc >> 32, regs->pc & 0xffffffff,
signal, DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
current->comm, current->pid, frame,
regs->pc >> 32, regs->pc & 0xffffffff,
DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
#endif
return; return 0;
give_sigsegv: give_sigsegv:
force_sigsegv(sig, current); force_sigsegv(sig, current);
return -EFAULT;
} }
/* /*
* OK, we're invoking a handler * OK, we're invoking a handler
*/ */
static void static int
handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
sigset_t *oldset, struct pt_regs * regs) sigset_t *oldset, struct pt_regs * regs)
{ {
int ret;
/* Are we from a system call? */ /* Are we from a system call? */
if (regs->syscall_nr >= 0) { if (regs->syscall_nr >= 0) {
/* If so, check system call restarting.. */ /* If so, check system call restarting.. */
...@@ -748,16 +744,23 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, ...@@ -748,16 +744,23 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
/* Set up the stack frame */ /* Set up the stack frame */
if (ka->sa.sa_flags & SA_SIGINFO) if (ka->sa.sa_flags & SA_SIGINFO)
setup_rt_frame(sig, ka, info, oldset, regs); ret = setup_rt_frame(sig, ka, info, oldset, regs);
else else
setup_frame(sig, ka, oldset, regs); ret = setup_frame(sig, ka, oldset, regs);
if (ka->sa.sa_flags & SA_ONESHOT)
ka->sa.sa_handler = SIG_DFL;
if (ret == 0) {
spin_lock_irq(&current->sighand->siglock);
sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
if (!(ka->sa.sa_flags & SA_NODEFER))
sigaddset(&current->blocked,sig);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
}
spin_lock_irq(&current->sighand->siglock); return ret;
sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
if (!(ka->sa.sa_flags & SA_NODEFER))
sigaddset(&current->blocked,sig);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
} }
asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment