aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel/ptrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/kernel/ptrace.c')
-rw-r--r--arch/sparc/kernel/ptrace.c813
1 files changed, 340 insertions, 473 deletions
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 */
35static inline void pt_error_return(struct pt_regs *regs, unsigned long error) 36void 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
43static inline void pt_succ_return(struct pt_regs *regs, unsigned long value) 41enum 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
51static void 46static int genregs32_get(struct task_struct *target,
52pt_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++, &reg_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, &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
64static void 107 if (kbuf)
65pt_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 }
114finish:
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... */ 122static int genregs32_set(struct task_struct *target,
74static 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++, &reg_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, &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) 196finish:
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
169static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset, 204static 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 }
228success:
229 pt_succ_return(regs, 0);
230 return;
231failure:
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
240char *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 */
256void ptrace_disable(struct task_struct *child)
257{
258 /* nothing to do */
259} 246}
260 247
261asmlinkage void do_ptrace(struct pt_regs *regs) 248static 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) 280static 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); 312static 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) { 317const 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: 322long 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 }
569out_tsk:
570 if (child)
571 put_task_struct(child);
572out:
573 unlock_kernel();
574} 449}
575 450
576asmlinkage void syscall_trace(void) 451asmlinkage 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;