in kernel/ptrace.c [1609:1680]
static void do_fpregs_set(struct unw_frame_info *info, void *arg)
{
struct regset_getset *dst = arg;
elf_fpreg_t fpreg, tmp[30];
int index, start, end;
if (unw_unwind_to_user(info) < 0)
return;
/* Skip pos 0 and 1 */
if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(2)) {
dst->ret = user_regset_copyin_ignore(&dst->pos, &dst->count,
&dst->u.set.kbuf,
&dst->u.set.ubuf,
0, ELF_FP_OFFSET(2));
if (dst->count == 0 || dst->ret)
return;
}
/* fr2-fr31 */
if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(32)) {
start = dst->pos;
end = min(((unsigned int)ELF_FP_OFFSET(32)),
dst->pos + dst->count);
dst->ret = user_regset_copyin(&dst->pos, &dst->count,
&dst->u.set.kbuf, &dst->u.set.ubuf, tmp,
ELF_FP_OFFSET(2), ELF_FP_OFFSET(32));
if (dst->ret)
return;
if (start & 0xF) { /* only write high part */
if (unw_get_fr(info, start / sizeof(elf_fpreg_t),
&fpreg)) {
dst->ret = -EIO;
return;
}
tmp[start / sizeof(elf_fpreg_t) - 2].u.bits[0]
= fpreg.u.bits[0];
start &= ~0xFUL;
}
if (end & 0xF) { /* only write low part */
if (unw_get_fr(info, end / sizeof(elf_fpreg_t),
&fpreg)) {
dst->ret = -EIO;
return;
}
tmp[end / sizeof(elf_fpreg_t) - 2].u.bits[1]
= fpreg.u.bits[1];
end = (end + 0xF) & ~0xFUL;
}
for ( ; start < end ; start += sizeof(elf_fpreg_t)) {
index = start / sizeof(elf_fpreg_t);
if (unw_set_fr(info, index, tmp[index - 2])) {
dst->ret = -EIO;
return;
}
}
if (dst->ret || dst->count == 0)
return;
}
/* fph */
if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(128)) {
ia64_sync_fph(dst->target);
dst->ret = user_regset_copyin(&dst->pos, &dst->count,
&dst->u.set.kbuf,
&dst->u.set.ubuf,
&dst->target->thread.fph,
ELF_FP_OFFSET(32), -1);
}
}