diff options
author | Paul Mundt <lethal@linux-sh.org> | 2008-07-30 06:55:30 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2008-08-01 15:39:33 -0400 |
commit | ab99c733ae73cce31f2a2434f7099564e5a73d95 (patch) | |
tree | c9eb381f05688b8b4e79d2ffe495b4d4b302f2d4 /arch/sh/kernel/signal_64.c | |
parent | c459dbf294b4a3d70490a468a7ca3907fb2c2f57 (diff) |
sh: Make syscall tracer use tracehook notifiers, add TIF_NOTIFY_RESUME.
This follows the changes in commits:
7d6d637dac2050f30a1b57b0a3dc5de4a10616ba
4f72c4279eab1e5f3ed1ac4e55d4527617582392
on powerpc. Adding in TIF_NOTIFY_RESUME, and cleaning up the syscall
tracing to be more generic. This is an incremental step to turning
on tracehook, as well as unifying more of the ptrace and signal code
across the 32/64 split.
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.c | 166 |
1 files changed, 88 insertions, 78 deletions
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c index 552eb810cd85..1d62dfef77f1 100644 --- a/arch/sh/kernel/signal_64.c +++ b/arch/sh/kernel/signal_64.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/ptrace.h> | 22 | #include <linux/ptrace.h> |
23 | #include <linux/unistd.h> | 23 | #include <linux/unistd.h> |
24 | #include <linux/stddef.h> | 24 | #include <linux/stddef.h> |
25 | #include <linux/tracehook.h> | ||
25 | #include <asm/ucontext.h> | 26 | #include <asm/ucontext.h> |
26 | #include <asm/uaccess.h> | 27 | #include <asm/uaccess.h> |
27 | #include <asm/pgtable.h> | 28 | #include <asm/pgtable.h> |
@@ -42,7 +43,84 @@ | |||
42 | 43 | ||
43 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 44 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
44 | 45 | ||
45 | asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); | 46 | /* |
47 | * Note that 'init' is a special process: it doesn't get signals it doesn't | ||
48 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | ||
49 | * mistake. | ||
50 | * | ||
51 | * Note that we go through the signals twice: once to check the signals that | ||
52 | * the kernel can handle, and then we build all the user-level signal handling | ||
53 | * stack-frames in one go after that. | ||
54 | */ | ||
55 | static int do_signal(struct pt_regs *regs, sigset_t *oldset) | ||
56 | { | ||
57 | siginfo_t info; | ||
58 | int signr; | ||
59 | struct k_sigaction ka; | ||
60 | |||
61 | /* | ||
62 | * We want the common case to go fast, which | ||
63 | * is why we may in certain cases get here from | ||
64 | * kernel mode. Just return without doing anything | ||
65 | * if so. | ||
66 | */ | ||
67 | if (!user_mode(regs)) | ||
68 | return 1; | ||
69 | |||
70 | if (try_to_freeze()) | ||
71 | goto no_signal; | ||
72 | |||
73 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
74 | oldset = ¤t->saved_sigmask; | ||
75 | else if (!oldset) | ||
76 | oldset = ¤t->blocked; | ||
77 | |||
78 | signr = get_signal_to_deliver(&info, &ka, regs, 0); | ||
79 | |||
80 | if (signr > 0) { | ||
81 | /* Whee! Actually deliver the signal. */ | ||
82 | handle_signal(signr, &info, &ka, oldset, regs); | ||
83 | |||
84 | /* | ||
85 | * If a signal was successfully delivered, the saved sigmask | ||
86 | * is in its frame, and we can clear the TIF_RESTORE_SIGMASK | ||
87 | * flag. | ||
88 | */ | ||
89 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
90 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
91 | |||
92 | tracehook_signal_handler(signr, &info, &ka, regs, 0); | ||
93 | return 1; | ||
94 | } | ||
95 | |||
96 | no_signal: | ||
97 | /* Did we come from a system call? */ | ||
98 | if (regs->syscall_nr >= 0) { | ||
99 | /* Restart the system call - no handlers present */ | ||
100 | switch (regs->regs[REG_RET]) { | ||
101 | case -ERESTARTNOHAND: | ||
102 | case -ERESTARTSYS: | ||
103 | case -ERESTARTNOINTR: | ||
104 | /* Decode Syscall # */ | ||
105 | regs->regs[REG_RET] = regs->syscall_nr; | ||
106 | regs->pc -= 4; | ||
107 | break; | ||
108 | |||
109 | case -ERESTART_RESTARTBLOCK: | ||
110 | regs->regs[REG_RET] = __NR_restart_syscall; | ||
111 | regs->pc -= 4; | ||
112 | break; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | /* No signal to deliver -- put the saved sigmask back */ | ||
117 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
118 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
119 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
120 | } | ||
121 | |||
122 | return 0; | ||
123 | } | ||
46 | 124 | ||
47 | /* | 125 | /* |
48 | * Atomically swap in the new signal mask, and wait for a signal. | 126 | * Atomically swap in the new signal mask, and wait for a signal. |
@@ -643,14 +721,13 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
643 | switch (regs->regs[REG_RET]) { | 721 | switch (regs->regs[REG_RET]) { |
644 | case -ERESTART_RESTARTBLOCK: | 722 | case -ERESTART_RESTARTBLOCK: |
645 | case -ERESTARTNOHAND: | 723 | case -ERESTARTNOHAND: |
724 | no_system_call_restart: | ||
646 | regs->regs[REG_RET] = -EINTR; | 725 | regs->regs[REG_RET] = -EINTR; |
647 | break; | 726 | break; |
648 | 727 | ||
649 | case -ERESTARTSYS: | 728 | case -ERESTARTSYS: |
650 | if (!(ka->sa.sa_flags & SA_RESTART)) { | 729 | if (!(ka->sa.sa_flags & SA_RESTART)) |
651 | regs->regs[REG_RET] = -EINTR; | 730 | goto no_system_call_restart; |
652 | break; | ||
653 | } | ||
654 | /* fallthrough */ | 731 | /* fallthrough */ |
655 | case -ERESTARTNOINTR: | 732 | case -ERESTARTNOINTR: |
656 | /* Decode syscall # */ | 733 | /* Decode syscall # */ |
@@ -673,80 +750,13 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
673 | spin_unlock_irq(¤t->sighand->siglock); | 750 | spin_unlock_irq(¤t->sighand->siglock); |
674 | } | 751 | } |
675 | 752 | ||
676 | /* | 753 | asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) |
677 | * Note that 'init' is a special process: it doesn't get signals it doesn't | ||
678 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | ||
679 | * mistake. | ||
680 | * | ||
681 | * Note that we go through the signals twice: once to check the signals that | ||
682 | * the kernel can handle, and then we build all the user-level signal handling | ||
683 | * stack-frames in one go after that. | ||
684 | */ | ||
685 | int do_signal(struct pt_regs *regs, sigset_t *oldset) | ||
686 | { | 754 | { |
687 | siginfo_t info; | 755 | if (thread_info_flags & _TIF_SIGPENDING) |
688 | int signr; | 756 | do_signal(regs, 0); |
689 | struct k_sigaction ka; | ||
690 | |||
691 | /* | ||
692 | * We want the common case to go fast, which | ||
693 | * is why we may in certain cases get here from | ||
694 | * kernel mode. Just return without doing anything | ||
695 | * if so. | ||
696 | */ | ||
697 | if (!user_mode(regs)) | ||
698 | return 1; | ||
699 | |||
700 | if (try_to_freeze()) | ||
701 | goto no_signal; | ||
702 | |||
703 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
704 | oldset = ¤t->saved_sigmask; | ||
705 | else if (!oldset) | ||
706 | oldset = ¤t->blocked; | ||
707 | |||
708 | signr = get_signal_to_deliver(&info, &ka, regs, 0); | ||
709 | |||
710 | if (signr > 0) { | ||
711 | /* Whee! Actually deliver the signal. */ | ||
712 | handle_signal(signr, &info, &ka, oldset, regs); | ||
713 | 757 | ||
714 | /* | 758 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
715 | * If a signal was successfully delivered, the saved sigmask | 759 | clear_thread_flag(TIF_NOTIFY_RESUME); |
716 | * is in its frame, and we can clear the TIF_RESTORE_SIGMASK | 760 | tracehook_notify_resume(regs); |
717 | * flag. | ||
718 | */ | ||
719 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
720 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
721 | |||
722 | return 1; | ||
723 | } | 761 | } |
724 | |||
725 | no_signal: | ||
726 | /* Did we come from a system call? */ | ||
727 | if (regs->syscall_nr >= 0) { | ||
728 | /* Restart the system call - no handlers present */ | ||
729 | switch (regs->regs[REG_RET]) { | ||
730 | case -ERESTARTNOHAND: | ||
731 | case -ERESTARTSYS: | ||
732 | case -ERESTARTNOINTR: | ||
733 | /* Decode Syscall # */ | ||
734 | regs->regs[REG_RET] = regs->syscall_nr; | ||
735 | regs->pc -= 4; | ||
736 | break; | ||
737 | |||
738 | case -ERESTART_RESTARTBLOCK: | ||
739 | regs->regs[REG_RET] = __NR_restart_syscall; | ||
740 | regs->pc -= 4; | ||
741 | break; | ||
742 | } | ||
743 | } | ||
744 | |||
745 | /* No signal to deliver -- put the saved sigmask back */ | ||
746 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
747 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
748 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
749 | } | ||
750 | |||
751 | return 0; | ||
752 | } | 762 | } |