0619958ecfdc497a9c2b6e45e7b32f72c9d1dacc
[cascardo/linux.git] / arch / sparc / kernel / ptrace.c
1 /* ptrace.c: Sparc process tracing support.
2  *
3  * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net)
4  *
5  * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
6  * and David Mosberger.
7  *
8  * Added Linux support -miguel (weird, eh?, the original code was meant
9  * to emulate SunOS).
10  */
11
12 #include <linux/kernel.h>
13 #include <linux/sched.h>
14 #include <linux/mm.h>
15 #include <linux/errno.h>
16 #include <linux/ptrace.h>
17 #include <linux/user.h>
18 #include <linux/smp.h>
19 #include <linux/smp_lock.h>
20 #include <linux/security.h>
21 #include <linux/signal.h>
22 #include <linux/regset.h>
23 #include <linux/elf.h>
24
25 #include <asm/pgtable.h>
26 #include <asm/system.h>
27 #include <asm/uaccess.h>
28
29 #define MAGIC_CONSTANT 0x80000000
30
31
32 /* Returning from ptrace is a bit tricky because the syscall return
33  * low level code assumes any value returned which is negative and
34  * is a valid errno will mean setting the condition codes to indicate
35  * an error return.  This doesn't work, so we have this hook.
36  */
37 static inline void pt_error_return(struct pt_regs *regs, unsigned long error)
38 {
39         regs->u_regs[UREG_I0] = error;
40         regs->psr |= PSR_C;
41         regs->pc = regs->npc;
42         regs->npc += 4;
43 }
44
45 static inline void pt_succ_return(struct pt_regs *regs, unsigned long value)
46 {
47         regs->u_regs[UREG_I0] = value;
48         regs->psr &= ~PSR_C;
49         regs->pc = regs->npc;
50         regs->npc += 4;
51 }
52
53 static void
54 pt_succ_return_linux(struct pt_regs *regs, unsigned long value, long __user *addr)
55 {
56         if (put_user(value, addr)) {
57                 pt_error_return(regs, EFAULT);
58                 return;
59         }
60         regs->u_regs[UREG_I0] = 0;
61         regs->psr &= ~PSR_C;
62         regs->pc = regs->npc;
63         regs->npc += 4;
64 }
65
66 static void
67 pt_os_succ_return (struct pt_regs *regs, unsigned long val, long __user *addr)
68 {
69         if (current->personality == PER_SUNOS)
70                 pt_succ_return (regs, val);
71         else
72                 pt_succ_return_linux (regs, val, addr);
73 }
74
75 /* Fuck me gently with a chainsaw... */
76 static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset,
77                                    struct task_struct *tsk, long __user *addr)
78 {
79         struct pt_regs *cregs = tsk->thread.kregs;
80         struct thread_info *t = task_thread_info(tsk);
81         int v;
82         
83         if(offset >= 1024)
84                 offset -= 1024; /* whee... */
85         if(offset & ((sizeof(unsigned long) - 1))) {
86                 pt_error_return(regs, EIO);
87                 return;
88         }
89         if(offset >= 16 && offset < 784) {
90                 offset -= 16; offset >>= 2;
91                 pt_os_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset), addr);
92                 return;
93         }
94         if(offset >= 784 && offset < 832) {
95                 offset -= 784; offset >>= 2;
96                 pt_os_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset), addr);
97                 return;
98         }
99         switch(offset) {
100         case 0:
101                 v = t->ksp;
102                 break;
103         case 4:
104                 v = t->kpc;
105                 break;
106         case 8:
107                 v = t->kpsr;
108                 break;
109         case 12:
110                 v = t->uwinmask;
111                 break;
112         case 832:
113                 v = t->w_saved;
114                 break;
115         case 896:
116                 v = cregs->u_regs[UREG_I0];
117                 break;
118         case 900:
119                 v = cregs->u_regs[UREG_I1];
120                 break;
121         case 904:
122                 v = cregs->u_regs[UREG_I2];
123                 break;
124         case 908:
125                 v = cregs->u_regs[UREG_I3];
126                 break;
127         case 912:
128                 v = cregs->u_regs[UREG_I4];
129                 break;
130         case 916:
131                 v = cregs->u_regs[UREG_I5];
132                 break;
133         case 920:
134                 v = cregs->u_regs[UREG_I6];
135                 break;
136         case 924:
137                 if(tsk->thread.flags & MAGIC_CONSTANT)
138                         v = cregs->u_regs[UREG_G1];
139                 else
140                         v = 0;
141                 break;
142         case 940:
143                 v = cregs->u_regs[UREG_I0];
144                 break;
145         case 944:
146                 v = cregs->u_regs[UREG_I1];
147                 break;
148
149         case 948:
150                 /* Isn't binary compatibility _fun_??? */
151                 if(cregs->psr & PSR_C)
152                         v = cregs->u_regs[UREG_I0] << 24;
153                 else
154                         v = 0;
155                 break;
156
157                 /* Rest of them are completely unsupported. */
158         default:
159                 printk("%s [%d]: Wants to read user offset %ld\n",
160                        current->comm, task_pid_nr(current), offset);
161                 pt_error_return(regs, EIO);
162                 return;
163         }
164         if (current->personality == PER_SUNOS)
165                 pt_succ_return (regs, v);
166         else
167                 pt_succ_return_linux (regs, v, addr);
168         return;
169 }
170
171 static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset,
172                                     struct task_struct *tsk)
173 {
174         struct pt_regs *cregs = tsk->thread.kregs;
175         struct thread_info *t = task_thread_info(tsk);
176         unsigned long value = regs->u_regs[UREG_I3];
177
178         if(offset >= 1024)
179                 offset -= 1024; /* whee... */
180         if(offset & ((sizeof(unsigned long) - 1)))
181                 goto failure;
182         if(offset >= 16 && offset < 784) {
183                 offset -= 16; offset >>= 2;
184                 *(((unsigned long *)(&t->reg_window[0]))+offset) = value;
185                 goto success;
186         }
187         if(offset >= 784 && offset < 832) {
188                 offset -= 784; offset >>= 2;
189                 *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value;
190                 goto success;
191         }
192         switch(offset) {
193         case 896:
194                 cregs->u_regs[UREG_I0] = value;
195                 break;
196         case 900:
197                 cregs->u_regs[UREG_I1] = value;
198                 break;
199         case 904:
200                 cregs->u_regs[UREG_I2] = value;
201                 break;
202         case 908:
203                 cregs->u_regs[UREG_I3] = value;
204                 break;
205         case 912:
206                 cregs->u_regs[UREG_I4] = value;
207                 break;
208         case 916:
209                 cregs->u_regs[UREG_I5] = value;
210                 break;
211         case 920:
212                 cregs->u_regs[UREG_I6] = value;
213                 break;
214         case 924:
215                 cregs->u_regs[UREG_I7] = value;
216                 break;
217         case 940:
218                 cregs->u_regs[UREG_I0] = value;
219                 break;
220         case 944:
221                 cregs->u_regs[UREG_I1] = value;
222                 break;
223
224                 /* Rest of them are completely unsupported or "no-touch". */
225         default:
226                 printk("%s [%d]: Wants to write user offset %ld\n",
227                        current->comm, task_pid_nr(current), offset);
228                 goto failure;
229         }
230 success:
231         pt_succ_return(regs, 0);
232         return;
233 failure:
234         pt_error_return(regs, EIO);
235         return;
236 }
237
238 /* #define ALLOW_INIT_TRACING */
239
240 /*
241  * Called by kernel/ptrace.c when detaching..
242  *
243  * Make sure single step bits etc are not set.
244  */
245 void ptrace_disable(struct task_struct *child)
246 {
247         /* nothing to do */
248 }
249
250 enum sparc_regset {
251         REGSET_GENERAL,
252         REGSET_FP,
253 };
254
255 static int genregs32_get(struct task_struct *target,
256                          const struct user_regset *regset,
257                          unsigned int pos, unsigned int count,
258                          void *kbuf, void __user *ubuf)
259 {
260         const struct pt_regs *regs = target->thread.kregs;
261         unsigned long __user *reg_window;
262         unsigned long *k = kbuf;
263         unsigned long __user *u = ubuf;
264         unsigned long reg;
265
266         if (target == current)
267                 flush_user_windows();
268
269         pos /= sizeof(reg);
270         count /= sizeof(reg);
271
272         if (kbuf) {
273                 for (; count > 0 && pos < 16; count--)
274                         *k++ = regs->u_regs[pos++];
275
276                 reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
277                 for (; count > 0 && pos < 32; count--) {
278                         if (get_user(*k++, &reg_window[pos++]))
279                                 return -EFAULT;
280                 }
281         } else {
282                 for (; count > 0 && pos < 16; count--) {
283                         if (put_user(regs->u_regs[pos++], u++))
284                                 return -EFAULT;
285                 }
286
287                 reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
288                 for (; count > 0 && pos < 32; count--) {
289                         if (get_user(reg, &reg_window[pos++]) ||
290                             put_user(reg, u++))
291                                 return -EFAULT;
292                 }
293         }
294         while (count > 0) {
295                 switch (pos) {
296                 case 32: /* PSR */
297                         reg = regs->psr;
298                         break;
299                 case 33: /* PC */
300                         reg = regs->pc;
301                         break;
302                 case 34: /* NPC */
303                         reg = regs->npc;
304                         break;
305                 case 35: /* Y */
306                         reg = regs->y;
307                         break;
308                 case 36: /* WIM */
309                 case 37: /* TBR */
310                         reg = 0;
311                         break;
312                 default:
313                         goto finish;
314                 }
315
316                 if (kbuf)
317                         *k++ = reg;
318                 else if (put_user(reg, u++))
319                         return -EFAULT;
320                 pos++;
321                 count--;
322         }
323 finish:
324         pos *= sizeof(reg);
325         count *= sizeof(reg);
326
327         return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
328                                         38 * sizeof(reg), -1);
329 }
330
331 static int genregs32_set(struct task_struct *target,
332                          const struct user_regset *regset,
333                          unsigned int pos, unsigned int count,
334                          const void *kbuf, const void __user *ubuf)
335 {
336         struct pt_regs *regs = target->thread.kregs;
337         unsigned long __user *reg_window;
338         const unsigned long *k = kbuf;
339         const unsigned long __user *u = ubuf;
340         unsigned long reg;
341
342         if (target == current)
343                 flush_user_windows();
344
345         pos /= sizeof(reg);
346         count /= sizeof(reg);
347
348         if (kbuf) {
349                 for (; count > 0 && pos < 16; count--)
350                         regs->u_regs[pos++] = *k++;
351
352                 reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
353                 for (; count > 0 && pos < 32; count--) {
354                         if (put_user(*k++, &reg_window[pos++]))
355                                 return -EFAULT;
356                 }
357         } else {
358                 for (; count > 0 && pos < 16; count--) {
359                         if (get_user(reg, u++))
360                                 return -EFAULT;
361                         regs->u_regs[pos++] = reg;
362                 }
363
364                 reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
365                 for (; count > 0 && pos < 32; count--) {
366                         if (get_user(reg, u++) ||
367                             put_user(reg, &reg_window[pos++]))
368                                 return -EFAULT;
369                 }
370         }
371         while (count > 0) {
372                 unsigned long psr;
373
374                 if (kbuf)
375                         reg = *k++;
376                 else if (get_user(reg, u++))
377                         return -EFAULT;
378
379                 switch (pos) {
380                 case 32: /* PSR */
381                         psr = regs->psr;
382                         psr &= ~PSR_ICC;
383                         psr |= (reg & PSR_ICC);
384                         regs->psr = psr;
385                         break;
386                 case 33: /* PC */
387                         regs->pc = reg;
388                         break;
389                 case 34: /* NPC */
390                         regs->npc = reg;
391                         break;
392                 case 35: /* Y */
393                         regs->y = reg;
394                         break;
395                 case 36: /* WIM */
396                 case 37: /* TBR */
397                         break;
398                 default:
399                         goto finish;
400                 }
401
402                 pos++;
403                 count--;
404         }
405 finish:
406         pos *= sizeof(reg);
407         count *= sizeof(reg);
408
409         return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
410                                          38 * sizeof(reg), -1);
411 }
412
413 static int fpregs32_get(struct task_struct *target,
414                         const struct user_regset *regset,
415                         unsigned int pos, unsigned int count,
416                         void *kbuf, void __user *ubuf)
417 {
418         const unsigned long *fpregs = target->thread.float_regs;
419         int ret = 0;
420
421 #if 0
422         if (target == current)
423                 save_and_clear_fpu();
424 #endif
425
426         ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
427                                   fpregs,
428                                   0, 32 * sizeof(u32));
429
430         if (!ret)
431                 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
432                                                32 * sizeof(u32),
433                                                33 * sizeof(u32));
434         if (!ret)
435                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
436                                           &target->thread.fsr,
437                                           33 * sizeof(u32),
438                                           34 * sizeof(u32));
439
440         if (!ret) {
441                 unsigned long val;
442
443                 val = (1 << 8) | (8 << 16);
444                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
445                                           &val,
446                                           34 * sizeof(u32),
447                                           35 * sizeof(u32));
448         }
449
450         if (!ret)
451                 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
452                                                35 * sizeof(u32), -1);
453
454         return ret;
455 }
456
457 static int fpregs32_set(struct task_struct *target,
458                         const struct user_regset *regset,
459                         unsigned int pos, unsigned int count,
460                         const void *kbuf, const void __user *ubuf)
461 {
462         unsigned long *fpregs = target->thread.float_regs;
463         int ret;
464
465 #if 0
466         if (target == current)
467                 save_and_clear_fpu();
468 #endif
469         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
470                                  fpregs,
471                                  0, 32 * sizeof(u32));
472         if (!ret)
473                 user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
474                                           32 * sizeof(u32),
475                                           33 * sizeof(u32));
476         if (!ret && count > 0) {
477                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
478                                          &target->thread.fsr,
479                                          33 * sizeof(u32),
480                                          34 * sizeof(u32));
481         }
482
483         if (!ret)
484                 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
485                                                 34 * sizeof(u32), -1);
486         return ret;
487 }
488
489 static const struct user_regset sparc32_regsets[] = {
490         /* Format is:
491          *      G0 --> G7
492          *      O0 --> O7
493          *      L0 --> L7
494          *      I0 --> I7
495          *      PSR, PC, nPC, Y, WIM, TBR
496          */
497         [REGSET_GENERAL] = {
498                 .core_note_type = NT_PRSTATUS,
499                 .n = 38 * sizeof(u32),
500                 .size = sizeof(u32), .align = sizeof(u32),
501                 .get = genregs32_get, .set = genregs32_set
502         },
503         /* Format is:
504          *      F0 --> F31
505          *      empty 32-bit word
506          *      FSR (32--bit word)
507          *      FPU QUEUE COUNT (8-bit char)
508          *      FPU QUEUE ENTRYSIZE (8-bit char)
509          *      FPU ENABLED (8-bit char)
510          *      empty 8-bit char
511          *      FPU QUEUE (64 32-bit ints)
512          */
513         [REGSET_FP] = {
514                 .core_note_type = NT_PRFPREG,
515                 .n = 99 * sizeof(u32),
516                 .size = sizeof(u32), .align = sizeof(u32),
517                 .get = fpregs32_get, .set = fpregs32_set
518         },
519 };
520
521 static const struct user_regset_view user_sparc32_view = {
522         .name = "sparc", .e_machine = EM_SPARC,
523         .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
524 };
525
526 const struct user_regset_view *task_user_regset_view(struct task_struct *task)
527 {
528         return &user_sparc32_view;
529 }
530
531 asmlinkage void do_ptrace(struct pt_regs *regs)
532 {
533         unsigned long request = regs->u_regs[UREG_I0];
534         unsigned long pid = regs->u_regs[UREG_I1];
535         unsigned long addr = regs->u_regs[UREG_I2];
536         unsigned long data = regs->u_regs[UREG_I3];
537         unsigned long addr2 = regs->u_regs[UREG_I4];
538         struct task_struct *child;
539         int ret;
540
541         lock_kernel();
542
543         if (request == PTRACE_TRACEME) {
544                 ret = ptrace_traceme();
545                 if (ret < 0)
546                         pt_error_return(regs, -ret);
547                 else
548                         pt_succ_return(regs, 0);
549                 goto out;
550         }
551
552         child = ptrace_get_task_struct(pid);
553         if (IS_ERR(child)) {
554                 ret = PTR_ERR(child);
555                 pt_error_return(regs, -ret);
556                 goto out;
557         }
558
559         if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH)
560             || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
561                 if (ptrace_attach(child)) {
562                         pt_error_return(regs, EPERM);
563                         goto out_tsk;
564                 }
565                 pt_succ_return(regs, 0);
566                 goto out_tsk;
567         }
568
569         ret = ptrace_check_attach(child, request == PTRACE_KILL);
570         if (ret < 0) {
571                 pt_error_return(regs, -ret);
572                 goto out_tsk;
573         }
574
575         switch(request) {
576         case PTRACE_PEEKTEXT: /* read word at location addr. */ 
577         case PTRACE_PEEKDATA: {
578                 unsigned long tmp;
579
580                 if (access_process_vm(child, addr,
581                                       &tmp, sizeof(tmp), 0) == sizeof(tmp))
582                         pt_os_succ_return(regs, tmp, (long __user *)data);
583                 else
584                         pt_error_return(regs, EIO);
585                 goto out_tsk;
586         }
587
588         case PTRACE_PEEKUSR:
589                 read_sunos_user(regs, addr, child, (long __user *) data);
590                 goto out_tsk;
591
592         case PTRACE_POKEUSR:
593                 write_sunos_user(regs, addr, child);
594                 goto out_tsk;
595
596         case PTRACE_POKETEXT: /* write the word at location addr. */
597         case PTRACE_POKEDATA: {
598                 if (access_process_vm(child, addr,
599                                       &data, sizeof(data), 1) == sizeof(data))
600                         pt_succ_return(regs, 0);
601                 else
602                         pt_error_return(regs, EIO);
603                 goto out_tsk;
604         }
605
606         case PTRACE_GETREGS: {
607                 struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
608                 struct pt_regs *cregs = child->thread.kregs;
609                 int rval;
610
611                 if (!access_ok(VERIFY_WRITE, pregs, sizeof(struct pt_regs))) {
612                         rval = -EFAULT;
613                         pt_error_return(regs, -rval);
614                         goto out_tsk;
615                 }
616                 __put_user(cregs->psr, (&pregs->psr));
617                 __put_user(cregs->pc, (&pregs->pc));
618                 __put_user(cregs->npc, (&pregs->npc));
619                 __put_user(cregs->y, (&pregs->y));
620                 for(rval = 1; rval < 16; rval++)
621                         __put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]));
622                 pt_succ_return(regs, 0);
623                 goto out_tsk;
624         }
625
626         case PTRACE_SETREGS: {
627                 struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
628                 struct pt_regs *cregs = child->thread.kregs;
629                 unsigned long psr, pc, npc, y;
630                 int i;
631
632                 /* Must be careful, tracing process can only set certain
633                  * bits in the psr.
634                  */
635                 if (!access_ok(VERIFY_READ, pregs, sizeof(struct pt_regs))) {
636                         pt_error_return(regs, EFAULT);
637                         goto out_tsk;
638                 }
639                 __get_user(psr, (&pregs->psr));
640                 __get_user(pc, (&pregs->pc));
641                 __get_user(npc, (&pregs->npc));
642                 __get_user(y, (&pregs->y));
643                 psr &= PSR_ICC;
644                 cregs->psr &= ~PSR_ICC;
645                 cregs->psr |= psr;
646                 if (!((pc | npc) & 3)) {
647                         cregs->pc = pc;
648                         cregs->npc =npc;
649                 }
650                 cregs->y = y;
651                 for(i = 1; i < 16; i++)
652                         __get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]));
653                 pt_succ_return(regs, 0);
654                 goto out_tsk;
655         }
656
657         case PTRACE_GETFPREGS: {
658                 struct fps {
659                         unsigned long regs[32];
660                         unsigned long fsr;
661                         unsigned long flags;
662                         unsigned long extra;
663                         unsigned long fpqd;
664                         struct fq {
665                                 unsigned long *insnaddr;
666                                 unsigned long insn;
667                         } fpq[16];
668                 };
669                 struct fps __user *fps = (struct fps __user *) addr;
670                 int i;
671
672                 if (!access_ok(VERIFY_WRITE, fps, sizeof(struct fps))) {
673                         i = -EFAULT;
674                         pt_error_return(regs, -i);
675                         goto out_tsk;
676                 }
677                 for(i = 0; i < 32; i++)
678                         __put_user(child->thread.float_regs[i], (&fps->regs[i]));
679                 __put_user(child->thread.fsr, (&fps->fsr));
680                 __put_user(child->thread.fpqdepth, (&fps->fpqd));
681                 __put_user(0, (&fps->flags));
682                 __put_user(0, (&fps->extra));
683                 for(i = 0; i < 16; i++) {
684                         __put_user(child->thread.fpqueue[i].insn_addr,
685                                    (&fps->fpq[i].insnaddr));
686                         __put_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn));
687                 }
688                 pt_succ_return(regs, 0);
689                 goto out_tsk;
690         }
691
692         case PTRACE_SETFPREGS: {
693                 struct fps {
694                         unsigned long regs[32];
695                         unsigned long fsr;
696                         unsigned long flags;
697                         unsigned long extra;
698                         unsigned long fpqd;
699                         struct fq {
700                                 unsigned long *insnaddr;
701                                 unsigned long insn;
702                         } fpq[16];
703                 };
704                 struct fps __user *fps = (struct fps __user *) addr;
705                 int i;
706
707                 if (!access_ok(VERIFY_READ, fps, sizeof(struct fps))) {
708                         i = -EFAULT;
709                         pt_error_return(regs, -i);
710                         goto out_tsk;
711                 }
712                 copy_from_user(&child->thread.float_regs[0], &fps->regs[0], (32 * sizeof(unsigned long)));
713                 __get_user(child->thread.fsr, (&fps->fsr));
714                 __get_user(child->thread.fpqdepth, (&fps->fpqd));
715                 for(i = 0; i < 16; i++) {
716                         __get_user(child->thread.fpqueue[i].insn_addr,
717                                    (&fps->fpq[i].insnaddr));
718                         __get_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn));
719                 }
720                 pt_succ_return(regs, 0);
721                 goto out_tsk;
722         }
723
724         case PTRACE_READTEXT:
725         case PTRACE_READDATA: {
726                 int res = ptrace_readdata(child, addr,
727                                           (void __user *) addr2, data);
728
729                 if (res == data) {
730                         pt_succ_return(regs, 0);
731                         goto out_tsk;
732                 }
733                 /* Partial read is an IO failure */
734                 if (res >= 0)
735                         res = -EIO;
736                 pt_error_return(regs, -res);
737                 goto out_tsk;
738         }
739
740         case PTRACE_WRITETEXT:
741         case PTRACE_WRITEDATA: {
742                 int res = ptrace_writedata(child, (void __user *) addr2,
743                                            addr, data);
744
745                 if (res == data) {
746                         pt_succ_return(regs, 0);
747                         goto out_tsk;
748                 }
749                 /* Partial write is an IO failure */
750                 if (res >= 0)
751                         res = -EIO;
752                 pt_error_return(regs, -res);
753                 goto out_tsk;
754         }
755
756         case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
757                 addr = 1;
758
759         case PTRACE_CONT: { /* restart after signal. */
760                 if (!valid_signal(data)) {
761                         pt_error_return(regs, EIO);
762                         goto out_tsk;
763                 }
764
765                 if (request == PTRACE_SYSCALL)
766                         set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
767                 else
768                         clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
769
770                 child->exit_code = data;
771                 wake_up_process(child);
772                 pt_succ_return(regs, 0);
773                 goto out_tsk;
774         }
775
776 /*
777  * make the child exit.  Best I can do is send it a sigkill. 
778  * perhaps it should be put in the status that it wants to 
779  * exit.
780  */
781         case PTRACE_KILL: {
782                 if (child->exit_state == EXIT_ZOMBIE) { /* already dead */
783                         pt_succ_return(regs, 0);
784                         goto out_tsk;
785                 }
786                 wake_up_process(child);
787                 child->exit_code = SIGKILL;
788                 pt_succ_return(regs, 0);
789                 goto out_tsk;
790         }
791
792         case PTRACE_SUNDETACH: { /* detach a process that was attached. */
793                 int err = ptrace_detach(child, data);
794                 if (err) {
795                         pt_error_return(regs, EIO);
796                         goto out_tsk;
797                 }
798                 pt_succ_return(regs, 0);
799                 goto out_tsk;
800         }
801
802         /* PTRACE_DUMPCORE unsupported... */
803
804         default: {
805                 int err = ptrace_request(child, request, addr, data);
806                 if (err)
807                         pt_error_return(regs, -err);
808                 else
809                         pt_succ_return(regs, 0);
810                 goto out_tsk;
811         }
812         }
813 out_tsk:
814         if (child)
815                 put_task_struct(child);
816 out:
817         unlock_kernel();
818 }
819
820 asmlinkage void syscall_trace(void)
821 {
822         if (!test_thread_flag(TIF_SYSCALL_TRACE))
823                 return;
824         if (!(current->ptrace & PT_PTRACED))
825                 return;
826         current->thread.flags ^= MAGIC_CONSTANT;
827         ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
828                                  ? 0x80 : 0));
829         /*
830          * this isn't the same as continuing with a signal, but it will do
831          * for normal use.  strace only continues with a signal if the
832          * stopping signal is not SIGTRAP.  -brl
833          */
834         if (current->exit_code) {
835                 send_sig (current->exit_code, current, 1);
836                 current->exit_code = 0;
837         }
838 }