diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2020-05-22 19:19:47 +0200 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2020-06-26 07:02:14 +0200 |
commit | 87d805331a69afdd7b3ee3d5c42760b747a4904f (patch) | |
tree | ea29565572de427cabc8f29f303a47c77bb47eb3 /arch | |
parent | sparc64: switch genregs32_get() to use of get_from_target() (diff) | |
download | linux-87d805331a69afdd7b3ee3d5c42760b747a4904f.tar.xz linux-87d805331a69afdd7b3ee3d5c42760b747a4904f.zip |
sparc32: get rid of odd callers of copy_regset_to_user()
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>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/sparc/kernel/ptrace_32.c | 117 |
1 files 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; } |