Blame view
arch/um/kernel/signal.c
4.81 KB
1d3468a66
|
1 |
/* |
ba180fd43
|
2 |
* Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
1da177e4c
|
3 4 |
* Licensed under the GPL */ |
c5d4bb171
|
5 6 7 8 9 10 |
#include <linux/module.h> #include <linux/ptrace.h> #include <linux/sched.h> #include <asm/siginfo.h> #include <asm/signal.h> #include <asm/unistd.h> |
1da177e4c
|
11 |
#include "frame_kern.h" |
ba180fd43
|
12 |
#include "kern_util.h" |
1da177e4c
|
13 14 15 16 17 18 19 20 21 22 |
EXPORT_SYMBOL(block_signals); EXPORT_SYMBOL(unblock_signals); #define _S(nr) (1<<((nr)-1)) #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) /* * OK, we're invoking a handler |
1d3468a66
|
23 |
*/ |
1da177e4c
|
24 25 26 27 28 29 30 31 32 33 34 |
static int handle_signal(struct pt_regs *regs, unsigned long signr, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset) { unsigned long sp; int err; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; /* Did we come from a system call? */ |
ba180fd43
|
35 |
if (PT_REGS_SYSCALL_NR(regs) >= 0) { |
1da177e4c
|
36 |
/* If so, check system call restarting.. */ |
c5d4bb171
|
37 |
switch (PT_REGS_SYSCALL_RET(regs)) { |
1da177e4c
|
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
case -ERESTART_RESTARTBLOCK: case -ERESTARTNOHAND: PT_REGS_SYSCALL_RET(regs) = -EINTR; break; case -ERESTARTSYS: if (!(ka->sa.sa_flags & SA_RESTART)) { PT_REGS_SYSCALL_RET(regs) = -EINTR; break; } /* fallthrough */ case -ERESTARTNOINTR: PT_REGS_RESTART_SYSCALL(regs); PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs); break; } } sp = PT_REGS_SP(regs); |
ba180fd43
|
57 |
if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags(sp) == 0)) |
1da177e4c
|
58 59 60 |
sp = current->sas_ss_sp + current->sas_ss_size; #ifdef CONFIG_ARCH_HAS_SC_SIGNALS |
ba180fd43
|
61 |
if (!(ka->sa.sa_flags & SA_SIGINFO)) |
1da177e4c
|
62 63 64 65 |
err = setup_signal_stack_sc(sp, signr, ka, regs, oldset); else #endif err = setup_signal_stack_si(sp, signr, ka, regs, info, oldset); |
ba180fd43
|
66 |
if (err) { |
1da177e4c
|
67 68 69 70 71 |
spin_lock_irq(¤t->sighand->siglock); current->blocked = *oldset; recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); force_sigsegv(signr, current); |
69be8f189
|
72 |
} else { |
1da177e4c
|
73 |
spin_lock_irq(¤t->sighand->siglock); |
1d3468a66
|
74 |
sigorsets(¤t->blocked, ¤t->blocked, |
1da177e4c
|
75 |
&ka->sa.sa_mask); |
ba180fd43
|
76 |
if (!(ka->sa.sa_flags & SA_NODEFER)) |
69be8f189
|
77 |
sigaddset(¤t->blocked, signr); |
1da177e4c
|
78 79 80 81 82 83 |
recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); } return err; } |
2fc10620e
|
84 |
static int kern_do_signal(struct pt_regs *regs) |
1da177e4c
|
85 86 87 |
{ struct k_sigaction ka_copy; siginfo_t info; |
2fc10620e
|
88 |
sigset_t *oldset; |
1da177e4c
|
89 |
int sig, handled_sig = 0; |
2fc10620e
|
90 91 92 93 |
if (test_thread_flag(TIF_RESTORE_SIGMASK)) oldset = ¤t->saved_sigmask; else oldset = ¤t->blocked; |
ba180fd43
|
94 |
while ((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0) { |
1da177e4c
|
95 96 |
handled_sig = 1; /* Whee! Actually deliver the signal. */ |
ba180fd43
|
97 98 99 |
if (!handle_signal(regs, sig, &ka_copy, &info, oldset)) { /* * a signal was successfully delivered; the saved |
2fc10620e
|
100 101 |
* sigmask will have been stored in the signal frame, * and will be restored by sigreturn, so we can simply |
ba180fd43
|
102 103 |
* clear the TIF_RESTORE_SIGMASK flag */ |
2fc10620e
|
104 105 |
if (test_thread_flag(TIF_RESTORE_SIGMASK)) clear_thread_flag(TIF_RESTORE_SIGMASK); |
1da177e4c
|
106 |
break; |
2fc10620e
|
107 |
} |
1da177e4c
|
108 109 110 |
} /* Did we come from a system call? */ |
ba180fd43
|
111 |
if (!handled_sig && (PT_REGS_SYSCALL_NR(regs) >= 0)) { |
1da177e4c
|
112 |
/* Restart the system call - no handlers present */ |
c5d4bb171
|
113 |
switch (PT_REGS_SYSCALL_RET(regs)) { |
2fc10620e
|
114 115 116 |
case -ERESTARTNOHAND: case -ERESTARTSYS: case -ERESTARTNOINTR: |
1da177e4c
|
117 118 |
PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs); PT_REGS_RESTART_SYSCALL(regs); |
2fc10620e
|
119 120 |
break; case -ERESTART_RESTARTBLOCK: |
1d3468a66
|
121 |
PT_REGS_ORIG_SYSCALL(regs) = __NR_restart_syscall; |
1da177e4c
|
122 |
PT_REGS_RESTART_SYSCALL(regs); |
2fc10620e
|
123 |
break; |
ba180fd43
|
124 |
} |
1da177e4c
|
125 |
} |
ba180fd43
|
126 127 |
/* * This closes a way to execute a system call on the host. If |
1da177e4c
|
128 129 130 |
* you set a breakpoint on a system call instruction and singlestep * from it, the tracing thread used to PTRACE_SINGLESTEP the process * rather than PTRACE_SYSCALL it, allowing the system call to execute |
1d3468a66
|
131 |
* on the host. The tracing thread will check this flag and |
1da177e4c
|
132 133 |
* PTRACE_SYSCALL if necessary. */ |
ba180fd43
|
134 |
if (current->ptrace & PT_DTRACE) |
1da177e4c
|
135 136 |
current->thread.singlestep_syscall = is_syscall(PT_REGS_IP(¤t->thread.regs)); |
2fc10620e
|
137 |
|
ba180fd43
|
138 139 140 141 |
/* * if there's no signal to deliver, we just put the saved sigmask * back */ |
2fc10620e
|
142 143 144 145 |
if (!handled_sig && test_thread_flag(TIF_RESTORE_SIGMASK)) { clear_thread_flag(TIF_RESTORE_SIGMASK); sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); } |
7c7a89499
|
146 |
return handled_sig; |
1da177e4c
|
147 148 149 150 |
} int do_signal(void) { |
7c7a89499
|
151 |
return kern_do_signal(¤t->thread.regs); |
1da177e4c
|
152 153 154 155 156 157 158 |
} /* * Atomically swap in the new signal mask, and wait for a signal. */ long sys_sigsuspend(int history0, int history1, old_sigset_t mask) { |
1da177e4c
|
159 160 |
mask &= _BLOCKABLE; spin_lock_irq(¤t->sighand->siglock); |
2fc10620e
|
161 |
current->saved_sigmask = current->blocked; |
1da177e4c
|
162 163 164 |
siginitset(¤t->blocked, mask); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); |
2fc10620e
|
165 166 167 168 |
current->state = TASK_INTERRUPTIBLE; schedule(); set_thread_flag(TIF_RESTORE_SIGMASK); return -ERESTARTNOHAND; |
1da177e4c
|
169 |
} |
1da177e4c
|
170 171 |
long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) { |
7c7a89499
|
172 |
return do_sigaltstack(uss, uoss, PT_REGS_SP(¤t->thread.regs)); |
1da177e4c
|
173 |
} |