From ce22e1d39429c7de9f054ce8d03278dd2010b642 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 7 Feb 2008 02:14:48 -0800 Subject: [PATCH 01/11] [SPARC64]: Fix booting on non-zero cpu. The early per-cpu handling needs a slight tweak to work when booting on a non-zero cpu. We got away with this for a long time, but can't any longer as now even printk() calls functions (cpu_clock() for example) that thus make early references to per-cpu variables. Signed-off-by: David S. Miller --- arch/sparc64/kernel/head.S | 25 +++++++++++++++++++++++++ arch/sparc64/prom/init.c | 3 +++ 2 files changed, 28 insertions(+) diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S index c4147ad8677b..44b105c04dd3 100644 --- a/arch/sparc64/kernel/head.S +++ b/arch/sparc64/kernel/head.S @@ -632,11 +632,36 @@ tlb_fixup_done: /* Not reached... */ 1: + /* If we boot on a non-zero cpu, all of the per-cpu + * variable references we make before setting up the + * per-cpu areas will use a bogus offset. Put a + * compensating factor into __per_cpu_base to handle + * this cleanly. + * + * What the per-cpu code calculates is: + * + * __per_cpu_base + (cpu << __per_cpu_shift) + * + * These two variables are zero initially, so to + * make it all cancel out to zero we need to put + * "0 - (cpu << 0)" into __per_cpu_base so that the + * above formula evaluates to zero. + * + * We cannot even perform a printk() until this stuff + * is setup as that calls cpu_clock() which uses + * per-cpu variables. + */ + sub %g0, %o0, %o1 + sethi %hi(__per_cpu_base), %o2 + stx %o1, [%o2 + %lo(__per_cpu_base)] #else mov 0, %o0 #endif sth %o0, [%g6 + TI_CPU] + call prom_init_report + nop + /* Off we go.... */ call start_kernel nop diff --git a/arch/sparc64/prom/init.c b/arch/sparc64/prom/init.c index 1c0db842a6f4..87e7c7ea0ee6 100644 --- a/arch/sparc64/prom/init.c +++ b/arch/sparc64/prom/init.c @@ -48,7 +48,10 @@ void __init prom_init(void *cif_handler, void *cif_stack) prom_getstring(node, "version", prom_version, sizeof(prom_version)); prom_printf("\n"); +} +void __init prom_init_report(void) +{ printk("PROMLIB: Sun IEEE Boot Prom '%s'\n", prom_version); printk("PROMLIB: Root node compatible: %s\n", prom_root_compatible); } From d09c2a23ee4220a6341166a7dab5601258fef91f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 6 Feb 2008 23:02:08 -0800 Subject: [PATCH 02/11] [SPARC64]: Add user regsets. Signed-off-by: David S. Miller --- arch/sparc64/kernel/ptrace.c | 582 ++++++++++++++++++++++++++++++++++- 1 file changed, 581 insertions(+), 1 deletion(-) diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index 81111a12f0a8..668f569498b6 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -1,6 +1,6 @@ /* ptrace.c: Sparc process tracing support. * - * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu) + * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net) * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson, @@ -22,6 +22,9 @@ #include #include #include +#include +#include +#include #include #include @@ -167,6 +170,583 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, } } +enum sparc_regset { + REGSET_GENERAL, + REGSET_FP, +}; + +static int genregs64_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 = task_pt_regs(target); + int ret; + + if (target == current) + flushw_user(); + + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + regs->u_regs, + 0, 16 * sizeof(u64)); + if (!ret) { + unsigned long __user *reg_window = (unsigned long __user *) + (regs->u_regs[UREG_I6] + STACK_BIAS); + unsigned long window[16]; + + if (copy_from_user(window, reg_window, sizeof(window))) + return -EFAULT; + + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + window, + 16 * sizeof(u64), + 32 * sizeof(u64)); + } + + if (!ret) { + /* TSTATE, TPC, TNPC */ + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + ®s->tstate, + 32 * sizeof(u64), + 35 * sizeof(u64)); + } + + if (!ret) { + unsigned long y = regs->y; + + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &y, + 35 * sizeof(u64), + 36 * sizeof(u64)); + } + + if (!ret) + ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + 36 * sizeof(u64), -1); + + return ret; +} + +static int genregs64_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + struct pt_regs *regs = task_pt_regs(target); + int ret; + + if (target == current) + flushw_user(); + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + regs->u_regs, + 0, 16 * sizeof(u64)); + if (!ret && count > 0) { + unsigned long __user *reg_window = (unsigned long __user *) + (regs->u_regs[UREG_I6] + STACK_BIAS); + unsigned long window[16]; + + if (copy_from_user(window, reg_window, sizeof(window))) + return -EFAULT; + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + window, + 16 * sizeof(u64), + 32 * sizeof(u64)); + if (!ret && + copy_to_user(reg_window, window, sizeof(window))) + return -EFAULT; + } + + if (!ret && count > 0) { + unsigned long tstate; + + /* TSTATE */ + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &tstate, + 32 * sizeof(u64), + 33 * sizeof(u64)); + if (!ret) { + /* Only the condition codes can be modified + * in the %tstate register. + */ + tstate &= (TSTATE_ICC | TSTATE_XCC); + regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC); + regs->tstate |= tstate; + } + } + + if (!ret) { + /* TPC, TNPC */ + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + ®s->tpc, + 33 * sizeof(u64), + 35 * sizeof(u64)); + } + + if (!ret) { + unsigned long y; + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &y, + 35 * sizeof(u64), + 36 * sizeof(u64)); + if (!ret) + regs->y = y; + } + + if (!ret) + ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + 36 * sizeof(u64), -1); + + return ret; +} + +static int fpregs64_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 = task_thread_info(target)->fpregs; + unsigned long fprs, fsr, gsr; + int ret; + + if (target == current) + save_and_clear_fpu(); + + fprs = task_thread_info(target)->fpsaved[0]; + + if (fprs & FPRS_DL) + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + fpregs, + 0, 16 * sizeof(u64)); + else + ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + 0, + 16 * sizeof(u64)); + + if (!ret) { + if (fprs & FPRS_DU) + ret = user_regset_copyout(&pos, &count, + &kbuf, &ubuf, + fpregs + 16, + 16 * sizeof(u64), + 32 * sizeof(u64)); + else + ret = user_regset_copyout_zero(&pos, &count, + &kbuf, &ubuf, + 16 * sizeof(u64), + 32 * sizeof(u64)); + } + + if (fprs & FPRS_FEF) { + fsr = task_thread_info(target)->xfsr[0]; + gsr = task_thread_info(target)->gsr[0]; + } else { + fsr = gsr = 0; + } + + if (!ret) + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &fsr, + 32 * sizeof(u64), + 33 * sizeof(u64)); + if (!ret) + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &gsr, + 33 * sizeof(u64), + 34 * sizeof(u64)); + if (!ret) + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &fprs, + 34 * sizeof(u64), + 35 * sizeof(u64)); + + if (!ret) + ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + 35 * sizeof(u64), -1); + + return ret; +} + +static int fpregs64_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + unsigned long *fpregs = task_thread_info(target)->fpregs; + unsigned long fprs; + int ret; + + if (target == current) + save_and_clear_fpu(); + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + fpregs, + 0, 32 * sizeof(u64)); + if (!ret) + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + task_thread_info(target)->xfsr, + 32 * sizeof(u64), + 33 * sizeof(u64)); + if (!ret) + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + task_thread_info(target)->gsr, + 33 * sizeof(u64), + 34 * sizeof(u64)); + + fprs = task_thread_info(target)->fpsaved[0]; + if (!ret && count > 0) { + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &fprs, + 34 * sizeof(u64), + 35 * sizeof(u64)); + } + + fprs |= (FPRS_FEF | FPRS_DL | FPRS_DU); + task_thread_info(target)->fpsaved[0] = fprs; + + if (!ret) + ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + 35 * sizeof(u64), -1); + return ret; +} + +static const struct user_regset sparc64_regsets[] = { + /* Format is: + * G0 --> G7 + * O0 --> O7 + * L0 --> L7 + * I0 --> I7 + * TSTATE, TPC, TNPC, Y + */ + [REGSET_GENERAL] = { + .core_note_type = NT_PRSTATUS, + .n = 36 * sizeof(u64), + .size = sizeof(u64), .align = sizeof(u64), + .get = genregs64_get, .set = genregs64_set + }, + /* Format is: + * F0 --> F63 + * FSR + * GSR + * FPRS + */ + [REGSET_FP] = { + .core_note_type = NT_PRFPREG, + .n = 35 * sizeof(u64), + .size = sizeof(u64), .align = sizeof(u64), + .get = fpregs64_get, .set = fpregs64_set + }, +}; + +static const struct user_regset_view user_sparc64_view = { + .name = "sparc64", .e_machine = EM_SPARCV9, + .regsets = sparc64_regsets, .n = ARRAY_SIZE(sparc64_regsets) +}; + +static int genregs32_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 = task_pt_regs(target); + compat_ulong_t __user *reg_window; + compat_ulong_t *k = kbuf; + compat_ulong_t __user *u = ubuf; + compat_ulong_t reg; + + if (target == current) + flushw_user(); + + pos /= sizeof(reg); + count /= sizeof(reg); + + if (kbuf) { + for (; count > 0 && pos < 16; count--) + *k++ = regs->u_regs[pos++]; + + reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; + for (; count > 0 && pos < 32; count--) { + if (get_user(*k++, ®_window[pos++])) + return -EFAULT; + } + } else { + for (; count > 0 && pos < 16; count--) { + if (put_user((compat_ulong_t) regs->u_regs[pos++], u++)) + return -EFAULT; + } + + reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; + for (; count > 0 && pos < 32; count--) { + if (get_user(reg, ®_window[pos++]) || + put_user(reg, u++)) + return -EFAULT; + } + } + while (count > 0) { + switch (pos) { + case 32: /* PSR */ + reg = tstate_to_psr(regs->tstate); + break; + case 33: /* PC */ + reg = regs->tpc; + break; + case 34: /* NPC */ + reg = regs->tnpc; + break; + case 35: /* Y */ + reg = regs->y; + break; + case 36: /* WIM */ + case 37: /* TBR */ + reg = 0; + break; + default: + goto finish; + } + + if (kbuf) + *k++ = reg; + else if (put_user(reg, u++)) + return -EFAULT; + pos++; + count--; + } +finish: + pos *= sizeof(reg); + count *= sizeof(reg); + + return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + 38 * sizeof(reg), -1); +} + +static int genregs32_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + struct pt_regs *regs = task_pt_regs(target); + compat_ulong_t __user *reg_window; + const compat_ulong_t *k = kbuf; + const compat_ulong_t __user *u = ubuf; + compat_ulong_t reg; + + if (target == current) + flushw_user(); + + pos /= sizeof(reg); + count /= sizeof(reg); + + if (kbuf) { + for (; count > 0 && pos < 16; count--) + regs->u_regs[pos++] = *k++; + + reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; + for (; count > 0 && pos < 32; count--) { + if (put_user(*k++, ®_window[pos++])) + return -EFAULT; + } + } else { + for (; count > 0 && pos < 16; count--) { + if (get_user(reg, u++)) + return -EFAULT; + regs->u_regs[pos++] = reg; + } + + reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; + for (; count > 0 && pos < 32; count--) { + if (get_user(reg, u++) || + put_user(reg, ®_window[pos++])) + return -EFAULT; + } + } + while (count > 0) { + unsigned long tstate; + + if (kbuf) + reg = *k++; + else if (get_user(reg, u++)) + return -EFAULT; + + switch (pos) { + case 32: /* PSR */ + tstate = regs->tstate; + tstate &= ~(TSTATE_ICC | TSTATE_XCC); + tstate |= psr_to_tstate_icc(reg); + regs->tstate = tstate; + break; + case 33: /* PC */ + regs->tpc = reg; + break; + case 34: /* NPC */ + regs->tnpc = reg; + break; + case 35: /* Y */ + regs->y = reg; + break; + case 36: /* WIM */ + case 37: /* TBR */ + break; + default: + goto finish; + } + + pos++; + count--; + } +finish: + pos *= sizeof(reg); + count *= sizeof(reg); + + return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + 38 * sizeof(reg), -1); +} + +static int fpregs32_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 = task_thread_info(target)->fpregs; + compat_ulong_t enabled; + unsigned long fprs; + compat_ulong_t fsr; + int ret = 0; + + if (target == current) + save_and_clear_fpu(); + + fprs = task_thread_info(target)->fpsaved[0]; + if (fprs & FPRS_FEF) { + fsr = task_thread_info(target)->xfsr[0]; + enabled = 1; + } else { + fsr = 0; + enabled = 0; + } + + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + fpregs, + 0, 32 * sizeof(u32)); + + if (!ret) + ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + 32 * sizeof(u32), + 33 * sizeof(u32)); + if (!ret) + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &fsr, + 33 * sizeof(u32), + 34 * sizeof(u32)); + + if (!ret) { + compat_ulong_t val; + + val = (enabled << 8) | (8 << 16); + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &val, + 34 * sizeof(u32), + 35 * sizeof(u32)); + } + + if (!ret) + ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + 35 * sizeof(u32), -1); + + return ret; +} + +static int fpregs32_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + unsigned long *fpregs = task_thread_info(target)->fpregs; + unsigned long fprs; + int ret; + + if (target == current) + save_and_clear_fpu(); + + fprs = task_thread_info(target)->fpsaved[0]; + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + fpregs, + 0, 32 * sizeof(u32)); + if (!ret) + user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + 32 * sizeof(u32), + 33 * sizeof(u32)); + if (!ret && count > 0) { + compat_ulong_t fsr; + unsigned long val; + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &fsr, + 33 * sizeof(u32), + 34 * sizeof(u32)); + if (!ret) { + val = task_thread_info(target)->xfsr[0]; + val &= 0xffffffff00000000UL; + val |= fsr; + task_thread_info(target)->xfsr[0] = val; + } + } + + fprs |= (FPRS_FEF | FPRS_DL); + task_thread_info(target)->fpsaved[0] = fprs; + + if (!ret) + ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + 34 * sizeof(u32), -1); + return ret; +} + +static const struct user_regset sparc32_regsets[] = { + /* Format is: + * G0 --> G7 + * O0 --> O7 + * L0 --> L7 + * I0 --> I7 + * PSR, PC, nPC, Y, WIM, TBR + */ + [REGSET_GENERAL] = { + .core_note_type = NT_PRSTATUS, + .n = 38 * sizeof(u32), + .size = sizeof(u32), .align = sizeof(u32), + .get = genregs32_get, .set = genregs32_set + }, + /* Format is: + * F0 --> F31 + * empty 32-bit word + * FSR (32--bit word) + * FPU QUEUE COUNT (8-bit char) + * FPU QUEUE ENTRYSIZE (8-bit char) + * FPU ENABLED (8-bit char) + * empty 8-bit char + * FPU QUEUE (64 32-bit ints) + */ + [REGSET_FP] = { + .core_note_type = NT_PRFPREG, + .n = 99 * sizeof(u32), + .size = sizeof(u32), .align = sizeof(u32), + .get = fpregs32_get, .set = fpregs32_set + }, +}; + +static const struct user_regset_view user_sparc32_view = { + .name = "sparc", .e_machine = EM_SPARC, + .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets) +}; + +const struct user_regset_view *task_user_regset_view(struct task_struct *task) +{ + if (test_tsk_thread_flag(task, TIF_32BIT)) + return &user_sparc32_view; + return &user_sparc64_view; +} + asmlinkage void do_ptrace(struct pt_regs *regs) { int request = regs->u_regs[UREG_I0]; From 8e3fe806e50d48d875bb56793ca3f984cba6c0db Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 6 Feb 2008 21:00:44 -0800 Subject: [PATCH 03/11] [SPARC32]: Add user regset support. It is missing lazy FPU handling for the current task, but that can be added later. Signed-off-by: David S. Miller --- arch/sparc/kernel/ptrace.c | 285 ++++++++++++++++++++++++++++++++++++- 1 file changed, 284 insertions(+), 1 deletion(-) diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c index 7452269bba2a..c1e7e6ae7c6f 100644 --- a/arch/sparc/kernel/ptrace.c +++ b/arch/sparc/kernel/ptrace.c @@ -1,6 +1,6 @@ /* ptrace.c: Sparc process tracing support. * - * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu) + * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net) * * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson, * and David Mosberger. @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include @@ -258,6 +260,287 @@ void ptrace_disable(struct task_struct *child) /* nothing to do */ } +enum sparc_regset { + REGSET_GENERAL, + REGSET_FP, +}; + +static int genregs32_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; + unsigned long __user *reg_window; + unsigned long *k = kbuf; + unsigned long __user *u = ubuf; + unsigned long reg; + + if (target == current) + flush_user_windows(); + + pos /= sizeof(reg); + count /= sizeof(reg); + + if (kbuf) { + for (; count > 0 && pos < 16; count--) + *k++ = regs->u_regs[pos++]; + + reg_window = (unsigned long __user *) regs->u_regs[UREG_I6]; + for (; count > 0 && pos < 32; count--) { + if (get_user(*k++, ®_window[pos++])) + return -EFAULT; + } + } else { + for (; count > 0 && pos < 16; count--) { + if (put_user(regs->u_regs[pos++], u++)) + return -EFAULT; + } + + reg_window = (unsigned long __user *) regs->u_regs[UREG_I6]; + for (; count > 0 && pos < 32; count--) { + if (get_user(reg, ®_window[pos++]) || + put_user(reg, u++)) + return -EFAULT; + } + } + while (count > 0) { + switch (pos) { + case 32: /* PSR */ + reg = regs->psr; + break; + case 33: /* PC */ + reg = regs->pc; + break; + case 34: /* NPC */ + reg = regs->npc; + break; + case 35: /* Y */ + reg = regs->y; + break; + case 36: /* WIM */ + case 37: /* TBR */ + reg = 0; + break; + default: + goto finish; + } + + if (kbuf) + *k++ = reg; + else if (put_user(reg, u++)) + return -EFAULT; + pos++; + count--; + } +finish: + pos *= sizeof(reg); + count *= sizeof(reg); + + return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + 38 * sizeof(reg), -1); +} + +static int genregs32_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + struct pt_regs *regs = target->thread.kregs; + unsigned long __user *reg_window; + const unsigned long *k = kbuf; + const unsigned long __user *u = ubuf; + unsigned long reg; + + if (target == current) + flush_user_windows(); + + pos /= sizeof(reg); + count /= sizeof(reg); + + if (kbuf) { + for (; count > 0 && pos < 16; count--) + regs->u_regs[pos++] = *k++; + + reg_window = (unsigned long __user *) regs->u_regs[UREG_I6]; + for (; count > 0 && pos < 32; count--) { + if (put_user(*k++, ®_window[pos++])) + return -EFAULT; + } + } else { + for (; count > 0 && pos < 16; count--) { + if (get_user(reg, u++)) + return -EFAULT; + regs->u_regs[pos++] = reg; + } + + reg_window = (unsigned long __user *) regs->u_regs[UREG_I6]; + for (; count > 0 && pos < 32; count--) { + if (get_user(reg, u++) || + put_user(reg, ®_window[pos++])) + return -EFAULT; + } + } + while (count > 0) { + unsigned long psr; + + if (kbuf) + reg = *k++; + else if (get_user(reg, u++)) + return -EFAULT; + + switch (pos) { + case 32: /* PSR */ + psr = regs->psr; + psr &= ~PSR_ICC; + psr |= (reg & PSR_ICC); + regs->psr = psr; + break; + case 33: /* PC */ + regs->pc = reg; + break; + case 34: /* NPC */ + regs->npc = reg; + break; + case 35: /* Y */ + regs->y = reg; + break; + case 36: /* WIM */ + case 37: /* TBR */ + break; + default: + goto finish; + } + + pos++; + count--; + } +finish: + pos *= sizeof(reg); + count *= sizeof(reg); + + return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + 38 * sizeof(reg), -1); +} + +static int fpregs32_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) + ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + 32 * sizeof(u32), + 33 * sizeof(u32)); + if (!ret) + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &target->thread.fsr, + 33 * sizeof(u32), + 34 * sizeof(u32)); + + if (!ret) { + unsigned long val; + + val = (1 << 8) | (8 << 16); + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &val, + 34 * sizeof(u32), + 35 * sizeof(u32)); + } + + if (!ret) + ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + 35 * sizeof(u32), -1); + + return ret; +} + +static int fpregs32_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + unsigned long *fpregs = target->thread.float_regs; + int ret; + +#if 0 + if (target == current) + save_and_clear_fpu(); +#endif + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + fpregs, + 0, 32 * sizeof(u32)); + if (!ret) + user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + 32 * sizeof(u32), + 33 * sizeof(u32)); + if (!ret && count > 0) { + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &target->thread.fsr, + 33 * sizeof(u32), + 34 * sizeof(u32)); + } + + if (!ret) + ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + 34 * sizeof(u32), -1); + return ret; +} + +static const struct user_regset sparc32_regsets[] = { + /* Format is: + * G0 --> G7 + * O0 --> O7 + * L0 --> L7 + * I0 --> I7 + * PSR, PC, nPC, Y, WIM, TBR + */ + [REGSET_GENERAL] = { + .core_note_type = NT_PRSTATUS, + .n = 38 * sizeof(u32), + .size = sizeof(u32), .align = sizeof(u32), + .get = genregs32_get, .set = genregs32_set + }, + /* Format is: + * F0 --> F31 + * empty 32-bit word + * FSR (32--bit word) + * FPU QUEUE COUNT (8-bit char) + * FPU QUEUE ENTRYSIZE (8-bit char) + * FPU ENABLED (8-bit char) + * empty 8-bit char + * FPU QUEUE (64 32-bit ints) + */ + [REGSET_FP] = { + .core_note_type = NT_PRFPREG, + .n = 99 * sizeof(u32), + .size = sizeof(u32), .align = sizeof(u32), + .get = fpregs32_get, .set = fpregs32_set + }, +}; + +static const struct user_regset_view user_sparc32_view = { + .name = "sparc", .e_machine = EM_SPARC, + .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets) +}; + +const struct user_regset_view *task_user_regset_view(struct task_struct *task) +{ + return &user_sparc32_view; +} + asmlinkage void do_ptrace(struct pt_regs *regs) { unsigned long request = regs->u_regs[UREG_I0]; From 38282764e3e76aa02c071af4673e6b6320e426ad Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 6 Feb 2008 22:01:01 -0800 Subject: [PATCH 04/11] [SPARC]: Kill DEBUG_PTRACE code. It has long exceeded it's usefulness. Signed-off-by: David S. Miller --- arch/sparc/kernel/ptrace.c | 46 ------------------------------------ arch/sparc64/kernel/ptrace.c | 43 --------------------------------- 2 files changed, 89 deletions(-) diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c index c1e7e6ae7c6f..0619958ecfdc 100644 --- a/arch/sparc/kernel/ptrace.c +++ b/arch/sparc/kernel/ptrace.c @@ -236,19 +236,6 @@ static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset, } /* #define ALLOW_INIT_TRACING */ -/* #define DEBUG_PTRACE */ - -#ifdef DEBUG_PTRACE -char *pt_rq [] = { - /* 0 */ "TRACEME", "PEEKTEXT", "PEEKDATA", "PEEKUSR", - /* 4 */ "POKETEXT", "POKEDATA", "POKEUSR", "CONT", - /* 8 */ "KILL", "SINGLESTEP", "SUNATTACH", "SUNDETACH", - /* 12 */ "GETREGS", "SETREGS", "GETFPREGS", "SETFPREGS", - /* 16 */ "READDATA", "WRITEDATA", "READTEXT", "WRITETEXT", - /* 20 */ "GETFPAREGS", "SETFPAREGS", "unknown", "unknown", - /* 24 */ "SYSCALL", "" -}; -#endif /* * Called by kernel/ptrace.c when detaching.. @@ -552,23 +539,6 @@ asmlinkage void do_ptrace(struct pt_regs *regs) int ret; lock_kernel(); -#ifdef DEBUG_PTRACE - { - char *s; - - if ((request >= 0) && (request <= 24)) - s = pt_rq [request]; - else - s = "unknown"; - - if (request == PTRACE_POKEDATA && data == 0x91d02001){ - printk ("do_ptrace: breakpoint pid=%d, addr=%08lx addr2=%08lx\n", - pid, addr, addr2); - } else - printk("do_ptrace: rq=%s(%d) pid=%d addr=%08lx data=%08lx addr2=%08lx\n", - s, (int) request, (int) pid, addr, data, addr2); - } -#endif if (request == PTRACE_TRACEME) { ret = ptrace_traceme(); @@ -650,9 +620,6 @@ asmlinkage void do_ptrace(struct pt_regs *regs) for(rval = 1; rval < 16; rval++) __put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1])); pt_succ_return(regs, 0); -#ifdef DEBUG_PTRACE - printk ("PC=%x nPC=%x o7=%x\n", cregs->pc, cregs->npc, cregs->u_regs [15]); -#endif goto out_tsk; } @@ -801,12 +768,6 @@ asmlinkage void do_ptrace(struct pt_regs *regs) clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); child->exit_code = data; -#ifdef DEBUG_PTRACE - printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n", - child->comm, child->pid, child->exit_code, - child->thread.kregs->pc, - child->thread.kregs->npc); -#endif wake_up_process(child); pt_succ_return(regs, 0); goto out_tsk; @@ -858,9 +819,6 @@ asmlinkage void do_ptrace(struct pt_regs *regs) asmlinkage void syscall_trace(void) { -#ifdef DEBUG_PTRACE - printk("%s [%d]: syscall_trace\n", current->comm, current->pid); -#endif if (!test_thread_flag(TIF_SYSCALL_TRACE)) return; if (!(current->ptrace & PT_PTRACED)) @@ -873,10 +831,6 @@ asmlinkage void syscall_trace(void) * for normal use. strace only continues with a signal if the * stopping signal is not SIGTRAP. -brl */ -#ifdef DEBUG_PTRACE - printk("%s [%d]: syscall_trace exit= %x\n", current->comm, - current->pid, current->exit_code); -#endif if (current->exit_code) { send_sig (current->exit_code, current, 1); current->exit_code = 0; diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index 668f569498b6..2232e85c8415 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -87,19 +87,6 @@ pt_os_succ_return (struct pt_regs *regs, unsigned long val, void __user *addr) } /* #define ALLOW_INIT_TRACING */ -/* #define DEBUG_PTRACE */ - -#ifdef DEBUG_PTRACE -char *pt_rq [] = { - /* 0 */ "TRACEME", "PEEKTEXT", "PEEKDATA", "PEEKUSR", - /* 4 */ "POKETEXT", "POKEDATA", "POKEUSR", "CONT", - /* 8 */ "KILL", "SINGLESTEP", "SUNATTACH", "SUNDETACH", - /* 12 */ "GETREGS", "SETREGS", "GETFPREGS", "SETFPREGS", - /* 16 */ "READDATA", "WRITEDATA", "READTEXT", "WRITETEXT", - /* 20 */ "GETFPAREGS", "SETFPAREGS", "unknown", "unknown", - /* 24 */ "SYSCALL", "" -}; -#endif /* * Called by kernel/ptrace.c when detaching.. @@ -763,23 +750,6 @@ asmlinkage void do_ptrace(struct pt_regs *regs) addr2 &= 0xffffffffUL; } lock_kernel(); -#ifdef DEBUG_PTRACE - { - char *s; - - if ((request >= 0) && (request <= 24)) - s = pt_rq [request]; - else - s = "unknown"; - - if (request == PTRACE_POKEDATA && data == 0x91d02001){ - printk ("do_ptrace: breakpoint pid=%d, addr=%016lx addr2=%016lx\n", - pid, addr, addr2); - } else - printk("do_ptrace: rq=%s(%d) pid=%d addr=%016lx data=%016lx addr2=%016lx\n", - s, request, pid, addr, data, addr2); - } -#endif if (request == PTRACE_TRACEME) { ret = ptrace_traceme(); if (ret < 0) @@ -905,9 +875,6 @@ asmlinkage void do_ptrace(struct pt_regs *regs) goto out_tsk; } pt_succ_return(regs, 0); -#ifdef DEBUG_PTRACE - printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]); -#endif goto out_tsk; } @@ -932,9 +899,6 @@ asmlinkage void do_ptrace(struct pt_regs *regs) goto out_tsk; } pt_succ_return(regs, 0); -#ifdef DEBUG_PTRACE - printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]); -#endif goto out_tsk; } @@ -1152,13 +1116,6 @@ asmlinkage void do_ptrace(struct pt_regs *regs) } child->exit_code = data; -#ifdef DEBUG_PTRACE - printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n", child->comm, - child->pid, child->exit_code, - task_pt_regs(child)->tpc, - task_pt_regs(child)->tnpc); - -#endif wake_up_process(child); pt_succ_return(regs, 0); goto out_tsk; From 190aa9f60f9575d1b7382cd1ee33e2589208c514 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 6 Feb 2008 22:08:18 -0800 Subject: [PATCH 05/11] [SPARC]: Remove PTRACE_SUN* handling. Supporting SunOS ptrace() is pretty pointless and these kinds of quirks keep us from being able to share more code with other platforms. Signed-off-by: David S. Miller --- arch/sparc/kernel/ptrace.c | 15 +-------------- arch/sparc64/kernel/ptrace.c | 15 +-------------- include/asm-sparc/ptrace.h | 2 -- include/asm-sparc64/ptrace.h | 2 -- 4 files changed, 2 insertions(+), 32 deletions(-) diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c index 0619958ecfdc..29fa6e5cb450 100644 --- a/arch/sparc/kernel/ptrace.c +++ b/arch/sparc/kernel/ptrace.c @@ -556,8 +556,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) goto out; } - if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH) - || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) { + if (request == PTRACE_ATTACH) { if (ptrace_attach(child)) { pt_error_return(regs, EPERM); goto out_tsk; @@ -789,18 +788,6 @@ asmlinkage void do_ptrace(struct pt_regs *regs) goto out_tsk; } - case PTRACE_SUNDETACH: { /* detach a process that was attached. */ - int err = ptrace_detach(child, data); - if (err) { - pt_error_return(regs, EIO); - goto out_tsk; - } - pt_succ_return(regs, 0); - goto out_tsk; - } - - /* PTRACE_DUMPCORE unsupported... */ - default: { int err = ptrace_request(child, request, addr, data); if (err) diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index 2232e85c8415..e881dbbd2c49 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -766,8 +766,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) goto out; } - if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH) - || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) { + if (request == PTRACE_ATTACH) { if (ptrace_attach(child)) { pt_error_return(regs, EPERM); goto out_tsk; @@ -1137,18 +1136,6 @@ asmlinkage void do_ptrace(struct pt_regs *regs) goto out_tsk; } - case PTRACE_SUNDETACH: { /* detach a process that was attached. */ - int error = ptrace_detach(child, data); - if (error) { - pt_error_return(regs, EIO); - goto out_tsk; - } - pt_succ_return(regs, 0); - goto out_tsk; - } - - /* PTRACE_DUMPCORE unsupported... */ - case PTRACE_GETEVENTMSG: { int err; diff --git a/include/asm-sparc/ptrace.h b/include/asm-sparc/ptrace.h index 714497099a42..a84345ba8bee 100644 --- a/include/asm-sparc/ptrace.h +++ b/include/asm-sparc/ptrace.h @@ -151,8 +151,6 @@ extern void show_regs(struct pt_regs *); #define SF_XXARG 0x5c /* Stuff for the ptrace system call */ -#define PTRACE_SUNATTACH 10 -#define PTRACE_SUNDETACH 11 #define PTRACE_GETREGS 12 #define PTRACE_SETREGS 13 #define PTRACE_GETFPREGS 14 diff --git a/include/asm-sparc64/ptrace.h b/include/asm-sparc64/ptrace.h index 7eba90c6c753..2ba989b3056e 100644 --- a/include/asm-sparc64/ptrace.h +++ b/include/asm-sparc64/ptrace.h @@ -261,8 +261,6 @@ extern void show_regs(struct pt_regs *); #define SF_XXARG 0x5c /* Stuff for the ptrace system call */ -#define PTRACE_SUNATTACH 10 -#define PTRACE_SUNDETACH 11 #define PTRACE_GETREGS 12 #define PTRACE_SETREGS 13 #define PTRACE_GETFPREGS 14 From 9775369ec06bad8edb2fbd8c77316f49b439c225 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 7 Feb 2008 03:00:17 -0800 Subject: [PATCH 06/11] [SPARC]: Move over to arch_ptrace(). Signed-off-by: David S. Miller --- arch/sparc/kernel/entry.S | 17 -- arch/sparc/kernel/ptrace.c | 460 +++++------------------------------ arch/sparc64/kernel/entry.S | 4 - arch/sparc64/kernel/ptrace.c | 407 +++++++++---------------------- include/asm-sparc/ptrace.h | 5 - include/asm-sparc64/ptrace.h | 16 -- 6 files changed, 180 insertions(+), 729 deletions(-) diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index 88d2cefd01be..c2eed8f71516 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S @@ -1224,23 +1224,6 @@ sys_nis_syscall: call c_sys_nis_syscall mov %l5, %o7 - .align 4 - .globl sys_ptrace -sys_ptrace: - call do_ptrace - add %sp, STACKFRAME_SZ, %o0 - - ld [%curptr + TI_FLAGS], %l5 - andcc %l5, _TIF_SYSCALL_TRACE, %g0 - be 1f - nop - - call syscall_trace - nop - -1: - RESTORE_ALL - .align 4 .globl sys_execve sys_execve: diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c index 29fa6e5cb450..1c0d5363f720 100644 --- a/arch/sparc/kernel/ptrace.c +++ b/arch/sparc/kernel/ptrace.c @@ -26,215 +26,6 @@ #include #include -#define MAGIC_CONSTANT 0x80000000 - - -/* Returning from ptrace is a bit tricky because the syscall return - * low level code assumes any value returned which is negative and - * is a valid errno will mean setting the condition codes to indicate - * an error return. This doesn't work, so we have this hook. - */ -static inline void pt_error_return(struct pt_regs *regs, unsigned long error) -{ - regs->u_regs[UREG_I0] = error; - regs->psr |= PSR_C; - regs->pc = regs->npc; - regs->npc += 4; -} - -static inline void pt_succ_return(struct pt_regs *regs, unsigned long value) -{ - regs->u_regs[UREG_I0] = value; - regs->psr &= ~PSR_C; - regs->pc = regs->npc; - regs->npc += 4; -} - -static void -pt_succ_return_linux(struct pt_regs *regs, unsigned long value, long __user *addr) -{ - if (put_user(value, addr)) { - pt_error_return(regs, EFAULT); - return; - } - regs->u_regs[UREG_I0] = 0; - regs->psr &= ~PSR_C; - regs->pc = regs->npc; - regs->npc += 4; -} - -static void -pt_os_succ_return (struct pt_regs *regs, unsigned long val, long __user *addr) -{ - if (current->personality == PER_SUNOS) - pt_succ_return (regs, val); - else - pt_succ_return_linux (regs, val, addr); -} - -/* Fuck me gently with a chainsaw... */ -static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset, - struct task_struct *tsk, long __user *addr) -{ - struct pt_regs *cregs = tsk->thread.kregs; - struct thread_info *t = task_thread_info(tsk); - int v; - - if(offset >= 1024) - offset -= 1024; /* whee... */ - if(offset & ((sizeof(unsigned long) - 1))) { - pt_error_return(regs, EIO); - return; - } - if(offset >= 16 && offset < 784) { - offset -= 16; offset >>= 2; - pt_os_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset), addr); - return; - } - if(offset >= 784 && offset < 832) { - offset -= 784; offset >>= 2; - pt_os_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset), addr); - return; - } - switch(offset) { - case 0: - v = t->ksp; - break; - case 4: - v = t->kpc; - break; - case 8: - v = t->kpsr; - break; - case 12: - v = t->uwinmask; - break; - case 832: - v = t->w_saved; - break; - case 896: - v = cregs->u_regs[UREG_I0]; - break; - case 900: - v = cregs->u_regs[UREG_I1]; - break; - case 904: - v = cregs->u_regs[UREG_I2]; - break; - case 908: - v = cregs->u_regs[UREG_I3]; - break; - case 912: - v = cregs->u_regs[UREG_I4]; - break; - case 916: - v = cregs->u_regs[UREG_I5]; - break; - case 920: - v = cregs->u_regs[UREG_I6]; - break; - case 924: - if(tsk->thread.flags & MAGIC_CONSTANT) - v = cregs->u_regs[UREG_G1]; - else - v = 0; - break; - case 940: - v = cregs->u_regs[UREG_I0]; - break; - case 944: - v = cregs->u_regs[UREG_I1]; - break; - - case 948: - /* Isn't binary compatibility _fun_??? */ - if(cregs->psr & PSR_C) - v = cregs->u_regs[UREG_I0] << 24; - else - v = 0; - break; - - /* Rest of them are completely unsupported. */ - default: - printk("%s [%d]: Wants to read user offset %ld\n", - current->comm, task_pid_nr(current), offset); - pt_error_return(regs, EIO); - return; - } - if (current->personality == PER_SUNOS) - pt_succ_return (regs, v); - else - pt_succ_return_linux (regs, v, addr); - return; -} - -static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset, - struct task_struct *tsk) -{ - struct pt_regs *cregs = tsk->thread.kregs; - struct thread_info *t = task_thread_info(tsk); - unsigned long value = regs->u_regs[UREG_I3]; - - if(offset >= 1024) - offset -= 1024; /* whee... */ - if(offset & ((sizeof(unsigned long) - 1))) - goto failure; - if(offset >= 16 && offset < 784) { - offset -= 16; offset >>= 2; - *(((unsigned long *)(&t->reg_window[0]))+offset) = value; - goto success; - } - if(offset >= 784 && offset < 832) { - offset -= 784; offset >>= 2; - *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value; - goto success; - } - switch(offset) { - case 896: - cregs->u_regs[UREG_I0] = value; - break; - case 900: - cregs->u_regs[UREG_I1] = value; - break; - case 904: - cregs->u_regs[UREG_I2] = value; - break; - case 908: - cregs->u_regs[UREG_I3] = value; - break; - case 912: - cregs->u_regs[UREG_I4] = value; - break; - case 916: - cregs->u_regs[UREG_I5] = value; - break; - case 920: - cregs->u_regs[UREG_I6] = value; - break; - case 924: - cregs->u_regs[UREG_I7] = value; - break; - case 940: - cregs->u_regs[UREG_I0] = value; - break; - case 944: - cregs->u_regs[UREG_I1] = value; - break; - - /* Rest of them are completely unsupported or "no-touch". */ - default: - printk("%s [%d]: Wants to write user offset %ld\n", - current->comm, task_pid_nr(current), offset); - goto failure; - } -success: - pt_succ_return(regs, 0); - return; -failure: - pt_error_return(regs, EIO); - return; -} - /* #define ALLOW_INIT_TRACING */ /* @@ -528,113 +319,42 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) return &user_sparc32_view; } -asmlinkage void do_ptrace(struct pt_regs *regs) +long arch_ptrace(struct task_struct *child, long request, long addr, long data) { - unsigned long request = regs->u_regs[UREG_I0]; - unsigned long pid = regs->u_regs[UREG_I1]; - unsigned long addr = regs->u_regs[UREG_I2]; - unsigned long data = regs->u_regs[UREG_I3]; - unsigned long addr2 = regs->u_regs[UREG_I4]; - struct task_struct *child; - int ret; - - lock_kernel(); - - if (request == PTRACE_TRACEME) { - ret = ptrace_traceme(); - if (ret < 0) - pt_error_return(regs, -ret); - else - pt_succ_return(regs, 0); - goto out; - } - - child = ptrace_get_task_struct(pid); - if (IS_ERR(child)) { - ret = PTR_ERR(child); - pt_error_return(regs, -ret); - goto out; - } - - if (request == PTRACE_ATTACH) { - if (ptrace_attach(child)) { - pt_error_return(regs, EPERM); - goto out_tsk; - } - pt_succ_return(regs, 0); - goto out_tsk; - } - - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret < 0) { - pt_error_return(regs, -ret); - goto out_tsk; - } + unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4]; + int i, ret; switch(request) { - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: { - unsigned long tmp; - - if (access_process_vm(child, addr, - &tmp, sizeof(tmp), 0) == sizeof(tmp)) - pt_os_succ_return(regs, tmp, (long __user *)data); - else - pt_error_return(regs, EIO); - goto out_tsk; - } - - case PTRACE_PEEKUSR: - read_sunos_user(regs, addr, child, (long __user *) data); - goto out_tsk; - - case PTRACE_POKEUSR: - write_sunos_user(regs, addr, child); - goto out_tsk; - - case PTRACE_POKETEXT: /* write the word at location addr. */ - case PTRACE_POKEDATA: { - if (access_process_vm(child, addr, - &data, sizeof(data), 1) == sizeof(data)) - pt_succ_return(regs, 0); - else - pt_error_return(regs, EIO); - goto out_tsk; - } - case PTRACE_GETREGS: { struct pt_regs __user *pregs = (struct pt_regs __user *) addr; struct pt_regs *cregs = child->thread.kregs; - int rval; - if (!access_ok(VERIFY_WRITE, pregs, sizeof(struct pt_regs))) { - rval = -EFAULT; - pt_error_return(regs, -rval); - goto out_tsk; - } + ret = -EFAULT; + if (!access_ok(VERIFY_WRITE, pregs, sizeof(struct pt_regs))) + break; + __put_user(cregs->psr, (&pregs->psr)); __put_user(cregs->pc, (&pregs->pc)); __put_user(cregs->npc, (&pregs->npc)); __put_user(cregs->y, (&pregs->y)); - for(rval = 1; rval < 16; rval++) - __put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1])); - pt_succ_return(regs, 0); - goto out_tsk; + for (i = 1; i < 16; i++) + __put_user(cregs->u_regs[i], &pregs->u_regs[i - 1]); + ret = 0; + break; } case PTRACE_SETREGS: { struct pt_regs __user *pregs = (struct pt_regs __user *) addr; struct pt_regs *cregs = child->thread.kregs; unsigned long psr, pc, npc, y; - int i; /* Must be careful, tracing process can only set certain * bits in the psr. */ - if (!access_ok(VERIFY_READ, pregs, sizeof(struct pt_regs))) { - pt_error_return(regs, EFAULT); - goto out_tsk; - } + ret = -EFAULT; + if (!access_ok(VERIFY_READ, pregs, sizeof(struct pt_regs))) + break; + __get_user(psr, (&pregs->psr)); __get_user(pc, (&pregs->pc)); __get_user(npc, (&pregs->npc)); @@ -647,10 +367,10 @@ asmlinkage void do_ptrace(struct pt_regs *regs) cregs->npc =npc; } cregs->y = y; - for(i = 1; i < 16; i++) - __get_user(cregs->u_regs[i], (&pregs->u_regs[i-1])); - pt_succ_return(regs, 0); - goto out_tsk; + for (i = 1; i < 16; i++) + __get_user(cregs->u_regs[i], &pregs->u_regs[i-1]); + ret = 0; + break; } case PTRACE_GETFPREGS: { @@ -666,26 +386,25 @@ asmlinkage void do_ptrace(struct pt_regs *regs) } fpq[16]; }; struct fps __user *fps = (struct fps __user *) addr; - int i; - if (!access_ok(VERIFY_WRITE, fps, sizeof(struct fps))) { - i = -EFAULT; - pt_error_return(regs, -i); - goto out_tsk; - } - for(i = 0; i < 32; i++) - __put_user(child->thread.float_regs[i], (&fps->regs[i])); + ret = -EFAULT; + if (!access_ok(VERIFY_WRITE, fps, sizeof(struct fps))) + break; + + for (i = 0; i < 32; i++) + __put_user(child->thread.float_regs[i], &fps->regs[i]); __put_user(child->thread.fsr, (&fps->fsr)); __put_user(child->thread.fpqdepth, (&fps->fpqd)); __put_user(0, (&fps->flags)); __put_user(0, (&fps->extra)); - for(i = 0; i < 16; i++) { + for (i = 0; i < 16; i++) { __put_user(child->thread.fpqueue[i].insn_addr, (&fps->fpq[i].insnaddr)); - __put_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn)); + __put_user(child->thread.fpqueue[i].insn, + &fps->fpq[i].insn); } - pt_succ_return(regs, 0); - goto out_tsk; + ret = 0; + break; } case PTRACE_SETFPREGS: { @@ -701,107 +420,53 @@ asmlinkage void do_ptrace(struct pt_regs *regs) } fpq[16]; }; struct fps __user *fps = (struct fps __user *) addr; - int i; - if (!access_ok(VERIFY_READ, fps, sizeof(struct fps))) { - i = -EFAULT; - pt_error_return(regs, -i); - goto out_tsk; - } - copy_from_user(&child->thread.float_regs[0], &fps->regs[0], (32 * sizeof(unsigned long))); + ret = -EFAULT; + if (!access_ok(VERIFY_READ, fps, sizeof(struct fps))) + break; + + copy_from_user(&child->thread.float_regs[0], &fps->regs[0], + (32 * sizeof(unsigned long))); __get_user(child->thread.fsr, (&fps->fsr)); __get_user(child->thread.fpqdepth, (&fps->fpqd)); - for(i = 0; i < 16; i++) { + for (i = 0; i < 16; i++) { __get_user(child->thread.fpqueue[i].insn_addr, (&fps->fpq[i].insnaddr)); - __get_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn)); + __get_user(child->thread.fpqueue[i].insn, + &fps->fpq[i].insn); } - pt_succ_return(regs, 0); - goto out_tsk; + ret = 0; + break; } case PTRACE_READTEXT: - case PTRACE_READDATA: { - int res = ptrace_readdata(child, addr, - (void __user *) addr2, data); + case PTRACE_READDATA: + ret = ptrace_readdata(child, addr, + (void __user *) addr2, data); - if (res == data) { - pt_succ_return(regs, 0); - goto out_tsk; - } - /* Partial read is an IO failure */ - if (res >= 0) - res = -EIO; - pt_error_return(regs, -res); - goto out_tsk; - } + if (ret == data) + ret = 0; + else if (ret >= 0) + ret = -EIO; + break; case PTRACE_WRITETEXT: - case PTRACE_WRITEDATA: { - int res = ptrace_writedata(child, (void __user *) addr2, - addr, data); + case PTRACE_WRITEDATA: + ret = ptrace_writedata(child, (void __user *) addr2, + addr, data); - if (res == data) { - pt_succ_return(regs, 0); - goto out_tsk; - } - /* Partial write is an IO failure */ - if (res >= 0) - res = -EIO; - pt_error_return(regs, -res); - goto out_tsk; + if (ret == data) + ret = 0; + else if (ret >= 0) + ret = -EIO; + break; + + default: + ret = ptrace_request(child, request, addr, data); + break; } - case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */ - addr = 1; - - case PTRACE_CONT: { /* restart after signal. */ - if (!valid_signal(data)) { - pt_error_return(regs, EIO); - goto out_tsk; - } - - if (request == PTRACE_SYSCALL) - set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - else - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - - child->exit_code = data; - wake_up_process(child); - pt_succ_return(regs, 0); - goto out_tsk; - } - -/* - * make the child exit. Best I can do is send it a sigkill. - * perhaps it should be put in the status that it wants to - * exit. - */ - case PTRACE_KILL: { - if (child->exit_state == EXIT_ZOMBIE) { /* already dead */ - pt_succ_return(regs, 0); - goto out_tsk; - } - wake_up_process(child); - child->exit_code = SIGKILL; - pt_succ_return(regs, 0); - goto out_tsk; - } - - default: { - int err = ptrace_request(child, request, addr, data); - if (err) - pt_error_return(regs, -err); - else - pt_succ_return(regs, 0); - goto out_tsk; - } - } -out_tsk: - if (child) - put_task_struct(child); -out: - unlock_kernel(); + return ret; } asmlinkage void syscall_trace(void) @@ -810,7 +475,6 @@ asmlinkage void syscall_trace(void) return; if (!(current->ptrace & PT_PTRACED)) return; - current->thread.flags ^= MAGIC_CONSTANT; ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); /* diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index ea257e828364..6be4d2d2904e 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -1477,10 +1477,6 @@ sys32_rt_sigreturn: add %o7, 1f-.-4, %o7 nop #endif -sys_ptrace: add %sp, PTREGS_OFF, %o0 - call do_ptrace - add %o7, 1f-.-4, %o7 - nop .align 32 1: ldx [%curptr + TI_FLAGS], %l5 andcc %l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0 diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index e881dbbd2c49..c831d426c4ac 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -36,56 +36,6 @@ #include #include -/* Returning from ptrace is a bit tricky because the syscall return - * low level code assumes any value returned which is negative and - * is a valid errno will mean setting the condition codes to indicate - * an error return. This doesn't work, so we have this hook. - */ -static inline void pt_error_return(struct pt_regs *regs, unsigned long error) -{ - regs->u_regs[UREG_I0] = error; - regs->tstate |= (TSTATE_ICARRY | TSTATE_XCARRY); - regs->tpc = regs->tnpc; - regs->tnpc += 4; -} - -static inline void pt_succ_return(struct pt_regs *regs, unsigned long value) -{ - regs->u_regs[UREG_I0] = value; - regs->tstate &= ~(TSTATE_ICARRY | TSTATE_XCARRY); - regs->tpc = regs->tnpc; - regs->tnpc += 4; -} - -static inline void -pt_succ_return_linux(struct pt_regs *regs, unsigned long value, void __user *addr) -{ - if (test_thread_flag(TIF_32BIT)) { - if (put_user(value, (unsigned int __user *) addr)) { - pt_error_return(regs, EFAULT); - return; - } - } else { - if (put_user(value, (long __user *) addr)) { - pt_error_return(regs, EFAULT); - return; - } - } - regs->u_regs[UREG_I0] = 0; - regs->tstate &= ~(TSTATE_ICARRY | TSTATE_XCARRY); - regs->tpc = regs->tnpc; - regs->tnpc += 4; -} - -static void -pt_os_succ_return (struct pt_regs *regs, unsigned long val, void __user *addr) -{ - if (current->personality == PER_SUNOS) - pt_succ_return (regs, val); - else - pt_succ_return_linux (regs, val, addr); -} - /* #define ALLOW_INIT_TRACING */ /* @@ -734,171 +684,113 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) return &user_sparc64_view; } -asmlinkage void do_ptrace(struct pt_regs *regs) +long arch_ptrace(struct task_struct *child, long request, long addr, long data) { - int request = regs->u_regs[UREG_I0]; - pid_t pid = regs->u_regs[UREG_I1]; - unsigned long addr = regs->u_regs[UREG_I2]; - unsigned long data = regs->u_regs[UREG_I3]; - unsigned long addr2 = regs->u_regs[UREG_I4]; - struct task_struct *child; - int ret; + long addr2 = task_pt_regs(current)->u_regs[UREG_I4]; + int i, ret; - if (test_thread_flag(TIF_32BIT)) { - addr &= 0xffffffffUL; - data &= 0xffffffffUL; +#if 1 + printk(KERN_INFO + "arch_ptrace: request[%ld] addr[%lx] data[%lx] addr2[%lx]\n", + request, addr, data, addr2); +#endif + if (test_thread_flag(TIF_32BIT)) addr2 &= 0xffffffffUL; - } - lock_kernel(); - if (request == PTRACE_TRACEME) { - ret = ptrace_traceme(); - if (ret < 0) - pt_error_return(regs, -ret); - else - pt_succ_return(regs, 0); - goto out; - } - - child = ptrace_get_task_struct(pid); - if (IS_ERR(child)) { - ret = PTR_ERR(child); - pt_error_return(regs, -ret); - goto out; - } - - if (request == PTRACE_ATTACH) { - if (ptrace_attach(child)) { - pt_error_return(regs, EPERM); - goto out_tsk; - } - pt_succ_return(regs, 0); - goto out_tsk; - } - - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret < 0) { - pt_error_return(regs, -ret); - goto out_tsk; - } - - if (!(test_thread_flag(TIF_32BIT)) && - ((request == PTRACE_READDATA64) || - (request == PTRACE_WRITEDATA64) || - (request == PTRACE_READTEXT64) || - (request == PTRACE_WRITETEXT64) || - (request == PTRACE_PEEKTEXT64) || - (request == PTRACE_POKETEXT64) || - (request == PTRACE_PEEKDATA64) || - (request == PTRACE_POKEDATA64))) { - addr = regs->u_regs[UREG_G2]; - addr2 = regs->u_regs[UREG_G3]; - request -= 30; /* wheee... */ - } switch(request) { case PTRACE_PEEKUSR: - if (addr != 0) - pt_error_return(regs, EIO); - else - pt_succ_return(regs, 0); - goto out_tsk; + ret = (addr != 0) ? -EIO : 0; + break; case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { unsigned long tmp64; unsigned int tmp32; - int res, copied; + int copied; - res = -EIO; + ret = -EIO; if (test_thread_flag(TIF_32BIT)) { copied = access_process_vm(child, addr, &tmp32, sizeof(tmp32), 0); - tmp64 = (unsigned long) tmp32; if (copied == sizeof(tmp32)) - res = 0; + ret = put_user(tmp32, + (unsigned int __user *) data); } else { copied = access_process_vm(child, addr, &tmp64, sizeof(tmp64), 0); if (copied == sizeof(tmp64)) - res = 0; + ret = put_user(tmp64, + (unsigned long __user *) data); } - if (res < 0) - pt_error_return(regs, -res); - else - pt_os_succ_return(regs, tmp64, (void __user *) data); - goto out_tsk; + break; } case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: { unsigned long tmp64; unsigned int tmp32; - int copied, res = -EIO; + int copied; + ret = -EIO; if (test_thread_flag(TIF_32BIT)) { tmp32 = data; copied = access_process_vm(child, addr, &tmp32, sizeof(tmp32), 1); if (copied == sizeof(tmp32)) - res = 0; + ret = 0; } else { tmp64 = data; copied = access_process_vm(child, addr, &tmp64, sizeof(tmp64), 1); if (copied == sizeof(tmp64)) - res = 0; + ret = 0; } - if (res < 0) - pt_error_return(regs, -res); - else - pt_succ_return(regs, res); - goto out_tsk; + break; } case PTRACE_GETREGS: { struct pt_regs32 __user *pregs = (struct pt_regs32 __user *) addr; struct pt_regs *cregs = task_pt_regs(child); - int rval; + ret = -EFAULT; if (__put_user(tstate_to_psr(cregs->tstate), (&pregs->psr)) || __put_user(cregs->tpc, (&pregs->pc)) || __put_user(cregs->tnpc, (&pregs->npc)) || - __put_user(cregs->y, (&pregs->y))) { - pt_error_return(regs, EFAULT); - goto out_tsk; + __put_user(cregs->y, (&pregs->y))) + break; + for (i = 1; i < 16; i++) { + if (__put_user(cregs->u_regs[i], + (&pregs->u_regs[i - 1]))) + break; } - for (rval = 1; rval < 16; rval++) - if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) { - pt_error_return(regs, EFAULT); - goto out_tsk; - } - pt_succ_return(regs, 0); - goto out_tsk; + if (i == 16) + ret = 0; + break; } case PTRACE_GETREGS64: { struct pt_regs __user *pregs = (struct pt_regs __user *) addr; struct pt_regs *cregs = task_pt_regs(child); unsigned long tpc = cregs->tpc; - int rval; if ((task_thread_info(child)->flags & _TIF_32BIT) != 0) tpc &= 0xffffffff; + + ret = -EFAULT; if (__put_user(cregs->tstate, (&pregs->tstate)) || __put_user(tpc, (&pregs->tpc)) || __put_user(cregs->tnpc, (&pregs->tnpc)) || - __put_user(cregs->y, (&pregs->y))) { - pt_error_return(regs, EFAULT); - goto out_tsk; + __put_user(cregs->y, (&pregs->y))) + break; + for (i = 1; i < 16; i++) { + if (__put_user(cregs->u_regs[i], + (&pregs->u_regs[i - 1]))) + break; } - for (rval = 1; rval < 16; rval++) - if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) { - pt_error_return(regs, EFAULT); - goto out_tsk; - } - pt_succ_return(regs, 0); - goto out_tsk; + if (i == 16) + ret = 0; + break; } case PTRACE_SETREGS: { @@ -906,18 +798,16 @@ asmlinkage void do_ptrace(struct pt_regs *regs) (struct pt_regs32 __user *) addr; struct pt_regs *cregs = task_pt_regs(child); unsigned int psr, pc, npc, y; - int i; /* Must be careful, tracing process can only set certain * bits in the psr. */ + ret = -EFAULT; if (__get_user(psr, (&pregs->psr)) || __get_user(pc, (&pregs->pc)) || __get_user(npc, (&pregs->npc)) || - __get_user(y, (&pregs->y))) { - pt_error_return(regs, EFAULT); - goto out_tsk; - } + __get_user(y, (&pregs->y))) + break; cregs->tstate &= ~(TSTATE_ICC); cregs->tstate |= psr_to_tstate_icc(psr); if (!((pc | npc) & 3)) { @@ -926,31 +816,28 @@ asmlinkage void do_ptrace(struct pt_regs *regs) } cregs->y = y; for (i = 1; i < 16; i++) { - if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) { - pt_error_return(regs, EFAULT); - goto out_tsk; - } + if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) + break; } - pt_succ_return(regs, 0); - goto out_tsk; + if (i == 16) + ret = 0; + break; } case PTRACE_SETREGS64: { struct pt_regs __user *pregs = (struct pt_regs __user *) addr; struct pt_regs *cregs = task_pt_regs(child); unsigned long tstate, tpc, tnpc, y; - int i; /* Must be careful, tracing process can only set certain * bits in the psr. */ + ret = -EFAULT; if (__get_user(tstate, (&pregs->tstate)) || __get_user(tpc, (&pregs->tpc)) || __get_user(tnpc, (&pregs->tnpc)) || - __get_user(y, (&pregs->y))) { - pt_error_return(regs, EFAULT); - goto out_tsk; - } + __get_user(y, (&pregs->y))) + break; if ((task_thread_info(child)->flags & _TIF_32BIT) != 0) { tpc &= 0xffffffff; tnpc &= 0xffffffff; @@ -964,13 +851,12 @@ asmlinkage void do_ptrace(struct pt_regs *regs) } cregs->y = y; for (i = 1; i < 16; i++) { - if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) { - pt_error_return(regs, EFAULT); - goto out_tsk; - } + if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) + break; } - pt_succ_return(regs, 0); - goto out_tsk; + if (i == 16) + ret = 0; + break; } case PTRACE_GETFPREGS: { @@ -988,18 +874,18 @@ asmlinkage void do_ptrace(struct pt_regs *regs) struct fps __user *fps = (struct fps __user *) addr; unsigned long *fpregs = task_thread_info(child)->fpregs; + ret = -EFAULT; if (copy_to_user(&fps->regs[0], fpregs, (32 * sizeof(unsigned int))) || __put_user(task_thread_info(child)->xfsr[0], (&fps->fsr)) || __put_user(0, (&fps->fpqd)) || __put_user(0, (&fps->flags)) || __put_user(0, (&fps->extra)) || - clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) { - pt_error_return(regs, EFAULT); - goto out_tsk; - } - pt_succ_return(regs, 0); - goto out_tsk; + clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) + break; + + ret = 0; + break; } case PTRACE_GETFPREGS64: { @@ -1010,14 +896,14 @@ asmlinkage void do_ptrace(struct pt_regs *regs) struct fps __user *fps = (struct fps __user *) addr; unsigned long *fpregs = task_thread_info(child)->fpregs; + ret = -EFAULT; if (copy_to_user(&fps->regs[0], fpregs, (64 * sizeof(unsigned int))) || - __put_user(task_thread_info(child)->xfsr[0], (&fps->fsr))) { - pt_error_return(regs, EFAULT); - goto out_tsk; - } - pt_succ_return(regs, 0); - goto out_tsk; + __put_user(task_thread_info(child)->xfsr[0], (&fps->fsr))) + break; + + ret = 0; + break; } case PTRACE_SETFPREGS: { @@ -1036,19 +922,19 @@ asmlinkage void do_ptrace(struct pt_regs *regs) unsigned long *fpregs = task_thread_info(child)->fpregs; unsigned fsr; + ret = -EFAULT; if (copy_from_user(fpregs, &fps->regs[0], (32 * sizeof(unsigned int))) || - __get_user(fsr, (&fps->fsr))) { - pt_error_return(regs, EFAULT); - goto out_tsk; - } + __get_user(fsr, (&fps->fsr))) + break; + task_thread_info(child)->xfsr[0] &= 0xffffffff00000000UL; task_thread_info(child)->xfsr[0] |= fsr; if (!(task_thread_info(child)->fpsaved[0] & FPRS_FEF)) task_thread_info(child)->gsr[0] = 0; task_thread_info(child)->fpsaved[0] |= (FPRS_FEF | FPRS_DL); - pt_succ_return(regs, 0); - goto out_tsk; + ret = 0; + break; } case PTRACE_SETFPREGS64: { @@ -1059,113 +945,56 @@ asmlinkage void do_ptrace(struct pt_regs *regs) struct fps __user *fps = (struct fps __user *) addr; unsigned long *fpregs = task_thread_info(child)->fpregs; + ret = -EFAULT; if (copy_from_user(fpregs, &fps->regs[0], (64 * sizeof(unsigned int))) || - __get_user(task_thread_info(child)->xfsr[0], (&fps->fsr))) { - pt_error_return(regs, EFAULT); - goto out_tsk; - } + __get_user(task_thread_info(child)->xfsr[0], (&fps->fsr))) + break; + if (!(task_thread_info(child)->fpsaved[0] & FPRS_FEF)) task_thread_info(child)->gsr[0] = 0; - task_thread_info(child)->fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU); - pt_succ_return(regs, 0); - goto out_tsk; - } - - case PTRACE_READTEXT: - case PTRACE_READDATA: { - int res = ptrace_readdata(child, addr, - (char __user *)addr2, data); - if (res == data) { - pt_succ_return(regs, 0); - goto out_tsk; - } - if (res >= 0) - res = -EIO; - pt_error_return(regs, -res); - goto out_tsk; - } - - case PTRACE_WRITETEXT: - case PTRACE_WRITEDATA: { - int res = ptrace_writedata(child, (char __user *) addr2, - addr, data); - if (res == data) { - pt_succ_return(regs, 0); - goto out_tsk; - } - if (res >= 0) - res = -EIO; - pt_error_return(regs, -res); - goto out_tsk; - } - case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */ - addr = 1; - - case PTRACE_CONT: { /* restart after signal. */ - if (!valid_signal(data)) { - pt_error_return(regs, EIO); - goto out_tsk; - } - - if (request == PTRACE_SYSCALL) { - set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - } else { - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - } - - child->exit_code = data; - wake_up_process(child); - pt_succ_return(regs, 0); - goto out_tsk; - } - -/* - * make the child exit. Best I can do is send it a sigkill. - * perhaps it should be put in the status that it wants to - * exit. - */ - case PTRACE_KILL: { - if (child->exit_state == EXIT_ZOMBIE) { /* already dead */ - pt_succ_return(regs, 0); - goto out_tsk; - } - child->exit_code = SIGKILL; - wake_up_process(child); - pt_succ_return(regs, 0); - goto out_tsk; - } - - case PTRACE_GETEVENTMSG: { - int err; - - if (test_thread_flag(TIF_32BIT)) - err = put_user(child->ptrace_message, - (unsigned int __user *) data); - else - err = put_user(child->ptrace_message, - (unsigned long __user *) data); - if (err) - pt_error_return(regs, -err); - else - pt_succ_return(regs, 0); + task_thread_info(child)->fpsaved[0] |= + (FPRS_FEF | FPRS_DL | FPRS_DU); + ret = 0; break; } - default: { - int err = ptrace_request(child, request, addr, data); - if (err) - pt_error_return(regs, -err); + case PTRACE_READTEXT: + case PTRACE_READDATA: + ret = ptrace_readdata(child, addr, + (char __user *)addr2, data); + if (ret == data) + ret = 0; + else if (ret >= 0) + ret = -EIO; + break; + + case PTRACE_WRITETEXT: + case PTRACE_WRITEDATA: + ret = ptrace_writedata(child, (char __user *) addr2, + addr, data); + if (ret == data) + ret = 0; + else if (ret >= 0) + ret = -EIO; + break; + + case PTRACE_GETEVENTMSG: { + if (test_thread_flag(TIF_32BIT)) + ret = put_user(child->ptrace_message, + (unsigned int __user *) data); else - pt_succ_return(regs, 0); - goto out_tsk; + ret = put_user(child->ptrace_message, + (unsigned long __user *) data); + break; } + + default: + ret = ptrace_request(child, request, addr, data); + break; } -out_tsk: - if (child) - put_task_struct(child); -out: - unlock_kernel(); + + return ret; } asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p) diff --git a/include/asm-sparc/ptrace.h b/include/asm-sparc/ptrace.h index a84345ba8bee..8201a7b29d49 100644 --- a/include/asm-sparc/ptrace.h +++ b/include/asm-sparc/ptrace.h @@ -61,8 +61,6 @@ struct sparc_stackf { #ifdef __KERNEL__ -#define __ARCH_SYS_PTRACE 1 - #define user_mode(regs) (!((regs)->psr & PSR_PS)) #define instruction_pointer(regs) ((regs)->pc) unsigned long profile_pc(struct pt_regs *); @@ -162,7 +160,4 @@ extern void show_regs(struct pt_regs *); #define PTRACE_GETFPAREGS 20 #define PTRACE_SETFPAREGS 21 -#define PTRACE_GETUCODE 29 /* stupid bsd-ism */ - - #endif /* !(_SPARC_PTRACE_H) */ diff --git a/include/asm-sparc64/ptrace.h b/include/asm-sparc64/ptrace.h index 2ba989b3056e..734a767f0a4e 100644 --- a/include/asm-sparc64/ptrace.h +++ b/include/asm-sparc64/ptrace.h @@ -95,8 +95,6 @@ struct sparc_trapf { #ifdef __KERNEL__ -#define __ARCH_SYS_PTRACE 1 - #define force_successful_syscall_return() \ do { current_thread_info()->syscall_noerror = 1; \ } while (0) @@ -282,18 +280,4 @@ extern void show_regs(struct pt_regs *); #define PTRACE_GETFPREGS64 25 #define PTRACE_SETFPREGS64 26 -#define PTRACE_GETUCODE 29 /* stupid bsd-ism */ - -/* These are for 32-bit processes debugging 64-bit ones. - * Here addr and addr2 are passed in %g2 and %g3 respectively. - */ -#define PTRACE_PEEKTEXT64 (30 + PTRACE_PEEKTEXT) -#define PTRACE_POKETEXT64 (30 + PTRACE_POKETEXT) -#define PTRACE_PEEKDATA64 (30 + PTRACE_PEEKDATA) -#define PTRACE_POKEDATA64 (30 + PTRACE_POKEDATA) -#define PTRACE_READDATA64 (30 + PTRACE_READDATA) -#define PTRACE_WRITEDATA64 (30 + PTRACE_WRITEDATA) -#define PTRACE_READTEXT64 (30 + PTRACE_READTEXT) -#define PTRACE_WRITETEXT64 (30 + PTRACE_WRITETEXT) - #endif /* !(_SPARC64_PTRACE_H) */ From e72d71c405ef581595ec64091be9f2fda0a726a9 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 7 Feb 2008 03:30:21 -0800 Subject: [PATCH 07/11] [SPARC64]: Remove unintentional ptrace debugging messages. Signed-off-by: David S. Miller --- arch/sparc64/kernel/ptrace.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index c831d426c4ac..7e28ee36419e 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -689,11 +689,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) long addr2 = task_pt_regs(current)->u_regs[UREG_I4]; int i, ret; -#if 1 - printk(KERN_INFO - "arch_ptrace: request[%ld] addr[%lx] data[%lx] addr2[%lx]\n", - request, addr, data, addr2); -#endif if (test_thread_flag(TIF_32BIT)) addr2 &= 0xffffffffUL; From 3389742f3c346d9ef5fb46e7baa04972bdd6d151 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 7 Feb 2008 04:19:34 -0800 Subject: [PATCH 08/11] [SPARC64]: Use regsets for ELF core dumping. Signed-off-by: David S. Miller --- arch/sparc64/kernel/binfmt_elf32.c | 31 ++++-------------------------- include/asm-sparc64/elf.h | 30 +++++------------------------ 2 files changed, 9 insertions(+), 52 deletions(-) diff --git a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c index 1587a29a4b0e..d141300e76b7 100644 --- a/arch/sparc64/kernel/binfmt_elf32.c +++ b/arch/sparc64/kernel/binfmt_elf32.c @@ -1,7 +1,7 @@ /* * binfmt_elf32.c: Support 32-bit Sparc ELF binaries on Ultra. * - * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@davemloft.net) + * Copyright (C) 1995, 1996, 1997, 1998, 2008 David S. Miller (davem@davemloft.net) * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz) */ @@ -9,13 +9,6 @@ #define ELF_CLASS ELFCLASS32 #define ELF_DATA ELFDATA2MSB; -/* For the most part we present code dumps in the format - * Solaris does. - */ -typedef unsigned int elf_greg_t; -#define ELF_NGREG 38 -typedef elf_greg_t elf_gregset_t[ELF_NGREG]; - /* Format is: * G0 --> G7 * O0 --> O7 @@ -23,25 +16,9 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG]; * I0 --> I7 * PSR, PC, nPC, Y, WIM, TBR */ -#include -#define ELF_CORE_COPY_REGS(__elf_regs, __pt_regs) \ -do { unsigned int *dest = &(__elf_regs[0]); \ - struct pt_regs *src = (__pt_regs); \ - unsigned int __user *sp; \ - int i; \ - for(i = 0; i < 16; i++) \ - dest[i] = (unsigned int) src->u_regs[i];\ - /* Don't try this at home kids... */ \ - sp = (unsigned int __user *) (src->u_regs[14] & \ - 0x00000000fffffffc); \ - for(i = 0; i < 16; i++) \ - __get_user(dest[i+16], &sp[i]); \ - dest[32] = tstate_to_psr(src->tstate); \ - dest[33] = (unsigned int) src->tpc; \ - dest[34] = (unsigned int) src->tnpc; \ - dest[35] = src->y; \ - dest[36] = dest[37] = 0; /* XXX */ \ -} while(0); +typedef unsigned int elf_greg_t; +#define ELF_NGREG 38 +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; typedef struct { union { diff --git a/include/asm-sparc64/elf.h b/include/asm-sparc64/elf.h index 8653e8665009..217d768cf7dd 100644 --- a/include/asm-sparc64/elf.h +++ b/include/asm-sparc64/elf.h @@ -72,6 +72,8 @@ #define HWCAP_SPARC_BLKINIT 64 #define HWCAP_SPARC_N2 128 +#define CORE_DUMP_USE_REGSET + /* * These are used to set parameters in the core dumps. */ @@ -80,10 +82,6 @@ #define ELF_CLASS ELFCLASS64 #define ELF_DATA ELFDATA2MSB -typedef unsigned long elf_greg_t; - -#define ELF_NGREG 36 -typedef elf_greg_t elf_gregset_t[ELF_NGREG]; /* Format of 64-bit elf_gregset_t is: * G0 --> G7 * O0 --> O7 @@ -94,24 +92,9 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG]; * TNPC * Y */ -#define ELF_CORE_COPY_REGS(__elf_regs, __pt_regs) \ -do { unsigned long *dest = &(__elf_regs[0]); \ - struct pt_regs *src = (__pt_regs); \ - unsigned long __user *sp; \ - int i; \ - for(i = 0; i < 16; i++) \ - dest[i] = src->u_regs[i]; \ - /* Don't try this at home kids... */ \ - sp = (unsigned long __user *) \ - ((src->u_regs[14] + STACK_BIAS) \ - & 0xfffffffffffffff8UL); \ - for(i = 0; i < 16; i++) \ - __get_user(dest[i+16], &sp[i]); \ - dest[32] = src->tstate; \ - dest[33] = src->tpc; \ - dest[34] = src->tnpc; \ - dest[35] = src->y; \ -} while (0); +typedef unsigned long elf_greg_t; +#define ELF_NGREG 36 +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; typedef struct { unsigned long pr_regs[32]; @@ -121,9 +104,6 @@ typedef struct { } elf_fpregset_t; #endif -#define ELF_CORE_COPY_TASK_REGS(__tsk, __elf_regs) \ - ({ ELF_CORE_COPY_REGS((*(__elf_regs)), task_pt_regs(__tsk)); 1; }) - /* * This is used to ensure we don't load something for the wrong architecture. */ From 5a4924d7be5df430132e109d3d2f26be610b4707 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 7 Feb 2008 04:36:02 -0800 Subject: [PATCH 09/11] [SPARC32]: Use regsets for ELF core dumping. Signed-off-by: David S. Miller --- include/asm-sparc/elf.h | 38 ++++++++------------------------------ 1 file changed, 8 insertions(+), 30 deletions(-) diff --git a/include/asm-sparc/elf.h b/include/asm-sparc/elf.h index aaf6ef40ee2f..2f8ff3fa0957 100644 --- a/include/asm-sparc/elf.h +++ b/include/asm-sparc/elf.h @@ -65,8 +65,14 @@ #define HWCAP_SPARC_V9 16 #define HWCAP_SPARC_ULTRA3 32 -/* For the most part we present code dumps in the format - * Solaris does. +#define CORE_DUMP_USE_REGSET + +/* Format is: + * G0 --> G7 + * O0 --> O7 + * L0 --> L7 + * I0 --> I7 + * PSR, PC, nPC, Y, WIM, TBR */ typedef unsigned long elf_greg_t; #define ELF_NGREG 38 @@ -87,34 +93,6 @@ typedef struct { #ifdef __KERNEL__ #include -#include - -/* Format is: - * G0 --> G7 - * O0 --> O7 - * L0 --> L7 - * I0 --> I7 - * PSR, PC, nPC, Y, WIM, TBR - */ -#define ELF_CORE_COPY_REGS(__elf_regs, __pt_regs) \ -do { unsigned long *dest = &(__elf_regs[0]); \ - struct pt_regs *src = (__pt_regs); \ - unsigned long __user *sp; \ - memcpy(&dest[0], &src->u_regs[0], \ - sizeof(unsigned long) * 16); \ - /* Don't try this at home kids... */ \ - sp = (unsigned long __user *) src->u_regs[14]; \ - copy_from_user(&dest[16], sp, \ - sizeof(unsigned long) * 16); \ - dest[32] = src->psr; \ - dest[33] = src->pc; \ - dest[34] = src->npc; \ - dest[35] = src->y; \ - dest[36] = dest[37] = 0; /* XXX */ \ -} while(0); /* Janitors: Don't touch this semicolon. */ - -#define ELF_CORE_COPY_TASK_REGS(__tsk, __elf_regs) \ - ({ ELF_CORE_COPY_REGS((*(__elf_regs)), (__tsk)->thread.kregs); 1; }) /* * This is used to ensure we don't load something for the wrong architecture. From 9473272af395e1f76cf917ddd20abd2326fc58f1 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 7 Feb 2008 05:06:12 -0800 Subject: [PATCH 10/11] [SPARC64]: Use regsets in arch_ptrace(). Signed-off-by: David S. Miller --- arch/sparc64/kernel/ptrace.c | 205 +++++++++++++---------------------- 1 file changed, 75 insertions(+), 130 deletions(-) diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index 7e28ee36419e..51f012410f9d 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -687,11 +687,14 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) long arch_ptrace(struct task_struct *child, long request, long addr, long data) { long addr2 = task_pt_regs(current)->u_regs[UREG_I4]; - int i, ret; + const struct user_regset_view *view; + int ret; if (test_thread_flag(TIF_32BIT)) addr2 &= 0xffffffffUL; + view = task_user_regset_view(child); + switch(request) { case PTRACE_PEEKUSR: ret = (addr != 0) ? -EIO : 0; @@ -746,111 +749,66 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) case PTRACE_GETREGS: { struct pt_regs32 __user *pregs = (struct pt_regs32 __user *) addr; - struct pt_regs *cregs = task_pt_regs(child); - ret = -EFAULT; - if (__put_user(tstate_to_psr(cregs->tstate), (&pregs->psr)) || - __put_user(cregs->tpc, (&pregs->pc)) || - __put_user(cregs->tnpc, (&pregs->npc)) || - __put_user(cregs->y, (&pregs->y))) - break; - for (i = 1; i < 16; i++) { - if (__put_user(cregs->u_regs[i], - (&pregs->u_regs[i - 1]))) - break; - } - if (i == 16) - ret = 0; + ret = copy_regset_to_user(child, view, REGSET_GENERAL, + 32 * sizeof(u32), + 4 * sizeof(u32), + &pregs->psr); + if (!ret) + ret = copy_regset_to_user(child, view, REGSET_GENERAL, + 1 * sizeof(u32), + 15 * sizeof(u32), + &pregs->u_regs[0]); break; } case PTRACE_GETREGS64: { struct pt_regs __user *pregs = (struct pt_regs __user *) addr; - struct pt_regs *cregs = task_pt_regs(child); - unsigned long tpc = cregs->tpc; - if ((task_thread_info(child)->flags & _TIF_32BIT) != 0) - tpc &= 0xffffffff; - - ret = -EFAULT; - if (__put_user(cregs->tstate, (&pregs->tstate)) || - __put_user(tpc, (&pregs->tpc)) || - __put_user(cregs->tnpc, (&pregs->tnpc)) || - __put_user(cregs->y, (&pregs->y))) - break; - for (i = 1; i < 16; i++) { - if (__put_user(cregs->u_regs[i], - (&pregs->u_regs[i - 1]))) - break; + ret = copy_regset_to_user(child, view, REGSET_GENERAL, + 1 * sizeof(u64), + 15 * sizeof(u64), + &pregs->u_regs[0]); + if (!ret) { + /* XXX doesn't handle 'y' register correctly XXX */ + ret = copy_regset_to_user(child, view, REGSET_GENERAL, + 32 * sizeof(u64), + 4 * sizeof(u64), + &pregs->tstate); } - if (i == 16) - ret = 0; break; } case PTRACE_SETREGS: { struct pt_regs32 __user *pregs = (struct pt_regs32 __user *) addr; - struct pt_regs *cregs = task_pt_regs(child); - unsigned int psr, pc, npc, y; - /* Must be careful, tracing process can only set certain - * bits in the psr. - */ - ret = -EFAULT; - if (__get_user(psr, (&pregs->psr)) || - __get_user(pc, (&pregs->pc)) || - __get_user(npc, (&pregs->npc)) || - __get_user(y, (&pregs->y))) - break; - cregs->tstate &= ~(TSTATE_ICC); - cregs->tstate |= psr_to_tstate_icc(psr); - if (!((pc | npc) & 3)) { - cregs->tpc = pc; - cregs->tnpc = npc; - } - cregs->y = y; - for (i = 1; i < 16; i++) { - if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) - break; - } - if (i == 16) - ret = 0; + ret = copy_regset_from_user(child, view, REGSET_GENERAL, + 32 * sizeof(u32), + 4 * sizeof(u32), + &pregs->psr); + if (!ret) + ret = copy_regset_from_user(child, view, REGSET_GENERAL, + 1 * sizeof(u32), + 15 * sizeof(u32), + &pregs->u_regs[0]); break; } case PTRACE_SETREGS64: { struct pt_regs __user *pregs = (struct pt_regs __user *) addr; - struct pt_regs *cregs = task_pt_regs(child); - unsigned long tstate, tpc, tnpc, y; - /* Must be careful, tracing process can only set certain - * bits in the psr. - */ - ret = -EFAULT; - if (__get_user(tstate, (&pregs->tstate)) || - __get_user(tpc, (&pregs->tpc)) || - __get_user(tnpc, (&pregs->tnpc)) || - __get_user(y, (&pregs->y))) - break; - if ((task_thread_info(child)->flags & _TIF_32BIT) != 0) { - tpc &= 0xffffffff; - tnpc &= 0xffffffff; + ret = copy_regset_from_user(child, view, REGSET_GENERAL, + 1 * sizeof(u64), + 15 * sizeof(u64), + &pregs->u_regs[0]); + if (!ret) { + /* XXX doesn't handle 'y' register correctly XXX */ + ret = copy_regset_from_user(child, view, REGSET_GENERAL, + 32 * sizeof(u64), + 4 * sizeof(u64), + &pregs->tstate); } - tstate &= (TSTATE_ICC | TSTATE_XCC); - cregs->tstate &= ~(TSTATE_ICC | TSTATE_XCC); - cregs->tstate |= tstate; - if (!((tpc | tnpc) & 3)) { - cregs->tpc = tpc; - cregs->tnpc = tnpc; - } - cregs->y = y; - for (i = 1; i < 16; i++) { - if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) - break; - } - if (i == 16) - ret = 0; break; } @@ -867,19 +825,23 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) } fpq[16]; }; struct fps __user *fps = (struct fps __user *) addr; - unsigned long *fpregs = task_thread_info(child)->fpregs; - ret = -EFAULT; - if (copy_to_user(&fps->regs[0], fpregs, - (32 * sizeof(unsigned int))) || - __put_user(task_thread_info(child)->xfsr[0], (&fps->fsr)) || - __put_user(0, (&fps->fpqd)) || - __put_user(0, (&fps->flags)) || - __put_user(0, (&fps->extra)) || - clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) - break; - - ret = 0; + 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->flags) || + __put_user(0, &fps->extra) || + __put_user(0, &fps->fpqd) || + clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) + ret = -EFAULT; + } break; } @@ -889,15 +851,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) unsigned long fsr; }; struct fps __user *fps = (struct fps __user *) addr; - unsigned long *fpregs = task_thread_info(child)->fpregs; - ret = -EFAULT; - if (copy_to_user(&fps->regs[0], fpregs, - (64 * sizeof(unsigned int))) || - __put_user(task_thread_info(child)->xfsr[0], (&fps->fsr))) - break; - - ret = 0; + ret = copy_regset_to_user(child, view, REGSET_FP, + 0 * sizeof(u64), + 33 * sizeof(u64), + fps); break; } @@ -914,21 +872,16 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) } fpq[16]; }; struct fps __user *fps = (struct fps __user *) addr; - unsigned long *fpregs = task_thread_info(child)->fpregs; - unsigned fsr; - ret = -EFAULT; - if (copy_from_user(fpregs, &fps->regs[0], - (32 * sizeof(unsigned int))) || - __get_user(fsr, (&fps->fsr))) - break; - - task_thread_info(child)->xfsr[0] &= 0xffffffff00000000UL; - task_thread_info(child)->xfsr[0] |= fsr; - if (!(task_thread_info(child)->fpsaved[0] & FPRS_FEF)) - task_thread_info(child)->gsr[0] = 0; - task_thread_info(child)->fpsaved[0] |= (FPRS_FEF | FPRS_DL); - ret = 0; + ret = copy_regset_from_user(child, view, REGSET_FP, + 0 * sizeof(u32), + 32 * sizeof(u32), + &fps->regs[0]); + if (!ret) + ret = copy_regset_from_user(child, view, REGSET_FP, + 33 * sizeof(u32), + 1 * sizeof(u32), + &fps->fsr); break; } @@ -938,19 +891,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) unsigned long fsr; }; struct fps __user *fps = (struct fps __user *) addr; - unsigned long *fpregs = task_thread_info(child)->fpregs; - ret = -EFAULT; - if (copy_from_user(fpregs, &fps->regs[0], - (64 * sizeof(unsigned int))) || - __get_user(task_thread_info(child)->xfsr[0], (&fps->fsr))) - break; - - if (!(task_thread_info(child)->fpsaved[0] & FPRS_FEF)) - task_thread_info(child)->gsr[0] = 0; - task_thread_info(child)->fpsaved[0] |= - (FPRS_FEF | FPRS_DL | FPRS_DU); - ret = 0; + ret = copy_regset_to_user(child, view, REGSET_FP, + 0 * sizeof(u64), + 33 * sizeof(u64), + fps); break; } From d256eb8db60e36fc5dd0a27ce8a64f65df31f7b5 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 7 Feb 2008 05:06:51 -0800 Subject: [PATCH 11/11] [SPARC32]: Use regsets in arch_ptrace(). Signed-off-by: David S. Miller --- arch/sparc/kernel/ptrace.c | 113 +++++++++++++++---------------------- 1 file changed, 46 insertions(+), 67 deletions(-) diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c index 1c0d5363f720..5b54f11f4e59 100644 --- a/arch/sparc/kernel/ptrace.c +++ b/arch/sparc/kernel/ptrace.c @@ -322,54 +322,39 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) long arch_ptrace(struct task_struct *child, long request, long addr, long data) { unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4]; - int i, ret; + const struct user_regset_view *view; + int ret; + + view = task_user_regset_view(child); switch(request) { case PTRACE_GETREGS: { struct pt_regs __user *pregs = (struct pt_regs __user *) addr; - struct pt_regs *cregs = child->thread.kregs; - ret = -EFAULT; - if (!access_ok(VERIFY_WRITE, pregs, sizeof(struct pt_regs))) - break; - - __put_user(cregs->psr, (&pregs->psr)); - __put_user(cregs->pc, (&pregs->pc)); - __put_user(cregs->npc, (&pregs->npc)); - __put_user(cregs->y, (&pregs->y)); - for (i = 1; i < 16; i++) - __put_user(cregs->u_regs[i], &pregs->u_regs[i - 1]); - ret = 0; + 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]); break; } case PTRACE_SETREGS: { struct pt_regs __user *pregs = (struct pt_regs __user *) addr; - struct pt_regs *cregs = child->thread.kregs; - unsigned long psr, pc, npc, y; - /* Must be careful, tracing process can only set certain - * bits in the psr. - */ - ret = -EFAULT; - if (!access_ok(VERIFY_READ, pregs, sizeof(struct pt_regs))) - break; - - __get_user(psr, (&pregs->psr)); - __get_user(pc, (&pregs->pc)); - __get_user(npc, (&pregs->npc)); - __get_user(y, (&pregs->y)); - psr &= PSR_ICC; - cregs->psr &= ~PSR_ICC; - cregs->psr |= psr; - if (!((pc | npc) & 3)) { - cregs->pc = pc; - cregs->npc =npc; - } - cregs->y = y; - for (i = 1; i < 16; i++) - __get_user(cregs->u_regs[i], &pregs->u_regs[i-1]); - ret = 0; + ret = copy_regset_from_user(child, view, REGSET_GENERAL, + 32 * sizeof(u32), + 4 * sizeof(u32), + &pregs->psr); + if (!ret) + copy_regset_from_user(child, view, REGSET_GENERAL, + 1 * sizeof(u32), + 15 * sizeof(u32), + &pregs->u_regs[0]); break; } @@ -387,23 +372,23 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) }; struct fps __user *fps = (struct fps __user *) addr; - ret = -EFAULT; - if (!access_ok(VERIFY_WRITE, fps, sizeof(struct fps))) - break; + 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); - for (i = 0; i < 32; i++) - __put_user(child->thread.float_regs[i], &fps->regs[i]); - __put_user(child->thread.fsr, (&fps->fsr)); - __put_user(child->thread.fpqdepth, (&fps->fpqd)); - __put_user(0, (&fps->flags)); - __put_user(0, (&fps->extra)); - for (i = 0; i < 16; i++) { - __put_user(child->thread.fpqueue[i].insn_addr, - (&fps->fpq[i].insnaddr)); - __put_user(child->thread.fpqueue[i].insn, - &fps->fpq[i].insn); + 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 = 0; break; } @@ -421,21 +406,15 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) }; struct fps __user *fps = (struct fps __user *) addr; - ret = -EFAULT; - if (!access_ok(VERIFY_READ, fps, sizeof(struct fps))) - break; - - copy_from_user(&child->thread.float_regs[0], &fps->regs[0], - (32 * sizeof(unsigned long))); - __get_user(child->thread.fsr, (&fps->fsr)); - __get_user(child->thread.fpqdepth, (&fps->fpqd)); - for (i = 0; i < 16; i++) { - __get_user(child->thread.fpqueue[i].insn_addr, - (&fps->fpq[i].insnaddr)); - __get_user(child->thread.fpqueue[i].insn, - &fps->fpq[i].insn); - } - ret = 0; + ret = copy_regset_from_user(child, view, REGSET_FP, + 0 * sizeof(u32), + 32 * sizeof(u32), + &fps->regs[0]); + if (!ret) + ret = copy_regset_from_user(child, view, REGSET_FP, + 33 * sizeof(u32), + 1 * sizeof(u32), + &fps->fsr); break; }