📄 signal.c
字号:
__put_user_error(current->thread.trap_no, &sf->uc.uc_mcontext.trap_no, err); __put_user_error(current->thread.error_code, &sf->uc.uc_mcontext.error_code, err); __put_user_error(current->thread.address, &sf->uc.uc_mcontext.fault_address, err); __put_user_error(set->sig[0], &sf->uc.uc_mcontext.oldmask, err); err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set)); aux = (struct aux_sigframe __user *) sf->uc.uc_regspace;#ifdef CONFIG_CRUNCH if (err == 0) err |= preserve_crunch_context(&aux->crunch);#endif#ifdef CONFIG_IWMMXT if (err == 0 && test_thread_flag(TIF_USING_IWMMXT)) err |= preserve_iwmmxt_context(&aux->iwmmxt);#endif#ifdef CONFIG_VFP// if (err == 0)// err |= vfp_save_state(&sf->aux.vfp);#endif __put_user_error(0, &aux->end_magic, err); return err;}static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, int framesize){ unsigned long sp = regs->ARM_sp; void __user *frame; /* * This is the X/Open sanctioned signal stack switching. */ if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) sp = current->sas_ss_sp + current->sas_ss_size; /* * ATPCS B01 mandates 8-byte alignment */ frame = (void __user *)((sp - framesize) & ~7); /* * Check that we can actually write to the signal frame. */ if (!access_ok(VERIFY_WRITE, frame, framesize)) frame = NULL; return frame;}static intsetup_return(struct pt_regs *regs, struct k_sigaction *ka, unsigned long __user *rc, void __user *frame, int usig){ unsigned long handler = (unsigned long)ka->sa.sa_handler; unsigned long retcode; int thumb = 0; unsigned long cpsr = regs->ARM_cpsr & ~PSR_f; /* * Maybe we need to deliver a 32-bit signal to a 26-bit task. */ if (ka->sa.sa_flags & SA_THIRTYTWO) cpsr = (cpsr & ~MODE_MASK) | USR_MODE;#ifdef CONFIG_ARM_THUMB if (elf_hwcap & HWCAP_THUMB) { /* * The LSB of the handler determines if we're going to * be using THUMB or ARM mode for this signal handler. */ thumb = handler & 1; if (thumb) cpsr |= PSR_T_BIT; else cpsr &= ~PSR_T_BIT; }#endif if (ka->sa.sa_flags & SA_RESTORER) { retcode = (unsigned long)ka->sa.sa_restorer; } else { unsigned int idx = thumb << 1; if (ka->sa.sa_flags & SA_SIGINFO) idx += 3; if (__put_user(sigreturn_codes[idx], rc) || __put_user(sigreturn_codes[idx+1], rc+1)) return 1; if (cpsr & MODE32_BIT) { /* * 32-bit code can use the new high-page * signal return code support. */ retcode = KERN_SIGRETURN_CODE + (idx << 2) + thumb; } else { /* * Ensure that the instruction cache sees * the return code written onto the stack. */ flush_icache_range((unsigned long)rc, (unsigned long)(rc + 2)); retcode = ((unsigned long)rc) + thumb; } } regs->ARM_r0 = usig; regs->ARM_sp = (unsigned long)frame; regs->ARM_lr = retcode; regs->ARM_pc = handler; regs->ARM_cpsr = cpsr; return 0;}static intsetup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs){ struct sigframe __user *frame = get_sigframe(ka, regs, sizeof(*frame)); int err = 0; if (!frame) return 1; /* * Set uc.uc_flags to a value which sc.trap_no would never have. */ __put_user_error(0x5ac3c35a, &frame->uc.uc_flags, err); err |= setup_sigframe(frame, regs, set); if (err == 0) err = setup_return(regs, ka, frame->retcode, frame, usig); return err;}static intsetup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs){ struct rt_sigframe __user *frame = get_sigframe(ka, regs, sizeof(*frame)); stack_t stack; int err = 0; if (!frame) return 1; err |= copy_siginfo_to_user(&frame->info, info); __put_user_error(0, &frame->sig.uc.uc_flags, err); __put_user_error(NULL, &frame->sig.uc.uc_link, err); memset(&stack, 0, sizeof(stack)); stack.ss_sp = (void __user *)current->sas_ss_sp; stack.ss_flags = sas_ss_flags(regs->ARM_sp); stack.ss_size = current->sas_ss_size; err |= __copy_to_user(&frame->sig.uc.uc_stack, &stack, sizeof(stack)); err |= setup_sigframe(&frame->sig, regs, set); if (err == 0) err = setup_return(regs, ka, frame->sig.retcode, frame, usig); if (err == 0) { /* * For realtime signals we must also set the second and third * arguments for the signal handler. * -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 2000-12-06 */ regs->ARM_r1 = (unsigned long)&frame->info; regs->ARM_r2 = (unsigned long)&frame->sig.uc; } return err;}static inline void restart_syscall(struct pt_regs *regs){ regs->ARM_r0 = regs->ARM_ORIG_r0; regs->ARM_pc -= thumb_mode(regs) ? 2 : 4;}/* * OK, we're invoking a handler */ static voidhandle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs * regs, int syscall){ struct thread_info *thread = current_thread_info(); struct task_struct *tsk = current; int usig = sig; int ret; /* * If we were from a system call, check for system call restarting... */ if (syscall) { switch (regs->ARM_r0) { case -ERESTART_RESTARTBLOCK: case -ERESTARTNOHAND: regs->ARM_r0 = -EINTR; break; case -ERESTARTSYS: if (!(ka->sa.sa_flags & SA_RESTART)) { regs->ARM_r0 = -EINTR; break; } /* fallthrough */ case -ERESTARTNOINTR: restart_syscall(regs); } } /* * translate the signal */ if (usig < 32 && thread->exec_domain && thread->exec_domain->signal_invmap) usig = thread->exec_domain->signal_invmap[usig]; /* * Set up the stack frame */ if (ka->sa.sa_flags & SA_SIGINFO) ret = setup_rt_frame(usig, ka, info, oldset, regs); else ret = setup_frame(usig, ka, oldset, regs); /* * Check that the resulting registers are actually sane. */ ret |= !valid_user_regs(regs); if (ret != 0) { force_sigsegv(sig, tsk); return; } /* * Block the signal if we were successful. */ spin_lock_irq(&tsk->sighand->siglock); sigorsets(&tsk->blocked, &tsk->blocked, &ka->sa.sa_mask); if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(&tsk->blocked, sig); recalc_sigpending(); spin_unlock_irq(&tsk->sighand->siglock);}/* * 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. * * Note that we go through the signals twice: once to check the signals that * the kernel can handle, and then we build all the user-level signal handling * stack-frames in one go after that. */static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall){ struct k_sigaction ka; siginfo_t info; int signr; /* * We want the common case to go fast, which * is why we may in certain cases get here from * kernel mode. Just return without doing anything * if so. */ if (!user_mode(regs)) return 0; if (try_to_freeze()) goto no_signal; single_step_clear(current); signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { handle_signal(signr, &ka, &info, oldset, regs, syscall); single_step_set(current); return 1; } no_signal: /* * No signal to deliver to the process - restart the syscall. */ if (syscall) { if (regs->ARM_r0 == -ERESTART_RESTARTBLOCK) { if (thumb_mode(regs)) { regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE; regs->ARM_pc -= 2; } else {#if defined(CONFIG_AEABI) && !defined(CONFIG_OABI_COMPAT) regs->ARM_r7 = __NR_restart_syscall; regs->ARM_pc -= 4;#else u32 __user *usp; u32 swival = __NR_restart_syscall; regs->ARM_sp -= 12; usp = (u32 __user *)regs->ARM_sp; /* * Either we supports OABI only, or we have * EABI with the OABI compat layer enabled. * In the later case we don't know if user * space is EABI or not, and if not we must * not clobber r7. Always using the OABI * syscall solves that issue and works for * all those cases. */ swival = swival - __NR_SYSCALL_BASE + __NR_OABI_SYSCALL_BASE; put_user(regs->ARM_pc, &usp[0]); /* swi __NR_restart_syscall */ put_user(0xef000000 | swival, &usp[1]); /* ldr pc, [sp], #12 */ put_user(0xe49df00c, &usp[2]); flush_icache_range((unsigned long)usp, (unsigned long)(usp + 3)); regs->ARM_pc = regs->ARM_sp + 4;#endif } } if (regs->ARM_r0 == -ERESTARTNOHAND || regs->ARM_r0 == -ERESTARTSYS || regs->ARM_r0 == -ERESTARTNOINTR) { restart_syscall(regs); } } single_step_set(current); return 0;}asmlinkage voiddo_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall){ if (thread_flags & _TIF_SIGPENDING) do_signal(¤t->blocked, regs, syscall);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -