📄 signal.c
字号:
asm ("mfsp %%sr3,%0" : "=r" (sid)); DBG(("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->gr[0] = USER_PSW; 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 */ DBG(("making sigreturn frame: %#lx + %#x = %#lx\n", regs->gr[30], PARISC_RT_SIGFRAME_SIZE, regs->gr[30] + PARISC_RT_SIGFRAME_SIZE)); /* Raise the user stack pointer to make a proper call frame. */ regs->gr[30] = ((HACK) frame + PARISC_RT_SIGFRAME_SIZE); DBG(("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(("setup_rt_frame sending SIGSEGV\n")); 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){ DBG(("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; 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; DBG(("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)); /* 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; DBG(("do_signal: oldset %08lx:%08lx\n", oldset->sig[0], oldset->sig[1])); for (;;) { unsigned long signr; spin_lock_irq(¤t->sigmask_lock); signr = dequeue_signal(¤t->blocked, &info); spin_unlock_irq(¤t->sigmask_lock); DBG(("do_signal: signr=%ld, pid=%d\n", signr, current->pid)); 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]; DBG(("sa_handler is %x\n", (unsigned int) ka->sa.sa_handler)); if (ka->sa.sa_handler == SIG_IGN) { if (signr != SIGCHLD) continue; while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0) /* nothing */; continue; } if (ka->sa.sa_handler == 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: sig_exit(signr, exit_code, &info); /* NOTREACHED */ } } /* Restart a system call if necessary. */ if (in_syscall) { /* Check the return code */ switch (regs->gr[28]) { case -ERESTARTNOHAND: DBG(("ERESTARTNOHAND: returning -EINTR\n")); regs->gr[28] = -EINTR; break; case -ERESTARTSYS: if (!(ka->sa.sa_flags & SA_RESTART)) { DBG(("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; } } /* 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)) { DBG((KERN_DEBUG "Exiting do_signal (success), regs->gr[28] = %ld\n", regs->gr[28])); 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; } } DBG(("Exiting do_signal (not delivered), regs->gr[28] = %ld\n", regs->gr[28])); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -