aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/signal_64.c
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2008-12-10 05:26:44 -0500
committerPaul Mundt <lethal@linux-sh.org>2008-12-22 04:44:04 -0500
commit6ac034375fe8b4341137657adf5e6ff0dcb5a99f (patch)
tree0fe119cb5e3f216240e75e9e823964cb4245921a /arch/sh/kernel/signal_64.c
parentf15b2dc02fef0c53aa5ffa3c4617e184f057d402 (diff)
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: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel/signal_64.c')
-rw-r--r--arch/sh/kernel/signal_64.c93
1 files changed, 48 insertions, 45 deletions
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c
index ce3e851dffcb..08828ddd97ff 100644
--- a/arch/sh/kernel/signal_64.c
+++ b/arch/sh/kernel/signal_64.c
@@ -2,7 +2,7 @@
2 * arch/sh/kernel/signal_64.c 2 * arch/sh/kernel/signal_64.c
3 * 3 *
4 * Copyright (C) 2000, 2001 Paolo Alberelli 4 * Copyright (C) 2000, 2001 Paolo Alberelli
5 * Copyright (C) 2003 Paul Mundt 5 * Copyright (C) 2003 - 2008 Paul Mundt
6 * Copyright (C) 2004 Richard Curnow 6 * Copyright (C) 2004 Richard Curnow
7 * 7 *
8 * This file is subject to the terms and conditions of the GNU General Public 8 * This file is subject to the terms and conditions of the GNU General Public
@@ -43,7 +43,7 @@
43 43
44#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) 44#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
45 45
46static void 46static int
47handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, 47handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
48 sigset_t *oldset, struct pt_regs * regs); 48 sigset_t *oldset, struct pt_regs * regs);
49 49
@@ -80,21 +80,20 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset)
80 oldset = &current->blocked; 80 oldset = &current->blocked;
81 81
82 signr = get_signal_to_deliver(&info, &ka, regs, 0); 82 signr = get_signal_to_deliver(&info, &ka, regs, 0);
83
84 if (signr > 0) { 83 if (signr > 0) {
85 /* Whee! Actually deliver the signal. */ 84 /* Whee! Actually deliver the signal. */
86 handle_signal(signr, &info, &ka, oldset, regs); 85 if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
87 86 /*
88 /* 87 * If a signal was successfully delivered, the
89 * If a signal was successfully delivered, the saved sigmask 88 * saved sigmask is in its frame, and we can
90 * is in its frame, and we can clear the TIF_RESTORE_SIGMASK 89 * clear the TIF_RESTORE_SIGMASK flag.
91 * flag. 90 */
92 */ 91 if (test_thread_flag(TIF_RESTORE_SIGMASK))
93 if (test_thread_flag(TIF_RESTORE_SIGMASK)) 92 clear_thread_flag(TIF_RESTORE_SIGMASK);
94 clear_thread_flag(TIF_RESTORE_SIGMASK); 93
95 94 tracehook_signal_handler(signr, &info, &ka, regs, 0);
96 tracehook_signal_handler(signr, &info, &ka, regs, 0); 95 return 1;
97 return 1; 96 }
98 } 97 }
99 98
100no_signal: 99no_signal:
@@ -504,8 +503,8 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
504void sa_default_restorer(void); /* See comments below */ 503void sa_default_restorer(void); /* See comments below */
505void sa_default_rt_restorer(void); /* See comments below */ 504void sa_default_rt_restorer(void); /* See comments below */
506 505
507static void setup_frame(int sig, struct k_sigaction *ka, 506static int setup_frame(int sig, struct k_sigaction *ka,
508 sigset_t *set, struct pt_regs *regs) 507 sigset_t *set, struct pt_regs *regs)
509{ 508{
510 struct sigframe __user *frame; 509 struct sigframe __user *frame;
511 int err = 0; 510 int err = 0;
@@ -596,23 +595,21 @@ static void setup_frame(int sig, struct k_sigaction *ka,
596 595
597 set_fs(USER_DS); 596 set_fs(USER_DS);
598 597
599#if DEBUG_SIG
600 /* Broken %016Lx */ 598 /* Broken %016Lx */
601 printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n", 599 pr_debug("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
602 signal, 600 signal, current->comm, current->pid, frame,
603 current->comm, current->pid, frame, 601 regs->pc >> 32, regs->pc & 0xffffffff,
604 regs->pc >> 32, regs->pc & 0xffffffff, 602 DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
605 DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
606#endif
607 603
608 return; 604 return 0;
609 605
610give_sigsegv: 606give_sigsegv:
611 force_sigsegv(sig, current); 607 force_sigsegv(sig, current);
608 return -EFAULT;
612} 609}
613 610
614static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, 611static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
615 sigset_t *set, struct pt_regs *regs) 612 sigset_t *set, struct pt_regs *regs)
616{ 613{
617 struct rt_sigframe __user *frame; 614 struct rt_sigframe __user *frame;
618 int err = 0; 615 int err = 0;
@@ -702,29 +699,28 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
702 699
703 set_fs(USER_DS); 700 set_fs(USER_DS);
704 701
705#if DEBUG_SIG 702 pr_debug("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
706 /* Broken %016Lx */ 703 signal, current->comm, current->pid, frame,
707 printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n", 704 regs->pc >> 32, regs->pc & 0xffffffff,
708 signal, 705 DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
709 current->comm, current->pid, frame,
710 regs->pc >> 32, regs->pc & 0xffffffff,
711 DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
712#endif
713 706
714 return; 707 return 0;
715 708
716give_sigsegv: 709give_sigsegv:
717 force_sigsegv(sig, current); 710 force_sigsegv(sig, current);
711 return -EFAULT;
718} 712}
719 713
720/* 714/*
721 * OK, we're invoking a handler 715 * OK, we're invoking a handler
722 */ 716 */
723 717
724static void 718static int
725handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, 719handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
726 sigset_t *oldset, struct pt_regs * regs) 720 sigset_t *oldset, struct pt_regs * regs)
727{ 721{
722 int ret;
723
728 /* Are we from a system call? */ 724 /* Are we from a system call? */
729 if (regs->syscall_nr >= 0) { 725 if (regs->syscall_nr >= 0) {
730 /* If so, check system call restarting.. */ 726 /* If so, check system call restarting.. */
@@ -748,16 +744,23 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
748 744
749 /* Set up the stack frame */ 745 /* Set up the stack frame */
750 if (ka->sa.sa_flags & SA_SIGINFO) 746 if (ka->sa.sa_flags & SA_SIGINFO)
751 setup_rt_frame(sig, ka, info, oldset, regs); 747 ret = setup_rt_frame(sig, ka, info, oldset, regs);
752 else 748 else
753 setup_frame(sig, ka, oldset, regs); 749 ret = setup_frame(sig, ka, oldset, regs);
750
751 if (ka->sa.sa_flags & SA_ONESHOT)
752 ka->sa.sa_handler = SIG_DFL;
753
754 if (ret == 0) {
755 spin_lock_irq(&current->sighand->siglock);
756 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
757 if (!(ka->sa.sa_flags & SA_NODEFER))
758 sigaddset(&current->blocked,sig);
759 recalc_sigpending();
760 spin_unlock_irq(&current->sighand->siglock);
761 }
754 762
755 spin_lock_irq(&current->sighand->siglock); 763 return ret;
756 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
757 if (!(ka->sa.sa_flags & SA_NODEFER))
758 sigaddset(&current->blocked,sig);
759 recalc_sigpending();
760 spin_unlock_irq(&current->sighand->siglock);
761} 764}
762 765
763asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) 766asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)