📄 signal.c
字号:
if (err) goto sigsegv; regs->u_regs[UREG_I0] = signr; regs->u_regs[UREG_I1] = (uint) si; regs->u_regs[UREG_I2] = (uint) uc; } return;sigill_and_return: do_exit(SIGILL);sigsegv: do_exit(SIGSEGV);}asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs){ svr4_gregset_t *gr; svr4_mcontext_t *mc; svr4_sigset_t setv; int err = 0; synchronize_user_stack(); if (current->thread.w_saved) goto sigsegv_and_return; err = clear_user(uc, sizeof (*uc)); if (err) return -EFAULT; /* Setup convenience variables */ mc = &uc->mcontext; gr = &mc->greg; setv.sigbits[0] = current->blocked.sig[0]; setv.sigbits[1] = current->blocked.sig[1]; if (_NSIG_WORDS >= 4) { setv.sigbits[2] = current->blocked.sig[2]; setv.sigbits[3] = current->blocked.sig[3]; err |= __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t)); } else err |= __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned int)); /* Store registers */ err |= __put_user(regs->pc, &uc->mcontext.greg [SVR4_PC]); err |= __put_user(regs->npc, &uc->mcontext.greg [SVR4_NPC]); err |= __put_user(regs->psr, &uc->mcontext.greg [SVR4_PSR]); err |= __put_user(regs->y, &uc->mcontext.greg [SVR4_Y]); /* Copy g [1..7] and o [0..7] registers */ err |= __copy_to_user(&(*gr)[SVR4_G1], ®s->u_regs [UREG_G1], sizeof (uint) * 7); err |= __copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs [UREG_I0], sizeof (uint) * 8); /* Setup sigaltstack */ err |= __put_user(current->sas_ss_sp, &uc->stack.sp); err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags); err |= __put_user(current->sas_ss_size, &uc->stack.size); /* The register file is not saved * we have already stuffed all of it with sync_user_stack */ return (err ? -EFAULT : 0);sigsegv_and_return: do_exit(SIGSEGV);}/* Set the context for a svr4 application, this is Solaris way to sigreturn */asmlinkage int svr4_setcontext (svr4_ucontext_t *c, struct pt_regs *regs){ struct thread_struct *tp = ¤t->thread; svr4_gregset_t *gr; unsigned long pc, npc, psr; sigset_t set; svr4_sigset_t setv; int err; stack_t st; /* Fixme: restore windows, or is this already taken care of in * svr4_setup_frame when sync_user_windows is done? */ flush_user_windows(); if (tp->w_saved) goto sigsegv_and_return; if (((uint) c) & 3) goto sigsegv_and_return; if(!__access_ok((unsigned long)c, sizeof(*c))) goto sigsegv_and_return; /* Check for valid PC and nPC */ gr = &c->mcontext.greg; err = __get_user(pc, &((*gr)[SVR4_PC])); err |= __get_user(npc, &((*gr)[SVR4_NPC])); if((pc | npc) & 3) goto sigsegv_and_return; /* Retrieve information from passed ucontext */ /* note that nPC is ored a 1, this is used to inform entry.S */ /* that we don't want it to mess with our PC and nPC */ /* This is pretty much atomic, no amount locking would prevent * the races which exist anyways. */ err |= __copy_from_user(&setv, &c->sigmask, sizeof(svr4_sigset_t)); err |= __get_user(st.ss_sp, &c->stack.sp); err |= __get_user(st.ss_flags, &c->stack.flags); err |= __get_user(st.ss_size, &c->stack.size); if (err) goto sigsegv_and_return; /* It is more difficult to avoid calling this function than to call it and ignore errors. */ do_sigaltstack(&st, NULL, regs->u_regs[UREG_I6]); set.sig[0] = setv.sigbits[0]; set.sig[1] = setv.sigbits[1]; if (_NSIG_WORDS >= 4) { set.sig[2] = setv.sigbits[2]; set.sig[3] = setv.sigbits[3]; } sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sigmask_lock); current->blocked = set; recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); regs->pc = pc; regs->npc = npc | 1; err |= __get_user(regs->y, &((*gr) [SVR4_Y])); err |= __get_user(psr, &((*gr) [SVR4_PSR])); regs->psr &= ~(PSR_ICC); regs->psr |= (psr & PSR_ICC); /* Restore g[1..7] and o[0..7] registers */ err |= __copy_from_user(®s->u_regs [UREG_G1], &(*gr)[SVR4_G1], sizeof (long) * 7); err |= __copy_from_user(®s->u_regs [UREG_I0], &(*gr)[SVR4_O0], sizeof (long) * 8); return (err ? -EFAULT : 0);sigsegv_and_return: do_exit(SIGSEGV);}static inline voidhandle_signal(unsigned long signr, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs *regs, int svr4_signal){ if (svr4_signal) setup_svr4_frame(&ka->sa, regs->pc, regs->npc, regs, signr, oldset); else { if (ka->sa.sa_flags & SA_SIGINFO) new_setup_rt_frame(ka, regs, signr, oldset, info); else if (current->thread.new_signal) new_setup_frame (ka, regs, signr, oldset); else setup_frame(&ka->sa, regs, signr, oldset, info); } if(ka->sa.sa_flags & SA_ONESHOT) ka->sa.sa_handler = SIG_DFL; if(!(ka->sa.sa_flags & SA_NOMASK)) { spin_lock_irq(¤t->sigmask_lock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); sigaddset(¤t->blocked, signr); recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); }}static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, struct sigaction *sa){ switch(regs->u_regs[UREG_I0]) { case ERESTARTNOHAND: no_system_call_restart: regs->u_regs[UREG_I0] = EINTR; regs->psr |= PSR_C; break; case ERESTARTSYS: if(!(sa->sa_flags & SA_RESTART)) goto no_system_call_restart; /* fallthrough */ case ERESTARTNOINTR: regs->u_regs[UREG_I0] = orig_i0; regs->pc -= 4; regs->npc -= 4; }}#ifdef DEBUG_SIGNALS_MAPS#define MAPS_LINE_FORMAT "%08lx-%08lx %s %08lx %s %lu "static inline void read_maps (void){ struct vm_area_struct * map, * next; char * buffer; ssize_t i; buffer = (char*)__get_free_page(GFP_KERNEL); if (!buffer) return; for (map = current->mm->mmap ; map ; map = next ) { /* produce the next line */ char *line; char str[5], *cp = str; int flags; kdev_t dev; unsigned long ino; /* * Get the next vma now (but it won't be used if we sleep). */ next = map->vm_next; flags = map->vm_flags; *cp++ = flags & VM_READ ? 'r' : '-'; *cp++ = flags & VM_WRITE ? 'w' : '-'; *cp++ = flags & VM_EXEC ? 'x' : '-'; *cp++ = flags & VM_MAYSHARE ? 's' : 'p'; *cp++ = 0; dev = 0; ino = 0; if (map->vm_file != NULL) { dev = map->vm_file->f_dentry->d_inode->i_dev; ino = map->vm_file->f_dentry->d_inode->i_ino; line = d_path(map->vm_file->f_dentry, map->vm_file->f_vfsmnt, buffer, PAGE_SIZE); } printk(MAPS_LINE_FORMAT, map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT, kdevname(dev), ino); if (map->vm_file != NULL) printk("%s\n", line); else printk("\n"); } free_page((unsigned long)buffer); return;}#endif/* 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. */asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, unsigned long orig_i0, int restart_syscall){ unsigned long signr; struct k_sigaction *ka; siginfo_t info; /* * XXX Disable svr4 signal handling until solaris emulation works. * It is buggy - Anton */#define SVR4_SIGNAL_BROKEN 1#ifdef SVR4_SIGNAL_BROKEN int svr4_signal = 0;#else int svr4_signal = current->personality == PER_SVR4;#endif if (!oldset) oldset = ¤t->blocked; for (;;) { spin_lock_irq(¤t->sigmask_lock); signr = dequeue_signal(¤t->blocked, &info); spin_unlock_irq(¤t->sigmask_lock); if (!signr) break; if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { current->exit_code = signr; current->state = TASK_STOPPED; /* This happens to be SMP safe so no need to * grab master kernel lock even in this case. */ notify_parent(current, SIGCHLD); schedule(); if (!(signr = current->exit_code)) continue; current->exit_code = 0; 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(ka->sa.sa_handler == SIG_IGN) { if(signr != SIGCHLD) continue; /* sys_wait4() grabs the master kernel lock, so * we need not do so, that sucker should be * threaded and would not be that difficult to * do anyways. */ while(sys_wait4(-1, NULL, WNOHANG, NULL) > 0) ; continue; } if(ka->sa.sa_handler == SIG_DFL) { unsigned long exit_code = signr; if(current->pid == 1) continue; switch(signr) { case SIGCONT: case SIGCHLD: case SIGWINCH: continue; case SIGTSTP: case SIGTTIN: case SIGTTOU: /* The operations performed by * is_orphaned_pgrp() are protected by * the tasklist_lock. */ if (is_orphaned_pgrp(current->pgrp)) continue; case SIGSTOP: if (current->ptrace & PT_PTRACED) continue; current->state = TASK_STOPPED; current->exit_code = signr; /* notify_parent() is SMP safe */ 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 (do_coredump(signr, regs)) exit_code |= 0x80;#ifdef DEBUG_SIGNALS /* Very useful to debug dynamic linker problems */ printk ("Sig %ld going for %s[%d]...\n", signr, current->comm, current->pid); show_regs (regs);#ifdef DEBUG_SIGNALS_TRACE { struct reg_window *rw = (struct reg_window *)regs->u_regs[UREG_FP]; unsigned int ins[8]; while(rw && !(((unsigned long) rw) & 0x3)) { copy_from_user(ins, &rw->ins[0], sizeof(ins)); printk("Caller[%08x](%08x,%08x,%08x,%08x,%08x,%08x)\n", ins[7], ins[0], ins[1], ins[2], ins[3], ins[4], ins[5]); rw = (struct reg_window *)(unsigned long)ins[6]; } }#endif#ifdef DEBUG_SIGNALS_MAPS printk("Maps:\n"); read_maps();#endif#endif /* fall through */ default: sigaddset(¤t->pending.signal, signr); recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); /* NOT REACHED */ } } if(restart_syscall) syscall_restart(orig_i0, regs, &ka->sa); handle_signal(signr, ka, &info, oldset, regs, svr4_signal); return 1; } if(restart_syscall && (regs->u_regs[UREG_I0] == ERESTARTNOHAND || regs->u_regs[UREG_I0] == ERESTARTSYS || regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { /* replay the system call when we are done */ regs->u_regs[UREG_I0] = orig_i0; regs->pc -= 4; regs->npc -= 4; } return 0;}asmlinkage intdo_sys_sigstack(struct sigstack *ssptr, struct sigstack *ossptr, unsigned long sp){ int ret = -EFAULT; /* First see if old state is wanted. */ if (ossptr) { if (put_user(current->sas_ss_sp + current->sas_ss_size, &ossptr->the_stack) || __put_user(on_sig_stack(sp), &ossptr->cur_status)) goto out; } /* Now see if we want to update the new state. */ if (ssptr) { void *ss_sp; if (get_user((long)ss_sp, &ssptr->the_stack)) goto out; /* If the current stack was set with sigaltstack, don't swap stacks while we are on it. */ ret = -EPERM; if (current->sas_ss_sp && on_sig_stack(sp)) goto out; /* Since we don't know the extent of the stack, and we don't track onstack-ness, but rather calculate it, we must presume a size. Ho hum this interface is lossy. */ current->sas_ss_sp = (unsigned long)ss_sp - SIGSTKSZ; current->sas_ss_size = SIGSTKSZ; } ret = 0;out: return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -