diff options
| author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-07 13:21:26 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-07 13:21:26 -0500 |
| commit | 0afc2edfada50980bec999f94dcea26ebad3dda6 (patch) | |
| tree | 8963dd8fd78ee5c3481acad5903bc459bd3d055c | |
| parent | a8e98d6d51a3eb7bb061b1625193a129c8bd094f (diff) | |
| parent | d256eb8db60e36fc5dd0a27ce8a64f65df31f7b5 (diff) | |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6:
[SPARC32]: Use regsets in arch_ptrace().
[SPARC64]: Use regsets in arch_ptrace().
[SPARC32]: Use regsets for ELF core dumping.
[SPARC64]: Use regsets for ELF core dumping.
[SPARC64]: Remove unintentional ptrace debugging messages.
[SPARC]: Move over to arch_ptrace().
[SPARC]: Remove PTRACE_SUN* handling.
[SPARC]: Kill DEBUG_PTRACE code.
[SPARC32]: Add user regset support.
[SPARC64]: Add user regsets.
[SPARC64]: Fix booting on non-zero cpu.
| -rw-r--r-- | arch/sparc/kernel/entry.S | 17 | ||||
| -rw-r--r-- | arch/sparc/kernel/ptrace.c | 813 | ||||
| -rw-r--r-- | arch/sparc64/kernel/binfmt_elf32.c | 31 | ||||
| -rw-r--r-- | arch/sparc64/kernel/entry.S | 4 | ||||
| -rw-r--r-- | arch/sparc64/kernel/head.S | 25 | ||||
| -rw-r--r-- | arch/sparc64/kernel/ptrace.c | 1095 | ||||
| -rw-r--r-- | arch/sparc64/prom/init.c | 3 | ||||
| -rw-r--r-- | include/asm-sparc/elf.h | 38 | ||||
| -rw-r--r-- | include/asm-sparc/ptrace.h | 7 | ||||
| -rw-r--r-- | include/asm-sparc64/elf.h | 30 | ||||
| -rw-r--r-- | include/asm-sparc64/ptrace.h | 18 |
11 files changed, 1079 insertions, 1002 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: | |||
| 1224 | call c_sys_nis_syscall | 1224 | call c_sys_nis_syscall |
| 1225 | mov %l5, %o7 | 1225 | mov %l5, %o7 |
| 1226 | 1226 | ||
| 1227 | .align 4 | ||
| 1228 | .globl sys_ptrace | ||
| 1229 | sys_ptrace: | ||
| 1230 | call do_ptrace | ||
| 1231 | add %sp, STACKFRAME_SZ, %o0 | ||
| 1232 | |||
| 1233 | ld [%curptr + TI_FLAGS], %l5 | ||
| 1234 | andcc %l5, _TIF_SYSCALL_TRACE, %g0 | ||
| 1235 | be 1f | ||
| 1236 | nop | ||
| 1237 | |||
| 1238 | call syscall_trace | ||
| 1239 | nop | ||
| 1240 | |||
| 1241 | 1: | ||
| 1242 | RESTORE_ALL | ||
| 1243 | |||
| 1244 | .align 4 | 1227 | .align 4 |
| 1245 | .globl sys_execve | 1228 | .globl sys_execve |
| 1246 | sys_execve: | 1229 | sys_execve: |
diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c index 7452269bba2a..5b54f11f4e59 100644 --- a/arch/sparc/kernel/ptrace.c +++ b/arch/sparc/kernel/ptrace.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* ptrace.c: Sparc process tracing support. | 1 | /* ptrace.c: Sparc process tracing support. |
| 2 | * | 2 | * |
| 3 | * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu) | 3 | * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net) |
| 4 | * | 4 | * |
| 5 | * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson, | 5 | * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson, |
| 6 | * and David Mosberger. | 6 | * and David Mosberger. |
| @@ -19,389 +19,343 @@ | |||
| 19 | #include <linux/smp_lock.h> | 19 | #include <linux/smp_lock.h> |
| 20 | #include <linux/security.h> | 20 | #include <linux/security.h> |
| 21 | #include <linux/signal.h> | 21 | #include <linux/signal.h> |
| 22 | #include <linux/regset.h> | ||
| 23 | #include <linux/elf.h> | ||
| 22 | 24 | ||
| 23 | #include <asm/pgtable.h> | 25 | #include <asm/pgtable.h> |
| 24 | #include <asm/system.h> | 26 | #include <asm/system.h> |
| 25 | #include <asm/uaccess.h> | 27 | #include <asm/uaccess.h> |
| 26 | 28 | ||
| 27 | #define MAGIC_CONSTANT 0x80000000 | 29 | /* #define ALLOW_INIT_TRACING */ |
| 28 | |||
| 29 | 30 | ||
| 30 | /* Returning from ptrace is a bit tricky because the syscall return | 31 | /* |
| 31 | * low level code assumes any value returned which is negative and | 32 | * Called by kernel/ptrace.c when detaching.. |
| 32 | * is a valid errno will mean setting the condition codes to indicate | 33 | * |
| 33 | * an error return. This doesn't work, so we have this hook. | 34 | * Make sure single step bits etc are not set. |
| 34 | */ | 35 | */ |
| 35 | static inline void pt_error_return(struct pt_regs *regs, unsigned long error) | 36 | void ptrace_disable(struct task_struct *child) |
| 36 | { | 37 | { |
| 37 | regs->u_regs[UREG_I0] = error; | 38 | /* nothing to do */ |
| 38 | regs->psr |= PSR_C; | ||
| 39 | regs->pc = regs->npc; | ||
| 40 | regs->npc += 4; | ||
| 41 | } | 39 | } |
| 42 | 40 | ||
| 43 | static inline void pt_succ_return(struct pt_regs *regs, unsigned long value) | 41 | enum sparc_regset { |
| 44 | { | 42 | REGSET_GENERAL, |
| 45 | regs->u_regs[UREG_I0] = value; | 43 | REGSET_FP, |
| 46 | regs->psr &= ~PSR_C; | 44 | }; |
| 47 | regs->pc = regs->npc; | ||
| 48 | regs->npc += 4; | ||
| 49 | } | ||
| 50 | 45 | ||
| 51 | static void | 46 | static int genregs32_get(struct task_struct *target, |
| 52 | pt_succ_return_linux(struct pt_regs *regs, unsigned long value, long __user *addr) | 47 | const struct user_regset *regset, |
| 48 | unsigned int pos, unsigned int count, | ||
| 49 | void *kbuf, void __user *ubuf) | ||
| 53 | { | 50 | { |
| 54 | if (put_user(value, addr)) { | 51 | const struct pt_regs *regs = target->thread.kregs; |
| 55 | pt_error_return(regs, EFAULT); | 52 | unsigned long __user *reg_window; |
| 56 | return; | 53 | unsigned long *k = kbuf; |
| 54 | unsigned long __user *u = ubuf; | ||
| 55 | unsigned long reg; | ||
| 56 | |||
| 57 | if (target == current) | ||
| 58 | flush_user_windows(); | ||
| 59 | |||
| 60 | pos /= sizeof(reg); | ||
| 61 | count /= sizeof(reg); | ||
| 62 | |||
| 63 | if (kbuf) { | ||
| 64 | for (; count > 0 && pos < 16; count--) | ||
| 65 | *k++ = regs->u_regs[pos++]; | ||
| 66 | |||
| 67 | reg_window = (unsigned long __user *) regs->u_regs[UREG_I6]; | ||
| 68 | for (; count > 0 && pos < 32; count--) { | ||
| 69 | if (get_user(*k++, ®_window[pos++])) | ||
| 70 | return -EFAULT; | ||
| 71 | } | ||
| 72 | } else { | ||
| 73 | for (; count > 0 && pos < 16; count--) { | ||
| 74 | if (put_user(regs->u_regs[pos++], u++)) | ||
| 75 | return -EFAULT; | ||
| 76 | } | ||
| 77 | |||
| 78 | reg_window = (unsigned long __user *) regs->u_regs[UREG_I6]; | ||
| 79 | for (; count > 0 && pos < 32; count--) { | ||
| 80 | if (get_user(reg, ®_window[pos++]) || | ||
| 81 | put_user(reg, u++)) | ||
| 82 | return -EFAULT; | ||
| 83 | } | ||
| 57 | } | 84 | } |
| 58 | regs->u_regs[UREG_I0] = 0; | 85 | while (count > 0) { |
| 59 | regs->psr &= ~PSR_C; | 86 | switch (pos) { |
| 60 | regs->pc = regs->npc; | 87 | case 32: /* PSR */ |
| 61 | regs->npc += 4; | 88 | reg = regs->psr; |
| 62 | } | 89 | break; |
| 90 | case 33: /* PC */ | ||
| 91 | reg = regs->pc; | ||
| 92 | break; | ||
| 93 | case 34: /* NPC */ | ||
| 94 | reg = regs->npc; | ||
| 95 | break; | ||
| 96 | case 35: /* Y */ | ||
| 97 | reg = regs->y; | ||
| 98 | break; | ||
| 99 | case 36: /* WIM */ | ||
| 100 | case 37: /* TBR */ | ||
| 101 | reg = 0; | ||
| 102 | break; | ||
| 103 | default: | ||
| 104 | goto finish; | ||
| 105 | } | ||
| 63 | 106 | ||
| 64 | static void | 107 | if (kbuf) |
| 65 | pt_os_succ_return (struct pt_regs *regs, unsigned long val, long __user *addr) | 108 | *k++ = reg; |
| 66 | { | 109 | else if (put_user(reg, u++)) |
| 67 | if (current->personality == PER_SUNOS) | 110 | return -EFAULT; |
| 68 | pt_succ_return (regs, val); | 111 | pos++; |
| 69 | else | 112 | count--; |
| 70 | pt_succ_return_linux (regs, val, addr); | 113 | } |
| 114 | finish: | ||
| 115 | pos *= sizeof(reg); | ||
| 116 | count *= sizeof(reg); | ||
| 117 | |||
| 118 | return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, | ||
| 119 | 38 * sizeof(reg), -1); | ||
| 71 | } | 120 | } |
| 72 | 121 | ||
| 73 | /* Fuck me gently with a chainsaw... */ | 122 | static int genregs32_set(struct task_struct *target, |
| 74 | static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset, | 123 | const struct user_regset *regset, |
| 75 | struct task_struct *tsk, long __user *addr) | 124 | unsigned int pos, unsigned int count, |
| 125 | const void *kbuf, const void __user *ubuf) | ||
| 76 | { | 126 | { |
| 77 | struct pt_regs *cregs = tsk->thread.kregs; | 127 | struct pt_regs *regs = target->thread.kregs; |
| 78 | struct thread_info *t = task_thread_info(tsk); | 128 | unsigned long __user *reg_window; |
| 79 | int v; | 129 | const unsigned long *k = kbuf; |
| 80 | 130 | const unsigned long __user *u = ubuf; | |
| 81 | if(offset >= 1024) | 131 | unsigned long reg; |
| 82 | offset -= 1024; /* whee... */ | 132 | |
| 83 | if(offset & ((sizeof(unsigned long) - 1))) { | 133 | if (target == current) |
| 84 | pt_error_return(regs, EIO); | 134 | flush_user_windows(); |
| 85 | return; | 135 | |
| 86 | } | 136 | pos /= sizeof(reg); |
| 87 | if(offset >= 16 && offset < 784) { | 137 | count /= sizeof(reg); |
| 88 | offset -= 16; offset >>= 2; | 138 | |
| 89 | pt_os_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset), addr); | 139 | if (kbuf) { |
| 90 | return; | 140 | for (; count > 0 && pos < 16; count--) |
| 91 | } | 141 | regs->u_regs[pos++] = *k++; |
| 92 | if(offset >= 784 && offset < 832) { | 142 | |
| 93 | offset -= 784; offset >>= 2; | 143 | reg_window = (unsigned long __user *) regs->u_regs[UREG_I6]; |
| 94 | pt_os_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset), addr); | 144 | for (; count > 0 && pos < 32; count--) { |
| 95 | return; | 145 | if (put_user(*k++, ®_window[pos++])) |
| 96 | } | 146 | return -EFAULT; |
| 97 | switch(offset) { | 147 | } |
| 98 | case 0: | 148 | } else { |
| 99 | v = t->ksp; | 149 | for (; count > 0 && pos < 16; count--) { |
| 100 | break; | 150 | if (get_user(reg, u++)) |
| 101 | case 4: | 151 | return -EFAULT; |
| 102 | v = t->kpc; | 152 | regs->u_regs[pos++] = reg; |
| 103 | break; | 153 | } |
| 104 | case 8: | ||
| 105 | v = t->kpsr; | ||
| 106 | break; | ||
| 107 | case 12: | ||
| 108 | v = t->uwinmask; | ||
| 109 | break; | ||
| 110 | case 832: | ||
| 111 | v = t->w_saved; | ||
| 112 | break; | ||
| 113 | case 896: | ||
| 114 | v = cregs->u_regs[UREG_I0]; | ||
| 115 | break; | ||
| 116 | case 900: | ||
| 117 | v = cregs->u_regs[UREG_I1]; | ||
| 118 | break; | ||
| 119 | case 904: | ||
| 120 | v = cregs->u_regs[UREG_I2]; | ||
| 121 | break; | ||
| 122 | case 908: | ||
| 123 | v = cregs->u_regs[UREG_I3]; | ||
| 124 | break; | ||
| 125 | case 912: | ||
| 126 | v = cregs->u_regs[UREG_I4]; | ||
| 127 | break; | ||
| 128 | case 916: | ||
| 129 | v = cregs->u_regs[UREG_I5]; | ||
| 130 | break; | ||
| 131 | case 920: | ||
| 132 | v = cregs->u_regs[UREG_I6]; | ||
| 133 | break; | ||
| 134 | case 924: | ||
| 135 | if(tsk->thread.flags & MAGIC_CONSTANT) | ||
| 136 | v = cregs->u_regs[UREG_G1]; | ||
| 137 | else | ||
| 138 | v = 0; | ||
| 139 | break; | ||
| 140 | case 940: | ||
| 141 | v = cregs->u_regs[UREG_I0]; | ||
| 142 | break; | ||
| 143 | case 944: | ||
| 144 | v = cregs->u_regs[UREG_I1]; | ||
| 145 | break; | ||
| 146 | 154 | ||
| 147 | case 948: | 155 | reg_window = (unsigned long __user *) regs->u_regs[UREG_I6]; |
| 148 | /* Isn't binary compatibility _fun_??? */ | 156 | for (; count > 0 && pos < 32; count--) { |
| 149 | if(cregs->psr & PSR_C) | 157 | if (get_user(reg, u++) || |
| 150 | v = cregs->u_regs[UREG_I0] << 24; | 158 | put_user(reg, ®_window[pos++])) |
| 151 | else | 159 | return -EFAULT; |
| 152 | v = 0; | 160 | } |
| 153 | break; | 161 | } |
| 162 | while (count > 0) { | ||
| 163 | unsigned long psr; | ||
| 164 | |||
| 165 | if (kbuf) | ||
| 166 | reg = *k++; | ||
| 167 | else if (get_user(reg, u++)) | ||
| 168 | return -EFAULT; | ||
| 169 | |||
| 170 | switch (pos) { | ||
| 171 | case 32: /* PSR */ | ||
| 172 | psr = regs->psr; | ||
| 173 | psr &= ~PSR_ICC; | ||
| 174 | psr |= (reg & PSR_ICC); | ||
| 175 | regs->psr = psr; | ||
| 176 | break; | ||
| 177 | case 33: /* PC */ | ||
| 178 | regs->pc = reg; | ||
| 179 | break; | ||
| 180 | case 34: /* NPC */ | ||
| 181 | regs->npc = reg; | ||
| 182 | break; | ||
| 183 | case 35: /* Y */ | ||
| 184 | regs->y = reg; | ||
| 185 | break; | ||
| 186 | case 36: /* WIM */ | ||
| 187 | case 37: /* TBR */ | ||
| 188 | break; | ||
| 189 | default: | ||
| 190 | goto finish; | ||
| 191 | } | ||
| 154 | 192 | ||
| 155 | /* Rest of them are completely unsupported. */ | 193 | pos++; |
| 156 | default: | 194 | count--; |
| 157 | printk("%s [%d]: Wants to read user offset %ld\n", | ||
| 158 | current->comm, task_pid_nr(current), offset); | ||
| 159 | pt_error_return(regs, EIO); | ||
| 160 | return; | ||
| 161 | } | 195 | } |
| 162 | if (current->personality == PER_SUNOS) | 196 | finish: |
| 163 | pt_succ_return (regs, v); | 197 | pos *= sizeof(reg); |
| 164 | else | 198 | count *= sizeof(reg); |
| 165 | pt_succ_return_linux (regs, v, addr); | 199 | |
| 166 | return; | 200 | return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, |
| 201 | 38 * sizeof(reg), -1); | ||
| 167 | } | 202 | } |
| 168 | 203 | ||
| 169 | static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset, | 204 | static int fpregs32_get(struct task_struct *target, |
| 170 | struct task_struct *tsk) | 205 | const struct user_regset *regset, |
| 206 | unsigned int pos, unsigned int count, | ||
| 207 | void *kbuf, void __user *ubuf) | ||
| 171 | { | 208 | { |
| 172 | struct pt_regs *cregs = tsk->thread.kregs; | 209 | const unsigned long *fpregs = target->thread.float_regs; |
| 173 | struct thread_info *t = task_thread_info(tsk); | 210 | int ret = 0; |
| 174 | unsigned long value = regs->u_regs[UREG_I3]; | ||
| 175 | |||
| 176 | if(offset >= 1024) | ||
| 177 | offset -= 1024; /* whee... */ | ||
| 178 | if(offset & ((sizeof(unsigned long) - 1))) | ||
| 179 | goto failure; | ||
| 180 | if(offset >= 16 && offset < 784) { | ||
| 181 | offset -= 16; offset >>= 2; | ||
| 182 | *(((unsigned long *)(&t->reg_window[0]))+offset) = value; | ||
| 183 | goto success; | ||
| 184 | } | ||
| 185 | if(offset >= 784 && offset < 832) { | ||
| 186 | offset -= 784; offset >>= 2; | ||
| 187 | *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value; | ||
| 188 | goto success; | ||
| 189 | } | ||
| 190 | switch(offset) { | ||
| 191 | case 896: | ||
| 192 | cregs->u_regs[UREG_I0] = value; | ||
| 193 | break; | ||
| 194 | case 900: | ||
| 195 | cregs->u_regs[UREG_I1] = value; | ||
| 196 | break; | ||
| 197 | case 904: | ||
| 198 | cregs->u_regs[UREG_I2] = value; | ||
| 199 | break; | ||
| 200 | case 908: | ||
| 201 | cregs->u_regs[UREG_I3] = value; | ||
| 202 | break; | ||
| 203 | case 912: | ||
| 204 | cregs->u_regs[UREG_I4] = value; | ||
| 205 | break; | ||
| 206 | case 916: | ||
| 207 | cregs->u_regs[UREG_I5] = value; | ||
| 208 | break; | ||
| 209 | case 920: | ||
| 210 | cregs->u_regs[UREG_I6] = value; | ||
| 211 | break; | ||
| 212 | case 924: | ||
| 213 | cregs->u_regs[UREG_I7] = value; | ||
| 214 | break; | ||
| 215 | case 940: | ||
| 216 | cregs->u_regs[UREG_I0] = value; | ||
| 217 | break; | ||
| 218 | case 944: | ||
| 219 | cregs->u_regs[UREG_I1] = value; | ||
| 220 | break; | ||
| 221 | 211 | ||
| 222 | /* Rest of them are completely unsupported or "no-touch". */ | 212 | #if 0 |
| 223 | default: | 213 | if (target == current) |
| 224 | printk("%s [%d]: Wants to write user offset %ld\n", | 214 | save_and_clear_fpu(); |
| 225 | current->comm, task_pid_nr(current), offset); | 215 | #endif |
| 226 | goto failure; | 216 | |
| 217 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
| 218 | fpregs, | ||
| 219 | 0, 32 * sizeof(u32)); | ||
| 220 | |||
| 221 | if (!ret) | ||
| 222 | ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, | ||
| 223 | 32 * sizeof(u32), | ||
| 224 | 33 * sizeof(u32)); | ||
| 225 | if (!ret) | ||
| 226 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
| 227 | &target->thread.fsr, | ||
| 228 | 33 * sizeof(u32), | ||
| 229 | 34 * sizeof(u32)); | ||
| 230 | |||
| 231 | if (!ret) { | ||
| 232 | unsigned long val; | ||
| 233 | |||
| 234 | val = (1 << 8) | (8 << 16); | ||
| 235 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
| 236 | &val, | ||
| 237 | 34 * sizeof(u32), | ||
| 238 | 35 * sizeof(u32)); | ||
| 227 | } | 239 | } |
| 228 | success: | ||
| 229 | pt_succ_return(regs, 0); | ||
| 230 | return; | ||
| 231 | failure: | ||
| 232 | pt_error_return(regs, EIO); | ||
| 233 | return; | ||
| 234 | } | ||
| 235 | 240 | ||
| 236 | /* #define ALLOW_INIT_TRACING */ | 241 | if (!ret) |
| 237 | /* #define DEBUG_PTRACE */ | 242 | ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, |
| 238 | 243 | 35 * sizeof(u32), -1); | |
| 239 | #ifdef DEBUG_PTRACE | ||
| 240 | char *pt_rq [] = { | ||
| 241 | /* 0 */ "TRACEME", "PEEKTEXT", "PEEKDATA", "PEEKUSR", | ||
| 242 | /* 4 */ "POKETEXT", "POKEDATA", "POKEUSR", "CONT", | ||
| 243 | /* 8 */ "KILL", "SINGLESTEP", "SUNATTACH", "SUNDETACH", | ||
| 244 | /* 12 */ "GETREGS", "SETREGS", "GETFPREGS", "SETFPREGS", | ||
| 245 | /* 16 */ "READDATA", "WRITEDATA", "READTEXT", "WRITETEXT", | ||
| 246 | /* 20 */ "GETFPAREGS", "SETFPAREGS", "unknown", "unknown", | ||
| 247 | /* 24 */ "SYSCALL", "" | ||
| 248 | }; | ||
| 249 | #endif | ||
| 250 | 244 | ||
| 251 | /* | 245 | return ret; |
| 252 | * Called by kernel/ptrace.c when detaching.. | ||
| 253 | * | ||
| 254 | * Make sure single step bits etc are not set. | ||
| 255 | */ | ||
| 256 | void ptrace_disable(struct task_struct *child) | ||
| 257 | { | ||
| 258 | /* nothing to do */ | ||
| 259 | } | 246 | } |
| 260 | 247 | ||
| 261 | asmlinkage void do_ptrace(struct pt_regs *regs) | 248 | static int fpregs32_set(struct task_struct *target, |
| 249 | const struct user_regset *regset, | ||
| 250 | unsigned int pos, unsigned int count, | ||
| 251 | const void *kbuf, const void __user *ubuf) | ||
| 262 | { | 252 | { |
| 263 | unsigned long request = regs->u_regs[UREG_I0]; | 253 | unsigned long *fpregs = target->thread.float_regs; |
| 264 | unsigned long pid = regs->u_regs[UREG_I1]; | ||
| 265 | unsigned long addr = regs->u_regs[UREG_I2]; | ||
| 266 | unsigned long data = regs->u_regs[UREG_I3]; | ||
| 267 | unsigned long addr2 = regs->u_regs[UREG_I4]; | ||
| 268 | struct task_struct *child; | ||
| 269 | int ret; | 254 | int ret; |
| 270 | 255 | ||
| 271 | lock_kernel(); | 256 | #if 0 |
| 272 | #ifdef DEBUG_PTRACE | 257 | if (target == current) |
| 273 | { | 258 | save_and_clear_fpu(); |
| 274 | char *s; | ||
| 275 | |||
| 276 | if ((request >= 0) && (request <= 24)) | ||
| 277 | s = pt_rq [request]; | ||
| 278 | else | ||
| 279 | s = "unknown"; | ||
| 280 | |||
| 281 | if (request == PTRACE_POKEDATA && data == 0x91d02001){ | ||
| 282 | printk ("do_ptrace: breakpoint pid=%d, addr=%08lx addr2=%08lx\n", | ||
| 283 | pid, addr, addr2); | ||
| 284 | } else | ||
| 285 | printk("do_ptrace: rq=%s(%d) pid=%d addr=%08lx data=%08lx addr2=%08lx\n", | ||
| 286 | s, (int) request, (int) pid, addr, data, addr2); | ||
| 287 | } | ||
| 288 | #endif | 259 | #endif |
| 289 | 260 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | |
| 290 | if (request == PTRACE_TRACEME) { | 261 | fpregs, |
| 291 | ret = ptrace_traceme(); | 262 | 0, 32 * sizeof(u32)); |
| 292 | if (ret < 0) | 263 | if (!ret) |
| 293 | pt_error_return(regs, -ret); | 264 | user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, |
| 294 | else | 265 | 32 * sizeof(u32), |
| 295 | pt_succ_return(regs, 0); | 266 | 33 * sizeof(u32)); |
| 296 | goto out; | 267 | if (!ret && count > 0) { |
| 268 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
| 269 | &target->thread.fsr, | ||
| 270 | 33 * sizeof(u32), | ||
| 271 | 34 * sizeof(u32)); | ||
| 297 | } | 272 | } |
| 298 | 273 | ||
| 299 | child = ptrace_get_task_struct(pid); | 274 | if (!ret) |
| 300 | if (IS_ERR(child)) { | 275 | ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, |
| 301 | ret = PTR_ERR(child); | 276 | 34 * sizeof(u32), -1); |
| 302 | pt_error_return(regs, -ret); | 277 | return ret; |
| 303 | goto out; | 278 | } |
| 304 | } | ||
| 305 | 279 | ||
| 306 | if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH) | 280 | static const struct user_regset sparc32_regsets[] = { |
| 307 | || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) { | 281 | /* Format is: |
| 308 | if (ptrace_attach(child)) { | 282 | * G0 --> G7 |
| 309 | pt_error_return(regs, EPERM); | 283 | * O0 --> O7 |
| 310 | goto out_tsk; | 284 | * L0 --> L7 |
| 311 | } | 285 | * I0 --> I7 |
| 312 | pt_succ_return(regs, 0); | 286 | * PSR, PC, nPC, Y, WIM, TBR |
| 313 | goto out_tsk; | 287 | */ |
| 314 | } | 288 | [REGSET_GENERAL] = { |
| 289 | .core_note_type = NT_PRSTATUS, | ||
| 290 | .n = 38 * sizeof(u32), | ||
| 291 | .size = sizeof(u32), .align = sizeof(u32), | ||
| 292 | .get = genregs32_get, .set = genregs32_set | ||
| 293 | }, | ||
| 294 | /* Format is: | ||
| 295 | * F0 --> F31 | ||
| 296 | * empty 32-bit word | ||
| 297 | * FSR (32--bit word) | ||
| 298 | * FPU QUEUE COUNT (8-bit char) | ||
| 299 | * FPU QUEUE ENTRYSIZE (8-bit char) | ||
| 300 | * FPU ENABLED (8-bit char) | ||
| 301 | * empty 8-bit char | ||
| 302 | * FPU QUEUE (64 32-bit ints) | ||
| 303 | */ | ||
| 304 | [REGSET_FP] = { | ||
| 305 | .core_note_type = NT_PRFPREG, | ||
| 306 | .n = 99 * sizeof(u32), | ||
| 307 | .size = sizeof(u32), .align = sizeof(u32), | ||
| 308 | .get = fpregs32_get, .set = fpregs32_set | ||
| 309 | }, | ||
| 310 | }; | ||
| 315 | 311 | ||
| 316 | ret = ptrace_check_attach(child, request == PTRACE_KILL); | 312 | static const struct user_regset_view user_sparc32_view = { |
| 317 | if (ret < 0) { | 313 | .name = "sparc", .e_machine = EM_SPARC, |
| 318 | pt_error_return(regs, -ret); | 314 | .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets) |
| 319 | goto out_tsk; | 315 | }; |
| 320 | } | ||
| 321 | 316 | ||
| 322 | switch(request) { | 317 | const struct user_regset_view *task_user_regset_view(struct task_struct *task) |
| 323 | case PTRACE_PEEKTEXT: /* read word at location addr. */ | 318 | { |
| 324 | case PTRACE_PEEKDATA: { | 319 | return &user_sparc32_view; |
| 325 | unsigned long tmp; | 320 | } |
| 326 | |||
| 327 | if (access_process_vm(child, addr, | ||
| 328 | &tmp, sizeof(tmp), 0) == sizeof(tmp)) | ||
| 329 | pt_os_succ_return(regs, tmp, (long __user *)data); | ||
| 330 | else | ||
| 331 | pt_error_return(regs, EIO); | ||
| 332 | goto out_tsk; | ||
| 333 | } | ||
| 334 | 321 | ||
| 335 | case PTRACE_PEEKUSR: | 322 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) |
| 336 | read_sunos_user(regs, addr, child, (long __user *) data); | 323 | { |
| 337 | goto out_tsk; | 324 | unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4]; |
| 338 | 325 | const struct user_regset_view *view; | |
| 339 | case PTRACE_POKEUSR: | 326 | int ret; |
| 340 | write_sunos_user(regs, addr, child); | 327 | |
| 341 | goto out_tsk; | 328 | view = task_user_regset_view(child); |
| 342 | |||
| 343 | case PTRACE_POKETEXT: /* write the word at location addr. */ | ||
| 344 | case PTRACE_POKEDATA: { | ||
| 345 | if (access_process_vm(child, addr, | ||
| 346 | &data, sizeof(data), 1) == sizeof(data)) | ||
| 347 | pt_succ_return(regs, 0); | ||
| 348 | else | ||
| 349 | pt_error_return(regs, EIO); | ||
| 350 | goto out_tsk; | ||
| 351 | } | ||
| 352 | 329 | ||
| 330 | switch(request) { | ||
| 353 | case PTRACE_GETREGS: { | 331 | case PTRACE_GETREGS: { |
| 354 | struct pt_regs __user *pregs = (struct pt_regs __user *) addr; | 332 | struct pt_regs __user *pregs = (struct pt_regs __user *) addr; |
| 355 | struct pt_regs *cregs = child->thread.kregs; | ||
| 356 | int rval; | ||
| 357 | 333 | ||
| 358 | if (!access_ok(VERIFY_WRITE, pregs, sizeof(struct pt_regs))) { | 334 | ret = copy_regset_to_user(child, view, REGSET_GENERAL, |
| 359 | rval = -EFAULT; | 335 | 32 * sizeof(u32), |
| 360 | pt_error_return(regs, -rval); | 336 | 4 * sizeof(u32), |
| 361 | goto out_tsk; | 337 | &pregs->psr); |
| 362 | } | 338 | if (!ret) |
| 363 | __put_user(cregs->psr, (&pregs->psr)); | 339 | copy_regset_to_user(child, view, REGSET_GENERAL, |
| 364 | __put_user(cregs->pc, (&pregs->pc)); | 340 | 1 * sizeof(u32), |
| 365 | __put_user(cregs->npc, (&pregs->npc)); | 341 | 15 * sizeof(u32), |
| 366 | __put_user(cregs->y, (&pregs->y)); | 342 | &pregs->u_regs[0]); |
| 367 | for(rval = 1; rval < 16; rval++) | 343 | break; |
| 368 | __put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1])); | ||
| 369 | pt_succ_return(regs, 0); | ||
| 370 | #ifdef DEBUG_PTRACE | ||
| 371 | printk ("PC=%x nPC=%x o7=%x\n", cregs->pc, cregs->npc, cregs->u_regs [15]); | ||
| 372 | #endif | ||
| 373 | goto out_tsk; | ||
| 374 | } | 344 | } |
| 375 | 345 | ||
| 376 | case PTRACE_SETREGS: { | 346 | case PTRACE_SETREGS: { |
| 377 | struct pt_regs __user *pregs = (struct pt_regs __user *) addr; | 347 | struct pt_regs __user *pregs = (struct pt_regs __user *) addr; |
| 378 | struct pt_regs *cregs = child->thread.kregs; | 348 | |
| 379 | unsigned long psr, pc, npc, y; | 349 | ret = copy_regset_from_user(child, view, REGSET_GENERAL, |
| 380 | int i; | 350 | 32 * sizeof(u32), |
| 381 | 351 | 4 * sizeof(u32), | |
| 382 | /* Must be careful, tracing process can only set certain | 352 | &pregs->psr); |
| 383 | * bits in the psr. | 353 | if (!ret) |
| 384 | */ | 354 | copy_regset_from_user(child, view, REGSET_GENERAL, |
| 385 | if (!access_ok(VERIFY_READ, pregs, sizeof(struct pt_regs))) { | 355 | 1 * sizeof(u32), |
| 386 | pt_error_return(regs, EFAULT); | 356 | 15 * sizeof(u32), |
| 387 | goto out_tsk; | 357 | &pregs->u_regs[0]); |
| 388 | } | 358 | break; |
| 389 | __get_user(psr, (&pregs->psr)); | ||
| 390 | __get_user(pc, (&pregs->pc)); | ||
| 391 | __get_user(npc, (&pregs->npc)); | ||
| 392 | __get_user(y, (&pregs->y)); | ||
| 393 | psr &= PSR_ICC; | ||
| 394 | cregs->psr &= ~PSR_ICC; | ||
| 395 | cregs->psr |= psr; | ||
| 396 | if (!((pc | npc) & 3)) { | ||
| 397 | cregs->pc = pc; | ||
| 398 | cregs->npc =npc; | ||
| 399 | } | ||
| 400 | cregs->y = y; | ||
| 401 | for(i = 1; i < 16; i++) | ||
| 402 | __get_user(cregs->u_regs[i], (&pregs->u_regs[i-1])); | ||
| 403 | pt_succ_return(regs, 0); | ||
| 404 | goto out_tsk; | ||
| 405 | } | 359 | } |
| 406 | 360 | ||
| 407 | case PTRACE_GETFPREGS: { | 361 | case PTRACE_GETFPREGS: { |
| @@ -417,26 +371,25 @@ asmlinkage void do_ptrace(struct pt_regs *regs) | |||
| 417 | } fpq[16]; | 371 | } fpq[16]; |
| 418 | }; | 372 | }; |
| 419 | struct fps __user *fps = (struct fps __user *) addr; | 373 | struct fps __user *fps = (struct fps __user *) addr; |
| 420 | int i; | ||
| 421 | 374 | ||
| 422 | if (!access_ok(VERIFY_WRITE, fps, sizeof(struct fps))) { | 375 | ret = copy_regset_to_user(child, view, REGSET_FP, |
| 423 | i = -EFAULT; | 376 | 0 * sizeof(u32), |
| 424 | pt_error_return(regs, -i); | 377 | 32 * sizeof(u32), |
| 425 | goto out_tsk; | 378 | &fps->regs[0]); |
| 426 | } | 379 | if (!ret) |
| 427 | for(i = 0; i < 32; i++) | 380 | ret = copy_regset_to_user(child, view, REGSET_FP, |
| 428 | __put_user(child->thread.float_regs[i], (&fps->regs[i])); | 381 | 33 * sizeof(u32), |
| 429 | __put_user(child->thread.fsr, (&fps->fsr)); | 382 | 1 * sizeof(u32), |
| 430 | __put_user(child->thread.fpqdepth, (&fps->fpqd)); | 383 | &fps->fsr); |
| 431 | __put_user(0, (&fps->flags)); | 384 | |
| 432 | __put_user(0, (&fps->extra)); | 385 | if (!ret) { |
| 433 | for(i = 0; i < 16; i++) { | 386 | if (__put_user(0, &fps->fpqd) || |
| 434 | __put_user(child->thread.fpqueue[i].insn_addr, | 387 | __put_user(0, &fps->flags) || |
| 435 | (&fps->fpq[i].insnaddr)); | 388 | __put_user(0, &fps->extra) || |
| 436 | __put_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn)); | 389 | clear_user(fps->fpq, sizeof(fps->fpq))) |
| 390 | ret = -EFAULT; | ||
| 437 | } | 391 | } |
| 438 | pt_succ_return(regs, 0); | 392 | break; |
| 439 | goto out_tsk; | ||
| 440 | } | 393 | } |
| 441 | 394 | ||
| 442 | case PTRACE_SETFPREGS: { | 395 | case PTRACE_SETFPREGS: { |
| @@ -452,137 +405,55 @@ asmlinkage void do_ptrace(struct pt_regs *regs) | |||
| 452 | } fpq[16]; | 405 | } fpq[16]; |
| 453 | }; | 406 | }; |
| 454 | struct fps __user *fps = (struct fps __user *) addr; | 407 | struct fps __user *fps = (struct fps __user *) addr; |
| 455 | int i; | ||
| 456 | 408 | ||
| 457 | if (!access_ok(VERIFY_READ, fps, sizeof(struct fps))) { | 409 | ret = copy_regset_from_user(child, view, REGSET_FP, |
| 458 | i = -EFAULT; | 410 | 0 * sizeof(u32), |
| 459 | pt_error_return(regs, -i); | 411 | 32 * sizeof(u32), |
| 460 | goto out_tsk; | 412 | &fps->regs[0]); |
| 461 | } | 413 | if (!ret) |
| 462 | copy_from_user(&child->thread.float_regs[0], &fps->regs[0], (32 * sizeof(unsigned long))); | 414 | ret = copy_regset_from_user(child, view, REGSET_FP, |
| 463 | __get_user(child->thread.fsr, (&fps->fsr)); | 415 | 33 * sizeof(u32), |
| 464 | __get_user(child->thread.fpqdepth, (&fps->fpqd)); | 416 | 1 * sizeof(u32), |
| 465 | for(i = 0; i < 16; i++) { | 417 | &fps->fsr); |
| 466 | __get_user(child->thread.fpqueue[i].insn_addr, | 418 | break; |
| 467 | (&fps->fpq[i].insnaddr)); | ||
| 468 | __get_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn)); | ||
| 469 | } | ||
| 470 | pt_succ_return(regs, 0); | ||
| 471 | goto out_tsk; | ||
| 472 | } | 419 | } |
| 473 | 420 | ||
| 474 | case PTRACE_READTEXT: | 421 | case PTRACE_READTEXT: |
| 475 | case PTRACE_READDATA: { | 422 | case PTRACE_READDATA: |
| 476 | int res = ptrace_readdata(child, addr, | 423 | ret = ptrace_readdata(child, addr, |
| 477 | (void __user *) addr2, data); | 424 | (void __user *) addr2, data); |
| 478 | 425 | ||
| 479 | if (res == data) { | 426 | if (ret == data) |
| 480 | pt_succ_return(regs, 0); | 427 | ret = 0; |
| 481 | goto out_tsk; | 428 | else if (ret >= 0) |
| 482 | } | 429 | ret = -EIO; |
| 483 | /* Partial read is an IO failure */ | 430 | break; |
| 484 | if (res >= 0) | ||
| 485 | res = -EIO; | ||
| 486 | pt_error_return(regs, -res); | ||
| 487 | goto out_tsk; | ||
| 488 | } | ||
| 489 | 431 | ||
| 490 | case PTRACE_WRITETEXT: | 432 | case PTRACE_WRITETEXT: |
| 491 | case PTRACE_WRITEDATA: { | 433 | case PTRACE_WRITEDATA: |
| 492 | int res = ptrace_writedata(child, (void __user *) addr2, | 434 | ret = ptrace_writedata(child, (void __user *) addr2, |
| 493 | addr, data); | 435 | addr, data); |
| 494 | 436 | ||
| 495 | if (res == data) { | 437 | if (ret == data) |
| 496 | pt_succ_return(regs, 0); | 438 | ret = 0; |
| 497 | goto out_tsk; | 439 | else if (ret >= 0) |
| 498 | } | 440 | ret = -EIO; |
| 499 | /* Partial write is an IO failure */ | 441 | break; |
| 500 | if (res >= 0) | ||
| 501 | res = -EIO; | ||
| 502 | pt_error_return(regs, -res); | ||
| 503 | goto out_tsk; | ||
| 504 | } | ||
| 505 | |||
| 506 | case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */ | ||
| 507 | addr = 1; | ||
| 508 | |||
| 509 | case PTRACE_CONT: { /* restart after signal. */ | ||
| 510 | if (!valid_signal(data)) { | ||
| 511 | pt_error_return(regs, EIO); | ||
| 512 | goto out_tsk; | ||
| 513 | } | ||
| 514 | |||
| 515 | if (request == PTRACE_SYSCALL) | ||
| 516 | set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
| 517 | else | ||
| 518 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
| 519 | |||
| 520 | child->exit_code = data; | ||
| 521 | #ifdef DEBUG_PTRACE | ||
| 522 | printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n", | ||
| 523 | child->comm, child->pid, child->exit_code, | ||
| 524 | child->thread.kregs->pc, | ||
| 525 | child->thread.kregs->npc); | ||
| 526 | #endif | ||
| 527 | wake_up_process(child); | ||
| 528 | pt_succ_return(regs, 0); | ||
| 529 | goto out_tsk; | ||
| 530 | } | ||
| 531 | |||
| 532 | /* | ||
| 533 | * make the child exit. Best I can do is send it a sigkill. | ||
| 534 | * perhaps it should be put in the status that it wants to | ||
| 535 | * exit. | ||
| 536 | */ | ||
| 537 | case PTRACE_KILL: { | ||
| 538 | if (child->exit_state == EXIT_ZOMBIE) { /* already dead */ | ||
| 539 | pt_succ_return(regs, 0); | ||
| 540 | goto out_tsk; | ||
| 541 | } | ||
| 542 | wake_up_process(child); | ||
| 543 | child->exit_code = SIGKILL; | ||
| 544 | pt_succ_return(regs, 0); | ||
| 545 | goto out_tsk; | ||
| 546 | } | ||
| 547 | 442 | ||
| 548 | case PTRACE_SUNDETACH: { /* detach a process that was attached. */ | 443 | default: |
| 549 | int err = ptrace_detach(child, data); | 444 | ret = ptrace_request(child, request, addr, data); |
| 550 | if (err) { | 445 | break; |
| 551 | pt_error_return(regs, EIO); | ||
| 552 | goto out_tsk; | ||
| 553 | } | ||
| 554 | pt_succ_return(regs, 0); | ||
| 555 | goto out_tsk; | ||
| 556 | } | 446 | } |
| 557 | 447 | ||
| 558 | /* PTRACE_DUMPCORE unsupported... */ | 448 | return ret; |
| 559 | |||
| 560 | default: { | ||
| 561 | int err = ptrace_request(child, request, addr, data); | ||
| 562 | if (err) | ||
| 563 | pt_error_return(regs, -err); | ||
| 564 | else | ||
| 565 | pt_succ_return(regs, 0); | ||
| 566 | goto out_tsk; | ||
| 567 | } | ||
| 568 | } | ||
| 569 | out_tsk: | ||
| 570 | if (child) | ||
| 571 | put_task_struct(child); | ||
| 572 | out: | ||
| 573 | unlock_kernel(); | ||
| 574 | } | 449 | } |
| 575 | 450 | ||
| 576 | asmlinkage void syscall_trace(void) | 451 | asmlinkage void syscall_trace(void) |
| 577 | { | 452 | { |
| 578 | #ifdef DEBUG_PTRACE | ||
| 579 | printk("%s [%d]: syscall_trace\n", current->comm, current->pid); | ||
| 580 | #endif | ||
| 581 | if (!test_thread_flag(TIF_SYSCALL_TRACE)) | 453 | if (!test_thread_flag(TIF_SYSCALL_TRACE)) |
| 582 | return; | 454 | return; |
| 583 | if (!(current->ptrace & PT_PTRACED)) | 455 | if (!(current->ptrace & PT_PTRACED)) |
| 584 | return; | 456 | return; |
| 585 | current->thread.flags ^= MAGIC_CONSTANT; | ||
| 586 | ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) | 457 | ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) |
| 587 | ? 0x80 : 0)); | 458 | ? 0x80 : 0)); |
| 588 | /* | 459 | /* |
| @@ -590,10 +461,6 @@ asmlinkage void syscall_trace(void) | |||
| 590 | * for normal use. strace only continues with a signal if the | 461 | * for normal use. strace only continues with a signal if the |
| 591 | * stopping signal is not SIGTRAP. -brl | 462 | * stopping signal is not SIGTRAP. -brl |
| 592 | */ | 463 | */ |
| 593 | #ifdef DEBUG_PTRACE | ||
| 594 | printk("%s [%d]: syscall_trace exit= %x\n", current->comm, | ||
| 595 | current->pid, current->exit_code); | ||
| 596 | #endif | ||
| 597 | if (current->exit_code) { | 464 | if (current->exit_code) { |
| 598 | send_sig (current->exit_code, current, 1); | 465 | send_sig (current->exit_code, current, 1); |
| 599 | current->exit_code = 0; | 466 | current->exit_code = 0; |
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 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * binfmt_elf32.c: Support 32-bit Sparc ELF binaries on Ultra. | 2 | * binfmt_elf32.c: Support 32-bit Sparc ELF binaries on Ultra. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@davemloft.net) | 4 | * Copyright (C) 1995, 1996, 1997, 1998, 2008 David S. Miller (davem@davemloft.net) |
| 5 | * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz) | 5 | * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz) |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| @@ -9,13 +9,6 @@ | |||
| 9 | #define ELF_CLASS ELFCLASS32 | 9 | #define ELF_CLASS ELFCLASS32 |
| 10 | #define ELF_DATA ELFDATA2MSB; | 10 | #define ELF_DATA ELFDATA2MSB; |
| 11 | 11 | ||
| 12 | /* For the most part we present code dumps in the format | ||
| 13 | * Solaris does. | ||
| 14 | */ | ||
| 15 | typedef unsigned int elf_greg_t; | ||
| 16 | #define ELF_NGREG 38 | ||
| 17 | typedef elf_greg_t elf_gregset_t[ELF_NGREG]; | ||
| 18 | |||
| 19 | /* Format is: | 12 | /* Format is: |
| 20 | * G0 --> G7 | 13 | * G0 --> G7 |
| 21 | * O0 --> O7 | 14 | * O0 --> O7 |
| @@ -23,25 +16,9 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG]; | |||
| 23 | * I0 --> I7 | 16 | * I0 --> I7 |
| 24 | * PSR, PC, nPC, Y, WIM, TBR | 17 | * PSR, PC, nPC, Y, WIM, TBR |
| 25 | */ | 18 | */ |
| 26 | #include <asm/psrcompat.h> | 19 | typedef unsigned int elf_greg_t; |
| 27 | #define ELF_CORE_COPY_REGS(__elf_regs, __pt_regs) \ | 20 | #define ELF_NGREG 38 |
| 28 | do { unsigned int *dest = &(__elf_regs[0]); \ | 21 | typedef elf_greg_t elf_gregset_t[ELF_NGREG]; |
| 29 | struct pt_regs *src = (__pt_regs); \ | ||
| 30 | unsigned int __user *sp; \ | ||
| 31 | int i; \ | ||
| 32 | for(i = 0; i < 16; i++) \ | ||
| 33 | dest[i] = (unsigned int) src->u_regs[i];\ | ||
| 34 | /* Don't try this at home kids... */ \ | ||
| 35 | sp = (unsigned int __user *) (src->u_regs[14] & \ | ||
| 36 | 0x00000000fffffffc); \ | ||
| 37 | for(i = 0; i < 16; i++) \ | ||
| 38 | __get_user(dest[i+16], &sp[i]); \ | ||
| 39 | dest[32] = tstate_to_psr(src->tstate); \ | ||
| 40 | dest[33] = (unsigned int) src->tpc; \ | ||
| 41 | dest[34] = (unsigned int) src->tnpc; \ | ||
| 42 | dest[35] = src->y; \ | ||
| 43 | dest[36] = dest[37] = 0; /* XXX */ \ | ||
| 44 | } while(0); | ||
| 45 | 22 | ||
| 46 | typedef struct { | 23 | typedef struct { |
| 47 | union { | 24 | union { |
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: | |||
| 1477 | add %o7, 1f-.-4, %o7 | 1477 | add %o7, 1f-.-4, %o7 |
| 1478 | nop | 1478 | nop |
| 1479 | #endif | 1479 | #endif |
| 1480 | sys_ptrace: add %sp, PTREGS_OFF, %o0 | ||
| 1481 | call do_ptrace | ||
| 1482 | add %o7, 1f-.-4, %o7 | ||
| 1483 | nop | ||
| 1484 | .align 32 | 1480 | .align 32 |
| 1485 | 1: ldx [%curptr + TI_FLAGS], %l5 | 1481 | 1: ldx [%curptr + TI_FLAGS], %l5 |
| 1486 | andcc %l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0 | 1482 | andcc %l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0 |
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: | |||
| 632 | /* Not reached... */ | 632 | /* Not reached... */ |
| 633 | 633 | ||
| 634 | 1: | 634 | 1: |
| 635 | /* If we boot on a non-zero cpu, all of the per-cpu | ||
| 636 | * variable references we make before setting up the | ||
| 637 | * per-cpu areas will use a bogus offset. Put a | ||
| 638 | * compensating factor into __per_cpu_base to handle | ||
| 639 | * this cleanly. | ||
| 640 | * | ||
| 641 | * What the per-cpu code calculates is: | ||
| 642 | * | ||
| 643 | * __per_cpu_base + (cpu << __per_cpu_shift) | ||
| 644 | * | ||
| 645 | * These two variables are zero initially, so to | ||
| 646 | * make it all cancel out to zero we need to put | ||
| 647 | * "0 - (cpu << 0)" into __per_cpu_base so that the | ||
| 648 | * above formula evaluates to zero. | ||
| 649 | * | ||
| 650 | * We cannot even perform a printk() until this stuff | ||
| 651 | * is setup as that calls cpu_clock() which uses | ||
| 652 | * per-cpu variables. | ||
| 653 | */ | ||
| 654 | sub %g0, %o0, %o1 | ||
| 655 | sethi %hi(__per_cpu_base), %o2 | ||
| 656 | stx %o1, [%o2 + %lo(__per_cpu_base)] | ||
| 635 | #else | 657 | #else |
| 636 | mov 0, %o0 | 658 | mov 0, %o0 |
| 637 | #endif | 659 | #endif |
| 638 | sth %o0, [%g6 + TI_CPU] | 660 | sth %o0, [%g6 + TI_CPU] |
| 639 | 661 | ||
| 662 | call prom_init_report | ||
| 663 | nop | ||
| 664 | |||
| 640 | /* Off we go.... */ | 665 | /* Off we go.... */ |
| 641 | call start_kernel | 666 | call start_kernel |
| 642 | nop | 667 | nop |
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index 81111a12f0a8..51f012410f9d 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* ptrace.c: Sparc process tracing support. | 1 | /* ptrace.c: Sparc process tracing support. |
| 2 | * | 2 | * |
| 3 | * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu) | 3 | * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net) |
| 4 | * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | 4 | * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) |
| 5 | * | 5 | * |
| 6 | * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson, | 6 | * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson, |
| @@ -22,6 +22,9 @@ | |||
| 22 | #include <linux/seccomp.h> | 22 | #include <linux/seccomp.h> |
| 23 | #include <linux/audit.h> | 23 | #include <linux/audit.h> |
| 24 | #include <linux/signal.h> | 24 | #include <linux/signal.h> |
| 25 | #include <linux/regset.h> | ||
| 26 | #include <linux/compat.h> | ||
| 27 | #include <linux/elf.h> | ||
| 25 | 28 | ||
| 26 | #include <asm/asi.h> | 29 | #include <asm/asi.h> |
| 27 | #include <asm/pgtable.h> | 30 | #include <asm/pgtable.h> |
| @@ -33,70 +36,7 @@ | |||
| 33 | #include <asm/page.h> | 36 | #include <asm/page.h> |
| 34 | #include <asm/cpudata.h> | 37 | #include <asm/cpudata.h> |
| 35 | 38 | ||
| 36 | /* Returning from ptrace is a bit tricky because the syscall return | ||
| 37 | * low level code assumes any value returned which is negative and | ||
| 38 | * is a valid errno will mean setting the condition codes to indicate | ||
| 39 | * an error return. This doesn't work, so we have this hook. | ||
| 40 | */ | ||
| 41 | static inline void pt_error_return(struct pt_regs *regs, unsigned long error) | ||
| 42 | { | ||
| 43 | regs->u_regs[UREG_I0] = error; | ||
| 44 | regs->tstate |= (TSTATE_ICARRY | TSTATE_XCARRY); | ||
| 45 | regs->tpc = regs->tnpc; | ||
| 46 | regs->tnpc += 4; | ||
| 47 | } | ||
| 48 | |||
| 49 | static inline void pt_succ_return(struct pt_regs *regs, unsigned long value) | ||
| 50 | { | ||
| 51 | regs->u_regs[UREG_I0] = value; | ||
| 52 | regs->tstate &= ~(TSTATE_ICARRY | TSTATE_XCARRY); | ||
| 53 | regs->tpc = regs->tnpc; | ||
| 54 | regs->tnpc += 4; | ||
| 55 | } | ||
| 56 | |||
| 57 | static inline void | ||
| 58 | pt_succ_return_linux(struct pt_regs *regs, unsigned long value, void __user *addr) | ||
| 59 | { | ||
| 60 | if (test_thread_flag(TIF_32BIT)) { | ||
| 61 | if (put_user(value, (unsigned int __user *) addr)) { | ||
| 62 | pt_error_return(regs, EFAULT); | ||
| 63 | return; | ||
| 64 | } | ||
| 65 | } else { | ||
| 66 | if (put_user(value, (long __user *) addr)) { | ||
| 67 | pt_error_return(regs, EFAULT); | ||
| 68 | return; | ||
| 69 | } | ||
| 70 | } | ||
| 71 | regs->u_regs[UREG_I0] = 0; | ||
| 72 | regs->tstate &= ~(TSTATE_ICARRY | TSTATE_XCARRY); | ||
| 73 | regs->tpc = regs->tnpc; | ||
| 74 | regs->tnpc += 4; | ||
| 75 | } | ||
| 76 | |||
| 77 | static void | ||
| 78 | pt_os_succ_return (struct pt_regs *regs, unsigned long val, void __user *addr) | ||
| 79 | { | ||
| 80 | if (current->personality == PER_SUNOS) | ||
| 81 | pt_succ_return (regs, val); | ||
| 82 | else | ||
| 83 | pt_succ_return_linux (regs, val, addr); | ||
| 84 | } | ||
| 85 | |||
| 86 | /* #define ALLOW_INIT_TRACING */ | 39 | /* #define ALLOW_INIT_TRACING */ |
| 87 | /* #define DEBUG_PTRACE */ | ||
| 88 | |||
| 89 | #ifdef DEBUG_PTRACE | ||
| 90 | char *pt_rq [] = { | ||
| 91 | /* 0 */ "TRACEME", "PEEKTEXT", "PEEKDATA", "PEEKUSR", | ||
| 92 | /* 4 */ "POKETEXT", "POKEDATA", "POKEUSR", "CONT", | ||
| 93 | /* 8 */ "KILL", "SINGLESTEP", "SUNATTACH", "SUNDETACH", | ||
| 94 | /* 12 */ "GETREGS", "SETREGS", "GETFPREGS", "SETFPREGS", | ||
| 95 | /* 16 */ "READDATA", "WRITEDATA", "READTEXT", "WRITETEXT", | ||
| 96 | /* 20 */ "GETFPAREGS", "SETFPAREGS", "unknown", "unknown", | ||
| 97 | /* 24 */ "SYSCALL", "" | ||
| 98 | }; | ||
| 99 | #endif | ||
| 100 | 40 | ||
| 101 | /* | 41 | /* |
| 102 | * Called by kernel/ptrace.c when detaching.. | 42 | * Called by kernel/ptrace.c when detaching.. |
| @@ -167,267 +107,709 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, | |||
| 167 | } | 107 | } |
| 168 | } | 108 | } |
| 169 | 109 | ||
| 170 | asmlinkage void do_ptrace(struct pt_regs *regs) | 110 | enum sparc_regset { |
| 111 | REGSET_GENERAL, | ||
| 112 | REGSET_FP, | ||
| 113 | }; | ||
| 114 | |||
| 115 | static int genregs64_get(struct task_struct *target, | ||
| 116 | const struct user_regset *regset, | ||
| 117 | unsigned int pos, unsigned int count, | ||
| 118 | void *kbuf, void __user *ubuf) | ||
| 171 | { | 119 | { |
| 172 | int request = regs->u_regs[UREG_I0]; | 120 | const struct pt_regs *regs = task_pt_regs(target); |
| 173 | pid_t pid = regs->u_regs[UREG_I1]; | ||
| 174 | unsigned long addr = regs->u_regs[UREG_I2]; | ||
| 175 | unsigned long data = regs->u_regs[UREG_I3]; | ||
| 176 | unsigned long addr2 = regs->u_regs[UREG_I4]; | ||
| 177 | struct task_struct *child; | ||
| 178 | int ret; | 121 | int ret; |
| 179 | 122 | ||
| 180 | if (test_thread_flag(TIF_32BIT)) { | 123 | if (target == current) |
| 181 | addr &= 0xffffffffUL; | 124 | flushw_user(); |
| 182 | data &= 0xffffffffUL; | 125 | |
| 183 | addr2 &= 0xffffffffUL; | 126 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
| 127 | regs->u_regs, | ||
| 128 | 0, 16 * sizeof(u64)); | ||
| 129 | if (!ret) { | ||
| 130 | unsigned long __user *reg_window = (unsigned long __user *) | ||
| 131 | (regs->u_regs[UREG_I6] + STACK_BIAS); | ||
| 132 | unsigned long window[16]; | ||
| 133 | |||
| 134 | if (copy_from_user(window, reg_window, sizeof(window))) | ||
| 135 | return -EFAULT; | ||
| 136 | |||
| 137 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
| 138 | window, | ||
| 139 | 16 * sizeof(u64), | ||
| 140 | 32 * sizeof(u64)); | ||
| 184 | } | 141 | } |
| 185 | lock_kernel(); | ||
| 186 | #ifdef DEBUG_PTRACE | ||
| 187 | { | ||
| 188 | char *s; | ||
| 189 | 142 | ||
| 190 | if ((request >= 0) && (request <= 24)) | 143 | if (!ret) { |
| 191 | s = pt_rq [request]; | 144 | /* TSTATE, TPC, TNPC */ |
| 192 | else | 145 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
| 193 | s = "unknown"; | 146 | ®s->tstate, |
| 147 | 32 * sizeof(u64), | ||
| 148 | 35 * sizeof(u64)); | ||
| 149 | } | ||
| 150 | |||
| 151 | if (!ret) { | ||
| 152 | unsigned long y = regs->y; | ||
| 194 | 153 | ||
| 195 | if (request == PTRACE_POKEDATA && data == 0x91d02001){ | 154 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
| 196 | printk ("do_ptrace: breakpoint pid=%d, addr=%016lx addr2=%016lx\n", | 155 | &y, |
| 197 | pid, addr, addr2); | 156 | 35 * sizeof(u64), |
| 198 | } else | 157 | 36 * sizeof(u64)); |
| 199 | printk("do_ptrace: rq=%s(%d) pid=%d addr=%016lx data=%016lx addr2=%016lx\n", | ||
| 200 | s, request, pid, addr, data, addr2); | ||
| 201 | } | 158 | } |
| 202 | #endif | 159 | |
| 203 | if (request == PTRACE_TRACEME) { | 160 | if (!ret) |
| 204 | ret = ptrace_traceme(); | 161 | ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, |
| 205 | if (ret < 0) | 162 | 36 * sizeof(u64), -1); |
| 206 | pt_error_return(regs, -ret); | 163 | |
| 164 | return ret; | ||
| 165 | } | ||
| 166 | |||
| 167 | static int genregs64_set(struct task_struct *target, | ||
| 168 | const struct user_regset *regset, | ||
| 169 | unsigned int pos, unsigned int count, | ||
| 170 | const void *kbuf, const void __user *ubuf) | ||
| 171 | { | ||
| 172 | struct pt_regs *regs = task_pt_regs(target); | ||
| 173 | int ret; | ||
| 174 | |||
| 175 | if (target == current) | ||
| 176 | flushw_user(); | ||
| 177 | |||
| 178 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
| 179 | regs->u_regs, | ||
| 180 | 0, 16 * sizeof(u64)); | ||
| 181 | if (!ret && count > 0) { | ||
| 182 | unsigned long __user *reg_window = (unsigned long __user *) | ||
| 183 | (regs->u_regs[UREG_I6] + STACK_BIAS); | ||
| 184 | unsigned long window[16]; | ||
| 185 | |||
| 186 | if (copy_from_user(window, reg_window, sizeof(window))) | ||
| 187 | return -EFAULT; | ||
| 188 | |||
| 189 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
| 190 | window, | ||
| 191 | 16 * sizeof(u64), | ||
| 192 | 32 * sizeof(u64)); | ||
| 193 | if (!ret && | ||
| 194 | copy_to_user(reg_window, window, sizeof(window))) | ||
| 195 | return -EFAULT; | ||
| 196 | } | ||
| 197 | |||
| 198 | if (!ret && count > 0) { | ||
| 199 | unsigned long tstate; | ||
| 200 | |||
| 201 | /* TSTATE */ | ||
| 202 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
| 203 | &tstate, | ||
| 204 | 32 * sizeof(u64), | ||
| 205 | 33 * sizeof(u64)); | ||
| 206 | if (!ret) { | ||
| 207 | /* Only the condition codes can be modified | ||
| 208 | * in the %tstate register. | ||
| 209 | */ | ||
| 210 | tstate &= (TSTATE_ICC | TSTATE_XCC); | ||
| 211 | regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC); | ||
| 212 | regs->tstate |= tstate; | ||
| 213 | } | ||
| 214 | } | ||
| 215 | |||
| 216 | if (!ret) { | ||
| 217 | /* TPC, TNPC */ | ||
| 218 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
| 219 | ®s->tpc, | ||
| 220 | 33 * sizeof(u64), | ||
| 221 | 35 * sizeof(u64)); | ||
| 222 | } | ||
| 223 | |||
| 224 | if (!ret) { | ||
| 225 | unsigned long y; | ||
| 226 | |||
| 227 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
| 228 | &y, | ||
| 229 | 35 * sizeof(u64), | ||
| 230 | 36 * sizeof(u64)); | ||
| 231 | if (!ret) | ||
| 232 | regs->y = y; | ||
| 233 | } | ||
| 234 | |||
| 235 | if (!ret) | ||
| 236 | ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, | ||
| 237 | 36 * sizeof(u64), -1); | ||
| 238 | |||
| 239 | return ret; | ||
| 240 | } | ||
| 241 | |||
| 242 | static int fpregs64_get(struct task_struct *target, | ||
| 243 | const struct user_regset *regset, | ||
| 244 | unsigned int pos, unsigned int count, | ||
| 245 | void *kbuf, void __user *ubuf) | ||
| 246 | { | ||
| 247 | const unsigned long *fpregs = task_thread_info(target)->fpregs; | ||
| 248 | unsigned long fprs, fsr, gsr; | ||
| 249 | int ret; | ||
| 250 | |||
| 251 | if (target == current) | ||
| 252 | save_and_clear_fpu(); | ||
| 253 | |||
| 254 | fprs = task_thread_info(target)->fpsaved[0]; | ||
| 255 | |||
| 256 | if (fprs & FPRS_DL) | ||
| 257 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
| 258 | fpregs, | ||
| 259 | 0, 16 * sizeof(u64)); | ||
| 260 | else | ||
| 261 | ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, | ||
| 262 | 0, | ||
| 263 | 16 * sizeof(u64)); | ||
| 264 | |||
| 265 | if (!ret) { | ||
| 266 | if (fprs & FPRS_DU) | ||
| 267 | ret = user_regset_copyout(&pos, &count, | ||
| 268 | &kbuf, &ubuf, | ||
| 269 | fpregs + 16, | ||
| 270 | 16 * sizeof(u64), | ||
| 271 | 32 * sizeof(u64)); | ||
| 207 | else | 272 | else |
| 208 | pt_succ_return(regs, 0); | 273 | ret = user_regset_copyout_zero(&pos, &count, |
| 209 | goto out; | 274 | &kbuf, &ubuf, |
| 275 | 16 * sizeof(u64), | ||
| 276 | 32 * sizeof(u64)); | ||
| 210 | } | 277 | } |
| 211 | 278 | ||
| 212 | child = ptrace_get_task_struct(pid); | 279 | if (fprs & FPRS_FEF) { |
| 213 | if (IS_ERR(child)) { | 280 | fsr = task_thread_info(target)->xfsr[0]; |
| 214 | ret = PTR_ERR(child); | 281 | gsr = task_thread_info(target)->gsr[0]; |
| 215 | pt_error_return(regs, -ret); | 282 | } else { |
| 216 | goto out; | 283 | fsr = gsr = 0; |
| 217 | } | 284 | } |
| 218 | 285 | ||
| 219 | if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH) | 286 | if (!ret) |
| 220 | || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) { | 287 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
| 221 | if (ptrace_attach(child)) { | 288 | &fsr, |
| 222 | pt_error_return(regs, EPERM); | 289 | 32 * sizeof(u64), |
| 223 | goto out_tsk; | 290 | 33 * sizeof(u64)); |
| 291 | if (!ret) | ||
| 292 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
| 293 | &gsr, | ||
| 294 | 33 * sizeof(u64), | ||
| 295 | 34 * sizeof(u64)); | ||
| 296 | if (!ret) | ||
| 297 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
| 298 | &fprs, | ||
| 299 | 34 * sizeof(u64), | ||
| 300 | 35 * sizeof(u64)); | ||
| 301 | |||
| 302 | if (!ret) | ||
| 303 | ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, | ||
| 304 | 35 * sizeof(u64), -1); | ||
| 305 | |||
| 306 | return ret; | ||
| 307 | } | ||
| 308 | |||
| 309 | static int fpregs64_set(struct task_struct *target, | ||
| 310 | const struct user_regset *regset, | ||
| 311 | unsigned int pos, unsigned int count, | ||
| 312 | const void *kbuf, const void __user *ubuf) | ||
| 313 | { | ||
| 314 | unsigned long *fpregs = task_thread_info(target)->fpregs; | ||
| 315 | unsigned long fprs; | ||
| 316 | int ret; | ||
| 317 | |||
| 318 | if (target == current) | ||
| 319 | save_and_clear_fpu(); | ||
| 320 | |||
| 321 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
| 322 | fpregs, | ||
| 323 | 0, 32 * sizeof(u64)); | ||
| 324 | if (!ret) | ||
| 325 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
| 326 | task_thread_info(target)->xfsr, | ||
| 327 | 32 * sizeof(u64), | ||
| 328 | 33 * sizeof(u64)); | ||
| 329 | if (!ret) | ||
| 330 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
| 331 | task_thread_info(target)->gsr, | ||
| 332 | 33 * sizeof(u64), | ||
| 333 | 34 * sizeof(u64)); | ||
| 334 | |||
| 335 | fprs = task_thread_info(target)->fpsaved[0]; | ||
| 336 | if (!ret && count > 0) { | ||
| 337 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
| 338 | &fprs, | ||
| 339 | 34 * sizeof(u64), | ||
| 340 | 35 * sizeof(u64)); | ||
| 341 | } | ||
| 342 | |||
| 343 | fprs |= (FPRS_FEF | FPRS_DL | FPRS_DU); | ||
| 344 | task_thread_info(target)->fpsaved[0] = fprs; | ||
| 345 | |||
| 346 | if (!ret) | ||
| 347 | ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, | ||
| 348 | 35 * sizeof(u64), -1); | ||
| 349 | return ret; | ||
| 350 | } | ||
| 351 | |||
| 352 | static const struct user_regset sparc64_regsets[] = { | ||
| 353 | /* Format is: | ||
| 354 | * G0 --> G7 | ||
| 355 | * O0 --> O7 | ||
| 356 | * L0 --> L7 | ||
| 357 | * I0 --> I7 | ||
| 358 | * TSTATE, TPC, TNPC, Y | ||
| 359 | */ | ||
| 360 | [REGSET_GENERAL] = { | ||
| 361 | .core_note_type = NT_PRSTATUS, | ||
| 362 | .n = 36 * sizeof(u64), | ||
| 363 | .size = sizeof(u64), .align = sizeof(u64), | ||
| 364 | .get = genregs64_get, .set = genregs64_set | ||
| 365 | }, | ||
| 366 | /* Format is: | ||
| 367 | * F0 --> F63 | ||
| 368 | * FSR | ||
| 369 | * GSR | ||
| 370 | * FPRS | ||
| 371 | */ | ||
| 372 | [REGSET_FP] = { | ||
| 373 | .core_note_type = NT_PRFPREG, | ||
| 374 | .n = 35 * sizeof(u64), | ||
| 375 | .size = sizeof(u64), .align = sizeof(u64), | ||
| 376 | .get = fpregs64_get, .set = fpregs64_set | ||
| 377 | }, | ||
| 378 | }; | ||
| 379 | |||
| 380 | static const struct user_regset_view user_sparc64_view = { | ||
| 381 | .name = "sparc64", .e_machine = EM_SPARCV9, | ||
| 382 | .regsets = sparc64_regsets, .n = ARRAY_SIZE(sparc64_regsets) | ||
| 383 | }; | ||
| 384 | |||
| 385 | static int genregs32_get(struct task_struct *target, | ||
| 386 | const struct user_regset *regset, | ||
| 387 | unsigned int pos, unsigned int count, | ||
| 388 | void *kbuf, void __user *ubuf) | ||
| 389 | { | ||
| 390 | const struct pt_regs *regs = task_pt_regs(target); | ||
| 391 | compat_ulong_t __user *reg_window; | ||
| 392 | compat_ulong_t *k = kbuf; | ||
| 393 | compat_ulong_t __user *u = ubuf; | ||
| 394 | compat_ulong_t reg; | ||
| 395 | |||
| 396 | if (target == current) | ||
| 397 | flushw_user(); | ||
| 398 | |||
| 399 | pos /= sizeof(reg); | ||
| 400 | count /= sizeof(reg); | ||
| 401 | |||
| 402 | if (kbuf) { | ||
| 403 | for (; count > 0 && pos < 16; count--) | ||
| 404 | *k++ = regs->u_regs[pos++]; | ||
| 405 | |||
| 406 | reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; | ||
| 407 | for (; count > 0 && pos < 32; count--) { | ||
| 408 | if (get_user(*k++, ®_window[pos++])) | ||
| 409 | return -EFAULT; | ||
| 410 | } | ||
| 411 | } else { | ||
| 412 | for (; count > 0 && pos < 16; count--) { | ||
| 413 | if (put_user((compat_ulong_t) regs->u_regs[pos++], u++)) | ||
| 414 | return -EFAULT; | ||
| 415 | } | ||
| 416 | |||
| 417 | reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; | ||
| 418 | for (; count > 0 && pos < 32; count--) { | ||
| 419 | if (get_user(reg, ®_window[pos++]) || | ||
| 420 | put_user(reg, u++)) | ||
| 421 | return -EFAULT; | ||
| 224 | } | 422 | } |
| 225 | pt_succ_return(regs, 0); | ||
| 226 | goto out_tsk; | ||
| 227 | } | 423 | } |
| 424 | while (count > 0) { | ||
| 425 | switch (pos) { | ||
| 426 | case 32: /* PSR */ | ||
| 427 | reg = tstate_to_psr(regs->tstate); | ||
| 428 | break; | ||
| 429 | case 33: /* PC */ | ||
| 430 | reg = regs->tpc; | ||
| 431 | break; | ||
| 432 | case 34: /* NPC */ | ||
| 433 | reg = regs->tnpc; | ||
| 434 | break; | ||
| 435 | case 35: /* Y */ | ||
| 436 | reg = regs->y; | ||
| 437 | break; | ||
| 438 | case 36: /* WIM */ | ||
| 439 | case 37: /* TBR */ | ||
| 440 | reg = 0; | ||
| 441 | break; | ||
| 442 | default: | ||
| 443 | goto finish; | ||
| 444 | } | ||
| 228 | 445 | ||
| 229 | ret = ptrace_check_attach(child, request == PTRACE_KILL); | 446 | if (kbuf) |
| 230 | if (ret < 0) { | 447 | *k++ = reg; |
| 231 | pt_error_return(regs, -ret); | 448 | else if (put_user(reg, u++)) |
| 232 | goto out_tsk; | 449 | return -EFAULT; |
| 450 | pos++; | ||
| 451 | count--; | ||
| 233 | } | 452 | } |
| 453 | finish: | ||
| 454 | pos *= sizeof(reg); | ||
| 455 | count *= sizeof(reg); | ||
| 456 | |||
| 457 | return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, | ||
| 458 | 38 * sizeof(reg), -1); | ||
| 459 | } | ||
| 234 | 460 | ||
| 235 | if (!(test_thread_flag(TIF_32BIT)) && | 461 | static int genregs32_set(struct task_struct *target, |
| 236 | ((request == PTRACE_READDATA64) || | 462 | const struct user_regset *regset, |
| 237 | (request == PTRACE_WRITEDATA64) || | 463 | unsigned int pos, unsigned int count, |
| 238 | (request == PTRACE_READTEXT64) || | 464 | const void *kbuf, const void __user *ubuf) |
| 239 | (request == PTRACE_WRITETEXT64) || | 465 | { |
| 240 | (request == PTRACE_PEEKTEXT64) || | 466 | struct pt_regs *regs = task_pt_regs(target); |
| 241 | (request == PTRACE_POKETEXT64) || | 467 | compat_ulong_t __user *reg_window; |
| 242 | (request == PTRACE_PEEKDATA64) || | 468 | const compat_ulong_t *k = kbuf; |
| 243 | (request == PTRACE_POKEDATA64))) { | 469 | const compat_ulong_t __user *u = ubuf; |
| 244 | addr = regs->u_regs[UREG_G2]; | 470 | compat_ulong_t reg; |
| 245 | addr2 = regs->u_regs[UREG_G3]; | 471 | |
| 246 | request -= 30; /* wheee... */ | 472 | if (target == current) |
| 473 | flushw_user(); | ||
| 474 | |||
| 475 | pos /= sizeof(reg); | ||
| 476 | count /= sizeof(reg); | ||
| 477 | |||
| 478 | if (kbuf) { | ||
| 479 | for (; count > 0 && pos < 16; count--) | ||
| 480 | regs->u_regs[pos++] = *k++; | ||
| 481 | |||
| 482 | reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; | ||
| 483 | for (; count > 0 && pos < 32; count--) { | ||
| 484 | if (put_user(*k++, ®_window[pos++])) | ||
| 485 | return -EFAULT; | ||
| 486 | } | ||
| 487 | } else { | ||
| 488 | for (; count > 0 && pos < 16; count--) { | ||
| 489 | if (get_user(reg, u++)) | ||
| 490 | return -EFAULT; | ||
| 491 | regs->u_regs[pos++] = reg; | ||
| 492 | } | ||
| 493 | |||
| 494 | reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; | ||
| 495 | for (; count > 0 && pos < 32; count--) { | ||
| 496 | if (get_user(reg, u++) || | ||
| 497 | put_user(reg, ®_window[pos++])) | ||
| 498 | return -EFAULT; | ||
| 499 | } | ||
| 247 | } | 500 | } |
| 501 | while (count > 0) { | ||
| 502 | unsigned long tstate; | ||
| 503 | |||
| 504 | if (kbuf) | ||
| 505 | reg = *k++; | ||
| 506 | else if (get_user(reg, u++)) | ||
| 507 | return -EFAULT; | ||
| 508 | |||
| 509 | switch (pos) { | ||
| 510 | case 32: /* PSR */ | ||
| 511 | tstate = regs->tstate; | ||
| 512 | tstate &= ~(TSTATE_ICC | TSTATE_XCC); | ||
| 513 | tstate |= psr_to_tstate_icc(reg); | ||
| 514 | regs->tstate = tstate; | ||
| 515 | break; | ||
| 516 | case 33: /* PC */ | ||
| 517 | regs->tpc = reg; | ||
| 518 | break; | ||
| 519 | case 34: /* NPC */ | ||
| 520 | regs->tnpc = reg; | ||
| 521 | break; | ||
| 522 | case 35: /* Y */ | ||
| 523 | regs->y = reg; | ||
| 524 | break; | ||
| 525 | case 36: /* WIM */ | ||
| 526 | case 37: /* TBR */ | ||
| 527 | break; | ||
| 528 | default: | ||
| 529 | goto finish; | ||
| 530 | } | ||
| 531 | |||
| 532 | pos++; | ||
| 533 | count--; | ||
| 534 | } | ||
| 535 | finish: | ||
| 536 | pos *= sizeof(reg); | ||
| 537 | count *= sizeof(reg); | ||
| 538 | |||
| 539 | return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, | ||
| 540 | 38 * sizeof(reg), -1); | ||
| 541 | } | ||
| 542 | |||
| 543 | static int fpregs32_get(struct task_struct *target, | ||
| 544 | const struct user_regset *regset, | ||
| 545 | unsigned int pos, unsigned int count, | ||
| 546 | void *kbuf, void __user *ubuf) | ||
| 547 | { | ||
| 548 | const unsigned long *fpregs = task_thread_info(target)->fpregs; | ||
| 549 | compat_ulong_t enabled; | ||
| 550 | unsigned long fprs; | ||
| 551 | compat_ulong_t fsr; | ||
| 552 | int ret = 0; | ||
| 553 | |||
| 554 | if (target == current) | ||
| 555 | save_and_clear_fpu(); | ||
| 556 | |||
| 557 | fprs = task_thread_info(target)->fpsaved[0]; | ||
| 558 | if (fprs & FPRS_FEF) { | ||
| 559 | fsr = task_thread_info(target)->xfsr[0]; | ||
| 560 | enabled = 1; | ||
| 561 | } else { | ||
| 562 | fsr = 0; | ||
| 563 | enabled = 0; | ||
| 564 | } | ||
| 565 | |||
| 566 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
| 567 | fpregs, | ||
| 568 | 0, 32 * sizeof(u32)); | ||
| 569 | |||
| 570 | if (!ret) | ||
| 571 | ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, | ||
| 572 | 32 * sizeof(u32), | ||
| 573 | 33 * sizeof(u32)); | ||
| 574 | if (!ret) | ||
| 575 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
| 576 | &fsr, | ||
| 577 | 33 * sizeof(u32), | ||
| 578 | 34 * sizeof(u32)); | ||
| 579 | |||
| 580 | if (!ret) { | ||
| 581 | compat_ulong_t val; | ||
| 582 | |||
| 583 | val = (enabled << 8) | (8 << 16); | ||
| 584 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
| 585 | &val, | ||
| 586 | 34 * sizeof(u32), | ||
| 587 | 35 * sizeof(u32)); | ||
| 588 | } | ||
| 589 | |||
| 590 | if (!ret) | ||
| 591 | ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, | ||
| 592 | 35 * sizeof(u32), -1); | ||
| 593 | |||
| 594 | return ret; | ||
| 595 | } | ||
| 596 | |||
| 597 | static int fpregs32_set(struct task_struct *target, | ||
| 598 | const struct user_regset *regset, | ||
| 599 | unsigned int pos, unsigned int count, | ||
| 600 | const void *kbuf, const void __user *ubuf) | ||
| 601 | { | ||
| 602 | unsigned long *fpregs = task_thread_info(target)->fpregs; | ||
| 603 | unsigned long fprs; | ||
| 604 | int ret; | ||
| 605 | |||
| 606 | if (target == current) | ||
| 607 | save_and_clear_fpu(); | ||
| 608 | |||
| 609 | fprs = task_thread_info(target)->fpsaved[0]; | ||
| 610 | |||
| 611 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
| 612 | fpregs, | ||
| 613 | 0, 32 * sizeof(u32)); | ||
| 614 | if (!ret) | ||
| 615 | user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, | ||
| 616 | 32 * sizeof(u32), | ||
| 617 | 33 * sizeof(u32)); | ||
| 618 | if (!ret && count > 0) { | ||
| 619 | compat_ulong_t fsr; | ||
| 620 | unsigned long val; | ||
| 621 | |||
| 622 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
| 623 | &fsr, | ||
| 624 | 33 * sizeof(u32), | ||
| 625 | 34 * sizeof(u32)); | ||
| 626 | if (!ret) { | ||
| 627 | val = task_thread_info(target)->xfsr[0]; | ||
| 628 | val &= 0xffffffff00000000UL; | ||
| 629 | val |= fsr; | ||
| 630 | task_thread_info(target)->xfsr[0] = val; | ||
| 631 | } | ||
| 632 | } | ||
| 633 | |||
| 634 | fprs |= (FPRS_FEF | FPRS_DL); | ||
| 635 | task_thread_info(target)->fpsaved[0] = fprs; | ||
| 636 | |||
| 637 | if (!ret) | ||
| 638 | ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, | ||
| 639 | 34 * sizeof(u32), -1); | ||
| 640 | return ret; | ||
| 641 | } | ||
| 642 | |||
| 643 | static const struct user_regset sparc32_regsets[] = { | ||
| 644 | /* Format is: | ||
| 645 | * G0 --> G7 | ||
| 646 | * O0 --> O7 | ||
| 647 | * L0 --> L7 | ||
| 648 | * I0 --> I7 | ||
| 649 | * PSR, PC, nPC, Y, WIM, TBR | ||
| 650 | */ | ||
| 651 | [REGSET_GENERAL] = { | ||
| 652 | .core_note_type = NT_PRSTATUS, | ||
| 653 | .n = 38 * sizeof(u32), | ||
| 654 | .size = sizeof(u32), .align = sizeof(u32), | ||
| 655 | .get = genregs32_get, .set = genregs32_set | ||
| 656 | }, | ||
| 657 | /* Format is: | ||
| 658 | * F0 --> F31 | ||
| 659 | * empty 32-bit word | ||
| 660 | * FSR (32--bit word) | ||
| 661 | * FPU QUEUE COUNT (8-bit char) | ||
| 662 | * FPU QUEUE ENTRYSIZE (8-bit char) | ||
| 663 | * FPU ENABLED (8-bit char) | ||
| 664 | * empty 8-bit char | ||
| 665 | * FPU QUEUE (64 32-bit ints) | ||
| 666 | */ | ||
| 667 | [REGSET_FP] = { | ||
| 668 | .core_note_type = NT_PRFPREG, | ||
| 669 | .n = 99 * sizeof(u32), | ||
| 670 | .size = sizeof(u32), .align = sizeof(u32), | ||
| 671 | .get = fpregs32_get, .set = fpregs32_set | ||
| 672 | }, | ||
| 673 | }; | ||
| 674 | |||
| 675 | static const struct user_regset_view user_sparc32_view = { | ||
| 676 | .name = "sparc", .e_machine = EM_SPARC, | ||
| 677 | .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets) | ||
| 678 | }; | ||
| 679 | |||
| 680 | const struct user_regset_view *task_user_regset_view(struct task_struct *task) | ||
| 681 | { | ||
| 682 | if (test_tsk_thread_flag(task, TIF_32BIT)) | ||
| 683 | return &user_sparc32_view; | ||
| 684 | return &user_sparc64_view; | ||
| 685 | } | ||
| 686 | |||
| 687 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) | ||
| 688 | { | ||
| 689 | long addr2 = task_pt_regs(current)->u_regs[UREG_I4]; | ||
| 690 | const struct user_regset_view *view; | ||
| 691 | int ret; | ||
| 692 | |||
| 693 | if (test_thread_flag(TIF_32BIT)) | ||
| 694 | addr2 &= 0xffffffffUL; | ||
| 695 | |||
| 696 | view = task_user_regset_view(child); | ||
| 248 | 697 | ||
| 249 | switch(request) { | 698 | switch(request) { |
| 250 | case PTRACE_PEEKUSR: | 699 | case PTRACE_PEEKUSR: |
| 251 | if (addr != 0) | 700 | ret = (addr != 0) ? -EIO : 0; |
| 252 | pt_error_return(regs, EIO); | 701 | break; |
| 253 | else | ||
| 254 | pt_succ_return(regs, 0); | ||
| 255 | goto out_tsk; | ||
| 256 | 702 | ||
| 257 | case PTRACE_PEEKTEXT: /* read word at location addr. */ | 703 | case PTRACE_PEEKTEXT: /* read word at location addr. */ |
| 258 | case PTRACE_PEEKDATA: { | 704 | case PTRACE_PEEKDATA: { |
| 259 | unsigned long tmp64; | 705 | unsigned long tmp64; |
| 260 | unsigned int tmp32; | 706 | unsigned int tmp32; |
| 261 | int res, copied; | 707 | int copied; |
| 262 | 708 | ||
| 263 | res = -EIO; | 709 | ret = -EIO; |
| 264 | if (test_thread_flag(TIF_32BIT)) { | 710 | if (test_thread_flag(TIF_32BIT)) { |
| 265 | copied = access_process_vm(child, addr, | 711 | copied = access_process_vm(child, addr, |
| 266 | &tmp32, sizeof(tmp32), 0); | 712 | &tmp32, sizeof(tmp32), 0); |
| 267 | tmp64 = (unsigned long) tmp32; | ||
| 268 | if (copied == sizeof(tmp32)) | 713 | if (copied == sizeof(tmp32)) |
| 269 | res = 0; | 714 | ret = put_user(tmp32, |
| 715 | (unsigned int __user *) data); | ||
| 270 | } else { | 716 | } else { |
| 271 | copied = access_process_vm(child, addr, | 717 | copied = access_process_vm(child, addr, |
| 272 | &tmp64, sizeof(tmp64), 0); | 718 | &tmp64, sizeof(tmp64), 0); |
| 273 | if (copied == sizeof(tmp64)) | 719 | if (copied == sizeof(tmp64)) |
| 274 | res = 0; | 720 | ret = put_user(tmp64, |
| 721 | (unsigned long __user *) data); | ||
| 275 | } | 722 | } |
| 276 | if (res < 0) | 723 | break; |
| 277 | pt_error_return(regs, -res); | ||
| 278 | else | ||
| 279 | pt_os_succ_return(regs, tmp64, (void __user *) data); | ||
| 280 | goto out_tsk; | ||
| 281 | } | 724 | } |
| 282 | 725 | ||
| 283 | case PTRACE_POKETEXT: /* write the word at location addr. */ | 726 | case PTRACE_POKETEXT: /* write the word at location addr. */ |
| 284 | case PTRACE_POKEDATA: { | 727 | case PTRACE_POKEDATA: { |
| 285 | unsigned long tmp64; | 728 | unsigned long tmp64; |
| 286 | unsigned int tmp32; | 729 | unsigned int tmp32; |
| 287 | int copied, res = -EIO; | 730 | int copied; |
| 288 | 731 | ||
| 732 | ret = -EIO; | ||
| 289 | if (test_thread_flag(TIF_32BIT)) { | 733 | if (test_thread_flag(TIF_32BIT)) { |
| 290 | tmp32 = data; | 734 | tmp32 = data; |
| 291 | copied = access_process_vm(child, addr, | 735 | copied = access_process_vm(child, addr, |
| 292 | &tmp32, sizeof(tmp32), 1); | 736 | &tmp32, sizeof(tmp32), 1); |
| 293 | if (copied == sizeof(tmp32)) | 737 | if (copied == sizeof(tmp32)) |
| 294 | res = 0; | 738 | ret = 0; |
| 295 | } else { | 739 | } else { |
| 296 | tmp64 = data; | 740 | tmp64 = data; |
| 297 | copied = access_process_vm(child, addr, | 741 | copied = access_process_vm(child, addr, |
| 298 | &tmp64, sizeof(tmp64), 1); | 742 | &tmp64, sizeof(tmp64), 1); |
| 299 | if (copied == sizeof(tmp64)) | 743 | if (copied == sizeof(tmp64)) |
| 300 | res = 0; | 744 | ret = 0; |
| 301 | } | 745 | } |
| 302 | if (res < 0) | 746 | break; |
| 303 | pt_error_return(regs, -res); | ||
| 304 | else | ||
| 305 | pt_succ_return(regs, res); | ||
| 306 | goto out_tsk; | ||
| 307 | } | 747 | } |
| 308 | 748 | ||
| 309 | case PTRACE_GETREGS: { | 749 | case PTRACE_GETREGS: { |
| 310 | struct pt_regs32 __user *pregs = | 750 | struct pt_regs32 __user *pregs = |
| 311 | (struct pt_regs32 __user *) addr; | 751 | (struct pt_regs32 __user *) addr; |
| 312 | struct pt_regs *cregs = task_pt_regs(child); | 752 | |
| 313 | int rval; | 753 | ret = copy_regset_to_user(child, view, REGSET_GENERAL, |
| 314 | 754 | 32 * sizeof(u32), | |
| 315 | if (__put_user(tstate_to_psr(cregs->tstate), (&pregs->psr)) || | 755 | 4 * sizeof(u32), |
| 316 | __put_user(cregs->tpc, (&pregs->pc)) || | 756 | &pregs->psr); |
| 317 | __put_user(cregs->tnpc, (&pregs->npc)) || | 757 | if (!ret) |
| 318 | __put_user(cregs->y, (&pregs->y))) { | 758 | ret = copy_regset_to_user(child, view, REGSET_GENERAL, |
| 319 | pt_error_return(regs, EFAULT); | 759 | 1 * sizeof(u32), |
| 320 | goto out_tsk; | 760 | 15 * sizeof(u32), |
| 321 | } | 761 | &pregs->u_regs[0]); |
| 322 | for (rval = 1; rval < 16; rval++) | 762 | break; |
| 323 | if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) { | ||
| 324 | pt_error_return(regs, EFAULT); | ||
| 325 | goto out_tsk; | ||
| 326 | } | ||
| 327 | pt_succ_return(regs, 0); | ||
| 328 | #ifdef DEBUG_PTRACE | ||
| 329 | printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]); | ||
| 330 | #endif | ||
| 331 | goto out_tsk; | ||
| 332 | } | 763 | } |
| 333 | 764 | ||
| 334 | case PTRACE_GETREGS64: { | 765 | case PTRACE_GETREGS64: { |
| 335 | struct pt_regs __user *pregs = (struct pt_regs __user *) addr; | 766 | struct pt_regs __user *pregs = (struct pt_regs __user *) addr; |
| 336 | struct pt_regs *cregs = task_pt_regs(child); | 767 | |
| 337 | unsigned long tpc = cregs->tpc; | 768 | ret = copy_regset_to_user(child, view, REGSET_GENERAL, |
| 338 | int rval; | 769 | 1 * sizeof(u64), |
| 339 | 770 | 15 * sizeof(u64), | |
| 340 | if ((task_thread_info(child)->flags & _TIF_32BIT) != 0) | 771 | &pregs->u_regs[0]); |
| 341 | tpc &= 0xffffffff; | 772 | if (!ret) { |
| 342 | if (__put_user(cregs->tstate, (&pregs->tstate)) || | 773 | /* XXX doesn't handle 'y' register correctly XXX */ |
| 343 | __put_user(tpc, (&pregs->tpc)) || | 774 | ret = copy_regset_to_user(child, view, REGSET_GENERAL, |
| 344 | __put_user(cregs->tnpc, (&pregs->tnpc)) || | 775 | 32 * sizeof(u64), |
| 345 | __put_user(cregs->y, (&pregs->y))) { | 776 | 4 * sizeof(u64), |
| 346 | pt_error_return(regs, EFAULT); | 777 | &pregs->tstate); |
| 347 | goto out_tsk; | ||
| 348 | } | 778 | } |
| 349 | for (rval = 1; rval < 16; rval++) | 779 | break; |
| 350 | if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) { | ||
| 351 | pt_error_return(regs, EFAULT); | ||
| 352 | goto out_tsk; | ||
| 353 | } | ||
| 354 | pt_succ_return(regs, 0); | ||
| 355 | #ifdef DEBUG_PTRACE | ||
| 356 | printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]); | ||
| 357 | #endif | ||
| 358 | goto out_tsk; | ||
| 359 | } | 780 | } |
| 360 | 781 | ||
| 361 | case PTRACE_SETREGS: { | 782 | case PTRACE_SETREGS: { |
| 362 | struct pt_regs32 __user *pregs = | 783 | struct pt_regs32 __user *pregs = |
| 363 | (struct pt_regs32 __user *) addr; | 784 | (struct pt_regs32 __user *) addr; |
| 364 | struct pt_regs *cregs = task_pt_regs(child); | 785 | |
| 365 | unsigned int psr, pc, npc, y; | 786 | ret = copy_regset_from_user(child, view, REGSET_GENERAL, |
| 366 | int i; | 787 | 32 * sizeof(u32), |
| 367 | 788 | 4 * sizeof(u32), | |
| 368 | /* Must be careful, tracing process can only set certain | 789 | &pregs->psr); |
| 369 | * bits in the psr. | 790 | if (!ret) |
| 370 | */ | 791 | ret = copy_regset_from_user(child, view, REGSET_GENERAL, |
| 371 | if (__get_user(psr, (&pregs->psr)) || | 792 | 1 * sizeof(u32), |
| 372 | __get_user(pc, (&pregs->pc)) || | 793 | 15 * sizeof(u32), |
| 373 | __get_user(npc, (&pregs->npc)) || | 794 | &pregs->u_regs[0]); |
| 374 | __get_user(y, (&pregs->y))) { | 795 | break; |
| 375 | pt_error_return(regs, EFAULT); | ||
| 376 | goto out_tsk; | ||
| 377 | } | ||
| 378 | cregs->tstate &= ~(TSTATE_ICC); | ||
| 379 | cregs->tstate |= psr_to_tstate_icc(psr); | ||
| 380 | if (!((pc | npc) & 3)) { | ||
| 381 | cregs->tpc = pc; | ||
| 382 | cregs->tnpc = npc; | ||
| 383 | } | ||
| 384 | cregs->y = y; | ||
| 385 | for (i = 1; i < 16; i++) { | ||
| 386 | if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) { | ||
| 387 | pt_error_return(regs, EFAULT); | ||
| 388 | goto out_tsk; | ||
| 389 | } | ||
| 390 | } | ||
| 391 | pt_succ_return(regs, 0); | ||
| 392 | goto out_tsk; | ||
| 393 | } | 796 | } |
| 394 | 797 | ||
| 395 | case PTRACE_SETREGS64: { | 798 | case PTRACE_SETREGS64: { |
| 396 | struct pt_regs __user *pregs = (struct pt_regs __user *) addr; | 799 | struct pt_regs __user *pregs = (struct pt_regs __user *) addr; |
| 397 | struct pt_regs *cregs = task_pt_regs(child); | 800 | |
| 398 | unsigned long tstate, tpc, tnpc, y; | 801 | ret = copy_regset_from_user(child, view, REGSET_GENERAL, |
| 399 | int i; | 802 | 1 * sizeof(u64), |
| 400 | 803 | 15 * sizeof(u64), | |
| 401 | /* Must be careful, tracing process can only set certain | 804 | &pregs->u_regs[0]); |
| 402 | * bits in the psr. | 805 | if (!ret) { |
| 403 | */ | 806 | /* XXX doesn't handle 'y' register correctly XXX */ |
| 404 | if (__get_user(tstate, (&pregs->tstate)) || | 807 | ret = copy_regset_from_user(child, view, REGSET_GENERAL, |
| 405 | __get_user(tpc, (&pregs->tpc)) || | 808 | 32 * sizeof(u64), |
| 406 | __get_user(tnpc, (&pregs->tnpc)) || | 809 | 4 * sizeof(u64), |
| 407 | __get_user(y, (&pregs->y))) { | 810 | &pregs->tstate); |
| 408 | pt_error_return(regs, EFAULT); | ||
| 409 | goto out_tsk; | ||
| 410 | } | ||
| 411 | if ((task_thread_info(child)->flags & _TIF_32BIT) != 0) { | ||
| 412 | tpc &= 0xffffffff; | ||
| 413 | tnpc &= 0xffffffff; | ||
| 414 | } | ||
| 415 | tstate &= (TSTATE_ICC | TSTATE_XCC); | ||
| 416 | cregs->tstate &= ~(TSTATE_ICC | TSTATE_XCC); | ||
| 417 | cregs->tstate |= tstate; | ||
| 418 | if (!((tpc | tnpc) & 3)) { | ||
| 419 | cregs->tpc = tpc; | ||
| 420 | cregs->tnpc = tnpc; | ||
| 421 | } | ||
| 422 | cregs->y = y; | ||
| 423 | for (i = 1; i < 16; i++) { | ||
| 424 | if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) { | ||
| 425 | pt_error_return(regs, EFAULT); | ||
| 426 | goto out_tsk; | ||
| 427 | } | ||
| 428 | } | 811 | } |
| 429 | pt_succ_return(regs, 0); | 812 | break; |
| 430 | goto out_tsk; | ||
| 431 | } | 813 | } |
| 432 | 814 | ||
| 433 | case PTRACE_GETFPREGS: { | 815 | case PTRACE_GETFPREGS: { |
| @@ -443,20 +825,24 @@ asmlinkage void do_ptrace(struct pt_regs *regs) | |||
| 443 | } fpq[16]; | 825 | } fpq[16]; |
| 444 | }; | 826 | }; |
| 445 | struct fps __user *fps = (struct fps __user *) addr; | 827 | struct fps __user *fps = (struct fps __user *) addr; |
| 446 | unsigned long *fpregs = task_thread_info(child)->fpregs; | 828 | |
| 447 | 829 | ret = copy_regset_to_user(child, view, REGSET_FP, | |
| 448 | if (copy_to_user(&fps->regs[0], fpregs, | 830 | 0 * sizeof(u32), |
| 449 | (32 * sizeof(unsigned int))) || | 831 | 32 * sizeof(u32), |
| 450 | __put_user(task_thread_info(child)->xfsr[0], (&fps->fsr)) || | 832 | &fps->regs[0]); |
| 451 | __put_user(0, (&fps->fpqd)) || | 833 | if (!ret) |
| 452 | __put_user(0, (&fps->flags)) || | 834 | ret = copy_regset_to_user(child, view, REGSET_FP, |
| 453 | __put_user(0, (&fps->extra)) || | 835 | 33 * sizeof(u32), |
| 454 | clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) { | 836 | 1 * sizeof(u32), |
| 455 | pt_error_return(regs, EFAULT); | 837 | &fps->fsr); |
| 456 | goto out_tsk; | 838 | if (!ret) { |
| 839 | if (__put_user(0, &fps->flags) || | ||
| 840 | __put_user(0, &fps->extra) || | ||
| 841 | __put_user(0, &fps->fpqd) || | ||
| 842 | clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) | ||
| 843 | ret = -EFAULT; | ||
| 457 | } | 844 | } |
| 458 | pt_succ_return(regs, 0); | 845 | break; |
| 459 | goto out_tsk; | ||
| 460 | } | 846 | } |
| 461 | 847 | ||
| 462 | case PTRACE_GETFPREGS64: { | 848 | case PTRACE_GETFPREGS64: { |
| @@ -465,16 +851,12 @@ asmlinkage void do_ptrace(struct pt_regs *regs) | |||
| 465 | unsigned long fsr; | 851 | unsigned long fsr; |
| 466 | }; | 852 | }; |
| 467 | struct fps __user *fps = (struct fps __user *) addr; | 853 | struct fps __user *fps = (struct fps __user *) addr; |
| 468 | unsigned long *fpregs = task_thread_info(child)->fpregs; | ||
| 469 | 854 | ||
| 470 | if (copy_to_user(&fps->regs[0], fpregs, | 855 | ret = copy_regset_to_user(child, view, REGSET_FP, |
| 471 | (64 * sizeof(unsigned int))) || | 856 | 0 * sizeof(u64), |
| 472 | __put_user(task_thread_info(child)->xfsr[0], (&fps->fsr))) { | 857 | 33 * sizeof(u64), |
| 473 | pt_error_return(regs, EFAULT); | 858 | fps); |
| 474 | goto out_tsk; | 859 | break; |
| 475 | } | ||
| 476 | pt_succ_return(regs, 0); | ||
| 477 | goto out_tsk; | ||
| 478 | } | 860 | } |
| 479 | 861 | ||
| 480 | case PTRACE_SETFPREGS: { | 862 | case PTRACE_SETFPREGS: { |
| @@ -490,22 +872,17 @@ asmlinkage void do_ptrace(struct pt_regs *regs) | |||
| 490 | } fpq[16]; | 872 | } fpq[16]; |
| 491 | }; | 873 | }; |
| 492 | struct fps __user *fps = (struct fps __user *) addr; | 874 | struct fps __user *fps = (struct fps __user *) addr; |
| 493 | unsigned long *fpregs = task_thread_info(child)->fpregs; | 875 | |
| 494 | unsigned fsr; | 876 | ret = copy_regset_from_user(child, view, REGSET_FP, |
| 495 | 877 | 0 * sizeof(u32), | |
| 496 | if (copy_from_user(fpregs, &fps->regs[0], | 878 | 32 * sizeof(u32), |
| 497 | (32 * sizeof(unsigned int))) || | 879 | &fps->regs[0]); |
| 498 | __get_user(fsr, (&fps->fsr))) { | 880 | if (!ret) |
| 499 | pt_error_return(regs, EFAULT); | 881 | ret = copy_regset_from_user(child, view, REGSET_FP, |
| 500 | goto out_tsk; | 882 | 33 * sizeof(u32), |
| 501 | } | 883 | 1 * sizeof(u32), |
| 502 | task_thread_info(child)->xfsr[0] &= 0xffffffff00000000UL; | 884 | &fps->fsr); |
| 503 | task_thread_info(child)->xfsr[0] |= fsr; | 885 | break; |
| 504 | if (!(task_thread_info(child)->fpsaved[0] & FPRS_FEF)) | ||
| 505 | task_thread_info(child)->gsr[0] = 0; | ||
| 506 | task_thread_info(child)->fpsaved[0] |= (FPRS_FEF | FPRS_DL); | ||
| 507 | pt_succ_return(regs, 0); | ||
| 508 | goto out_tsk; | ||
| 509 | } | 886 | } |
| 510 | 887 | ||
| 511 | case PTRACE_SETFPREGS64: { | 888 | case PTRACE_SETFPREGS64: { |
| @@ -514,134 +891,50 @@ asmlinkage void do_ptrace(struct pt_regs *regs) | |||
| 514 | unsigned long fsr; | 891 | unsigned long fsr; |
| 515 | }; | 892 | }; |
| 516 | struct fps __user *fps = (struct fps __user *) addr; | 893 | struct fps __user *fps = (struct fps __user *) addr; |
| 517 | unsigned long *fpregs = task_thread_info(child)->fpregs; | ||
| 518 | 894 | ||
| 519 | if (copy_from_user(fpregs, &fps->regs[0], | 895 | ret = copy_regset_to_user(child, view, REGSET_FP, |
| 520 | (64 * sizeof(unsigned int))) || | 896 | 0 * sizeof(u64), |
| 521 | __get_user(task_thread_info(child)->xfsr[0], (&fps->fsr))) { | 897 | 33 * sizeof(u64), |
| 522 | pt_error_return(regs, EFAULT); | 898 | fps); |
| 523 | goto out_tsk; | 899 | break; |
| 524 | } | ||
| 525 | if (!(task_thread_info(child)->fpsaved[0] & FPRS_FEF)) | ||
| 526 | task_thread_info(child)->gsr[0] = 0; | ||
| 527 | task_thread_info(child)->fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU); | ||
| 528 | pt_succ_return(regs, 0); | ||
| 529 | goto out_tsk; | ||
| 530 | } | 900 | } |
| 531 | 901 | ||
| 532 | case PTRACE_READTEXT: | 902 | case PTRACE_READTEXT: |
| 533 | case PTRACE_READDATA: { | 903 | case PTRACE_READDATA: |
| 534 | int res = ptrace_readdata(child, addr, | 904 | ret = ptrace_readdata(child, addr, |
| 535 | (char __user *)addr2, data); | 905 | (char __user *)addr2, data); |
| 536 | if (res == data) { | 906 | if (ret == data) |
| 537 | pt_succ_return(regs, 0); | 907 | ret = 0; |
| 538 | goto out_tsk; | 908 | else if (ret >= 0) |
| 539 | } | 909 | ret = -EIO; |
| 540 | if (res >= 0) | 910 | break; |
| 541 | res = -EIO; | ||
| 542 | pt_error_return(regs, -res); | ||
| 543 | goto out_tsk; | ||
| 544 | } | ||
| 545 | 911 | ||
| 546 | case PTRACE_WRITETEXT: | 912 | case PTRACE_WRITETEXT: |
| 547 | case PTRACE_WRITEDATA: { | 913 | case PTRACE_WRITEDATA: |
| 548 | int res = ptrace_writedata(child, (char __user *) addr2, | 914 | ret = ptrace_writedata(child, (char __user *) addr2, |
| 549 | addr, data); | 915 | addr, data); |
| 550 | if (res == data) { | 916 | if (ret == data) |
| 551 | pt_succ_return(regs, 0); | 917 | ret = 0; |
| 552 | goto out_tsk; | 918 | else if (ret >= 0) |
| 553 | } | 919 | ret = -EIO; |
| 554 | if (res >= 0) | 920 | break; |
| 555 | res = -EIO; | ||
| 556 | pt_error_return(regs, -res); | ||
| 557 | goto out_tsk; | ||
| 558 | } | ||
| 559 | case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */ | ||
| 560 | addr = 1; | ||
| 561 | |||
| 562 | case PTRACE_CONT: { /* restart after signal. */ | ||
| 563 | if (!valid_signal(data)) { | ||
| 564 | pt_error_return(regs, EIO); | ||
| 565 | goto out_tsk; | ||
| 566 | } | ||
| 567 | |||
| 568 | if (request == PTRACE_SYSCALL) { | ||
| 569 | set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
| 570 | } else { | ||
| 571 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
| 572 | } | ||
| 573 | |||
| 574 | child->exit_code = data; | ||
| 575 | #ifdef DEBUG_PTRACE | ||
| 576 | printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n", child->comm, | ||
| 577 | child->pid, child->exit_code, | ||
| 578 | task_pt_regs(child)->tpc, | ||
| 579 | task_pt_regs(child)->tnpc); | ||
| 580 | |||
| 581 | #endif | ||
| 582 | wake_up_process(child); | ||
| 583 | pt_succ_return(regs, 0); | ||
| 584 | goto out_tsk; | ||
| 585 | } | ||
| 586 | |||
| 587 | /* | ||
| 588 | * make the child exit. Best I can do is send it a sigkill. | ||
| 589 | * perhaps it should be put in the status that it wants to | ||
| 590 | * exit. | ||
| 591 | */ | ||
| 592 | case PTRACE_KILL: { | ||
| 593 | if (child->exit_state == EXIT_ZOMBIE) { /* already dead */ | ||
| 594 | pt_succ_return(regs, 0); | ||
| 595 | goto out_tsk; | ||
| 596 | } | ||
| 597 | child->exit_code = SIGKILL; | ||
| 598 | wake_up_process(child); | ||
| 599 | pt_succ_return(regs, 0); | ||
| 600 | goto out_tsk; | ||
| 601 | } | ||
| 602 | |||
| 603 | case PTRACE_SUNDETACH: { /* detach a process that was attached. */ | ||
| 604 | int error = ptrace_detach(child, data); | ||
| 605 | if (error) { | ||
| 606 | pt_error_return(regs, EIO); | ||
| 607 | goto out_tsk; | ||
| 608 | } | ||
| 609 | pt_succ_return(regs, 0); | ||
| 610 | goto out_tsk; | ||
| 611 | } | ||
| 612 | |||
| 613 | /* PTRACE_DUMPCORE unsupported... */ | ||
| 614 | 921 | ||
| 615 | case PTRACE_GETEVENTMSG: { | 922 | case PTRACE_GETEVENTMSG: { |
| 616 | int err; | ||
| 617 | |||
| 618 | if (test_thread_flag(TIF_32BIT)) | 923 | if (test_thread_flag(TIF_32BIT)) |
| 619 | err = put_user(child->ptrace_message, | 924 | ret = put_user(child->ptrace_message, |
| 620 | (unsigned int __user *) data); | 925 | (unsigned int __user *) data); |
| 621 | else | 926 | else |
| 622 | err = put_user(child->ptrace_message, | 927 | ret = put_user(child->ptrace_message, |
| 623 | (unsigned long __user *) data); | 928 | (unsigned long __user *) data); |
| 624 | if (err) | ||
| 625 | pt_error_return(regs, -err); | ||
| 626 | else | ||
| 627 | pt_succ_return(regs, 0); | ||
| 628 | break; | 929 | break; |
| 629 | } | 930 | } |
| 630 | 931 | ||
| 631 | default: { | 932 | default: |
| 632 | int err = ptrace_request(child, request, addr, data); | 933 | ret = ptrace_request(child, request, addr, data); |
| 633 | if (err) | 934 | break; |
| 634 | pt_error_return(regs, -err); | ||
| 635 | else | ||
| 636 | pt_succ_return(regs, 0); | ||
| 637 | goto out_tsk; | ||
| 638 | } | ||
| 639 | } | 935 | } |
| 640 | out_tsk: | 936 | |
| 641 | if (child) | 937 | return ret; |
| 642 | put_task_struct(child); | ||
| 643 | out: | ||
| 644 | unlock_kernel(); | ||
| 645 | } | 938 | } |
| 646 | 939 | ||
| 647 | asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p) | 940 | asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p) |
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) | |||
| 48 | prom_getstring(node, "version", prom_version, sizeof(prom_version)); | 48 | prom_getstring(node, "version", prom_version, sizeof(prom_version)); |
| 49 | 49 | ||
| 50 | prom_printf("\n"); | 50 | prom_printf("\n"); |
| 51 | } | ||
| 51 | 52 | ||
| 53 | void __init prom_init_report(void) | ||
| 54 | { | ||
| 52 | printk("PROMLIB: Sun IEEE Boot Prom '%s'\n", prom_version); | 55 | printk("PROMLIB: Sun IEEE Boot Prom '%s'\n", prom_version); |
| 53 | printk("PROMLIB: Root node compatible: %s\n", prom_root_compatible); | 56 | printk("PROMLIB: Root node compatible: %s\n", prom_root_compatible); |
| 54 | } | 57 | } |
diff --git a/include/asm-sparc/elf.h b/include/asm-sparc/elf.h index 668814e1e539..d2516eed3a38 100644 --- a/include/asm-sparc/elf.h +++ b/include/asm-sparc/elf.h | |||
| @@ -65,8 +65,14 @@ | |||
| 65 | #define HWCAP_SPARC_V9 16 | 65 | #define HWCAP_SPARC_V9 16 |
| 66 | #define HWCAP_SPARC_ULTRA3 32 | 66 | #define HWCAP_SPARC_ULTRA3 32 |
| 67 | 67 | ||
| 68 | /* For the most part we present code dumps in the format | 68 | #define CORE_DUMP_USE_REGSET |
| 69 | * Solaris does. | 69 | |
| 70 | /* Format is: | ||
| 71 | * G0 --> G7 | ||
| 72 | * O0 --> O7 | ||
| 73 | * L0 --> L7 | ||
| 74 | * I0 --> I7 | ||
| 75 | * PSR, PC, nPC, Y, WIM, TBR | ||
| 70 | */ | 76 | */ |
| 71 | typedef unsigned long elf_greg_t; | 77 | typedef unsigned long elf_greg_t; |
| 72 | #define ELF_NGREG 38 | 78 | #define ELF_NGREG 38 |
| @@ -86,34 +92,6 @@ typedef struct { | |||
| 86 | } elf_fpregset_t; | 92 | } elf_fpregset_t; |
| 87 | 93 | ||
| 88 | #include <asm/mbus.h> | 94 | #include <asm/mbus.h> |
| 89 | #include <asm/uaccess.h> | ||
| 90 | |||
| 91 | /* Format is: | ||
| 92 | * G0 --> G7 | ||
| 93 | * O0 --> O7 | ||
| 94 | * L0 --> L7 | ||
| 95 | * I0 --> I7 | ||
| 96 | * PSR, PC, nPC, Y, WIM, TBR | ||
| 97 | */ | ||
| 98 | #define ELF_CORE_COPY_REGS(__elf_regs, __pt_regs) \ | ||
| 99 | do { unsigned long *dest = &(__elf_regs[0]); \ | ||
| 100 | struct pt_regs *src = (__pt_regs); \ | ||
| 101 | unsigned long __user *sp; \ | ||
| 102 | memcpy(&dest[0], &src->u_regs[0], \ | ||
| 103 | sizeof(unsigned long) * 16); \ | ||
| 104 | /* Don't try this at home kids... */ \ | ||
| 105 | sp = (unsigned long __user *) src->u_regs[14]; \ | ||
| 106 | copy_from_user(&dest[16], sp, \ | ||
| 107 | sizeof(unsigned long) * 16); \ | ||
| 108 | dest[32] = src->psr; \ | ||
| 109 | dest[33] = src->pc; \ | ||
| 110 | dest[34] = src->npc; \ | ||
| 111 | dest[35] = src->y; \ | ||
| 112 | dest[36] = dest[37] = 0; /* XXX */ \ | ||
| 113 | } while(0); /* Janitors: Don't touch this semicolon. */ | ||
| 114 | |||
| 115 | #define ELF_CORE_COPY_TASK_REGS(__tsk, __elf_regs) \ | ||
| 116 | ({ ELF_CORE_COPY_REGS((*(__elf_regs)), (__tsk)->thread.kregs); 1; }) | ||
| 117 | 95 | ||
| 118 | /* | 96 | /* |
| 119 | * This is used to ensure we don't load something for the wrong architecture. | 97 | * This is used to ensure we don't load something for the wrong architecture. |
diff --git a/include/asm-sparc/ptrace.h b/include/asm-sparc/ptrace.h index 714497099a42..8201a7b29d49 100644 --- a/include/asm-sparc/ptrace.h +++ b/include/asm-sparc/ptrace.h | |||
| @@ -61,8 +61,6 @@ struct sparc_stackf { | |||
| 61 | 61 | ||
| 62 | #ifdef __KERNEL__ | 62 | #ifdef __KERNEL__ |
| 63 | 63 | ||
| 64 | #define __ARCH_SYS_PTRACE 1 | ||
| 65 | |||
| 66 | #define user_mode(regs) (!((regs)->psr & PSR_PS)) | 64 | #define user_mode(regs) (!((regs)->psr & PSR_PS)) |
| 67 | #define instruction_pointer(regs) ((regs)->pc) | 65 | #define instruction_pointer(regs) ((regs)->pc) |
| 68 | unsigned long profile_pc(struct pt_regs *); | 66 | unsigned long profile_pc(struct pt_regs *); |
| @@ -151,8 +149,6 @@ extern void show_regs(struct pt_regs *); | |||
| 151 | #define SF_XXARG 0x5c | 149 | #define SF_XXARG 0x5c |
| 152 | 150 | ||
| 153 | /* Stuff for the ptrace system call */ | 151 | /* Stuff for the ptrace system call */ |
| 154 | #define PTRACE_SUNATTACH 10 | ||
| 155 | #define PTRACE_SUNDETACH 11 | ||
| 156 | #define PTRACE_GETREGS 12 | 152 | #define PTRACE_GETREGS 12 |
| 157 | #define PTRACE_SETREGS 13 | 153 | #define PTRACE_SETREGS 13 |
| 158 | #define PTRACE_GETFPREGS 14 | 154 | #define PTRACE_GETFPREGS 14 |
| @@ -164,7 +160,4 @@ extern void show_regs(struct pt_regs *); | |||
| 164 | #define PTRACE_GETFPAREGS 20 | 160 | #define PTRACE_GETFPAREGS 20 |
| 165 | #define PTRACE_SETFPAREGS 21 | 161 | #define PTRACE_SETFPAREGS 21 |
| 166 | 162 | ||
| 167 | #define PTRACE_GETUCODE 29 /* stupid bsd-ism */ | ||
| 168 | |||
| 169 | |||
| 170 | #endif /* !(_SPARC_PTRACE_H) */ | 163 | #endif /* !(_SPARC_PTRACE_H) */ |
diff --git a/include/asm-sparc64/elf.h b/include/asm-sparc64/elf.h index dc7bc63e507e..272a65873f2e 100644 --- a/include/asm-sparc64/elf.h +++ b/include/asm-sparc64/elf.h | |||
| @@ -70,6 +70,8 @@ | |||
| 70 | #define HWCAP_SPARC_BLKINIT 64 | 70 | #define HWCAP_SPARC_BLKINIT 64 |
| 71 | #define HWCAP_SPARC_N2 128 | 71 | #define HWCAP_SPARC_N2 128 |
| 72 | 72 | ||
| 73 | #define CORE_DUMP_USE_REGSET | ||
| 74 | |||
| 73 | /* | 75 | /* |
| 74 | * These are used to set parameters in the core dumps. | 76 | * These are used to set parameters in the core dumps. |
| 75 | */ | 77 | */ |
| @@ -78,10 +80,6 @@ | |||
| 78 | #define ELF_CLASS ELFCLASS64 | 80 | #define ELF_CLASS ELFCLASS64 |
| 79 | #define ELF_DATA ELFDATA2MSB | 81 | #define ELF_DATA ELFDATA2MSB |
| 80 | 82 | ||
| 81 | typedef unsigned long elf_greg_t; | ||
| 82 | |||
| 83 | #define ELF_NGREG 36 | ||
| 84 | typedef elf_greg_t elf_gregset_t[ELF_NGREG]; | ||
| 85 | /* Format of 64-bit elf_gregset_t is: | 83 | /* Format of 64-bit elf_gregset_t is: |
| 86 | * G0 --> G7 | 84 | * G0 --> G7 |
| 87 | * O0 --> O7 | 85 | * O0 --> O7 |
| @@ -92,24 +90,9 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG]; | |||
| 92 | * TNPC | 90 | * TNPC |
| 93 | * Y | 91 | * Y |
| 94 | */ | 92 | */ |
| 95 | #define ELF_CORE_COPY_REGS(__elf_regs, __pt_regs) \ | 93 | typedef unsigned long elf_greg_t; |
| 96 | do { unsigned long *dest = &(__elf_regs[0]); \ | 94 | #define ELF_NGREG 36 |
| 97 | struct pt_regs *src = (__pt_regs); \ | 95 | typedef elf_greg_t elf_gregset_t[ELF_NGREG]; |
| 98 | unsigned long __user *sp; \ | ||
| 99 | int i; \ | ||
| 100 | for(i = 0; i < 16; i++) \ | ||
| 101 | dest[i] = src->u_regs[i]; \ | ||
| 102 | /* Don't try this at home kids... */ \ | ||
| 103 | sp = (unsigned long __user *) \ | ||
| 104 | ((src->u_regs[14] + STACK_BIAS) \ | ||
| 105 | & 0xfffffffffffffff8UL); \ | ||
| 106 | for(i = 0; i < 16; i++) \ | ||
| 107 | __get_user(dest[i+16], &sp[i]); \ | ||
| 108 | dest[32] = src->tstate; \ | ||
| 109 | dest[33] = src->tpc; \ | ||
| 110 | dest[34] = src->tnpc; \ | ||
| 111 | dest[35] = src->y; \ | ||
| 112 | } while (0); | ||
| 113 | 96 | ||
| 114 | typedef struct { | 97 | typedef struct { |
| 115 | unsigned long pr_regs[32]; | 98 | unsigned long pr_regs[32]; |
| @@ -119,9 +102,6 @@ typedef struct { | |||
| 119 | } elf_fpregset_t; | 102 | } elf_fpregset_t; |
| 120 | #endif | 103 | #endif |
| 121 | 104 | ||
| 122 | #define ELF_CORE_COPY_TASK_REGS(__tsk, __elf_regs) \ | ||
| 123 | ({ ELF_CORE_COPY_REGS((*(__elf_regs)), task_pt_regs(__tsk)); 1; }) | ||
| 124 | |||
| 125 | /* | 105 | /* |
| 126 | * This is used to ensure we don't load something for the wrong architecture. | 106 | * This is used to ensure we don't load something for the wrong architecture. |
| 127 | */ | 107 | */ |
diff --git a/include/asm-sparc64/ptrace.h b/include/asm-sparc64/ptrace.h index 7eba90c6c753..734a767f0a4e 100644 --- a/include/asm-sparc64/ptrace.h +++ b/include/asm-sparc64/ptrace.h | |||
| @@ -95,8 +95,6 @@ struct sparc_trapf { | |||
| 95 | 95 | ||
| 96 | #ifdef __KERNEL__ | 96 | #ifdef __KERNEL__ |
| 97 | 97 | ||
| 98 | #define __ARCH_SYS_PTRACE 1 | ||
| 99 | |||
| 100 | #define force_successful_syscall_return() \ | 98 | #define force_successful_syscall_return() \ |
| 101 | do { current_thread_info()->syscall_noerror = 1; \ | 99 | do { current_thread_info()->syscall_noerror = 1; \ |
| 102 | } while (0) | 100 | } while (0) |
| @@ -261,8 +259,6 @@ extern void show_regs(struct pt_regs *); | |||
| 261 | #define SF_XXARG 0x5c | 259 | #define SF_XXARG 0x5c |
| 262 | 260 | ||
| 263 | /* Stuff for the ptrace system call */ | 261 | /* Stuff for the ptrace system call */ |
| 264 | #define PTRACE_SUNATTACH 10 | ||
| 265 | #define PTRACE_SUNDETACH 11 | ||
| 266 | #define PTRACE_GETREGS 12 | 262 | #define PTRACE_GETREGS 12 |
| 267 | #define PTRACE_SETREGS 13 | 263 | #define PTRACE_SETREGS 13 |
| 268 | #define PTRACE_GETFPREGS 14 | 264 | #define PTRACE_GETFPREGS 14 |
| @@ -284,18 +280,4 @@ extern void show_regs(struct pt_regs *); | |||
| 284 | #define PTRACE_GETFPREGS64 25 | 280 | #define PTRACE_GETFPREGS64 25 |
| 285 | #define PTRACE_SETFPREGS64 26 | 281 | #define PTRACE_SETFPREGS64 26 |
| 286 | 282 | ||
| 287 | #define PTRACE_GETUCODE 29 /* stupid bsd-ism */ | ||
| 288 | |||
| 289 | /* These are for 32-bit processes debugging 64-bit ones. | ||
| 290 | * Here addr and addr2 are passed in %g2 and %g3 respectively. | ||
| 291 | */ | ||
| 292 | #define PTRACE_PEEKTEXT64 (30 + PTRACE_PEEKTEXT) | ||
| 293 | #define PTRACE_POKETEXT64 (30 + PTRACE_POKETEXT) | ||
| 294 | #define PTRACE_PEEKDATA64 (30 + PTRACE_PEEKDATA) | ||
| 295 | #define PTRACE_POKEDATA64 (30 + PTRACE_POKEDATA) | ||
| 296 | #define PTRACE_READDATA64 (30 + PTRACE_READDATA) | ||
| 297 | #define PTRACE_WRITEDATA64 (30 + PTRACE_WRITEDATA) | ||
| 298 | #define PTRACE_READTEXT64 (30 + PTRACE_READTEXT) | ||
| 299 | #define PTRACE_WRITETEXT64 (30 + PTRACE_WRITETEXT) | ||
| 300 | |||
| 301 | #endif /* !(_SPARC64_PTRACE_H) */ | 283 | #endif /* !(_SPARC64_PTRACE_H) */ |
