📄 signal.c
字号:
#ifndef CONFIG_UCLINUX if (fsize < 0) {#ifdef DEBUG printk ("setup_frame: Unknown frame format %#x\n", regs->format);#endif goto give_sigsegv; } frame = get_sigframe(ka, regs, sizeof(*frame) + fsize); if (fsize) { err |= copy_to_user (frame + 1, regs + 1, fsize); regs->stkadj = fsize; }#else /* ! CONFIG_UCLINUX */ frame = get_sigframe(ka, regs, sizeof(*frame));#endif /* ! CONFIG_UCLINUX */ err |= __put_user((current->exec_domain && current->exec_domain->signal_invmap && sig < 32 ? current->exec_domain->signal_invmap[sig] : sig), &frame->sig); err |= __put_user(regs->vector, &frame->code); err |= __put_user(&frame->sc, &frame->psc); if (_NSIG_WORDS > 1) err |= copy_to_user(frame->extramask, &set->sig[1], sizeof(frame->extramask)); setup_sigcontext(&context, regs, set->sig[0]); err |= copy_to_user (&frame->sc, &context, sizeof(context)); /* Set up to return from userspace. */ err |= __put_user(frame->retcode, &frame->pretcode); /* movea.l #,a5; moveq #,d0; trap #0 */ a5 = ((struct switch_stack *)regs - 1)->a5; err != __put_user(0x2a7c0000 + ((a5 >> 16) & 0xffff), (long *)(frame->retcode + 0)); err != __put_user(0x00007000 + ((a5 & 0xffff) << 16) + __NR_sigreturn, (long *)(frame->retcode + 4)); err |= __put_user(0x4e40, (short *)(frame->retcode + 8)); if (err) goto give_sigsegv; push_cache ((unsigned long) &frame->retcode); /* Set up registers for signal handler */ wrusp ((unsigned long) frame); regs->pc = (unsigned long) ka->sa.sa_handler;adjust_stack: /* Prepare to skip over the extra stuff in the exception frame. */ if (regs->stkadj) { struct pt_regs *tregs = (struct pt_regs *)((ulong)regs + regs->stkadj);#if DEBUG printk("Performing stackadjust=%04x\n", regs->stkadj);#endif /* This must be copied with decreasing addresses to handle overlaps. */ tregs->vector = 0; tregs->format = 0; tregs->pc = regs->pc; tregs->sr = regs->sr; } return;give_sigsegv: if (sig == SIGSEGV) ka->sa.sa_handler = SIG_DFL; force_sig(SIGSEGV, current); goto adjust_stack;}static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs){ struct rt_sigframe *frame; unsigned long a5;#ifndef CONFIG_UCLINUX int fsize = frame_extra_sizes[regs->format];#endif int err = 0;#ifndef CONFIG_UCLINUX if (fsize < 0) {#ifdef DEBUG printk ("setup_frame: Unknown frame format %#x\n", regs->format);#endif goto give_sigsegv; }#endif frame = get_sigframe(ka, regs, sizeof(*frame));#ifndef CONFIG_UCLINUX if (fsize) { err |= copy_to_user (&frame->uc.uc_extra, regs + 1, fsize); regs->stkadj = fsize; }#endif err |= __put_user((current->exec_domain && current->exec_domain->signal_invmap && sig < 32 ? current->exec_domain->signal_invmap[sig] : sig), &frame->sig); err |= __put_user(&frame->info, &frame->pinfo); err |= __put_user(&frame->uc, &frame->puc); err |= copy_siginfo_to_user(&frame->info, info); /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_link); err |= __put_user((void *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); err |= __put_user(sas_ss_flags(rdusp()), &frame->uc.uc_stack.ss_flags); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); err |= rt_setup_ucontext(&frame->uc, regs); err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set)); /* Set up to return from userspace. */ err |= __put_user(frame->retcode, &frame->pretcode); /* moveq #,d0; notb d0; movea.l #,a5; trap #0 */ a5 = ((struct switch_stack *)regs - 1)->a5; err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16), (long *)(frame->retcode + 0)); err != __put_user(0x2a7c0000 + ((a5 >> 16) & 0xffff), (long *)(frame->retcode + 4)); err != __put_user(0x00004e40 + ((a5 & 0xffff) << 16), (long *)(frame->retcode + 8)); if (err) goto give_sigsegv; push_cache ((unsigned long) &frame->retcode); /* Set up registers for signal handler */ wrusp ((unsigned long) frame); regs->pc = (unsigned long) ka->sa.sa_handler;adjust_stack: /* Prepare to skip over the extra stuff in the exception frame. */ if (regs->stkadj) { struct pt_regs *tregs = (struct pt_regs *)((ulong)regs + regs->stkadj);#if DEBUG printk("Performing stackadjust=%04x\n", regs->stkadj);#endif /* This must be copied with decreasing addresses to handle overlaps. */ tregs->vector = 0; tregs->format = 0; tregs->pc = regs->pc; tregs->sr = regs->sr; } return;give_sigsegv: if (sig == SIGSEGV) ka->sa.sa_handler = SIG_DFL; force_sig(SIGSEGV, current); goto adjust_stack;}static inline voidhandle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler){ switch (regs->d0) { case -ERESTARTNOHAND: if (!has_handler) goto do_restart; regs->d0 = -EINTR; break; case -ERESTARTSYS: if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) { regs->d0 = -EINTR; break; } /* fallthrough */ case -ERESTARTNOINTR: do_restart: regs->d0 = regs->orig_d0; regs->pc -= 2; break; }}/* * OK, we're invoking a handler */static voidhandle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs *regs){ /* are we from a system call? */ if (regs->orig_d0 >= 0) /* If so, check system call restarting.. */ handle_restart(regs, ka, 1); /* set up the stack frame */ if (ka->sa.sa_flags & SA_SIGINFO) setup_rt_frame(sig, ka, info, oldset, regs); else setup_frame(sig, ka, oldset, regs); if (ka->sa.sa_flags & SA_ONESHOT) ka->sa.sa_handler = SIG_DFL; sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked,sig); recalc_sigpending(current);}/* * 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. */asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs){ siginfo_t info; struct k_sigaction *ka; current->thread.esp0 = (unsigned long) regs; if (!oldset) oldset = ¤t->blocked; for (;;) { int signr; signr = dequeue_signal(¤t->blocked, &info); if (!signr) break; if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { current->exit_code = signr; current->state = TASK_STOPPED; regs->sr &= ~PS_T; /* Did we come from a system call? */ if (regs->orig_d0 >= 0) { /* Restart the system call the same way as if the process were not traced. */ struct k_sigaction *ka = ¤t->sig->action[signr-1]; int has_handler = (ka->sa.sa_handler != SIG_IGN && ka->sa.sa_handler != SIG_DFL); handle_restart(regs, ka, has_handler); } notify_parent(current, SIGCHLD); schedule(); /* We're back. Did the debugger cancel the sig? */ if (!(signr = current->exit_code)) { discard_frame:#ifndef CONFIG_UCLINUX /* Make sure that a faulted bus cycle isn't restarted (only needed on the 680[23]0). */ if (regs->format == 10 || regs->format == 11) regs->stkadj = frame_extra_sizes[regs->format];#endif continue; } current->exit_code = 0; /* The debugger continued. Ignore SIGSTOP. */ if (signr == SIGSTOP) goto discard_frame; /* 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 (ka->sa.sa_handler == SIG_IGN) { if (signr != SIGCHLD) continue; /* Check for SIGCHLD: it's special. */ while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0) /* nothing */; continue; } if (ka->sa.sa_handler == SIG_DFL) { int exit_code = signr; if (current->pid == 1) continue; switch (signr) { case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG: continue; case SIGTSTP: case SIGTTIN: case SIGTTOU: if (is_orphaned_pgrp(current->pgrp)) continue; /* FALLTHRU */ case SIGSTOP: { struct signal_struct *sig; current->state = TASK_STOPPED; current->exit_code = signr; sig = current->p_pptr->sig; if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) notify_parent(current, SIGCHLD); schedule(); continue; } case SIGQUIT: case SIGILL: case SIGTRAP: case SIGIOT: case SIGFPE: case SIGSEGV: case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: if (do_coredump(signr, regs)) exit_code |= 0x80; /* FALLTHRU */ default: sig_exit(signr, exit_code, &info); /* NOTREACHED */ } } /* Whee! Actually deliver the signal. */ handle_signal(signr, ka, &info, oldset, regs); return 1; } /* Did we come from a system call? */ if (regs->orig_d0 >= 0) /* Restart the system call - no handlers present */ handle_restart(regs, NULL, 0); /* If we are about to discard some frame stuff we must copy over the remaining frame. */ if (regs->stkadj) { struct pt_regs *tregs = (struct pt_regs *) ((ulong) regs + regs->stkadj); /* This must be copied with decreasing addresses to handle overlaps. */ tregs->vector = 0; tregs->format = 0; tregs->pc = regs->pc; tregs->sr = regs->sr; } return 0;}/* * return the correct value for a5/start_data, mainly for signal * handlers to ensure they get the correct data segment. */unsigned longget_pic_a5(){#ifdef DEBUG unsigned long a5; __asm__ __volatile__("movel %/a5,%0" : "=a" (a5)); if (current->mm->start_data != a5)#ifdef CONFIG_BINFMT_SHARED_FLAT { int i; /* It simply isn't sufficient to check for a5 having changed, we * must verify that the GOT pointers are equal for both segments. */ for (i=0; i<4; i++) { if (*(long *)(current->mm->start_data - 4*i - 4) != *(long *)(a5 - 4*i - 4)) { printk("%s: broken a5 (%d) 0x%x (0x%x)\n", current->comm, i, a5, current->mm->start_data); break; } } }#else printk("broken a5 0x%x != 0x%x\n", current->mm->start_data, a5);#endif#endif return current->mm->start_data;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -