Merge master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6 into for-linus
[linux-2.6] / arch / sparc64 / kernel / ptrace.c
1 /* ptrace.c: Sparc process tracing support.
2  *
3  * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net)
4  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
5  *
6  * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
7  * and David Mosberger.
8  *
9  * Added Linux support -miguel (weird, eh?, the original code was meant
10  * to emulate SunOS).
11  */
12
13 #include <linux/kernel.h>
14 #include <linux/sched.h>
15 #include <linux/mm.h>
16 #include <linux/errno.h>
17 #include <linux/ptrace.h>
18 #include <linux/user.h>
19 #include <linux/smp.h>
20 #include <linux/smp_lock.h>
21 #include <linux/security.h>
22 #include <linux/seccomp.h>
23 #include <linux/audit.h>
24 #include <linux/signal.h>
25 #include <linux/regset.h>
26 #include <linux/compat.h>
27 #include <linux/elf.h>
28
29 #include <asm/asi.h>
30 #include <asm/pgtable.h>
31 #include <asm/system.h>
32 #include <asm/uaccess.h>
33 #include <asm/psrcompat.h>
34 #include <asm/visasm.h>
35 #include <asm/spitfire.h>
36 #include <asm/page.h>
37 #include <asm/cpudata.h>
38 #include <asm/cacheflush.h>
39
40 #include "entry.h"
41
42 /* #define ALLOW_INIT_TRACING */
43
44 /*
45  * Called by kernel/ptrace.c when detaching..
46  *
47  * Make sure single step bits etc are not set.
48  */
49 void ptrace_disable(struct task_struct *child)
50 {
51         /* nothing to do */
52 }
53
54 /* To get the necessary page struct, access_process_vm() first calls
55  * get_user_pages().  This has done a flush_dcache_page() on the
56  * accessed page.  Then our caller (copy_{to,from}_user_page()) did
57  * to memcpy to read/write the data from that page.
58  *
59  * Now, the only thing we have to do is:
60  * 1) flush the D-cache if it's possible than an illegal alias
61  *    has been created
62  * 2) flush the I-cache if this is pre-cheetah and we did a write
63  */
64 void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
65                          unsigned long uaddr, void *kaddr,
66                          unsigned long len, int write)
67 {
68         BUG_ON(len > PAGE_SIZE);
69
70         if (tlb_type == hypervisor)
71                 return;
72
73         preempt_disable();
74
75 #ifdef DCACHE_ALIASING_POSSIBLE
76         /* If bit 13 of the kernel address we used to access the
77          * user page is the same as the virtual address that page
78          * is mapped to in the user's address space, we can skip the
79          * D-cache flush.
80          */
81         if ((uaddr ^ (unsigned long) kaddr) & (1UL << 13)) {
82                 unsigned long start = __pa(kaddr);
83                 unsigned long end = start + len;
84                 unsigned long dcache_line_size;
85
86                 dcache_line_size = local_cpu_data().dcache_line_size;
87
88                 if (tlb_type == spitfire) {
89                         for (; start < end; start += dcache_line_size)
90                                 spitfire_put_dcache_tag(start & 0x3fe0, 0x0);
91                 } else {
92                         start &= ~(dcache_line_size - 1);
93                         for (; start < end; start += dcache_line_size)
94                                 __asm__ __volatile__(
95                                         "stxa %%g0, [%0] %1\n\t"
96                                         "membar #Sync"
97                                         : /* no outputs */
98                                         : "r" (start),
99                                         "i" (ASI_DCACHE_INVALIDATE));
100                 }
101         }
102 #endif
103         if (write && tlb_type == spitfire) {
104                 unsigned long start = (unsigned long) kaddr;
105                 unsigned long end = start + len;
106                 unsigned long icache_line_size;
107
108                 icache_line_size = local_cpu_data().icache_line_size;
109
110                 for (; start < end; start += icache_line_size)
111                         flushi(start);
112         }
113
114         preempt_enable();
115 }
116
117 enum sparc_regset {
118         REGSET_GENERAL,
119         REGSET_FP,
120 };
121
122 static int genregs64_get(struct task_struct *target,
123                          const struct user_regset *regset,
124                          unsigned int pos, unsigned int count,
125                          void *kbuf, void __user *ubuf)
126 {
127         const struct pt_regs *regs = task_pt_regs(target);
128         int ret;
129
130         if (target == current)
131                 flushw_user();
132
133         ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
134                                   regs->u_regs,
135                                   0, 16 * sizeof(u64));
136         if (!ret) {
137                 unsigned long __user *reg_window = (unsigned long __user *)
138                         (regs->u_regs[UREG_I6] + STACK_BIAS);
139                 unsigned long window[16];
140
141                 if (copy_from_user(window, reg_window, sizeof(window)))
142                         return -EFAULT;
143
144                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
145                                           window,
146                                           16 * sizeof(u64),
147                                           32 * sizeof(u64));
148         }
149
150         if (!ret) {
151                 /* TSTATE, TPC, TNPC */
152                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
153                                           &regs->tstate,
154                                           32 * sizeof(u64),
155                                           35 * sizeof(u64));
156         }
157
158         if (!ret) {
159                 unsigned long y = regs->y;
160
161                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
162                                           &y,
163                                           35 * sizeof(u64),
164                                           36 * sizeof(u64));
165         }
166
167         if (!ret)
168                 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
169                                                36 * sizeof(u64), -1);
170
171         return ret;
172 }
173
174 static int genregs64_set(struct task_struct *target,
175                          const struct user_regset *regset,
176                          unsigned int pos, unsigned int count,
177                          const void *kbuf, const void __user *ubuf)
178 {
179         struct pt_regs *regs = task_pt_regs(target);
180         int ret;
181
182         if (target == current)
183                 flushw_user();
184
185         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
186                                  regs->u_regs,
187                                  0, 16 * sizeof(u64));
188         if (!ret && count > 0) {
189                 unsigned long __user *reg_window = (unsigned long __user *)
190                         (regs->u_regs[UREG_I6] + STACK_BIAS);
191                 unsigned long window[16];
192
193                 if (copy_from_user(window, reg_window, sizeof(window)))
194                         return -EFAULT;
195
196                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
197                                          window,
198                                          16 * sizeof(u64),
199                                          32 * sizeof(u64));
200                 if (!ret &&
201                     copy_to_user(reg_window, window, sizeof(window)))
202                         return -EFAULT;
203         }
204
205         if (!ret && count > 0) {
206                 unsigned long tstate;
207
208                 /* TSTATE */
209                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
210                                          &tstate,
211                                          32 * sizeof(u64),
212                                          33 * sizeof(u64));
213                 if (!ret) {
214                         /* Only the condition codes can be modified
215                          * in the %tstate register.
216                          */
217                         tstate &= (TSTATE_ICC | TSTATE_XCC);
218                         regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC);
219                         regs->tstate |= tstate;
220                 }
221         }
222
223         if (!ret) {
224                 /* TPC, TNPC */
225                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
226                                          &regs->tpc,
227                                          33 * sizeof(u64),
228                                          35 * sizeof(u64));
229         }
230
231         if (!ret) {
232                 unsigned long y;
233
234                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
235                                          &y,
236                                          35 * sizeof(u64),
237                                          36 * sizeof(u64));
238                 if (!ret)
239                         regs->y = y;
240         }
241
242         if (!ret)
243                 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
244                                                 36 * sizeof(u64), -1);
245
246         return ret;
247 }
248
249 static int fpregs64_get(struct task_struct *target,
250                         const struct user_regset *regset,
251                         unsigned int pos, unsigned int count,
252                         void *kbuf, void __user *ubuf)
253 {
254         const unsigned long *fpregs = task_thread_info(target)->fpregs;
255         unsigned long fprs, fsr, gsr;
256         int ret;
257
258         if (target == current)
259                 save_and_clear_fpu();
260
261         fprs = task_thread_info(target)->fpsaved[0];
262
263         if (fprs & FPRS_DL)
264                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
265                                           fpregs,
266                                           0, 16 * sizeof(u64));
267         else
268                 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
269                                                0,
270                                                16 * sizeof(u64));
271
272         if (!ret) {
273                 if (fprs & FPRS_DU)
274                         ret = user_regset_copyout(&pos, &count,
275                                                   &kbuf, &ubuf,
276                                                   fpregs + 16,
277                                                   16 * sizeof(u64),
278                                                   32 * sizeof(u64));
279                 else
280                         ret = user_regset_copyout_zero(&pos, &count,
281                                                        &kbuf, &ubuf,
282                                                        16 * sizeof(u64),
283                                                        32 * sizeof(u64));
284         }
285
286         if (fprs & FPRS_FEF) {
287                 fsr = task_thread_info(target)->xfsr[0];
288                 gsr = task_thread_info(target)->gsr[0];
289         } else {
290                 fsr = gsr = 0;
291         }
292
293         if (!ret)
294                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
295                                           &fsr,
296                                           32 * sizeof(u64),
297                                           33 * sizeof(u64));
298         if (!ret)
299                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
300                                           &gsr,
301                                           33 * sizeof(u64),
302                                           34 * sizeof(u64));
303         if (!ret)
304                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
305                                           &fprs,
306                                           34 * sizeof(u64),
307                                           35 * sizeof(u64));
308
309         if (!ret)
310                 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
311                                                35 * sizeof(u64), -1);
312
313         return ret;
314 }
315
316 static int fpregs64_set(struct task_struct *target,
317                         const struct user_regset *regset,
318                         unsigned int pos, unsigned int count,
319                         const void *kbuf, const void __user *ubuf)
320 {
321         unsigned long *fpregs = task_thread_info(target)->fpregs;
322         unsigned long fprs;
323         int ret;
324
325         if (target == current)
326                 save_and_clear_fpu();
327
328         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
329                                  fpregs,
330                                  0, 32 * sizeof(u64));
331         if (!ret)
332                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
333                                          task_thread_info(target)->xfsr,
334                                          32 * sizeof(u64),
335                                          33 * sizeof(u64));
336         if (!ret)
337                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
338                                          task_thread_info(target)->gsr,
339                                          33 * sizeof(u64),
340                                          34 * sizeof(u64));
341
342         fprs = task_thread_info(target)->fpsaved[0];
343         if (!ret && count > 0) {
344                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
345                                          &fprs,
346                                          34 * sizeof(u64),
347                                          35 * sizeof(u64));
348         }
349
350         fprs |= (FPRS_FEF | FPRS_DL | FPRS_DU);
351         task_thread_info(target)->fpsaved[0] = fprs;
352
353         if (!ret)
354                 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
355                                                 35 * sizeof(u64), -1);
356         return ret;
357 }
358
359 static const struct user_regset sparc64_regsets[] = {
360         /* Format is:
361          *      G0 --> G7
362          *      O0 --> O7
363          *      L0 --> L7
364          *      I0 --> I7
365          *      TSTATE, TPC, TNPC, Y
366          */
367         [REGSET_GENERAL] = {
368                 .core_note_type = NT_PRSTATUS,
369                 .n = 36 * sizeof(u64),
370                 .size = sizeof(u64), .align = sizeof(u64),
371                 .get = genregs64_get, .set = genregs64_set
372         },
373         /* Format is:
374          *      F0 --> F63
375          *      FSR
376          *      GSR
377          *      FPRS
378          */
379         [REGSET_FP] = {
380                 .core_note_type = NT_PRFPREG,
381                 .n = 35 * sizeof(u64),
382                 .size = sizeof(u64), .align = sizeof(u64),
383                 .get = fpregs64_get, .set = fpregs64_set
384         },
385 };
386
387 static const struct user_regset_view user_sparc64_view = {
388         .name = "sparc64", .e_machine = EM_SPARCV9,
389         .regsets = sparc64_regsets, .n = ARRAY_SIZE(sparc64_regsets)
390 };
391
392 #ifdef CONFIG_COMPAT
393 static int genregs32_get(struct task_struct *target,
394                          const struct user_regset *regset,
395                          unsigned int pos, unsigned int count,
396                          void *kbuf, void __user *ubuf)
397 {
398         const struct pt_regs *regs = task_pt_regs(target);
399         compat_ulong_t __user *reg_window;
400         compat_ulong_t *k = kbuf;
401         compat_ulong_t __user *u = ubuf;
402         compat_ulong_t reg;
403
404         if (target == current)
405                 flushw_user();
406
407         pos /= sizeof(reg);
408         count /= sizeof(reg);
409
410         if (kbuf) {
411                 for (; count > 0 && pos < 16; count--)
412                         *k++ = regs->u_regs[pos++];
413
414                 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
415                 for (; count > 0 && pos < 32; count--) {
416                         if (get_user(*k++, &reg_window[pos++]))
417                                 return -EFAULT;
418                 }
419         } else {
420                 for (; count > 0 && pos < 16; count--) {
421                         if (put_user((compat_ulong_t) regs->u_regs[pos++], u++))
422                                 return -EFAULT;
423                 }
424
425                 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
426                 for (; count > 0 && pos < 32; count--) {
427                         if (get_user(reg, &reg_window[pos++]) ||
428                             put_user(reg, u++))
429                                 return -EFAULT;
430                 }
431         }
432         while (count > 0) {
433                 switch (pos) {
434                 case 32: /* PSR */
435                         reg = tstate_to_psr(regs->tstate);
436                         break;
437                 case 33: /* PC */
438                         reg = regs->tpc;
439                         break;
440                 case 34: /* NPC */
441                         reg = regs->tnpc;
442                         break;
443                 case 35: /* Y */
444                         reg = regs->y;
445                         break;
446                 case 36: /* WIM */
447                 case 37: /* TBR */
448                         reg = 0;
449                         break;
450                 default:
451                         goto finish;
452                 }
453
454                 if (kbuf)
455                         *k++ = reg;
456                 else if (put_user(reg, u++))
457                         return -EFAULT;
458                 pos++;
459                 count--;
460         }
461 finish:
462         pos *= sizeof(reg);
463         count *= sizeof(reg);
464
465         return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
466                                         38 * sizeof(reg), -1);
467 }
468
469 static int genregs32_set(struct task_struct *target,
470                          const struct user_regset *regset,
471                          unsigned int pos, unsigned int count,
472                          const void *kbuf, const void __user *ubuf)
473 {
474         struct pt_regs *regs = task_pt_regs(target);
475         compat_ulong_t __user *reg_window;
476         const compat_ulong_t *k = kbuf;
477         const compat_ulong_t __user *u = ubuf;
478         compat_ulong_t reg;
479
480         if (target == current)
481                 flushw_user();
482
483         pos /= sizeof(reg);
484         count /= sizeof(reg);
485
486         if (kbuf) {
487                 for (; count > 0 && pos < 16; count--)
488                         regs->u_regs[pos++] = *k++;
489
490                 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
491                 for (; count > 0 && pos < 32; count--) {
492                         if (put_user(*k++, &reg_window[pos++]))
493                                 return -EFAULT;
494                 }
495         } else {
496                 for (; count > 0 && pos < 16; count--) {
497                         if (get_user(reg, u++))
498                                 return -EFAULT;
499                         regs->u_regs[pos++] = reg;
500                 }
501
502                 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
503                 for (; count > 0 && pos < 32; count--) {
504                         if (get_user(reg, u++) ||
505                             put_user(reg, &reg_window[pos++]))
506                                 return -EFAULT;
507                 }
508         }
509         while (count > 0) {
510                 unsigned long tstate;
511
512                 if (kbuf)
513                         reg = *k++;
514                 else if (get_user(reg, u++))
515                         return -EFAULT;
516
517                 switch (pos) {
518                 case 32: /* PSR */
519                         tstate = regs->tstate;
520                         tstate &= ~(TSTATE_ICC | TSTATE_XCC);
521                         tstate |= psr_to_tstate_icc(reg);
522                         regs->tstate = tstate;
523                         break;
524                 case 33: /* PC */
525                         regs->tpc = reg;
526                         break;
527                 case 34: /* NPC */
528                         regs->tnpc = reg;
529                         break;
530                 case 35: /* Y */
531                         regs->y = reg;
532                         break;
533                 case 36: /* WIM */
534                 case 37: /* TBR */
535                         break;
536                 default:
537                         goto finish;
538                 }
539
540                 pos++;
541                 count--;
542         }
543 finish:
544         pos *= sizeof(reg);
545         count *= sizeof(reg);
546
547         return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
548                                          38 * sizeof(reg), -1);
549 }
550
551 static int fpregs32_get(struct task_struct *target,
552                         const struct user_regset *regset,
553                         unsigned int pos, unsigned int count,
554                         void *kbuf, void __user *ubuf)
555 {
556         const unsigned long *fpregs = task_thread_info(target)->fpregs;
557         compat_ulong_t enabled;
558         unsigned long fprs;
559         compat_ulong_t fsr;
560         int ret = 0;
561
562         if (target == current)
563                 save_and_clear_fpu();
564
565         fprs = task_thread_info(target)->fpsaved[0];
566         if (fprs & FPRS_FEF) {
567                 fsr = task_thread_info(target)->xfsr[0];
568                 enabled = 1;
569         } else {
570                 fsr = 0;
571                 enabled = 0;
572         }
573
574         ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
575                                   fpregs,
576                                   0, 32 * sizeof(u32));
577
578         if (!ret)
579                 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
580                                                32 * sizeof(u32),
581                                                33 * sizeof(u32));
582         if (!ret)
583                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
584                                           &fsr,
585                                           33 * sizeof(u32),
586                                           34 * sizeof(u32));
587
588         if (!ret) {
589                 compat_ulong_t val;
590
591                 val = (enabled << 8) | (8 << 16);
592                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
593                                           &val,
594                                           34 * sizeof(u32),
595                                           35 * sizeof(u32));
596         }
597
598         if (!ret)
599                 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
600                                                35 * sizeof(u32), -1);
601
602         return ret;
603 }
604
605 static int fpregs32_set(struct task_struct *target,
606                         const struct user_regset *regset,
607                         unsigned int pos, unsigned int count,
608                         const void *kbuf, const void __user *ubuf)
609 {
610         unsigned long *fpregs = task_thread_info(target)->fpregs;
611         unsigned long fprs;
612         int ret;
613
614         if (target == current)
615                 save_and_clear_fpu();
616
617         fprs = task_thread_info(target)->fpsaved[0];
618
619         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
620                                  fpregs,
621                                  0, 32 * sizeof(u32));
622         if (!ret)
623                 user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
624                                           32 * sizeof(u32),
625                                           33 * sizeof(u32));
626         if (!ret && count > 0) {
627                 compat_ulong_t fsr;
628                 unsigned long val;
629
630                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
631                                          &fsr,
632                                          33 * sizeof(u32),
633                                          34 * sizeof(u32));
634                 if (!ret) {
635                         val = task_thread_info(target)->xfsr[0];
636                         val &= 0xffffffff00000000UL;
637                         val |= fsr;
638                         task_thread_info(target)->xfsr[0] = val;
639                 }
640         }
641
642         fprs |= (FPRS_FEF | FPRS_DL);
643         task_thread_info(target)->fpsaved[0] = fprs;
644
645         if (!ret)
646                 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
647                                                 34 * sizeof(u32), -1);
648         return ret;
649 }
650
651 static const struct user_regset sparc32_regsets[] = {
652         /* Format is:
653          *      G0 --> G7
654          *      O0 --> O7
655          *      L0 --> L7
656          *      I0 --> I7
657          *      PSR, PC, nPC, Y, WIM, TBR
658          */
659         [REGSET_GENERAL] = {
660                 .core_note_type = NT_PRSTATUS,
661                 .n = 38 * sizeof(u32),
662                 .size = sizeof(u32), .align = sizeof(u32),
663                 .get = genregs32_get, .set = genregs32_set
664         },
665         /* Format is:
666          *      F0 --> F31
667          *      empty 32-bit word
668          *      FSR (32--bit word)
669          *      FPU QUEUE COUNT (8-bit char)
670          *      FPU QUEUE ENTRYSIZE (8-bit char)
671          *      FPU ENABLED (8-bit char)
672          *      empty 8-bit char
673          *      FPU QUEUE (64 32-bit ints)
674          */
675         [REGSET_FP] = {
676                 .core_note_type = NT_PRFPREG,
677                 .n = 99 * sizeof(u32),
678                 .size = sizeof(u32), .align = sizeof(u32),
679                 .get = fpregs32_get, .set = fpregs32_set
680         },
681 };
682
683 static const struct user_regset_view user_sparc32_view = {
684         .name = "sparc", .e_machine = EM_SPARC,
685         .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
686 };
687 #endif /* CONFIG_COMPAT */
688
689 const struct user_regset_view *task_user_regset_view(struct task_struct *task)
690 {
691 #ifdef CONFIG_COMPAT
692         if (test_tsk_thread_flag(task, TIF_32BIT))
693                 return &user_sparc32_view;
694 #endif
695         return &user_sparc64_view;
696 }
697
698 #ifdef CONFIG_COMPAT
699 struct compat_fps {
700         unsigned int regs[32];
701         unsigned int fsr;
702         unsigned int flags;
703         unsigned int extra;
704         unsigned int fpqd;
705         struct compat_fq {
706                 unsigned int insnaddr;
707                 unsigned int insn;
708         } fpq[16];
709 };
710
711 long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
712                         compat_ulong_t caddr, compat_ulong_t cdata)
713 {
714         const struct user_regset_view *view = task_user_regset_view(child);
715         compat_ulong_t caddr2 = task_pt_regs(current)->u_regs[UREG_I4];
716         struct pt_regs32 __user *pregs;
717         struct compat_fps __user *fps;
718         unsigned long addr2 = caddr2;
719         unsigned long addr = caddr;
720         unsigned long data = cdata;
721         int ret;
722
723         pregs = (struct pt_regs32 __user *) addr;
724         fps = (struct compat_fps __user *) addr;
725
726         switch (request) {
727         case PTRACE_PEEKUSR:
728                 ret = (addr != 0) ? -EIO : 0;
729                 break;
730
731         case PTRACE_GETREGS:
732                 ret = copy_regset_to_user(child, view, REGSET_GENERAL,
733                                           32 * sizeof(u32),
734                                           4 * sizeof(u32),
735                                           &pregs->psr);
736                 if (!ret)
737                         ret = copy_regset_to_user(child, view, REGSET_GENERAL,
738                                                   1 * sizeof(u32),
739                                                   15 * sizeof(u32),
740                                                   &pregs->u_regs[0]);
741                 break;
742
743         case PTRACE_SETREGS:
744                 ret = copy_regset_from_user(child, view, REGSET_GENERAL,
745                                             32 * sizeof(u32),
746                                             4 * sizeof(u32),
747                                             &pregs->psr);
748                 if (!ret)
749                         ret = copy_regset_from_user(child, view, REGSET_GENERAL,
750                                                     1 * sizeof(u32),
751                                                     15 * sizeof(u32),
752                                                     &pregs->u_regs[0]);
753                 break;
754
755         case PTRACE_GETFPREGS:
756                 ret = copy_regset_to_user(child, view, REGSET_FP,
757                                           0 * sizeof(u32),
758                                           32 * sizeof(u32),
759                                           &fps->regs[0]);
760                 if (!ret)
761                         ret = copy_regset_to_user(child, view, REGSET_FP,
762                                                   33 * sizeof(u32),
763                                                   1 * sizeof(u32),
764                                                   &fps->fsr);
765                 if (!ret) {
766                         if (__put_user(0, &fps->flags) ||
767                             __put_user(0, &fps->extra) ||
768                             __put_user(0, &fps->fpqd) ||
769                             clear_user(&fps->fpq[0], 32 * sizeof(unsigned int)))
770                                 ret = -EFAULT;
771                 }
772                 break;
773
774         case PTRACE_SETFPREGS:
775                 ret = copy_regset_from_user(child, view, REGSET_FP,
776                                             0 * sizeof(u32),
777                                             32 * sizeof(u32),
778                                             &fps->regs[0]);
779                 if (!ret)
780                         ret = copy_regset_from_user(child, view, REGSET_FP,
781                                                     33 * sizeof(u32),
782                                                     1 * sizeof(u32),
783                                                     &fps->fsr);
784                 break;
785
786         case PTRACE_READTEXT:
787         case PTRACE_READDATA:
788                 ret = ptrace_readdata(child, addr,
789                                       (char __user *)addr2, data);
790                 if (ret == data)
791                         ret = 0;
792                 else if (ret >= 0)
793                         ret = -EIO;
794                 break;
795
796         case PTRACE_WRITETEXT:
797         case PTRACE_WRITEDATA:
798                 ret = ptrace_writedata(child, (char __user *) addr2,
799                                        addr, data);
800                 if (ret == data)
801                         ret = 0;
802                 else if (ret >= 0)
803                         ret = -EIO;
804                 break;
805
806         default:
807                 ret = compat_ptrace_request(child, request, addr, data);
808                 break;
809         }
810
811         return ret;
812 }
813 #endif /* CONFIG_COMPAT */
814
815 struct fps {
816         unsigned int regs[64];
817         unsigned long fsr;
818 };
819
820 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
821 {
822         const struct user_regset_view *view = task_user_regset_view(child);
823         unsigned long addr2 = task_pt_regs(current)->u_regs[UREG_I4];
824         struct pt_regs __user *pregs;
825         struct fps __user *fps;
826         int ret;
827
828         pregs = (struct pt_regs __user *) (unsigned long) addr;
829         fps = (struct fps __user *) (unsigned long) addr;
830
831         switch (request) {
832         case PTRACE_PEEKUSR:
833                 ret = (addr != 0) ? -EIO : 0;
834                 break;
835
836         case PTRACE_GETREGS64:
837                 ret = copy_regset_to_user(child, view, REGSET_GENERAL,
838                                           1 * sizeof(u64),
839                                           15 * sizeof(u64),
840                                           &pregs->u_regs[0]);
841                 if (!ret) {
842                         /* XXX doesn't handle 'y' register correctly XXX */
843                         ret = copy_regset_to_user(child, view, REGSET_GENERAL,
844                                                   32 * sizeof(u64),
845                                                   4 * sizeof(u64),
846                                                   &pregs->tstate);
847                 }
848                 break;
849
850         case PTRACE_SETREGS64:
851                 ret = copy_regset_from_user(child, view, REGSET_GENERAL,
852                                             1 * sizeof(u64),
853                                             15 * sizeof(u64),
854                                             &pregs->u_regs[0]);
855                 if (!ret) {
856                         /* XXX doesn't handle 'y' register correctly XXX */
857                         ret = copy_regset_from_user(child, view, REGSET_GENERAL,
858                                                     32 * sizeof(u64),
859                                                     4 * sizeof(u64),
860                                                     &pregs->tstate);
861                 }
862                 break;
863
864         case PTRACE_GETFPREGS64:
865                 ret = copy_regset_to_user(child, view, REGSET_FP,
866                                           0 * sizeof(u64),
867                                           33 * sizeof(u64),
868                                           fps);
869                 break;
870
871         case PTRACE_SETFPREGS64:
872                 ret = copy_regset_to_user(child, view, REGSET_FP,
873                                           0 * sizeof(u64),
874                                           33 * sizeof(u64),
875                                           fps);
876                 break;
877
878         case PTRACE_READTEXT:
879         case PTRACE_READDATA:
880                 ret = ptrace_readdata(child, addr,
881                                       (char __user *)addr2, data);
882                 if (ret == data)
883                         ret = 0;
884                 else if (ret >= 0)
885                         ret = -EIO;
886                 break;
887
888         case PTRACE_WRITETEXT:
889         case PTRACE_WRITEDATA:
890                 ret = ptrace_writedata(child, (char __user *) addr2,
891                                        addr, data);
892                 if (ret == data)
893                         ret = 0;
894                 else if (ret >= 0)
895                         ret = -EIO;
896                 break;
897
898         default:
899                 ret = ptrace_request(child, request, addr, data);
900                 break;
901         }
902
903         return ret;
904 }
905
906 asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p)
907 {
908         /* do the secure computing check first */
909         secure_computing(regs->u_regs[UREG_G1]);
910
911         if (unlikely(current->audit_context) && syscall_exit_p) {
912                 unsigned long tstate = regs->tstate;
913                 int result = AUDITSC_SUCCESS;
914
915                 if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
916                         result = AUDITSC_FAILURE;
917
918                 audit_syscall_exit(result, regs->u_regs[UREG_I0]);
919         }
920
921         if (!(current->ptrace & PT_PTRACED))
922                 goto out;
923
924         if (!test_thread_flag(TIF_SYSCALL_TRACE))
925                 goto out;
926
927         ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
928                                  ? 0x80 : 0));
929
930         /*
931          * this isn't the same as continuing with a signal, but it will do
932          * for normal use.  strace only continues with a signal if the
933          * stopping signal is not SIGTRAP.  -brl
934          */
935         if (current->exit_code) {
936                 send_sig(current->exit_code, current, 1);
937                 current->exit_code = 0;
938         }
939
940 out:
941         if (unlikely(current->audit_context) && !syscall_exit_p)
942                 audit_syscall_entry((test_thread_flag(TIF_32BIT) ?
943                                      AUDIT_ARCH_SPARC :
944                                      AUDIT_ARCH_SPARC64),
945                                     regs->u_regs[UREG_G1],
946                                     regs->u_regs[UREG_I0],
947                                     regs->u_regs[UREG_I1],
948                                     regs->u_regs[UREG_I2],
949                                     regs->u_regs[UREG_I3]);
950 }