signal.c
来自「linux 内核源代码」· C语言 代码 · 共 648 行 · 第 1/2 页
C
648 行
asm ("mfsp %%sr3,%0" : "=r" (sid)); DBG(1,"setup_rt_frame: Flushing 64 bytes at space %#x offset %p\n", sid, frame->tramp); }#endif flush_user_dcache_range((unsigned long) &frame->tramp[0], (unsigned long) &frame->tramp[TRAMP_SIZE]); flush_user_icache_range((unsigned long) &frame->tramp[0], (unsigned long) &frame->tramp[TRAMP_SIZE]); /* TRAMP Words 0-4, Lenght 5 = SIGRESTARTBLOCK_TRAMP * TRAMP Words 5-9, Length 4 = SIGRETURN_TRAMP * So the SIGRETURN_TRAMP is at the end of SIGRESTARTBLOCK_TRAMP */ rp = (unsigned long) &frame->tramp[SIGRESTARTBLOCK_TRAMP]; if (err) goto give_sigsegv; haddr = A(ka->sa.sa_handler); /* The sa_handler may be a pointer to a function descriptor */#ifdef CONFIG_64BIT if (is_compat_task()) {#endif if (haddr & PA_PLABEL_FDESC) { Elf32_Fdesc fdesc; Elf32_Fdesc __user *ufdesc = (Elf32_Fdesc __user *)A(haddr & ~3); err = __copy_from_user(&fdesc, ufdesc, sizeof(fdesc)); if (err) goto give_sigsegv; haddr = fdesc.addr; regs->gr[19] = fdesc.gp; }#ifdef CONFIG_64BIT } else { Elf64_Fdesc fdesc; Elf64_Fdesc __user *ufdesc = (Elf64_Fdesc __user *)A(haddr & ~3); err = __copy_from_user(&fdesc, ufdesc, sizeof(fdesc)); if (err) goto give_sigsegv; haddr = fdesc.addr; regs->gr[19] = fdesc.gp; DBG(1,"setup_rt_frame: 64 bit signal, exe=%#lx, r19=%#lx, in_syscall=%d\n", haddr, regs->gr[19], in_syscall); }#endif /* The syscall return path will create IAOQ values from r31. */ sigframe_size = PARISC_RT_SIGFRAME_SIZE;#ifdef CONFIG_64BIT if (is_compat_task()) sigframe_size = PARISC_RT_SIGFRAME_SIZE32;#endif if (in_syscall) { regs->gr[31] = haddr;#ifdef CONFIG_64BIT if (!test_thread_flag(TIF_32BIT)) sigframe_size |= 1;#endif } else { unsigned long psw = USER_PSW;#ifdef CONFIG_64BIT if (!test_thread_flag(TIF_32BIT)) psw |= PSW_W;#endif /* If we are singlestepping, arrange a trap to be delivered when we return to userspace. Note the semantics -- we should trap before the first insn in the handler is executed. Ref: http://sources.redhat.com/ml/gdb/2004-11/msg00245.html */ if (pa_psw(current)->r) { pa_psw(current)->r = 0; psw |= PSW_R; mtctl(-1, 0); } regs->gr[0] = psw; regs->iaoq[0] = haddr | 3; regs->iaoq[1] = regs->iaoq[0] + 4; } regs->gr[2] = rp; /* userland return pointer */ regs->gr[26] = sig; /* signal number */ #ifdef CONFIG_64BIT if (is_compat_task()) { regs->gr[25] = A(&compat_frame->info); /* siginfo pointer */ regs->gr[24] = A(&compat_frame->uc); /* ucontext pointer */ } else#endif { regs->gr[25] = A(&frame->info); /* siginfo pointer */ regs->gr[24] = A(&frame->uc); /* ucontext pointer */ } DBG(1,"setup_rt_frame: making sigreturn frame: %#lx + %#lx = %#lx\n", regs->gr[30], sigframe_size, regs->gr[30] + sigframe_size); /* Raise the user stack pointer to make a proper call frame. */ regs->gr[30] = (A(frame) + sigframe_size); DBG(1,"setup_rt_frame: sig deliver (%s,%d) frame=0x%p sp=%#lx iaoq=%#lx/%#lx rp=%#lx\n", current->comm, current->pid, frame, regs->gr[30], regs->iaoq[0], regs->iaoq[1], rp); return 1;give_sigsegv: DBG(1,"setup_rt_frame: sending SIGSEGV\n"); force_sigsegv(sig, current); return 0;}/* * OK, we're invoking a handler. */ static longhandle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs, int in_syscall){ DBG(1,"handle_signal: sig=%ld, ka=%p, info=%p, oldset=%p, regs=%p\n", sig, ka, info, oldset, regs); /* Set up the stack frame */ if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall)) return 0; spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked,sig); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); return 1;}static inline voidsyscall_restart(struct pt_regs *regs, struct k_sigaction *ka){ /* Check the return code */ switch (regs->gr[28]) { case -ERESTART_RESTARTBLOCK: current_thread_info()->restart_block.fn = do_no_restart_syscall; case -ERESTARTNOHAND: DBG(1,"ERESTARTNOHAND: returning -EINTR\n"); regs->gr[28] = -EINTR; break; case -ERESTARTSYS: if (!(ka->sa.sa_flags & SA_RESTART)) { DBG(1,"ERESTARTSYS: putting -EINTR\n"); regs->gr[28] = -EINTR; break; } /* fallthrough */ case -ERESTARTNOINTR: /* A syscall is just a branch, so all * we have to do is fiddle the return pointer. */ regs->gr[31] -= 8; /* delayed branching */ /* Preserve original r28. */ regs->gr[28] = regs->orig_r28; break; }}static inline voidinsert_restart_trampoline(struct pt_regs *regs){ switch(regs->gr[28]) { case -ERESTART_RESTARTBLOCK: { /* Restart the system call - no handlers present */ unsigned int *usp = (unsigned int *)regs->gr[30]; /* Setup a trampoline to restart the syscall * with __NR_restart_syscall * * 0: <return address (orig r31)> * 4: <2nd half for 64-bit> * 8: ldw 0(%sp), %r31 * 12: be 0x100(%sr2, %r0) * 16: ldi __NR_restart_syscall, %r20 */#ifdef CONFIG_64BIT put_user(regs->gr[31] >> 32, &usp[0]); put_user(regs->gr[31] & 0xffffffff, &usp[1]); put_user(0x0fc010df, &usp[2]);#else put_user(regs->gr[31], &usp[0]); put_user(0x0fc0109f, &usp[2]);#endif put_user(0xe0008200, &usp[3]); put_user(0x34140000, &usp[4]); /* Stack is 64-byte aligned, and we only need * to flush 1 cache line. * Flushing one cacheline is cheap. * "sync" on bigger (> 4 way) boxes is not. */ flush_icache_range(regs->gr[30], regs->gr[30] + 4); regs->gr[31] = regs->gr[30] + 8; /* Preserve original r28. */ regs->gr[28] = regs->orig_r28; return; } case -ERESTARTNOHAND: case -ERESTARTSYS: case -ERESTARTNOINTR: { /* Hooray for delayed branching. We don't * have to restore %r20 (the system call * number) because it gets loaded in the delay * slot of the branch external instruction. */ regs->gr[31] -= 8; /* Preserve original r28. */ regs->gr[28] = regs->orig_r28; return; } default: 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. * * We need to be able to restore the syscall arguments (r21-r26) to * restart syscalls. Thus, the syscall path should save them in the * pt_regs structure (it's okay to do so since they are caller-save * registers). As noted below, the syscall number gets restored for * us due to the magic of delayed branching. */asmlinkage voiddo_signal(struct pt_regs *regs, long in_syscall){ siginfo_t info; struct k_sigaction ka; int signr; sigset_t *oldset; DBG(1,"\ndo_signal: oldset=0x%p, regs=0x%p, sr7 %#lx, in_syscall=%d\n", oldset, regs, regs->sr[7], in_syscall); /* Everyone else checks to see if they are in kernel mode at this point and exits if that's the case. I'm not sure why we would be called in that case, but for some reason we are. */ if (test_thread_flag(TIF_RESTORE_SIGMASK)) oldset = ¤t->saved_sigmask; else oldset = ¤t->blocked; DBG(1,"do_signal: oldset %08lx / %08lx\n", oldset->sig[0], oldset->sig[1]); /* May need to force signal if handle_signal failed to deliver */ while (1) { signr = get_signal_to_deliver(&info, &ka, regs, NULL); DBG(3,"do_signal: signr = %d, regs->gr[28] = %ld\n", signr, regs->gr[28]); if (signr <= 0) break; /* Restart a system call if necessary. */ if (in_syscall) syscall_restart(regs, &ka); /* Whee! Actually deliver the signal. If the delivery failed, we need to continue to iterate in this loop so we can deliver the SIGSEGV... */ if (handle_signal(signr, &info, &ka, oldset, regs, in_syscall)) { DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n", regs->gr[28]); if (test_thread_flag(TIF_RESTORE_SIGMASK)) clear_thread_flag(TIF_RESTORE_SIGMASK); return; } } /* end of while(1) looping forever if we can't force a signal */ /* Did we come from a system call? */ if (in_syscall) insert_restart_trampoline(regs); DBG(1,"do_signal: Exit (not delivered), regs->gr[28] = %ld\n", regs->gr[28]); if (test_thread_flag(TIF_RESTORE_SIGMASK)) { clear_thread_flag(TIF_RESTORE_SIGMASK); sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); } return;}void do_notify_resume(struct pt_regs *regs, long in_syscall){ if (test_thread_flag(TIF_SIGPENDING) || test_thread_flag(TIF_RESTORE_SIGMASK)) do_signal(regs, in_syscall);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?