[PATCH 10/41] sparc32: get rid of odd callers of copy_regset_to_user()

From: Al Viro
Date: Mon Jun 29 2020 - 17:28:13 EST


From: Al Viro <viro@xxxxxxxxxxxxxxxxxx>

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@xxxxxxxxxxxxxxxxxx>
---
arch/sparc/kernel/ptrace_32.c | 117 +++++++++++++++++++++++++++++-------------
1 file changed, 82 insertions(+), 35 deletions(-)

diff --git a/arch/sparc/kernel/ptrace_32.c b/arch/sparc/kernel/ptrace_32.c
index 47eb315d411c..f72b7d2c4716 100644
--- a/arch/sparc/kernel/ptrace_32.c
+++ b/arch/sparc/kernel/ptrace_32.c
@@ -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;
}

--
2.11.0