📄 signal.c
字号:
already in userspace. */ err |= __put_user(in_syscall ? INSN_LDI_R25_1 : INSN_LDI_R25_0, &frame->tramp[0]); err |= __put_user(INSN_LDI_R20, &frame->tramp[1]); err |= __put_user(INSN_BLE_SR2_R0, &frame->tramp[2]); err |= __put_user(INSN_NOP, &frame->tramp[3]);#if DEBUG_SIG /* Assert that we're flushing in the correct space... */ { int sid; asm ("mfsp %%sr3,%0" : "=r" (sid)); printk("flushing 64 bytes at space %#x offset %p\n", sid, frame->tramp); }#endif#if CACHE_FLUSHING_IS_NOT_BROKEN flush_icache_range((unsigned long) &frame->tramp[0], (unsigned long) &frame->tramp[4]);#else /* It should *always* be cache line-aligned, but the compiler sometimes screws up. */ asm volatile("fdc 0(%%sr3,%0)\n\t" "fdc %1(%%sr3,%0)\n\t" "sync\n\t" "fic 0(%%sr3,%0)\n\t" "fic %1(%%sr3,%0)\n\t" "sync\n\t" : : "r" (frame->tramp), "r" (L1_CACHE_BYTES));#endif rp = (unsigned long) frame->tramp; if (err) goto give_sigsegv;#ifdef __LP64__/* Much more has to happen with signals than this -- but it'll at least *//* provide a pointer to some places which definitely need a look. */#define HACK unsigned int#else#define HACK unsigned long#endif haddr = (HACK) ka->sa.sa_handler; /* ARGH! Fucking brain damage. You don't want to know. */ if (haddr & 2) { HACK *plabel; HACK ltp; plabel = (HACK *) (haddr & ~3); err |= __get_user(haddr, plabel); err |= __get_user(ltp, plabel + 1); if (err) goto give_sigsegv; regs->gr[19] = ltp; } /* The syscall return path will create IAOQ values from r31. */ if (in_syscall) regs->gr[31] = (HACK) haddr; else { regs->iaoq[0] = (HACK) haddr | 3; regs->iaoq[1] = regs->iaoq[0] + 4; } regs->gr[2] = rp; /* userland return pointer */ regs->gr[26] = sig; /* signal number */ regs->gr[25] = (HACK) &frame->info; /* siginfo pointer */ regs->gr[24] = (HACK) &frame->uc; /* ucontext pointer */#if DEBUG_SIG printk("making sigreturn frame: %#lx + %#lx = %#lx\n", regs->gr[30], PARISC_RT_SIGFRAME_SIZE, regs->gr[30] + PARISC_RT_SIGFRAME_SIZE);#endif /* Raise the user stack pointer to make a proper call frame. */ regs->gr[30] = ((HACK) frame + PARISC_RT_SIGFRAME_SIZE);#if DEBUG_SIG printk("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);#endif return 1;give_sigsegv:#if DEBUG_SIG printk("fuckup in setup_rt_frame, sending SIGSEGV\n");#endif if (sig == SIGSEGV) ka->sa.sa_handler = SIG_DFL; si.si_signo = SIGSEGV; si.si_errno = 0; si.si_code = SI_KERNEL; si.si_pid = current->pid; si.si_uid = current->uid; si.si_addr = frame; force_sig_info(SIGSEGV, &si, current); return 0;}/* * OK, we're invoking a handler. */ static longhandle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs *regs, int in_syscall){#if DEBUG_SIG printk("handle_signal(sig=%ld, ka=%p, info=%p, oldset=%p, regs=%p)\n", sig, ka, info, oldset, regs);#endif /* Set up the stack frame */ if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall)) return 0; if (ka->sa.sa_flags & SA_ONESHOT) ka->sa.sa_handler = SIG_DFL; if (!(ka->sa.sa_flags & SA_NODEFER)) { spin_lock_irq(¤t->sigmask_lock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); sigaddset(¤t->blocked,sig); recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); } return 1;}/* * 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 intdo_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall){ siginfo_t info; struct k_sigaction *ka;#if DEBUG_SIG printk("do_signal(oldset=0x%p, regs=0x%p, sr7 %#lx, pending %d, in_syscall=%d\n", oldset, regs, regs->sr[7], current->sigpending, in_syscall);#endif /* 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 (!oldset) oldset = ¤t->blocked;#if DEBUG_SIG printk("do_signal: oldset %08lx:%08lx\n", oldset->sig[0], oldset->sig[1]);#endif for (;;) { unsigned long signr; spin_lock_irq(¤t->sigmask_lock); signr = dequeue_signal(¤t->blocked, &info); spin_unlock_irq(¤t->sigmask_lock);#if DEBUG_SIG printk("do_signal: signr=%ld, pid=%d\n", signr, current->pid);#endif if (!signr) break; if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { /* Let the debugger run. */ current->exit_code = signr; set_current_state(TASK_STOPPED); notify_parent(current, SIGCHLD); schedule(); /* We're back. Did the debugger cancel the sig? */ if (!(signr = current->exit_code)) continue; current->exit_code = 0; /* The debugger continued. Ignore SIGSTOP. */ if (signr == SIGSTOP) continue; /* Update the siginfo structure. Is this good? */ if (signr != info.si_signo) { info.si_signo = signr; info.si_errno = 0; info.si_code = SI_USER; info.si_pid = current->p_pptr->pid; info.si_uid = current->p_pptr->uid; } /* If the (new) signal is now blocked, requeue it. */ if (sigismember(¤t->blocked, signr)) { send_sig_info(signr, &info, current); continue; } } ka = ¤t->sig->action[signr-1];#if DEBUG_SIG printk("sa_handler is %lx\n", ka->sa.sa_handler);#endif if ((unsigned long) ka->sa.sa_handler == (unsigned long) SIG_IGN) { if (signr != SIGCHLD) continue; while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0) /* nothing */; continue; } if ((unsigned long) ka->sa.sa_handler == (unsigned long) SIG_DFL) { int exit_code = signr; /* Init gets no signals it doesn't want. */ if (current->pid == 1) continue; switch (signr) { case SIGCONT: case SIGCHLD: case SIGWINCH: continue; case SIGTSTP: case SIGTTIN: case SIGTTOU: if (is_orphaned_pgrp(current->pgrp)) continue; /* FALLTHRU */ case SIGSTOP: set_current_state(TASK_STOPPED); current->exit_code = signr; if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) notify_parent(current, SIGCHLD); schedule(); continue; case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: if (signr == SIGQUIT) /* Userspace debugging */ show_regs(regs); if (do_coredump(signr, regs)) exit_code |= 0x80; /* FALLTHRU */ default: lock_kernel(); sigaddset(¤t->pending.signal, signr); recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); /* NOTREACHED */ } } /* Restart a system call if necessary. */ if (in_syscall) { /* Check the return code */ switch (regs->gr[28]) { case -ERESTARTNOHAND:#if DEBUG_SIG printk("ERESTARTNOHAND: returning -EINTR\n");#endif regs->gr[28] = -EINTR; break; case -ERESTARTSYS: if (!(ka->sa.sa_flags & SA_RESTART)) {#if DEBUG_SIG printk("ERESTARTSYS: putting -EINTR\n");#endif 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; } } /* 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, ka, &info, oldset, regs, in_syscall)) {#if DEBUG_SIG printk("Exiting do_signal (success), regs->gr[28] = %ld\n", regs->gr[28]);#endif return 1; } } /* Did we come from a system call? */ if (in_syscall) { /* Restart the system call - no handlers present */ if (regs->gr[28] == -ERESTARTNOHAND || regs->gr[28] == -ERESTARTSYS || regs->gr[28] == -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; } }#if DEBUG_SIG printk("Exiting do_signal (not delivered), regs->gr[28] = %ld\n", regs->gr[28]);#endif return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -