📄 signal32.c
字号:
switch (_NSIG_WORDS) { case 4: seta.sig[7] = (oldset->sig[3] >> 32); seta.sig[6] = oldset->sig[3]; case 3: seta.sig[5] = (oldset->sig[2] >> 32); seta.sig[4] = oldset->sig[2]; case 2: seta.sig[3] = (oldset->sig[1] >> 32); seta.sig[2] = oldset->sig[1]; case 1: seta.sig[1] = (oldset->sig[0] >> 32); seta.sig[0] = oldset->sig[0]; } err |= __copy_to_user(&sf->mask, &seta, sizeof(sigset_t32)); err |= copy_in_user((u32 *)sf, (u32 *)(regs->u_regs[UREG_FP]), sizeof(struct reg_window32)); if (err) goto sigsegv; /* 3. signal handler back-trampoline and parameters */ regs->u_regs[UREG_FP] = (unsigned long) sf; regs->u_regs[UREG_I0] = signr; regs->u_regs[UREG_I1] = (unsigned long) &sf->info; regs->u_regs[UREG_I2] = (unsigned long) &sf->regs; /* 4. signal handler */ regs->tpc = (unsigned long) ka->sa.sa_handler; regs->tnpc = (regs->tpc + 4); if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { regs->tpc &= 0xffffffff; regs->tnpc &= 0xffffffff; } /* 5. return to kernel instructions */ if (ka->ka_restorer) regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; else { /* Flush instruction space. */ unsigned long address = ((unsigned long)&(sf->insns[0])); pgd_t *pgdp = pgd_offset(current->mm, address); pmd_t *pmdp = pmd_offset(pgdp, address); pte_t *ptep = pte_offset(pmdp, address); regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2); /* mov __NR_rt_sigreturn, %g1 */ err |= __put_user(0x82102065, &sf->insns[0]); /* t 0x10 */ err |= __put_user(0x91d02010, &sf->insns[1]); if (err) goto sigsegv; if(pte_present(*ptep)) { unsigned long page = (unsigned long) page_address(pte_page(*ptep)); __asm__ __volatile__( " membar #StoreStore\n" " flush %0 + %1" : : "r" (page), "r" (address & (PAGE_SIZE - 1)) : "memory"); } } return;sigill: do_exit(SIGILL);sigsegv: do_exit(SIGSEGV);}static inline void handle_signal32(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_frame32(&ka->sa, regs->tpc, regs->tnpc, regs, signr, oldset); else { if (ka->sa.sa_flags & SA_SIGINFO) setup_rt_frame32(ka, regs, signr, oldset, info); else if (current->thread.flags & SPARC_FLAG_NEWSIGNALS) new_setup_frame32(ka, regs, signr, oldset); else setup_frame32(&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_restart32(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->tstate |= TSTATE_ICARRY; 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->tpc -= 4; regs->tnpc -= 4; }}#ifdef DEBUG_SIGNALS_MAPS#define MAPS_LINE_FORMAT "%016lx-%016lx %s %016lx %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_signal32(sigset_t *oldset, struct pt_regs * regs, unsigned long orig_i0, int restart_syscall){ unsigned long signr; struct k_sigaction *ka; siginfo_t info; int svr4_signal = current->personality == PER_SVR4; 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) { /* Do the syscall restart before we let the debugger * look at the child registers. */ if (restart_syscall && (regs->u_regs[UREG_I0] == ERESTARTNOHAND || regs->u_regs[UREG_I0] == ERESTARTSYS || regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { regs->u_regs[UREG_I0] = orig_i0; regs->tpc -= 4; regs->tnpc -= 4; restart_syscall = 0; } current->exit_code = signr; current->state = TASK_STOPPED; 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: if (is_orphaned_pgrp(current->pgrp)) continue; case SIGSTOP: if (current->ptrace & PT_PTRACED) continue; 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 (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); /* On SMP we are only interested in the current * CPU's registers. */ __show_regs (regs);#ifdef DEBUG_SIGNALS_TLB do { extern void sparc_ultra_dump_itlb(void); extern void sparc_ultra_dump_dtlb(void); sparc_ultra_dump_dtlb(); sparc_ultra_dump_itlb(); } while(0);#endif#ifdef DEBUG_SIGNALS_TRACE { struct reg_window32 *rw = (struct reg_window32 *)(regs->u_regs[UREG_FP] & 0xffffffff); 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_window32 *)(unsigned long)ins[6]; } }#endif #ifdef DEBUG_SIGNALS_MAPS printk("Maps:\n"); read_maps();#endif#endif /* fall through */ default: sig_exit(signr, exit_code, &info); /* NOT REACHED */ } } if (restart_syscall) syscall_restart32(orig_i0, regs, &ka->sa); handle_signal32(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->tpc -= 4; regs->tnpc -= 4; } return 0;}struct sigstack32 { u32 the_stack; int cur_status;};asmlinkage int do_sys32_sigstack(u32 u_ssptr, u32 u_ossptr, unsigned long sp){ struct sigstack32 *ssptr = (struct sigstack32 *)((unsigned long)(u_ssptr)); struct sigstack32 *ossptr = (struct sigstack32 *)((unsigned long)(u_ossptr)); 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;}asmlinkage int do_sys32_sigaltstack(u32 ussa, u32 uossa, unsigned long sp){ stack_t uss, uoss; int ret; mm_segment_t old_fs; if (ussa && (get_user((long)uss.ss_sp, &((stack_t32 *)(long)ussa)->ss_sp) || __get_user(uss.ss_flags, &((stack_t32 *)(long)ussa)->ss_flags) || __get_user(uss.ss_size, &((stack_t32 *)(long)ussa)->ss_size))) return -EFAULT; old_fs = get_fs(); set_fs(KERNEL_DS); ret = do_sigaltstack(ussa ? &uss : NULL, uossa ? &uoss : NULL, sp); set_fs(old_fs); if (!ret && uossa && (put_user((long)uoss.ss_sp, &((stack_t32 *)(long)uossa)->ss_sp) || __put_user(uoss.ss_flags, &((stack_t32 *)(long)uossa)->ss_flags) || __put_user(uoss.ss_size, &((stack_t32 *)(long)uossa)->ss_size))) return -EFAULT; return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -