From: Al Viro <viro@xxxxxxxxxxxxxxxxxx> Signed-off-by: Al Viro <viro@xxxxxxxxxxxxxxxxxx> --- arch/ia64/kernel/ptrace.c | 149 ++++++++++++++++++---------------------------- 1 file changed, 58 insertions(+), 91 deletions(-) diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index eae7b094f608..990ac8caae8c 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -1489,9 +1489,17 @@ access_elf_reg(struct task_struct *target, struct unw_frame_info *info, return access_elf_areg(target, info, addr, data, write_access); } +struct regset_membuf { + struct membuf to; + int ret; +}; + void do_gpregs_get(struct unw_frame_info *info, void *arg) { - struct regset_getset *dst = arg; + struct regset_membuf *dst = arg; + struct membuf to = dst->to; + unsigned int n; + elf_greg_t reg; if (unw_unwind_to_user(info) < 0) return; @@ -1509,35 +1517,13 @@ void do_gpregs_get(struct unw_frame_info *info, void *arg) /* Skip r0 */ - if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(1)) { - dst->ret = user_regset_copyout_zero(&dst->pos, &dst->count, - &dst->u.get.kbuf, - &dst->u.get.ubuf, - 0, ELF_GR_OFFSET(1)); - if (dst->ret) + membuf_zero(&to, 8); + for (n = 8; to.left && n < ELF_AR_END_OFFSET; n += 8) { + if (access_elf_reg(info->task, info, n, ®, 0) < 0) { + dst->ret = -EIO; return; - } - - while (dst->count && dst->pos < ELF_AR_END_OFFSET) { - unsigned int n, from, to; - elf_greg_t tmp[16]; - - from = dst->pos; - to = from + min(dst->count, (unsigned)sizeof(tmp)); - if (to > ELF_AR_END_OFFSET) - to = ELF_AR_END_OFFSET; - for (n = 0; from < to; from += sizeof(elf_greg_t), n++) { - if (access_elf_reg(dst->target, info, from, - &tmp[n], 0) < 0) { - dst->ret = -EIO; - return; - } } - dst->ret = user_regset_copyout(&dst->pos, &dst->count, - &dst->u.get.kbuf, &dst->u.get.ubuf, tmp, - dst->pos, to); - if (dst->ret) - return; + membuf_store(&to, reg); } } @@ -1588,60 +1574,36 @@ void do_gpregs_set(struct unw_frame_info *info, void *arg) void do_fpregs_get(struct unw_frame_info *info, void *arg) { - struct regset_getset *dst = arg; - struct task_struct *task = dst->target; - elf_fpreg_t tmp[30]; - int index, min_copy, i; + struct task_struct *task = info->task; + struct regset_membuf *dst = arg; + struct membuf to = dst->to; + elf_fpreg_t reg; + unsigned int n; 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_copyout_zero(&dst->pos, &dst->count, - &dst->u.get.kbuf, - &dst->u.get.ubuf, - 0, ELF_FP_OFFSET(2)); - if (dst->count == 0 || dst->ret) - return; - } + membuf_zero(&to, 2 * sizeof(elf_fpreg_t)); /* fr2-fr31 */ - if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(32)) { - index = (dst->pos - ELF_FP_OFFSET(2)) / sizeof(elf_fpreg_t); - - min_copy = min(((unsigned int)ELF_FP_OFFSET(32)), - dst->pos + dst->count); - for (i = dst->pos; i < min_copy; i += sizeof(elf_fpreg_t), - index++) - if (unw_get_fr(info, i / sizeof(elf_fpreg_t), - &tmp[index])) { - dst->ret = -EIO; - return; - } - dst->ret = user_regset_copyout(&dst->pos, &dst->count, - &dst->u.get.kbuf, &dst->u.get.ubuf, tmp, - ELF_FP_OFFSET(2), ELF_FP_OFFSET(32)); - if (dst->count == 0 || dst->ret) + for (n = 2; to.left && n < 32; n++) { + if (unw_get_fr(info, n, ®)) { + dst->ret = -EIO; return; + } + membuf_write(&to, ®, sizeof(reg)); } /* fph */ - if (dst->count > 0) { - ia64_flush_fph(dst->target); - if (task->thread.flags & IA64_THREAD_FPH_VALID) - dst->ret = user_regset_copyout( - &dst->pos, &dst->count, - &dst->u.get.kbuf, &dst->u.get.ubuf, - &dst->target->thread.fph, - ELF_FP_OFFSET(32), -1); - else - /* Zero fill instead. */ - dst->ret = user_regset_copyout_zero( - &dst->pos, &dst->count, - &dst->u.get.kbuf, &dst->u.get.ubuf, - ELF_FP_OFFSET(32), -1); - } + if (!to.left) + return; + + ia64_flush_fph(task); + if (task->thread.flags & IA64_THREAD_FPH_VALID) + membuf_write(&to, &task->thread.fph, 96 * sizeof(reg)); + else + membuf_zero(&to, 96 * sizeof(reg)); } void do_fpregs_set(struct unw_frame_info *info, void *arg) @@ -1717,6 +1679,20 @@ void do_fpregs_set(struct unw_frame_info *info, void *arg) } } +static void +unwind_and_call(void (*call)(struct unw_frame_info *, void *), + struct task_struct *target, void *data) +{ + if (target == current) + unw_init_running(call, data); + else { + struct unw_frame_info info; + memset(&info, 0, sizeof(info)); + unw_init_from_blocked_task(&info, target); + (*call)(&info, data); + } +} + static int do_regset_call(void (*call)(struct unw_frame_info *, void *), struct task_struct *target, @@ -1728,27 +1704,18 @@ do_regset_call(void (*call)(struct unw_frame_info *, void *), .pos = pos, .count = count, .u.set = { .kbuf = kbuf, .ubuf = ubuf }, .ret = 0 }; - - if (target == current) - unw_init_running(call, &info); - else { - struct unw_frame_info ufi; - memset(&ufi, 0, sizeof(ufi)); - unw_init_from_blocked_task(&ufi, target); - (*call)(&ufi, &info); - } - + unwind_and_call(call, target, &info); return info.ret; } static int gpregs_get(struct task_struct *target, const struct user_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) + struct membuf to) { - return do_regset_call(do_gpregs_get, target, regset, pos, count, - kbuf, ubuf); + struct regset_membuf info = {.to = to}; + unwind_and_call(do_gpregs_get, target, &info); + return info.ret; } static int gpregs_set(struct task_struct *target, @@ -1790,11 +1757,11 @@ fpregs_active(struct task_struct *target, const struct user_regset *regset) static int fpregs_get(struct task_struct *target, const struct user_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) + struct membuf to) { - return do_regset_call(do_fpregs_get, target, regset, pos, count, - kbuf, ubuf); + struct regset_membuf info = {.to = to}; + unwind_and_call(do_fpregs_get, target, &info); + return info.ret; } static int fpregs_set(struct task_struct *target, @@ -2033,14 +2000,14 @@ static const struct user_regset native_regsets[] = { .core_note_type = NT_PRSTATUS, .n = ELF_NGREG, .size = sizeof(elf_greg_t), .align = sizeof(elf_greg_t), - .get = gpregs_get, .set = gpregs_set, + .get2 = gpregs_get, .set = gpregs_set, .writeback = gpregs_writeback }, { .core_note_type = NT_PRFPREG, .n = ELF_NFPREG, .size = sizeof(elf_fpreg_t), .align = sizeof(elf_fpreg_t), - .get = fpregs_get, .set = fpregs_set, .active = fpregs_active + .get2 = fpregs_get, .set = fpregs_set, .active = fpregs_active }, }; -- 2.11.0