1 /* 2 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 3 * Licensed under the GPL 4 */ 5 6 #include <linux/module.h> 7 #include <linux/ptrace.h> 8 #include <linux/sched.h> 9 #include <asm/siginfo.h> 10 #include <asm/signal.h> 11 #include <asm/unistd.h> 12 #include <frame_kern.h> 13 #include <kern_util.h> 14 15 EXPORT_SYMBOL(block_signals); 16 EXPORT_SYMBOL(unblock_signals); 17 18 /* 19 * OK, we're invoking a handler 20 */ 21 static void handle_signal(struct pt_regs *regs, unsigned long signr, 22 struct k_sigaction *ka, siginfo_t *info) 23 { 24 sigset_t *oldset = sigmask_to_save(); 25 int singlestep = 0; 26 unsigned long sp; 27 int err; 28 29 if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED)) 30 singlestep = 1; 31 32 /* Did we come from a system call? */ 33 if (PT_REGS_SYSCALL_NR(regs) >= 0) { 34 /* If so, check system call restarting.. */ 35 switch (PT_REGS_SYSCALL_RET(regs)) { 36 case -ERESTART_RESTARTBLOCK: 37 case -ERESTARTNOHAND: 38 PT_REGS_SYSCALL_RET(regs) = -EINTR; 39 break; 40 41 case -ERESTARTSYS: 42 if (!(ka->sa.sa_flags & SA_RESTART)) { 43 PT_REGS_SYSCALL_RET(regs) = -EINTR; 44 break; 45 } 46 /* fallthrough */ 47 case -ERESTARTNOINTR: 48 PT_REGS_RESTART_SYSCALL(regs); 49 PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs); 50 break; 51 } 52 } 53 54 sp = PT_REGS_SP(regs); 55 if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags(sp) == 0)) 56 sp = current->sas_ss_sp + current->sas_ss_size; 57 58 #ifdef CONFIG_ARCH_HAS_SC_SIGNALS 59 if (!(ka->sa.sa_flags & SA_SIGINFO)) 60 err = setup_signal_stack_sc(sp, signr, ka, regs, oldset); 61 else 62 #endif 63 err = setup_signal_stack_si(sp, signr, ka, regs, info, oldset); 64 65 if (err) 66 force_sigsegv(signr, current); 67 else 68 signal_delivered(signr, info, ka, regs, singlestep); 69 } 70 71 static int kern_do_signal(struct pt_regs *regs) 72 { 73 struct k_sigaction ka_copy; 74 siginfo_t info; 75 int sig, handled_sig = 0; 76 77 while ((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0) { 78 handled_sig = 1; 79 /* Whee! Actually deliver the signal. */ 80 handle_signal(regs, sig, &ka_copy, &info); 81 } 82 83 /* Did we come from a system call? */ 84 if (!handled_sig && (PT_REGS_SYSCALL_NR(regs) >= 0)) { 85 /* Restart the system call - no handlers present */ 86 switch (PT_REGS_SYSCALL_RET(regs)) { 87 case -ERESTARTNOHAND: 88 case -ERESTARTSYS: 89 case -ERESTARTNOINTR: 90 PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs); 91 PT_REGS_RESTART_SYSCALL(regs); 92 break; 93 case -ERESTART_RESTARTBLOCK: 94 PT_REGS_ORIG_SYSCALL(regs) = __NR_restart_syscall; 95 PT_REGS_RESTART_SYSCALL(regs); 96 break; 97 } 98 } 99 100 /* 101 * This closes a way to execute a system call on the host. If 102 * you set a breakpoint on a system call instruction and singlestep 103 * from it, the tracing thread used to PTRACE_SINGLESTEP the process 104 * rather than PTRACE_SYSCALL it, allowing the system call to execute 105 * on the host. The tracing thread will check this flag and 106 * PTRACE_SYSCALL if necessary. 107 */ 108 if (current->ptrace & PT_DTRACE) 109 current->thread.singlestep_syscall = 110 is_syscall(PT_REGS_IP(¤t->thread.regs)); 111 112 /* 113 * if there's no signal to deliver, we just put the saved sigmask 114 * back 115 */ 116 if (!handled_sig) 117 restore_saved_sigmask(); 118 return handled_sig; 119 } 120 121 int do_signal(void) 122 { 123 return kern_do_signal(¤t->thread.regs); 124 } 125