fedora core 6 1.2949 + vserver 2.2.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
208         return err;
209 }
210
211 static int fpregs_set(struct task_struct *target,
212                       const struct utrace_regset *regset,
213                       unsigned int pos, unsigned int count,
214                       const void *kbuf, const void __user *ubuf)
215 {
216         struct thread_info *t = task_thread_info(target);
217         int err;
218
219         err = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
220                                    t->fpregs, FPREG_F0 * 8, FPREG_FSR * 8);
221
222         if (err == 0)
223                 err = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
224                                            &t->xfsr[0], FPREG_FSR * 8,
225                                            FPREG_GSR * 8);
226
227         if (err == 0)
228                 err = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
229                                            &t->gsr[0], FPREG_GSR * 8,
230                                            FPREG_FPRS * 8);
231
232         if (err == 0 && count > 0) {
233                 struct pt_regs *regs = task_pt_regs(target);
234
235                 if (kbuf)
236                         regs->fprs = *(unsigned long *) kbuf;
237                 else if (get_user(regs->fprs, (unsigned long __user *) ubuf))
238                         return -EFAULT;
239         }
240
241         return err;
242 }
243
244 static const struct utrace_regset native_regsets[] = {
245         {
246                 .n = SPARC64_NGREGS,
247                 .size = sizeof(long), .align = sizeof(long),
248                 .get = genregs_get, .set = genregs_set
249         },
250         {
251                 .n = SPARC64_NFPREGS,
252                 .size = sizeof(long), .align = sizeof(long),
253                 .get = fpregs_get, .set = fpregs_set
254         },
255 };
256
257 const struct utrace_regset_view utrace_sparc64_native_view = {
258         .name = UTS_MACHINE, .e_machine = ELF_ARCH,
259         .regsets = native_regsets, .n = ARRAY_SIZE(native_regsets)
260 };
261 EXPORT_SYMBOL_GPL(utrace_sparc64_native_view);
262
263 #ifdef CONFIG_COMPAT
264
265 #define GENREG32_G0     0
266 #define GENREG32_O0     8
267 #define GENREG32_L0     16
268 #define GENREG32_I0     24
269 #define GENREG32_PSR    32
270 #define GENREG32_PC     33
271 #define GENREG32_NPC    34
272 #define GENREG32_Y      35
273 #define GENREG32_WIM    36
274 #define GENREG32_TBR    37
275
276 #define SPARC32_NGREGS  38
277
278 static int genregs32_get(struct task_struct *target,
279                          const struct utrace_regset *regset,
280                          unsigned int pos, unsigned int count,
281                          void *kbuf, void __user *ubuf)
282 {
283         struct pt_regs *regs = task_pt_regs(target);
284
285         while (count > 0 && pos < (GENREG32_L0 * 4)) {
286                 u32 val = regs->u_regs[(pos - (GENREG32_G0*4))/sizeof(u32)];
287                 if (kbuf) {
288                         *(u32 *) kbuf = val;
289                         kbuf += sizeof(u32);
290                 } else if (put_user(val, (u32 __user *) ubuf))
291                         return -EFAULT;
292                 else
293                         ubuf += sizeof(u32);
294                 pos += sizeof(u32);
295                 count -= sizeof(u32);
296         }
297
298         if (count > 0 && pos < (GENREG32_PSR * 4)) {
299                 struct thread_info *t = task_thread_info(target);
300                 unsigned long fp;
301                 u32 rwindow[16];
302                 int wsaved;
303
304                 if (target == current)
305                         flushw_user();
306
307                 wsaved = __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_WSAVED];
308                 fp = regs->u_regs[UREG_FP] & 0xffffffffUL;
309                 if (wsaved && t->rwbuf_stkptrs[wsaved - 1] == fp) {
310                         int i;
311                         for (i = 0; i < 8; i++)
312                                 rwindow[i + 0] =
313                                         t->reg_window[wsaved-1].locals[i];
314                         for (i = 0; i < 8; i++)
315                                 rwindow[i + 8] =
316                                         t->reg_window[wsaved-1].ins[i];
317                 } else {
318                         int err;
319
320                         if (target == current) {
321                                 err = 0;
322                                 if (copy_from_user(rwindow, (void __user *) fp,
323                                                    16 * sizeof(u32)))
324                                         err = -EFAULT;
325                         } else
326                                 err = access_process_vm(target, fp, rwindow,
327                                                         16 * sizeof(u32), 0);
328                         if (err)
329                                 return err;
330                 }
331
332                 while (count > 0 && pos < (GENREG32_PSR * 4)) {
333                         u32 val = rwindow[(pos - (GENREG32_L0*4))/sizeof(u32)];
334
335                         if (kbuf) {
336                                 *(u32 *) kbuf = val;
337                                 kbuf += sizeof(u32);
338                         } else if (put_user(val, (u32 __user *) ubuf))
339                                 return -EFAULT;
340                         else
341                                 ubuf += sizeof(u32);
342                         pos += sizeof(u32);
343                         count -= sizeof(u32);
344                 }
345         }
346
347         if (count > 0 && pos == (GENREG32_PSR * 4)) {
348                 u32 psr = tstate_to_psr(regs->tstate);
349
350                 if (kbuf) {
351                         *(u32 *) kbuf = psr;
352                         kbuf += sizeof(u32);
353                 } else if (put_user(psr, (u32 __user *) ubuf))
354                         return -EFAULT;
355                 else
356                         ubuf += sizeof(u32);
357                 pos += sizeof(u32);
358                 count -= sizeof(u32);
359         }
360
361         if (count > 0 && pos == (GENREG32_PC * 4)) {
362                 u32 val = regs->tpc;
363
364                 if (kbuf) {
365                         *(u32 *) kbuf = val;
366                         kbuf += sizeof(u32);
367                 } else if (put_user(val, (u32 __user *) ubuf))
368                         return -EFAULT;
369                 else
370                         ubuf += sizeof(u32);
371                 pos += sizeof(u32);
372                 count -= sizeof(u32);
373         }
374
375         if (count > 0 && pos == (GENREG32_NPC * 4)) {
376                 u32 val = regs->tnpc;
377
378                 if (kbuf) {
379                         *(u32 *) kbuf = val;
380                         kbuf += sizeof(u32);
381                 } else if (put_user(val, (u32 __user *) ubuf))
382                         return -EFAULT;
383                 else
384                         ubuf += sizeof(u32);
385                 pos += sizeof(u32);
386                 count -= sizeof(u32);
387         }
388
389         if (count > 0 && pos == (GENREG32_Y * 4)) {
390                 if (kbuf) {
391                         *(u32 *) kbuf = regs->y;
392                         kbuf += sizeof(u32);
393                 } else if (put_user(regs->y, (u32 __user *) ubuf))
394                         return -EFAULT;
395                 else
396                         ubuf += sizeof(u32);
397                 pos += sizeof(u32);
398                 count -= sizeof(u32);
399         }
400
401         if (count > 0) {
402                 if (kbuf)
403                         memset(kbuf, 0, count);
404                 else if (clear_user(ubuf, count))
405                         return -EFAULT;
406         }
407
408         return 0;
409 }
410
411 static int genregs32_set(struct task_struct *target,
412                          const struct utrace_regset *regset,
413                          unsigned int pos, unsigned int count,
414                          const void *kbuf, const void __user *ubuf)
415 {
416         struct pt_regs *regs = task_pt_regs(target);
417
418         while (count > 0 && pos < (GENREG32_L0 * 4)) {
419                 unsigned long *loc;
420                 loc = &regs->u_regs[(pos - (GENREG32_G0*4))/sizeof(u32)];
421                 if (kbuf) {
422                         *loc = *(u32 *) kbuf;
423                         kbuf += sizeof(u32);
424                 } else if (get_user(*loc, (u32 __user *) ubuf))
425                         return -EFAULT;
426                 else
427                         ubuf += sizeof(u32);
428                 pos += sizeof(u32);
429                 count -= sizeof(u32);
430         }
431
432         if (count > 0 && pos < (GENREG32_PSR * 4)) {
433                 unsigned long fp;
434                 u32 regbuf[16];
435                 unsigned int off, copy;
436                 int err;
437
438                 if (target == current)
439                         flushw_user();
440
441                 copy = (GENREG32_PSR * 4) - pos;
442                 if (count < copy)
443                         copy = count;
444                 BUG_ON(copy > 16 * sizeof(u32));
445
446                 fp = regs->u_regs[UREG_FP] & 0xffffffffUL;
447                 off = pos - (GENREG32_L0 * 4);
448                 if (kbuf) {
449                         memcpy(regbuf, kbuf, copy);
450                         kbuf += copy;
451                 } else if (copy_from_user(regbuf, ubuf, copy))
452                         return -EFAULT;
453                 else
454                         ubuf += copy;
455                 pos += copy;
456                 count -= copy;
457
458                 if (target == current) {
459                         err = 0;
460                         if (copy_to_user((void __user *) fp + off,
461                                          regbuf, count))
462                                 err = -EFAULT;
463                 } else
464                         err = access_process_vm(target, fp + off,
465                                                 regbuf, count, 1);
466                 if (err)
467                         return err;
468         }
469
470         if (count > 0 && pos == (GENREG32_PSR * 4)) {
471                 unsigned long tstate, tstate_save;
472                 u32 psr;
473
474                 tstate_save = regs->tstate&~(TSTATE_ICC|TSTATE_XCC);
475
476                 if (kbuf) {
477                         psr = *(u32 *) kbuf;
478                         kbuf += sizeof(u32);
479                 } else if (get_user(psr, (u32 __user *) ubuf))
480                         return -EFAULT;
481                 else
482                         ubuf += sizeof(u32);
483                 pos += sizeof(u32);
484                 count -= sizeof(u32);
485
486                 tstate = psr_to_tstate_icc(psr);
487                 regs->tstate = tstate_save | tstate;
488         }
489
490         if (count > 0 && pos == (GENREG32_PC * 4)) {
491                 if (kbuf) {
492                         regs->tpc = *(u32 *) kbuf;
493                         kbuf += sizeof(u32);
494                 } else if (get_user(regs->tpc, (u32 __user *) ubuf))
495                         return -EFAULT;
496                 else
497                         ubuf += sizeof(u32);
498                 pos += sizeof(u32);
499                 count -= sizeof(u32);
500         }
501
502         if (count > 0 && pos == (GENREG32_NPC * 4)) {
503                 if (kbuf) {
504                         regs->tnpc = *(u32 *) kbuf;
505                         kbuf += sizeof(u32);
506                 } else if (get_user(regs->tnpc, (u32 __user *) ubuf))
507                         return -EFAULT;
508                 else
509                         ubuf += sizeof(u32);
510                 pos += sizeof(u32);
511                 count -= sizeof(u32);
512         }
513
514         if (count > 0 && pos == (GENREG32_Y * 4)) {
515                 if (kbuf) {
516                         regs->y = *(u32 *) kbuf;
517                         kbuf += sizeof(u32);
518                 } else if (get_user(regs->y, (u32 __user *) ubuf))
519                         return -EFAULT;
520                 else
521                         ubuf += sizeof(u32);
522                 pos += sizeof(u32);
523                 count -= sizeof(u32);
524         }
525
526         /* Ignore WIM and TBR */
527
528         return 0;
529 }
530
531 #define FPREG32_F0      0
532 #define FPREG32_FSR     32
533
534 #define SPARC32_NFPREGS 33
535
536 static int fpregs32_get(struct task_struct *target,
537                         const struct utrace_regset *regset,
538                         unsigned int pos, unsigned int count,
539                         void *kbuf, void __user *ubuf)
540 {
541         struct thread_info *t = task_thread_info(target);
542         int err;
543
544         err = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
545                                     t->fpregs, FPREG32_F0 * 4,
546                                     FPREG32_FSR * 4);
547
548         if (err == 0 && count > 0) {
549                 if (kbuf) {
550                         *(u32 *) kbuf = t->xfsr[0];
551                 } else if (put_user(t->xfsr[0], (u32 __user *) ubuf))
552                         return -EFAULT;
553         }
554
555         return err;
556 }
557
558 static int fpregs32_set(struct task_struct *target,
559                         const struct utrace_regset *regset,
560                         unsigned int pos, unsigned int count,
561                         const void *kbuf, const void __user *ubuf)
562 {
563         struct thread_info *t = task_thread_info(target);
564         int err;
565
566         err = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
567                                    t->fpregs, FPREG32_F0 * 4,
568                                    FPREG32_FSR * 4);
569
570         if (err == 0 && count > 0) {
571                 u32 fsr;
572                 if (kbuf) {
573                         fsr = *(u32 *) kbuf;
574                 } else if (get_user(fsr, (u32 __user *) ubuf))
575                         return -EFAULT;
576                 t->xfsr[0] = (t->xfsr[0] & 0xffffffff00000000UL) | fsr;
577         }
578
579         return 0;
580 }
581
582 static const struct utrace_regset sparc32_regsets[] = {
583         {
584                 .n = SPARC32_NGREGS,
585                 .size = sizeof(u32), .align = sizeof(u32),
586                 .get = genregs32_get, .set = genregs32_set
587         },
588         {
589                 .n = SPARC32_NFPREGS,
590                 .size = sizeof(u32), .align = sizeof(u32),
591                 .get = fpregs32_get, .set = fpregs32_set
592         },
593 };
594
595 const struct utrace_regset_view utrace_sparc32_view = {
596         .name = "sparc", .e_machine = EM_SPARC,
597         .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
598 };
599 EXPORT_SYMBOL_GPL(utrace_sparc32_view);
600
601 #endif  /* CONFIG_COMPAT */
602
603 /* To get the necessary page struct, access_process_vm() first calls
604  * get_user_pages().  This has done a flush_dcache_page() on the
605  * accessed page.  Then our caller (copy_{to,from}_user_page()) did
606  * to memcpy to read/write the data from that page.
607  *
608  * Now, the only thing we have to do is:
609  * 1) flush the D-cache if it's possible than an illegal alias
610  *    has been created
611  * 2) flush the I-cache if this is pre-cheetah and we did a write
612  */
613 void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
614                          unsigned long uaddr, void *kaddr,
615                          unsigned long len, int write)
616 {
617         BUG_ON(len > PAGE_SIZE);
618
619         if (tlb_type == hypervisor)
620                 return;
621
622 #ifdef DCACHE_ALIASING_POSSIBLE
623         /* If bit 13 of the kernel address we used to access the
624          * user page is the same as the virtual address that page
625          * is mapped to in the user's address space, we can skip the
626          * D-cache flush.
627          */
628         if ((uaddr ^ (unsigned long) kaddr) & (1UL << 13)) {
629                 unsigned long start = __pa(kaddr);
630                 unsigned long end = start + len;
631                 unsigned long dcache_line_size;
632
633                 dcache_line_size = local_cpu_data().dcache_line_size;
634
635                 if (tlb_type == spitfire) {
636                         for (; start < end; start += dcache_line_size)
637                                 spitfire_put_dcache_tag(start & 0x3fe0, 0x0);
638                 } else {
639                         start &= ~(dcache_line_size - 1);
640                         for (; start < end; start += dcache_line_size)
641                                 __asm__ __volatile__(
642                                         "stxa %%g0, [%0] %1\n\t"
643                                         "membar #Sync"
644                                         : /* no outputs */
645                                         : "r" (start),
646                                         "i" (ASI_DCACHE_INVALIDATE));
647                 }
648         }
649 #endif
650         if (write && tlb_type == spitfire) {
651                 unsigned long start = (unsigned long) kaddr;
652                 unsigned long end = start + len;
653                 unsigned long icache_line_size;
654
655                 icache_line_size = local_cpu_data().icache_line_size;
656
657                 for (; start < end; start += icache_line_size)
658                         flushi(start);
659         }
660 }
661
662 #ifdef CONFIG_PTRACE
663 static const struct ptrace_layout_segment sparc64_getregs_layout[] = {
664         { 0, offsetof(struct pt_regs, u_regs[15]), 0, sizeof(long) },
665         { offsetof(struct pt_regs, u_regs[15]),
666           offsetof(struct pt_regs, tstate),
667           -1, 0 },
668         { offsetof(struct pt_regs, tstate), offsetof(struct pt_regs, y),
669           0, 32 * sizeof(long) },
670         {0, 0, -1, 0}
671 };
672
673 int arch_ptrace(long *request, struct task_struct *child,
674                 struct utrace_attached_engine *engine,
675                 unsigned long addr, unsigned long data,
676                 long *retval)
677 {
678         void __user *uaddr = (void __user *) addr;
679         struct pt_regs *uregs = uaddr;
680         int err = -ENOSYS;
681
682         switch (*request) {
683         case PTRACE_GETREGS64:
684                 err = ptrace_layout_access(child, engine,
685                                            &utrace_sparc64_native_view,
686                                            sparc64_getregs_layout,
687                                            0, offsetof(struct pt_regs, y),
688                                            uaddr, NULL, 0);
689                 if (!err &&
690                     (put_user(task_pt_regs(child)->y, &uregs->y) ||
691                      put_user(task_pt_regs(child)->fprs, &uregs->fprs)))
692                         err = -EFAULT;
693                 break;
694
695         case PTRACE_SETREGS64:
696                 err = ptrace_layout_access(child, engine,
697                                            &utrace_sparc64_native_view,
698                                            sparc64_getregs_layout,
699                                            0, offsetof(struct pt_regs, y),
700                                            uaddr, NULL, 1);
701                 if (!err &&
702                     (get_user(task_pt_regs(child)->y, &uregs->y) ||
703                      get_user(task_pt_regs(child)->fprs, &uregs->fprs)))
704                         err = -EFAULT;
705                 break;
706
707         case PTRACE_GETFPREGS64:
708         case PTRACE_SETFPREGS64:
709                 err = ptrace_regset_access(child, engine,
710                                            utrace_native_view(current),
711                                            2, 0, 34 * sizeof(long), uaddr,
712                                            (*request == PTRACE_SETFPREGS64));
713                 break;
714
715         case PTRACE_SUNDETACH:
716                 *request = PTRACE_DETACH;
717                 break;
718                        
719         default:
720                 break;
721         };
722         return err;
723 }
724
725 #ifdef CONFIG_COMPAT
726 static const struct ptrace_layout_segment sparc32_getregs_layout[] = {
727         { 0, offsetof(struct pt_regs32, u_regs[0]),
728           0, GENREG32_PSR * sizeof(u32) },
729         { offsetof(struct pt_regs32, u_regs[0]),
730           offsetof(struct pt_regs32, u_regs[15]),
731           0, 1 * sizeof(u32) },
732         { offsetof(struct pt_regs32, u_regs[15]), sizeof(struct pt_regs32),
733           -1, 0 },
734         {0, 0, -1, 0}
735 };
736
737 int arch_compat_ptrace(compat_long_t *request, struct task_struct *child,
738                        struct utrace_attached_engine *engine,
739                        compat_ulong_t addr, compat_ulong_t data,
740                        compat_long_t *retval)
741 {
742         void __user *uaddr = (void __user *) (unsigned long) addr;
743         int err = -ENOSYS;
744
745         switch (*request) {
746         case PTRACE_GETREGS:
747         case PTRACE_SETREGS:
748                 err = ptrace_layout_access(child, engine,
749                                            &utrace_sparc32_view,
750                                            sparc32_getregs_layout,
751                                            0, sizeof(struct pt_regs32),
752                                            uaddr, NULL,
753                                            (*request ==
754                                             PTRACE_SETREGS));
755                 break;
756
757         case PTRACE_GETFPREGS:
758         case PTRACE_SETFPREGS:
759                 err = ptrace_whole_regset(child, engine, addr, 1,
760                                           (*request == PTRACE_SETFPREGS));
761                 break;
762
763         case PTRACE_SUNDETACH:
764                 *request = PTRACE_DETACH;
765                 break;
766
767         default:
768                 break;
769         };
770         return err;
771 }
772 #endif  /* CONFIG_COMPAT */
773 #endif /* CONFIG_PTRACE */
774
775 asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p)
776 {
777         /* do the secure computing check first */
778         if (!syscall_exit_p)
779                 secure_computing(regs->u_regs[UREG_G1]);
780
781         if (unlikely(current->audit_context) && syscall_exit_p) {
782                 unsigned long tstate = regs->tstate;
783                 int result = AUDITSC_SUCCESS;
784
785                 if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
786                         result = AUDITSC_FAILURE;
787
788                 audit_syscall_exit(result, regs->u_regs[UREG_I0]);
789         }
790
791         if (test_thread_flag(TIF_SYSCALL_TRACE))
792                 tracehook_report_syscall(regs, syscall_exit_p);
793
794         if (unlikely(current->audit_context) && !syscall_exit_p)
795                 audit_syscall_entry((test_thread_flag(TIF_32BIT) ?
796                                      AUDIT_ARCH_SPARC :
797                                      AUDIT_ARCH_SPARC64),
798                                     regs->u_regs[UREG_G1],
799                                     regs->u_regs[UREG_I0],
800                                     regs->u_regs[UREG_I1],
801                                     regs->u_regs[UREG_I2],
802                                     regs->u_regs[UREG_I3]);
803 }