/* * The following define adds a 64 byte gap between the signal * stack frame and previous contents of the stack. This allows * frame unwinding in a function epilogue but only if a frame * pointer is used in the function. This is necessary because * current gcc compilers (<4.3) do not generate unwind info on * SH for function epilogues.
*/ #define UNWINDGUARD 64
/* * Do a signal return; undo the signal stack.
*/
#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */ #ifdefined(CONFIG_CPU_SH2) #define TRAP_NOARG 0xc320 /* Syscall w/no args (NR in R3) */ #else #define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) */ #endif #define OR_R0_R0 0x200b /* or r0,r0 (insert to avoid hardware bug) */
/* These symbols are defined with the addresses in the vsyscall page.
See vsyscall-trapa.S. */ externvoid __kernel_sigreturn(void); externvoid __kernel_rt_sigreturn(void);
if (_NSIG_WORDS > 1)
err |= __copy_to_user(frame->extramask, &set->sig[1], sizeof(frame->extramask));
/* Set up to return from userspace. If provided, use a stub
already in userspace. */ if (ksig->ka.sa.sa_flags & SA_RESTORER) {
regs->pr = (unsignedlong) ksig->ka.sa.sa_restorer; #ifdef CONFIG_VSYSCALL
} elseif (likely(current->mm->context.vdso)) {
regs->pr = VDSO_SYM(&__kernel_sigreturn); #endif
} else { /* Generate return code (system call to sigreturn) */
err |= __put_user(MOVW(7), &frame->retcode[0]);
err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
err |= __put_user(OR_R0_R0, &frame->retcode[2]);
err |= __put_user(OR_R0_R0, &frame->retcode[3]);
err |= __put_user(OR_R0_R0, &frame->retcode[4]);
err |= __put_user(OR_R0_R0, &frame->retcode[5]);
err |= __put_user(OR_R0_R0, &frame->retcode[6]);
err |= __put_user((__NR_sigreturn), &frame->retcode[7]);
regs->pr = (unsignedlong) frame->retcode;
flush_icache_range(regs->pr, regs->pr + sizeof(frame->retcode));
}
if (err) return -EFAULT;
/* Set up registers for signal handler */
regs->regs[15] = (unsignedlong) frame;
regs->regs[4] = sig; /* Arg for signal handler */
regs->regs[5] = 0;
regs->regs[6] = (unsignedlong) &frame->sc;
/* Set up to return from userspace. If provided, use a stub
already in userspace. */ if (ksig->ka.sa.sa_flags & SA_RESTORER) {
regs->pr = (unsignedlong) ksig->ka.sa.sa_restorer; #ifdef CONFIG_VSYSCALL
} elseif (likely(current->mm->context.vdso)) {
regs->pr = VDSO_SYM(&__kernel_rt_sigreturn); #endif
} else { /* Generate return code (system call to rt_sigreturn) */
err |= __put_user(MOVW(7), &frame->retcode[0]);
err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
err |= __put_user(OR_R0_R0, &frame->retcode[2]);
err |= __put_user(OR_R0_R0, &frame->retcode[3]);
err |= __put_user(OR_R0_R0, &frame->retcode[4]);
err |= __put_user(OR_R0_R0, &frame->retcode[5]);
err |= __put_user(OR_R0_R0, &frame->retcode[6]);
err |= __put_user((__NR_rt_sigreturn), &frame->retcode[7]);
regs->pr = (unsignedlong) frame->retcode;
flush_icache_range(regs->pr, regs->pr + sizeof(frame->retcode));
}
if (err) return -EFAULT;
/* Set up registers for signal handler */
regs->regs[15] = (unsignedlong) frame;
regs->regs[4] = sig; /* Arg for signal handler */
regs->regs[5] = (unsignedlong) &frame->info;
regs->regs[6] = (unsignedlong) &frame->uc;
staticinlinevoid
handle_syscall_restart(unsignedlong save_r0, struct pt_regs *regs, struct sigaction *sa)
{ /* If we're not from a syscall, bail out */ if (regs->tra < 0) return;
/* check for system call restart.. */ switch (regs->regs[0]) { case -ERESTART_RESTARTBLOCK: case -ERESTARTNOHAND:
no_system_call_restart:
regs->regs[0] = -EINTR; break;
case -ERESTARTSYS: if (!(sa->sa_flags & SA_RESTART)) goto no_system_call_restart;
fallthrough; case -ERESTARTNOINTR:
regs->regs[0] = save_r0;
regs->pc -= instruction_size(__raw_readw(regs->pc - 4)); break;
}
}
/* Set up the stack frame */ if (ksig->ka.sa.sa_flags & SA_SIGINFO)
ret = setup_rt_frame(ksig, oldset, regs); else
ret = setup_frame(ksig, oldset, regs);
/* * 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.
*/ staticvoid do_signal(struct pt_regs *regs, unsignedint save_r0)
{ struct ksignal ksig;
/* * We want the common case to go fast, which * is why we may in certain cases get here from * kernel mode. Just return without doing anything * if so.
*/ if (!user_mode(regs)) return;
if (get_signal(&ksig)) {
handle_syscall_restart(save_r0, regs, &ksig.ka.sa);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.