Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / arch / sparc64 / kernel / ptrace.c
1 /* ptrace.c: Sparc64 process tracing support.
2  *
3  * Copyright (C) 1996, 2006 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/module.h>
15 #include <linux/sched.h>
16 #include <linux/mm.h>
17 #include <linux/security.h>
18 #include <linux/seccomp.h>
19 #include <linux/audit.h>
20 #include <linux/tracehook.h>
21 #include <linux/elf.h>
22 #include <linux/ptrace.h>
23
24 #include <asm/asi.h>
25 #include <asm/pgtable.h>
26 #include <asm/system.h>
27 #include <asm/spitfire.h>
28 #include <asm/page.h>
29 #include <asm/cpudata.h>
30 #include <asm/psrcompat.h>
31
32 #define GENREG_G0       0
33 #define GENREG_O0       8
34 #define GENREG_L0       16
35 #define GENREG_I0       24
36 #define GENREG_TSTATE   32
37 #define GENREG_TPC      33
38 #define GENREG_TNPC     34
39 #define GENREG_Y        35
40
41 #define SPARC64_NGREGS  36
42
43 static int genregs_get(struct task_struct *target,
44                        const struct utrace_regset *regset,
45                        unsigned int pos, unsigned int count,
46                        void *kbuf, void __user *ubuf)
47 {
48         struct pt_regs *regs = task_pt_regs(target);
49         int err;
50
51         err = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, regs->u_regs,
52                                     GENREG_G0 * 8, GENREG_L0 * 8);
53
54         if (err == 0 && count > 0 && pos < (GENREG_TSTATE * 8)) {
55                 struct thread_info *t = task_thread_info(target);
56                 unsigned long rwindow[16], fp, *win;
57                 int wsaved;
58
59                 if (target == current)
60                         flushw_user();
61
62                 wsaved = __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_WSAVED];
63                 fp = regs->u_regs[UREG_FP] + STACK_BIAS;
64                 if (wsaved && t->rwbuf_stkptrs[wsaved - 1] == fp)
65                         win = &t->reg_window[wsaved - 1].locals[0];
66                 else {
67                         if (target == current) {
68                                 if (copy_from_user(rwindow,
69                                                    (void __user *) fp,
70                                                    16 * sizeof(long)))
71                                         err = -EFAULT;
72                         } else
73                                 err = access_process_vm(target, fp, rwindow,
74                                                         16 * sizeof(long), 0);
75                         if (err)
76                                 return err;
77                         win = rwindow;
78                 }
79
80                 err = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
81                                             win, GENREG_L0 * 8,
82                                             GENREG_TSTATE * 8);
83         }
84
85         if (err == 0)
86                 err = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
87                                             &regs->tstate, GENREG_TSTATE * 8,
88                                             GENREG_Y * 8);
89         if (err == 0 && count > 0) {
90                 if (kbuf)
91                         *(unsigned long *) kbuf = regs->y;
92                 else if (put_user(regs->y, (unsigned long __user *) ubuf))
93                         return -EFAULT;
94         }
95
96         return err;
97 }
98
99 /* Consistent with signal handling, we only allow userspace to
100  * modify the %asi, %icc, and %xcc fields of the %tstate register.
101  */
102 #define TSTATE_DEBUGCHANGE      (TSTATE_ASI | TSTATE_ICC | TSTATE_XCC)
103
104 static int genregs_set(struct task_struct *target,
105                        const struct utrace_regset *regset,
106                        unsigned int pos, unsigned int count,
107                        const void *kbuf, const void __user *ubuf)
108 {
109         struct pt_regs *regs = task_pt_regs(target);
110         unsigned long tstate_save;
111         int err;
112
113         err = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, regs->u_regs,
114                                    GENREG_G0 * 8, GENREG_L0 * 8);
115
116         if (err == 0 && count > 0 && pos < (GENREG_TSTATE * 8)) {
117                 unsigned long fp = regs->u_regs[UREG_FP] + STACK_BIAS;
118                 unsigned long rwindow[16], *winbuf;
119                 unsigned int copy = (GENREG_TSTATE * 8) - pos;
120                 unsigned int off;
121                 int err;
122
123                 if (target == current)
124                         flushw_user();
125
126                 if (count < copy)
127                         copy = count;
128                 off = pos - (GENREG_L0 * 8);
129
130                 if (kbuf) {
131                         winbuf = (unsigned long *) kbuf;
132                         kbuf += copy;
133                 }
134                 else {
135                         winbuf = rwindow;
136                         if (copy_from_user(winbuf, ubuf, copy))
137                                 return -EFAULT;
138                         ubuf += copy;
139                 }
140                 count -= copy;
141                 pos += copy;
142
143                 if (target == current)
144                         err = copy_to_user((void __user *) fp + off,
145                                            winbuf, copy);
146                 else
147                         err = access_process_vm(target, fp + off,
148                                                 winbuf, copy, 1);
149         }
150
151         tstate_save = regs->tstate &~ TSTATE_DEBUGCHANGE;
152
153         if (err == 0)
154                 err = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
155                                             &regs->tstate, GENREG_TSTATE * 8,
156                                             GENREG_Y * 8);
157
158         regs->tstate &= TSTATE_DEBUGCHANGE;
159         regs->tstate |= tstate_save;
160
161         if (err == 0 && count > 0) {
162                 if (kbuf)
163                         regs->y = *(unsigned long *) kbuf;
164                 else if (get_user(regs->y, (unsigned long __user *) ubuf))
165                         return -EFAULT;
166         }
167
168         return err;
169 }
170
171 #define FPREG_F0        0
172 #define FPREG_FSR       32
173 #define FPREG_GSR       33
174 #define FPREG_FPRS      34
175
176 #define SPARC64_NFPREGS 35
177
178 static int fpregs_get(struct task_struct *target,
179                       const struct utrace_regset *regset,
180                       unsigned int pos, unsigned int count,
181                       void *kbuf, void __user *ubuf)
182 {
183         struct thread_info *t = task_thread_info(target);
184         int err;
185
186         err = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
187                                     t->fpregs, FPREG_F0 * 8, FPREG_FSR * 8);
188
189         if (err == 0)
190                 err = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
191                                             &t->xfsr[0], FPREG_FSR * 8,
192                                             FPREG_GSR * 8);
193
194         if (err == 0)
195                 err = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
196                                             &t->gsr[0], FPREG_GSR * 8,
197                                             FPREG_FPRS * 8);
198
199         if (err == 0 && count > 0) {
200                 struct pt_regs *regs = task_pt_regs(target);
201
202                 if (kbuf)
203                         *(unsigned long *) kbuf = regs->fprs;
204                 else if (put_user(regs->fprs, (unsigned long __user *) ubuf))
205                         return -EFAULT;
206         }
207         if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) {
208                 pt_error_return(regs, ESRCH);
209                 goto out_tsk;
210         }
211
212         return err;
213 }
214
215 static int fpregs_set(struct task_struct *target,
216                       const struct utrace_regset *regset,
217                       unsigned int pos, unsigned int count,
218                       const void *kbuf, const void __user *ubuf)
219 {
220         struct thread_info *t = task_thread_info(target);
221         int err;
222
223         err = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
224                                    t->fpregs, FPREG_F0 * 8, FPREG_FSR * 8);
225
226         if (err == 0)
227                 err = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
228                                            &t->xfsr[0], FPREG_FSR * 8,
229                                            FPREG_GSR * 8);
230
231         if (err == 0)
232                 err = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
233                                            &t->gsr[0], FPREG_GSR * 8,
234                                            FPREG_FPRS * 8);
235
236         if (err == 0 && count > 0) {
237                 struct pt_regs *regs = task_pt_regs(target);
238
239                 if (kbuf)
240                         regs->fprs = *(unsigned long *) kbuf;
241                 else if (get_user(regs->fprs, (unsigned long __user *) ubuf))
242                         return -EFAULT;
243         }
244
245         return err;
246 }
247
248 static const struct utrace_regset native_regsets[] = {
249         {
250                 .n = SPARC64_NGREGS,
251                 .size = sizeof(long), .align = sizeof(long),
252                 .get = genregs_get, .set = genregs_set
253         },
254         {
255                 .n = SPARC64_NFPREGS,
256                 .size = sizeof(long), .align = sizeof(long),
257                 .get = fpregs_get, .set = fpregs_set
258         },
259 };
260
261 const struct utrace_regset_view utrace_sparc64_native_view = {
262         .name = UTS_MACHINE, .e_machine = ELF_ARCH,
263         .regsets = native_regsets,
264         .n = sizeof native_regsets / sizeof native_regsets[0],
265 };
266 EXPORT_SYMBOL_GPL(utrace_sparc64_native_view);
267
268 #ifdef CONFIG_COMPAT
269
270 #define GENREG32_G0     0
271 #define GENREG32_O0     8
272 #define GENREG32_L0     16
273 #define GENREG32_I0     24
274 #define GENREG32_PSR    32
275 #define GENREG32_PC     33
276 #define GENREG32_NPC    34
277 #define GENREG32_Y      35
278 #define GENREG32_WIM    36
279 #define GENREG32_TBR    37
280
281 #define SPARC32_NGREGS  38
282
283 static int genregs32_get(struct task_struct *target,
284                          const struct utrace_regset *regset,
285                          unsigned int pos, unsigned int count,
286                          void *kbuf, void __user *ubuf)
287 {
288         struct pt_regs *regs = task_pt_regs(target);
289
290         while (count > 0 && pos < (GENREG32_L0 * 4)) {
291                 u32 val = regs->u_regs[(pos - (GENREG32_G0*4))/sizeof(u32)];
292                 if (kbuf) {
293                         *(u32 *) kbuf = val;
294                         kbuf += sizeof(u32);
295                 } else if (put_user(val, (u32 __user *) ubuf))
296                         return -EFAULT;
297                 else
298                         ubuf += sizeof(u32);
299                 pos += sizeof(u32);
300                 count -= sizeof(u32);
301         }
302
303         if (count > 0 && pos < (GENREG32_PSR * 4)) {
304                 struct thread_info *t = task_thread_info(target);
305                 unsigned long fp;
306                 u32 rwindow[16];
307                 int wsaved;
308
309                 if (target == current)
310                         flushw_user();
311
312                 wsaved = __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_WSAVED];
313                 fp = regs->u_regs[UREG_FP] & 0xffffffffUL;
314                 if (wsaved && t->rwbuf_stkptrs[wsaved - 1] == fp) {
315                         int i;
316                         for (i = 0; i < 8; i++)
317                                 rwindow[i + 0] =
318                                         t->reg_window[wsaved-1].locals[i];
319                         for (i = 0; i < 8; i++)
320                                 rwindow[i + 8] =
321                                         t->reg_window[wsaved-1].ins[i];
322                 } else {
323                         int err;
324
325                         if (target == current) {
326                                 err = 0;
327                                 if (copy_from_user(rwindow, (void __user *) fp,
328                                                    16 * sizeof(u32)))
329                                         err = -EFAULT;
330                         } else
331                                 err = access_process_vm(target, fp, rwindow,
332                                                         16 * sizeof(u32), 0);
333                         if (err)
334                                 return err;
335                 }
336
337                 while (count > 0 && pos < (GENREG32_PSR * 4)) {
338                         u32 val = rwindow[(pos - (GENREG32_L0*4))/sizeof(u32)];
339
340                         if (kbuf) {
341                                 *(u32 *) kbuf = val;
342                                 kbuf += sizeof(u32);
343                         } else if (put_user(val, (u32 __user *) ubuf))
344                                 return -EFAULT;
345                         else
346                                 ubuf += sizeof(u32);
347                         pos += sizeof(u32);
348                         count -= sizeof(u32);
349                 }
350         }
351
352         if (count > 0 && pos == (GENREG32_PSR * 4)) {
353                 u32 psr = tstate_to_psr(regs->tstate);
354
355                 if (kbuf) {
356                         *(u32 *) kbuf = psr;
357                         kbuf += sizeof(u32);
358                 } else if (put_user(psr, (u32 __user *) ubuf))
359                         return -EFAULT;
360                 else
361                         ubuf += sizeof(u32);
362                 pos += sizeof(u32);
363                 count -= sizeof(u32);
364         }
365
366         if (count > 0 && pos == (GENREG32_PC * 4)) {
367                 u32 val = regs->tpc;
368
369                 if (kbuf) {
370                         *(u32 *) kbuf = val;
371                         kbuf += sizeof(u32);
372                 } else if (put_user(val, (u32 __user *) ubuf))
373                         return -EFAULT;
374                 else
375                         ubuf += sizeof(u32);
376                 pos += sizeof(u32);
377                 count -= sizeof(u32);
378         }
379
380         if (count > 0 && pos == (GENREG32_NPC * 4)) {
381                 u32 val = regs->tnpc;
382
383                 if (kbuf) {
384                         *(u32 *) kbuf = val;
385                         kbuf += sizeof(u32);
386                 } else if (put_user(val, (u32 __user *) ubuf))
387                         return -EFAULT;
388                 else
389                         ubuf += sizeof(u32);
390                 pos += sizeof(u32);
391                 count -= sizeof(u32);
392         }
393
394         if (count > 0 && pos == (GENREG32_Y * 4)) {
395                 if (kbuf) {
396                         *(u32 *) kbuf = regs->y;
397                         kbuf += sizeof(u32);
398                 } else if (put_user(regs->y, (u32 __user *) ubuf))
399                         return -EFAULT;
400                 else
401                         ubuf += sizeof(u32);
402                 pos += sizeof(u32);
403                 count -= sizeof(u32);
404         }
405
406         if (count > 0) {
407                 if (kbuf)
408                         memset(kbuf, 0, count);
409                 else if (clear_user(ubuf, count))
410                         return -EFAULT;
411         }
412
413         return 0;
414 }
415
416 static int genregs32_set(struct task_struct *target,
417                          const struct utrace_regset *regset,
418                          unsigned int pos, unsigned int count,
419                          const void *kbuf, const void __user *ubuf)
420 {
421         struct pt_regs *regs = task_pt_regs(target);
422
423         while (count > 0 && pos < (GENREG32_L0 * 4)) {
424                 unsigned long *loc;
425                 loc = &regs->u_regs[(pos - (GENREG32_G0*4))/sizeof(u32)];
426                 if (kbuf) {
427                         *loc = *(u32 *) kbuf;
428                         kbuf += sizeof(u32);
429                 } else if (get_user(*loc, (u32 __user *) ubuf))
430                         return -EFAULT;
431                 else
432                         ubuf += sizeof(u32);
433                 pos += sizeof(u32);
434                 count -= sizeof(u32);
435         }
436
437         if (count > 0 && pos < (GENREG32_PSR * 4)) {
438                 unsigned long fp;
439                 u32 regbuf[16];
440                 unsigned int off, copy;
441                 int err;
442
443                 if (target == current)
444                         flushw_user();
445
446                 copy = (GENREG32_PSR * 4) - pos;
447                 if (count < copy)
448                         copy = count;
449                 BUG_ON(copy > 16 * sizeof(u32));
450
451                 fp = regs->u_regs[UREG_FP] & 0xffffffffUL;
452                 off = pos - (GENREG32_L0 * 4);
453                 if (kbuf) {
454                         memcpy(regbuf, kbuf, copy);
455                         kbuf += copy;
456                 } else if (copy_from_user(regbuf, ubuf, copy))
457                         return -EFAULT;
458                 else
459                         ubuf += copy;
460                 pos += copy;
461                 count -= copy;
462
463                 if (target == current) {
464                         err = 0;
465                         if (copy_to_user((void __user *) fp + off,
466                                          regbuf, count))
467                                 err = -EFAULT;
468                 } else
469                         err = access_process_vm(target, fp + off,
470                                                 regbuf, count, 1);
471                 if (err)
472                         return err;
473         }
474
475         if (count > 0 && pos == (GENREG32_PSR * 4)) {
476                 unsigned long tstate, tstate_save;
477                 u32 psr;
478
479                 tstate_save = regs->tstate&~(TSTATE_ICC|TSTATE_XCC);
480
481                 if (kbuf) {
482                         psr = *(u32 *) kbuf;
483                         kbuf += sizeof(u32);
484                 } else if (get_user(psr, (u32 __user *) ubuf))
485                         return -EFAULT;
486                 else
487                         ubuf += sizeof(u32);
488                 pos += sizeof(u32);
489                 count -= sizeof(u32);
490
491                 tstate = psr_to_tstate_icc(psr);
492                 regs->tstate = tstate_save | tstate;
493         }
494
495         if (count > 0 && pos == (GENREG32_PC * 4)) {
496                 if (kbuf) {
497                         regs->tpc = *(u32 *) kbuf;
498                         kbuf += sizeof(u32);
499                 } else if (get_user(regs->tpc, (u32 __user *) ubuf))
500                         return -EFAULT;
501                 else
502                         ubuf += sizeof(u32);
503                 pos += sizeof(u32);
504                 count -= sizeof(u32);
505         }
506
507         if (count > 0 && pos == (GENREG32_NPC * 4)) {
508                 if (kbuf) {
509                         regs->tnpc = *(u32 *) kbuf;
510                         kbuf += sizeof(u32);
511                 } else if (get_user(regs->tnpc, (u32 __user *) ubuf))
512                         return -EFAULT;
513                 else
514                         ubuf += sizeof(u32);
515                 pos += sizeof(u32);
516                 count -= sizeof(u32);
517         }
518
519         if (count > 0 && pos == (GENREG32_Y * 4)) {
520                 if (kbuf) {
521                         regs->y = *(u32 *) kbuf;
522                         kbuf += sizeof(u32);
523                 } else if (get_user(regs->y, (u32 __user *) ubuf))
524                         return -EFAULT;
525                 else
526                         ubuf += sizeof(u32);
527                 pos += sizeof(u32);
528                 count -= sizeof(u32);
529         }
530
531         /* Ignore WIM and TBR */
532
533         return 0;
534 }
535
536 #define FPREG32_F0      0
537 #define FPREG32_FSR     32
538
539 #define SPARC32_NFPREGS 33
540
541 static int fpregs32_get(struct task_struct *target,
542                         const struct utrace_regset *regset,
543                         unsigned int pos, unsigned int count,
544                         void *kbuf, void __user *ubuf)
545 {
546         struct thread_info *t = task_thread_info(target);
547         int err;
548
549         err = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
550                                     t->fpregs, FPREG32_F0 * 4,
551                                     FPREG32_FSR * 4);
552
553         if (err == 0 && count > 0) {
554                 if (kbuf) {
555                         *(u32 *) kbuf = t->xfsr[0];
556                 } else if (put_user(t->xfsr[0], (u32 __user *) ubuf))
557                         return -EFAULT;
558         }
559
560         return err;
561 }
562
563 static int fpregs32_set(struct task_struct *target,
564                         const struct utrace_regset *regset,
565                         unsigned int pos, unsigned int count,
566                         const void *kbuf, const void __user *ubuf)
567 {
568         struct thread_info *t = task_thread_info(target);
569         int err;
570
571         err = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
572                                    t->fpregs, FPREG32_F0 * 4,
573                                    FPREG32_FSR * 4);
574
575         if (err == 0 && count > 0) {
576                 u32 fsr;
577                 if (kbuf) {
578                         fsr = *(u32 *) kbuf;
579                 } else if (get_user(fsr, (u32 __user *) ubuf))
580                         return -EFAULT;
581                 t->xfsr[0] = (t->xfsr[0] & 0xffffffff00000000UL) | fsr;
582         }
583
584         return 0;
585 }
586
587 static const struct utrace_regset sparc32_regsets[] = {
588         {
589                 .n = SPARC32_NGREGS,
590                 .size = sizeof(u32), .align = sizeof(u32),
591                 .get = genregs32_get, .set = genregs32_set
592         },
593         {
594                 .n = SPARC32_NFPREGS,
595                 .size = sizeof(u32), .align = sizeof(u32),
596                 .get = fpregs32_get, .set = fpregs32_set
597         },
598 };
599
600 const struct utrace_regset_view utrace_sparc32_view = {
601         .name = "sparc", .e_machine = EM_SPARC,
602         .regsets = sparc32_regsets,
603         .n = sizeof sparc32_regsets / sizeof sparc32_regsets[0],
604 };
605 EXPORT_SYMBOL_GPL(utrace_sparc32_view);
606
607 #endif  /* CONFIG_COMPAT */
608
609 /* To get the necessary page struct, access_process_vm() first calls
610  * get_user_pages().  This has done a flush_dcache_page() on the
611  * accessed page.  Then our caller (copy_{to,from}_user_page()) did
612  * to memcpy to read/write the data from that page.
613  *
614  * Now, the only thing we have to do is:
615  * 1) flush the D-cache if it's possible than an illegal alias
616  *    has been created
617  * 2) flush the I-cache if this is pre-cheetah and we did a write
618  */
619 void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
620                          unsigned long uaddr, void *kaddr,
621                          unsigned long len, int write)
622 {
623         BUG_ON(len > PAGE_SIZE);
624
625         if (tlb_type == hypervisor)
626                 return;
627
628 #ifdef DCACHE_ALIASING_POSSIBLE
629         /* If bit 13 of the kernel address we used to access the
630          * user page is the same as the virtual address that page
631          * is mapped to in the user's address space, we can skip the
632          * D-cache flush.
633          */
634         if ((uaddr ^ (unsigned long) kaddr) & (1UL << 13)) {
635                 unsigned long start = __pa(kaddr);
636                 unsigned long end = start + len;
637                 unsigned long dcache_line_size;
638
639                 dcache_line_size = local_cpu_data().dcache_line_size;
640
641                 if (tlb_type == spitfire) {
642                         for (; start < end; start += dcache_line_size)
643                                 spitfire_put_dcache_tag(start & 0x3fe0, 0x0);
644                 } else {
645                         start &= ~(dcache_line_size - 1);
646                         for (; start < end; start += dcache_line_size)
647                                 __asm__ __volatile__(
648                                         "stxa %%g0, [%0] %1\n\t"
649                                         "membar #Sync"
650                                         : /* no outputs */
651                                         : "r" (start),
652                                         "i" (ASI_DCACHE_INVALIDATE));
653                 }
654         }
655 #endif
656         if (write && tlb_type == spitfire) {
657                 unsigned long start = (unsigned long) kaddr;
658                 unsigned long end = start + len;
659                 unsigned long icache_line_size;
660
661                 icache_line_size = local_cpu_data().icache_line_size;
662
663                 for (; start < end; start += icache_line_size)
664                         flushi(start);
665         }
666 }
667
668 #ifdef CONFIG_PTRACE
669 static const struct ptrace_layout_segment sparc64_getregs_layout[] = {
670         { 0, offsetof(struct pt_regs, u_regs[15]), 0, sizeof(long) },
671         { offsetof(struct pt_regs, u_regs[15]),
672           offsetof(struct pt_regs, tstate),
673           -1, 0 },
674         { offsetof(struct pt_regs, tstate), offsetof(struct pt_regs, y),
675           0, 32 * sizeof(long) },
676         {0, 0, -1, 0}
677 };
678
679 int arch_ptrace(long *request, struct task_struct *child,
680                 struct utrace_attached_engine *engine,
681                 unsigned long addr, unsigned long data,
682                 long *retval)
683 {
684         void __user *uaddr = (void __user *) addr;
685         struct pt_regs *uregs = uaddr;
686         int err = -ENOSYS;
687
688         switch (*request) {
689         case PTRACE_GETREGS64:
690                 err = ptrace_layout_access(child, engine,
691                                            &utrace_sparc64_native_view,
692                                            sparc64_getregs_layout,
693                                            0, offsetof(struct pt_regs, y),
694                                            uaddr, NULL, 0);
695                 if (!err &&
696                     (put_user(task_pt_regs(child)->y, &uregs->y) ||
697                      put_user(task_pt_regs(child)->fprs, &uregs->fprs)))
698                         err = -EFAULT;
699                 break;
700
701         case PTRACE_SETREGS64:
702                 err = ptrace_layout_access(child, engine,
703                                            &utrace_sparc64_native_view,
704                                            sparc64_getregs_layout,
705                                            0, offsetof(struct pt_regs, y),
706                                            uaddr, NULL, 1);
707                 if (!err &&
708                     (get_user(task_pt_regs(child)->y, &uregs->y) ||
709                      get_user(task_pt_regs(child)->fprs, &uregs->fprs)))
710                         err = -EFAULT;
711                 break;
712
713         case PTRACE_GETFPREGS64:
714         case PTRACE_SETFPREGS64:
715                 err = ptrace_regset_access(child, engine,
716                                            utrace_native_view(current),
717                                            2, 0, 34 * sizeof(long), uaddr,
718                                            (*request == PTRACE_SETFPREGS64));
719                 break;
720
721         case PTRACE_SUNDETACH:
722                 *request = PTRACE_DETACH;
723                 break;
724                        
725         default:
726                 break;
727         };
728         return err;
729 }
730
731 #ifdef CONFIG_COMPAT
732 static const struct ptrace_layout_segment sparc32_getregs_layout[] = {
733         { 0, offsetof(struct pt_regs32, u_regs[0]),
734           0, GENREG32_PSR * sizeof(u32) },
735         { offsetof(struct pt_regs32, u_regs[0]),
736           offsetof(struct pt_regs32, u_regs[15]),
737           0, 1 * sizeof(u32) },
738         { offsetof(struct pt_regs32, u_regs[15]), sizeof(struct pt_regs32),
739           -1, 0 },
740         {0, 0, -1, 0}
741 };
742
743 int arch_compat_ptrace(compat_long_t *request, struct task_struct *child,
744                        struct utrace_attached_engine *engine,
745                        compat_ulong_t addr, compat_ulong_t data,
746                        compat_long_t *retval)
747 {
748         void __user *uaddr = (void __user *) (unsigned long) addr;
749         int err = -ENOSYS;
750
751         switch (*request) {
752         case PTRACE_GETREGS:
753         case PTRACE_SETREGS:
754                 err = ptrace_layout_access(child, engine,
755                                            &utrace_sparc32_view,
756                                            sparc32_getregs_layout,
757                                            0, sizeof(struct pt_regs32),
758                                            uaddr, NULL,
759                                            (*request ==
760                                             PTRACE_SETREGS));
761                 break;
762
763         case PTRACE_GETFPREGS:
764         case PTRACE_SETFPREGS:
765                 err = ptrace_whole_regset(child, engine, addr, 1,
766                                           (*request == PTRACE_SETFPREGS));
767                 break;
768
769         case PTRACE_SUNDETACH:
770                 *request = PTRACE_DETACH;
771                 break;
772
773         default:
774                 break;
775         };
776         return err;
777 }
778 #endif  /* CONFIG_COMPAT */
779 #endif /* CONFIG_PTRACE */
780
781 asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p)
782 {
783         /* do the secure computing check first */
784         if (!syscall_exit_p)
785                 secure_computing(regs->u_regs[UREG_G1]);
786
787         if (unlikely(current->audit_context) && syscall_exit_p) {
788                 unsigned long tstate = regs->tstate;
789                 int result = AUDITSC_SUCCESS;
790
791                 if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
792                         result = AUDITSC_FAILURE;
793
794                 audit_syscall_exit(result, regs->u_regs[UREG_I0]);
795         }
796
797         if (test_thread_flag(TIF_SYSCALL_TRACE))
798                 tracehook_report_syscall(regs, syscall_exit_p);
799
800         if (unlikely(current->audit_context) && !syscall_exit_p)
801                 audit_syscall_entry((test_thread_flag(TIF_32BIT) ?
802                                      AUDIT_ARCH_SPARC :
803                                      AUDIT_ARCH_SPARC64),
804                                     regs->u_regs[UREG_G1],
805                                     regs->u_regs[UREG_I0],
806                                     regs->u_regs[UREG_I1],
807                                     regs->u_regs[UREG_I2],
808                                     regs->u_regs[UREG_I3]);
809 }