⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 signal_64.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Handle {get,set,swap}_context operations */int sys_swapcontext(struct ucontext __user *old_ctx,		    struct ucontext __user *new_ctx,		    long ctx_size, long r6, long r7, long r8, struct pt_regs *regs){	unsigned char tmp;	sigset_t set;	/* Context size is for future use. Right now, we only make sure	 * we are passed something we understand	 */	if (ctx_size < sizeof(struct ucontext))		return -EINVAL;	if (old_ctx != NULL) {		if (!access_ok(VERIFY_WRITE, old_ctx, sizeof(*old_ctx))		    || setup_sigcontext(&old_ctx->uc_mcontext, regs, 0, NULL, 0)		    || __copy_to_user(&old_ctx->uc_sigmask,				      &current->blocked, sizeof(sigset_t)))			return -EFAULT;	}	if (new_ctx == NULL)		return 0;	if (!access_ok(VERIFY_READ, new_ctx, sizeof(*new_ctx))	    || __get_user(tmp, (u8 __user *) new_ctx)	    || __get_user(tmp, (u8 __user *) (new_ctx + 1) - 1))		return -EFAULT;	/*	 * If we get a fault copying the context into the kernel's	 * image of the user's registers, we can't just return -EFAULT	 * because the user's registers will be corrupted.  For instance	 * the NIP value may have been updated but not some of the	 * other registers.  Given that we have done the access_ok	 * and successfully read the first and last bytes of the region	 * above, this should only happen in an out-of-memory situation	 * or if another thread unmaps the region containing the context.	 * We kill the task with a SIGSEGV in this situation.	 */	if (__copy_from_user(&set, &new_ctx->uc_sigmask, sizeof(set)))		do_exit(SIGSEGV);	restore_sigmask(&set);	if (restore_sigcontext(regs, NULL, 0, &new_ctx->uc_mcontext))		do_exit(SIGSEGV);	/* This returns like rt_sigreturn */	return 0;}/* * Do a signal return; undo the signal stack. */int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,		     unsigned long r6, unsigned long r7, unsigned long r8,		     struct pt_regs *regs){	struct ucontext __user *uc = (struct ucontext __user *)regs->gpr[1];	sigset_t set;	/* Always make any pending restarted system calls return -EINTR */	current_thread_info()->restart_block.fn = do_no_restart_syscall;	if (!access_ok(VERIFY_READ, uc, sizeof(*uc)))		goto badframe;	if (__copy_from_user(&set, &uc->uc_sigmask, sizeof(set)))		goto badframe;	restore_sigmask(&set);	if (restore_sigcontext(regs, NULL, 1, &uc->uc_mcontext))		goto badframe;	/* do_sigaltstack expects a __user pointer and won't modify	 * what's in there anyway	 */	do_sigaltstack(&uc->uc_stack, NULL, regs->gpr[1]);	return regs->result;badframe:#if DEBUG_SIG	printk("badframe in sys_rt_sigreturn, regs=%p uc=%p &uc->uc_mcontext=%p\n",	       regs, uc, &uc->uc_mcontext);#endif	force_sig(SIGSEGV, current);	return 0;}static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,		sigset_t *set, struct pt_regs *regs){	/* Handler is *really* a pointer to the function descriptor for	 * the signal routine.  The first entry in the function	 * descriptor is the entry address of signal and the second	 * entry is the TOC value we need to use.	 */	func_descr_t __user *funct_desc_ptr;	struct rt_sigframe __user *frame;	unsigned long newsp = 0;	long err = 0;	frame = get_sigframe(ka, regs, sizeof(*frame));	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))		goto badframe;	err |= __put_user(&frame->info, &frame->pinfo);	err |= __put_user(&frame->uc, &frame->puc);	err |= copy_siginfo_to_user(&frame->info, info);	if (err)		goto badframe;	/* Create the ucontext.  */	err |= __put_user(0, &frame->uc.uc_flags);	err |= __put_user(0, &frame->uc.uc_link);	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);	err |= __put_user(sas_ss_flags(regs->gpr[1]),			  &frame->uc.uc_stack.ss_flags);	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);	err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, signr, NULL,				(unsigned long)ka->sa.sa_handler);	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));	if (err)		goto badframe;	/* Make sure signal handler doesn't get spurious FP exceptions */	current->thread.fpscr.val = 0;	/* Set up to return from userspace. */	if (vdso64_rt_sigtramp && current->thread.vdso_base) {		regs->link = current->thread.vdso_base + vdso64_rt_sigtramp;	} else {		err |= setup_trampoline(__NR_rt_sigreturn, &frame->tramp[0]);		if (err)			goto badframe;		regs->link = (unsigned long) &frame->tramp[0];	}	funct_desc_ptr = (func_descr_t __user *) ka->sa.sa_handler;	/* Allocate a dummy caller frame for the signal handler. */	newsp = (unsigned long)frame - __SIGNAL_FRAMESIZE;	err |= put_user(regs->gpr[1], (unsigned long __user *)newsp);	/* Set up "regs" so we "return" to the signal handler. */	err |= get_user(regs->nip, &funct_desc_ptr->entry);	regs->gpr[1] = newsp;	err |= get_user(regs->gpr[2], &funct_desc_ptr->toc);	regs->gpr[3] = signr;	regs->result = 0;	if (ka->sa.sa_flags & SA_SIGINFO) {		err |= get_user(regs->gpr[4], (unsigned long __user *)&frame->pinfo);		err |= get_user(regs->gpr[5], (unsigned long __user *)&frame->puc);		regs->gpr[6] = (unsigned long) frame;	} else {		regs->gpr[4] = (unsigned long)&frame->uc.uc_mcontext;	}	if (err)		goto badframe;	if (test_thread_flag(TIF_SINGLESTEP))		ptrace_notify(SIGTRAP);	return 1;badframe:#if DEBUG_SIG	printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n",	       regs, frame, newsp);#endif	force_sigsegv(signr, current);	return 0;}/* * OK, we're invoking a handler */static int handle_signal(unsigned long sig, struct k_sigaction *ka,			 siginfo_t *info, sigset_t *oldset, struct pt_regs *regs){	int ret;	/* Set up Signal Frame */	ret = setup_rt_frame(sig, ka, info, oldset, regs);	if (ret) {		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);	}	return ret;}static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka){	switch ((int)regs->result) {	case -ERESTART_RESTARTBLOCK:	case -ERESTARTNOHAND:		/* ERESTARTNOHAND means that the syscall should only be		 * restarted if there was no handler for the signal, and since		 * we only get here if there is a handler, we dont restart.		 */		regs->result = -EINTR;		break;	case -ERESTARTSYS:		/* ERESTARTSYS means to restart the syscall if there is no		 * handler or the handler was registered with SA_RESTART		 */		if (!(ka->sa.sa_flags & SA_RESTART)) {			regs->result = -EINTR;			break;		}		/* fallthrough */	case -ERESTARTNOINTR:		/* ERESTARTNOINTR means that the syscall should be		 * called again after the signal handler returns.		 */		regs->gpr[3] = regs->orig_gpr3;		regs->nip -= 4;		regs->result = 0;		break;	}}/* * Note that 'init' is a special process: it doesn't get signals it doesn't * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. */int do_signal(sigset_t *oldset, struct pt_regs *regs){	siginfo_t info;	int signr;	struct k_sigaction ka;	/*	 * If the current thread is 32 bit - invoke the	 * 32 bit signal handling code	 */	if (test_thread_flag(TIF_32BIT))		return do_signal32(oldset, regs);	if (!oldset)		oldset = &current->blocked;	signr = get_signal_to_deliver(&info, &ka, regs, NULL);	if (signr > 0) {		/* Whee!  Actually deliver the signal.  */		if (TRAP(regs) == 0x0C00)			syscall_restart(regs, &ka);		/*		 * Reenable the DABR before delivering the signal to		 * user space. The DABR will have been cleared if it		 * triggered inside the kernel.		 */		if (current->thread.dabr)			set_dabr(current->thread.dabr);		return handle_signal(signr, &ka, &info, oldset, regs);	}	if (TRAP(regs) == 0x0C00) {	/* System Call! */		if ((int)regs->result == -ERESTARTNOHAND ||		    (int)regs->result == -ERESTARTSYS ||		    (int)regs->result == -ERESTARTNOINTR) {			regs->gpr[3] = regs->orig_gpr3;			regs->nip -= 4; /* Back up & retry system call */			regs->result = 0;		} else if ((int)regs->result == -ERESTART_RESTARTBLOCK) {			regs->gpr[0] = __NR_restart_syscall;			regs->nip -= 4;			regs->result = 0;		}	}	return 0;}EXPORT_SYMBOL(do_signal);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -