/* gcc will complain if a pointer is cast to an integer of different *size.Ifyoureallyneedtodothis(andwedoforanELF32user *applicationinanELF64kernel)thenyouhavetodoacasttoan *integerofthesamesizefirst.TheA()macroaccomplishes
* this. */ #define A(__x) ((unsignedlong)(__x))
/* Unwind the user stack to get the rt_sigframe structure. */
frame = (struct rt_sigframe __user *)
(usp - sigframe_size);
DBG(2, "%s: frame is %p pid %d\n", __func__, frame, task_pid_nr(current));
regs->orig_r28 = 1; /* no restarts for sigreturn */
if (is_compat_task()) { if (get_compat_sigset(&set, &compat_frame->uc.uc_sigmask)) goto give_sigsegv;
} else #endif
{ if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto give_sigsegv;
}
set_current_blocked(&set);
/* Good thing we saved the old gr[30], eh? */ #ifdef CONFIG_64BIT if (is_compat_task()) {
DBG(1, "%s: compat_frame->uc.uc_mcontext 0x%p\n",
__func__, &compat_frame->uc.uc_mcontext); // FIXME: Load upper half from register file if (restore_sigcontext32(&compat_frame->uc.uc_mcontext,
&compat_frame->regs, regs)) goto give_sigsegv;
DBG(1, "%s: usp %#08lx stack 0x%p\n",
__func__, usp, &compat_frame->uc.uc_stack); if (compat_restore_altstack(&compat_frame->uc.uc_stack)) goto give_sigsegv;
} else #endif
{
DBG(1, "%s: frame->uc.uc_mcontext 0x%p\n",
__func__, &frame->uc.uc_mcontext); if (restore_sigcontext(&frame->uc.uc_mcontext, regs)) goto give_sigsegv;
DBG(1, "%s: usp %#08lx stack 0x%p\n",
__func__, usp, &frame->uc.uc_stack); if (restore_altstack(&frame->uc.uc_stack)) goto give_sigsegv;
}
/* If we are on the syscall path IAOQ will not be restored, and *ifweareontheinterruptpathwemustnotcorruptgr31.
*/ if (in_syscall)
regs->gr[31] = regs->iaoq[0];
staticinlinevoid __user *
get_sigframe(struct k_sigaction *ka, unsignedlong sp, size_t frame_size)
{ /*FIXME: ELF32 vs. ELF64 has different frame_size, but since we
don't use the parameter it doesn't matter */
#ifdef CONFIG_64BIT if (!is_compat_task())
rp = VDSO64_SYMBOL(current, sigtramp_rt); else #endif
rp = VDSO32_SYMBOL(current, sigtramp_rt);
if (in_syscall)
rp += 4*4; /* skip 4 instructions and start at ldi 1,%r25 */
haddr = A(ksig->ka.sa.sa_handler); /* The sa_handler may be a pointer to a function descriptor */ #ifdef CONFIG_64BIT if (is_compat_task()) { #endif if (haddr & PA_PLABEL_FDESC) {
Elf32_Fdesc fdesc;
Elf32_Fdesc __user *ufdesc = (Elf32_Fdesc __user *)A(haddr & ~3);
/* The syscall return path will create IAOQ values from r31.
*/ if (in_syscall) {
regs->gr[31] = haddr; #ifdef CONFIG_64BIT if (!test_thread_flag(TIF_32BIT))
sigframe_size |= 1; /* XXX ???? */ #endif
} else { unsignedlong psw = USER_PSW; #ifdef CONFIG_64BIT if (!test_thread_flag(TIF_32BIT))
psw |= PSW_W; #endif
/* If we are singlestepping, arrange a trap to be delivered whenwereturntouserspace.Notethesemantics--we shouldtrapbeforethefirstinsninthehandleris executed.Ref: http://sources.redhat.com/ml/gdb/2004-11/msg00245.html
*/ if (pa_psw(current)->r) {
pa_psw(current)->r = 0;
psw |= PSW_R;
mtctl(-1, 0);
}
/* Usually we don't have to restore %r20 (the system call number) *becauseitgetsloadedinthedelayslotofthebranchexternal *instructionviatheldiinstruction. *Insomecasesaregister-to-registercopyinstructionmighthave *beenusedinstead,inwhichcaseweneedtocopythesyscall *numberintothesourceregisterbeforereturningtouserspace.
*/
/* A syscall is just a branch, so all we have to do is fiddle the *returnpointersothatthebleinstructiongetsexecutedagain.
*/
regs->gr[31] -= 8; /* delayed branching */
/* Get assembler opcode of code in delay branch */
uaddr = (u32 __user *) ((regs->gr[31] & ~3) + 4);
err = get_user(opcode, uaddr); if (err) return;
/* Check if delay branch uses "ldi int,%r20" */ if ((opcode & 0xffff0000) == 0x34140000) return; /* everything ok, just return */
/* Check if delay branch uses "nop" */ if (opcode == INSN_NOP) return;
switch (regs->gr[28]) { case -ERESTART_RESTARTBLOCK: { /* Restart the system call - no handlers present */ unsignedint *usp = (unsignedint *)regs->gr[30]; unsignedlong rp; long err = 0;
/* check that we don't exceed the stack */ if (A(&usp[0]) >= TASK_SIZE_MAX - 5 * sizeof(int)) return;
/* Call trampoline in vdso to restart the syscall *with__NR_restart_syscall. *Originalreturnaddressesareonstacklikethis: * *0:<returnaddress(origr31)> *4:<2ndhalffor64-bit>
*/ #ifdef CONFIG_64BIT if (!is_compat_task()) {
err |= put_user(regs->gr[31] >> 32, &usp[0]);
err |= put_user(regs->gr[31] & 0xffffffff, &usp[1]);
rp = VDSO64_SYMBOL(current, restart_syscall);
} else #endif
{
err |= put_user(regs->gr[31], &usp[0]);
rp = VDSO32_SYMBOL(current, restart_syscall);
}
WARN_ON(err);
regs->gr[31] = rp;
DBG(1, "%s: ERESTART_RESTARTBLOCK\n", __func__); return;
} case -EINTR: /* ok, was handled before and should be returned. */ break; case -ERESTARTNOHAND: case -ERESTARTSYS: case -ERESTARTNOINTR:
DBG(1, "%s: Type %ld\n", __func__, regs->gr[28]);
check_syscallno_in_delay_branch(regs); return; default: break;
}
}
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.