sparc32: get rid of odd callers of copy_regset_to_user()
authorAl Viro <viro@zeniv.linux.org.uk>
Fri, 22 May 2020 17:19:47 +0000 (13:19 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Fri, 26 Jun 2020 05:02:14 +0000 (01:02 -0400)
the life is much simpler if copy_regset_to_user() (and ->get())
gets called only with pos == 0; sparc32 PTRACE_GETREGS and
PTRACE_GETFPREGS are among the few things that use it to fetch
pieces of regset _not_ starting at the beginning.  It's actually
easier to define a separate regset that would provide what
we need, rather than trying to cobble that from the one
PTRACE_GETREGSET uses.

Extra ->get() instances do not amount to much code and once
we get the conversion of ->get() to new API (dependent upon the
lack of weird callers of ->get()) they'll shrink a lot, along
with the rest of ->get() instances...

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
arch/sparc/kernel/ptrace_32.c

index 47eb315..f72b7d2 100644 (file)
@@ -99,15 +99,13 @@ static int genregs32_get(struct task_struct *target,
        if (ret || !count)
                return ret;
 
-       if (pos < 32 * sizeof(u32)) {
-               if (regwindow32_get(target, regs, uregs))
-                       return -EFAULT;
-               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
-                                         uregs,
-                                         16 * sizeof(u32), 32 * sizeof(u32));
-               if (ret || !count)
-                       return ret;
-       }
+       if (regwindow32_get(target, regs, uregs))
+               return -EFAULT;
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                 uregs,
+                                 16 * sizeof(u32), 32 * sizeof(u32));
+       if (ret)
+               return ret;
 
        uregs[0] = regs->psr;
        uregs[1] = regs->pc;
@@ -288,6 +286,73 @@ static const struct user_regset sparc32_regsets[] = {
        },
 };
 
+static int getregs_get(struct task_struct *target,
+                        const struct user_regset *regset,
+                        unsigned int pos, unsigned int count,
+                        void *kbuf, void __user *ubuf)
+{
+       const struct pt_regs *regs = target->thread.kregs;
+       u32 v[4];
+       int ret;
+
+       if (target == current)
+               flush_user_windows();
+
+       v[0] = regs->psr;
+       v[1] = regs->pc;
+       v[2] = regs->npc;
+       v[3] = regs->y;
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                 v,
+                                 0 * sizeof(u32), 4 * sizeof(u32));
+       if (ret)
+               return ret;
+
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                 regs->u_regs + 1,
+                                 4 * sizeof(u32), 19 * sizeof(u32));
+}
+
+static int getfpregs_get(struct task_struct *target,
+                       const struct user_regset *regset,
+                       unsigned int pos, unsigned int count,
+                       void *kbuf, void __user *ubuf)
+{
+       const unsigned long *fpregs = target->thread.float_regs;
+       int ret = 0;
+
+#if 0
+       if (target == current)
+               save_and_clear_fpu();
+#endif
+
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                 fpregs,
+                                 0, 32 * sizeof(u32));
+       if (ret)
+               return ret;
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                 &target->thread.fsr,
+                                 32 * sizeof(u32), 33 * sizeof(u32));
+       if (ret)
+               return ret;
+       return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+                                 33 * sizeof(u32), 68 * sizeof(u32));
+}
+
+static const struct user_regset ptrace32_regsets[] = {
+       [REGSET_GENERAL] = {
+               .n = 19, .size = sizeof(u32), .get = getregs_get,
+       },
+       [REGSET_FP] = {
+               .n = 68, .size = sizeof(u32), .get = getfpregs_get,
+       },
+};
+
+static const struct user_regset_view ptrace32_view = {
+       .regsets = ptrace32_regsets, .n = ARRAY_SIZE(ptrace32_regsets)
+};
+
 static const struct user_regset_view user_sparc32_view = {
        .name = "sparc", .e_machine = EM_SPARC,
        .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
@@ -327,15 +392,10 @@ long arch_ptrace(struct task_struct *child, long request,
 
        switch(request) {
        case PTRACE_GETREGS: {
-               ret = copy_regset_to_user(child, view, REGSET_GENERAL,
-                                         32 * sizeof(u32),
-                                         4 * sizeof(u32),
-                                         &pregs->psr);
-               if (!ret)
-                       copy_regset_to_user(child, view, REGSET_GENERAL,
-                                           1 * sizeof(u32),
-                                           15 * sizeof(u32),
-                                           &pregs->u_regs[0]);
+               ret = copy_regset_to_user(child, &ptrace32_view,
+                                         REGSET_GENERAL, 0,
+                                         19 * sizeof(u32),
+                                         pregs);
                break;
        }
 
@@ -353,23 +413,10 @@ long arch_ptrace(struct task_struct *child, long request,
        }
 
        case PTRACE_GETFPREGS: {
-               ret = copy_regset_to_user(child, view, REGSET_FP,
-                                         0 * sizeof(u32),
-                                         32 * sizeof(u32),
-                                         &fps->regs[0]);
-               if (!ret)
-                       ret = copy_regset_to_user(child, view, REGSET_FP,
-                                                 33 * sizeof(u32),
-                                                 1 * sizeof(u32),
-                                                 &fps->fsr);
-
-               if (!ret) {
-                       if (__put_user(0, &fps->fpqd) ||
-                           __put_user(0, &fps->flags) ||
-                           __put_user(0, &fps->extra) ||
-                           clear_user(fps->fpq, sizeof(fps->fpq)))
-                               ret = -EFAULT;
-               }
+               ret = copy_regset_to_user(child, &ptrace32_view,
+                                         REGSET_FP, 0,
+                                         68 * sizeof(u32),
+                                         fps);
                break;
        }