/* Store registers needed to create the signal frame */ staticvoid store_sigregs(void)
{
save_access_regs(current->thread.acrs);
save_user_fpu_regs();
}
/* Load registers after signal return */ staticvoid load_sigregs(void)
{
restore_access_regs(current->thread.acrs);
}
/* Copy a 'clean' PSW mask to the user to avoid leaking
information about whether PER is currently on. */
user_sregs.regs.psw.mask = PSW_USER_BITS |
(regs->psw.mask & (PSW_MASK_USER | PSW_MASK_RI));
user_sregs.regs.psw.addr = regs->psw.addr;
memcpy(&user_sregs.regs.gprs, ®s->gprs, sizeof(sregs->regs.gprs));
memcpy(&user_sregs.regs.acrs, current->thread.acrs, sizeof(user_sregs.regs.acrs));
fpregs_store(&user_sregs.fpregs, ¤t->thread.ufpu); if (__copy_to_user(sregs, &user_sregs, sizeof(_sigregs))) return -EFAULT; return 0;
}
clear_pt_regs_flag(regs, PIF_SYSCALL); /* No longer in a system call */ return 0;
}
/* Returns non-zero on fault. */ staticint save_sigregs_ext(struct pt_regs *regs,
_sigregs_ext __user *sregs_ext)
{
__u64 vxrs[__NUM_VXRS_LOW]; int i;
/* Save vector registers to signal stack */ if (cpu_has_vx()) { for (i = 0; i < __NUM_VXRS_LOW; i++)
vxrs[i] = current->thread.ufpu.vxrs[i].low; if (__copy_to_user(&sregs_ext->vxrs_low, vxrs, sizeof(sregs_ext->vxrs_low)) ||
__copy_to_user(&sregs_ext->vxrs_high,
current->thread.ufpu.vxrs + __NUM_VXRS_LOW, sizeof(sregs_ext->vxrs_high))) return -EFAULT;
} return 0;
}
/* Default to using normal stack */
sp = regs->gprs[15];
/* Overflow on alternate signal stack gives SIGSEGV. */ if (on_sig_stack(sp) && !on_sig_stack((sp - frame_size) & -8UL)) return (void __user *) -1UL;
/* This is the X/Open sanctioned signal stack switching. */ if (ka->sa.sa_flags & SA_ONSTACK) { if (! sas_ss_flags(sp))
sp = current->sas_ss_sp + current->sas_ss_size;
}
/* * gprs_high are only present for a 31-bit task running on * a 64-bit kernel (see compat_signal.c) but the space for * gprs_high need to be allocated if vector registers are * included in the signal frame on a 31-bit system.
*/
frame_size = sizeof(*frame) - sizeof(frame->sregs_ext); if (cpu_has_vx())
frame_size += sizeof(frame->sregs_ext);
frame = get_sigframe(ka, regs, frame_size); if (frame == (void __user *) -1UL) return -EFAULT;
/* Set up backchain. */ if (__put_user(regs->gprs[15], (addr_t __user *) frame)) return -EFAULT;
/* Create struct sigcontext on the signal stack */
memcpy(&sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE);
sc.sregs = (_sigregs __user __force *) &frame->sregs; if (__copy_to_user(&frame->sc, &sc, sizeof(frame->sc))) return -EFAULT;
/* Store registers needed to create the signal frame */
store_sigregs();
/* Create _sigregs on the signal stack */ if (save_sigregs(regs, &frame->sregs)) return -EFAULT;
/* Place signal number on stack to allow backtrace from handler. */ if (__put_user(regs->gprs[2], (int __user *) &frame->signo)) return -EFAULT;
/* Create _sigregs_ext on the signal stack */ if (save_sigregs_ext(regs, &frame->sregs_ext)) return -EFAULT;
/* Set up to return from userspace. If provided, use a stub
already in userspace. */ if (ka->sa.sa_flags & SA_RESTORER)
restorer = (unsignedlong) ka->sa.sa_restorer; else
restorer = VDSO64_SYMBOL(current, sigreturn);
/* Set up registers for signal handler */
regs->gprs[14] = restorer;
regs->gprs[15] = (unsignedlong) frame; /* Force default amode and default user address space control. */
regs->psw.mask = PSW_MASK_EA | PSW_MASK_BA |
(PSW_USER_BITS & PSW_MASK_ASC) |
(regs->psw.mask & ~PSW_MASK_ASC);
regs->psw.addr = (unsignedlong) ka->sa.sa_handler;
/* We forgot to include these in the sigcontext.
To avoid breaking binary compatibility, they are passed as args. */ if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
sig == SIGTRAP || sig == SIGFPE) { /* set extra registers only for synchronous signals */
regs->gprs[4] = regs->int_code & 127;
regs->gprs[5] = regs->int_parm_long;
regs->gprs[6] = current->thread.last_break;
} return 0;
}
frame_size = sizeof(struct rt_sigframe) - sizeof(_sigregs_ext); /* * gprs_high are only present for a 31-bit task running on * a 64-bit kernel (see compat_signal.c) but the space for * gprs_high need to be allocated if vector registers are * included in the signal frame on a 31-bit system.
*/
uc_flags = 0; if (cpu_has_vx()) {
frame_size += sizeof(_sigregs_ext);
uc_flags |= UC_VXRS;
}
frame = get_sigframe(&ksig->ka, regs, frame_size); if (frame == (void __user *) -1UL) return -EFAULT;
/* Set up backchain. */ if (__put_user(regs->gprs[15], (addr_t __user *) frame)) return -EFAULT;
/* Set up to return from userspace. If provided, use a stub
already in userspace. */ if (ksig->ka.sa.sa_flags & SA_RESTORER)
restorer = (unsignedlong) ksig->ka.sa.sa_restorer; else
restorer = VDSO64_SYMBOL(current, rt_sigreturn);
/* Create siginfo on the signal stack */ if (copy_siginfo_to_user(&frame->info, &ksig->info)) return -EFAULT;
/* Store registers needed to create the signal frame */
store_sigregs();
/* Create ucontext on the signal stack. */ if (__put_user(uc_flags, &frame->uc.uc_flags) ||
__put_user(NULL, &frame->uc.uc_link) ||
__save_altstack(&frame->uc.uc_stack, regs->gprs[15]) ||
save_sigregs(regs, &frame->uc.uc_mcontext) ||
__copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)) ||
save_sigregs_ext(regs, &frame->uc.uc_mcontext_ext)) return -EFAULT;
/* Set up registers for signal handler */
regs->gprs[14] = restorer;
regs->gprs[15] = (unsignedlong) frame; /* Force default amode and default user address space control. */
regs->psw.mask = PSW_MASK_EA | PSW_MASK_BA |
(PSW_USER_BITS & PSW_MASK_ASC) |
(regs->psw.mask & ~PSW_MASK_ASC);
regs->psw.addr = (unsignedlong) ksig->ka.sa.sa_handler;
/* 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->sig, &ksig->ka, 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.
*/
/* * Get signal to deliver. When running under ptrace, at this point * the debugger may change all our registers, including the system * call information.
*/
current->thread.system_call =
test_pt_regs_flag(regs, PIF_SYSCALL) ? regs->int_code : 0;
if (get_signal(&ksig)) { /* Whee! Actually deliver the signal. */ if (current->thread.system_call) {
regs->int_code = current->thread.system_call; /* Check for system call restarting. */ switch (regs->gprs[2]) { case -ERESTART_RESTARTBLOCK: case -ERESTARTNOHAND:
regs->gprs[2] = -EINTR; break; case -ERESTARTSYS: if (!(ksig.ka.sa.sa_flags & SA_RESTART)) {
regs->gprs[2] = -EINTR; break;
}
fallthrough; case -ERESTARTNOINTR:
regs->gprs[2] = regs->orig_gpr2;
regs->psw.addr =
__rewind_psw(regs->psw,
regs->int_code >> 16); break;
}
} /* No longer in a system call */
clear_pt_regs_flag(regs, PIF_SYSCALL);
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.