ia64: switch to ->regset_get()
authorAl Viro <viro@zeniv.linux.org.uk>
Tue, 16 Jun 2020 15:20:51 +0000 (11:20 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Mon, 27 Jul 2020 18:31:09 +0000 (14:31 -0400)
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
arch/ia64/kernel/ptrace.c

index eae7b094f608295aaf8738cf584a3adfb6307ea6..33ca9fa0fbf5552126c5035c5588897b1ad8b336 100644 (file)
@@ -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, &reg, 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, &reg)) {
+                       dst->ret = -EIO;
                        return;
+               }
+               membuf_write(&to, &reg, 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,
+               .regset_get = 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
+               .regset_get = fpregs_get, .set = fpregs_set, .active = fpregs_active
        },
 };