[SPARC64]: flush_ptrace_access() needs preemption disable.
[linux-2.6/kvm.git] / arch / sparc64 / kernel / ptrace.c
blobaaae865e79329aafd093974a2fb1a26c61992a5f
1 /* ptrace.c: Sparc process tracing support.
3 * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net)
4 * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
6 * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
7 * and David Mosberger.
9 * Added Linux support -miguel (weird, eh?, the original code was meant
10 * to emulate SunOS).
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>
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>
40 #include "entry.h"
42 /* #define ALLOW_INIT_TRACING */
45 * Called by kernel/ptrace.c when detaching..
47 * Make sure single step bits etc are not set.
49 void ptrace_disable(struct task_struct *child)
51 /* nothing to do */
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.
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
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)
68 BUG_ON(len > PAGE_SIZE);
70 if (tlb_type == hypervisor)
71 return;
73 preempt_disable();
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.
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;
86 dcache_line_size = local_cpu_data().dcache_line_size;
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));
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;
108 icache_line_size = local_cpu_data().icache_line_size;
110 for (; start < end; start += icache_line_size)
111 flushi(start);
114 preempt_enable();
117 enum sparc_regset {
118 REGSET_GENERAL,
119 REGSET_FP,
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)
127 const struct pt_regs *regs = task_pt_regs(target);
128 int ret;
130 if (target == current)
131 flushw_user();
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];
141 if (copy_from_user(window, reg_window, sizeof(window)))
142 return -EFAULT;
144 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
145 window,
146 16 * sizeof(u64),
147 32 * sizeof(u64));
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));
158 if (!ret) {
159 unsigned long y = regs->y;
161 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
163 35 * sizeof(u64),
164 36 * sizeof(u64));
167 if (!ret)
168 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
169 36 * sizeof(u64), -1);
171 return ret;
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)
179 struct pt_regs *regs = task_pt_regs(target);
180 int ret;
182 if (target == current)
183 flushw_user();
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];
193 if (copy_from_user(window, reg_window, sizeof(window)))
194 return -EFAULT;
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;
205 if (!ret && count > 0) {
206 unsigned long tstate;
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.
217 tstate &= (TSTATE_ICC | TSTATE_XCC);
218 regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC);
219 regs->tstate |= tstate;
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));
231 if (!ret) {
232 unsigned long y;
234 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
236 35 * sizeof(u64),
237 36 * sizeof(u64));
238 if (!ret)
239 regs->y = y;
242 if (!ret)
243 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
244 36 * sizeof(u64), -1);
246 return ret;
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)
254 const unsigned long *fpregs = task_thread_info(target)->fpregs;
255 unsigned long fprs, fsr, gsr;
256 int ret;
258 if (target == current)
259 save_and_clear_fpu();
261 fprs = task_thread_info(target)->fpsaved[0];
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,
270 16 * sizeof(u64));
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));
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;
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));
309 if (!ret)
310 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
311 35 * sizeof(u64), -1);
313 return ret;
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)
321 unsigned long *fpregs = task_thread_info(target)->fpregs;
322 unsigned long fprs;
323 int ret;
325 if (target == current)
326 save_and_clear_fpu();
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));
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));
350 fprs |= (FPRS_FEF | FPRS_DL | FPRS_DU);
351 task_thread_info(target)->fpsaved[0] = fprs;
353 if (!ret)
354 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
355 35 * sizeof(u64), -1);
356 return ret;
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
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
373 /* Format is:
374 * F0 --> F63
375 * FSR
376 * GSR
377 * FPRS
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
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)
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)
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;
404 if (target == current)
405 flushw_user();
407 pos /= sizeof(reg);
408 count /= sizeof(reg);
410 if (kbuf) {
411 for (; count > 0 && pos < 16; count--)
412 *k++ = regs->u_regs[pos++];
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;
419 } else {
420 for (; count > 0 && pos < 16; count--) {
421 if (put_user((compat_ulong_t) regs->u_regs[pos++], u++))
422 return -EFAULT;
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;
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;
454 if (kbuf)
455 *k++ = reg;
456 else if (put_user(reg, u++))
457 return -EFAULT;
458 pos++;
459 count--;
461 finish:
462 pos *= sizeof(reg);
463 count *= sizeof(reg);
465 return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
466 38 * sizeof(reg), -1);
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)
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;
480 if (target == current)
481 flushw_user();
483 pos /= sizeof(reg);
484 count /= sizeof(reg);
486 if (kbuf) {
487 for (; count > 0 && pos < 16; count--)
488 regs->u_regs[pos++] = *k++;
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;
495 } else {
496 for (; count > 0 && pos < 16; count--) {
497 if (get_user(reg, u++))
498 return -EFAULT;
499 regs->u_regs[pos++] = reg;
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;
509 while (count > 0) {
510 unsigned long tstate;
512 if (kbuf)
513 reg = *k++;
514 else if (get_user(reg, u++))
515 return -EFAULT;
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;
540 pos++;
541 count--;
543 finish:
544 pos *= sizeof(reg);
545 count *= sizeof(reg);
547 return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
548 38 * sizeof(reg), -1);
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)
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;
562 if (target == current)
563 save_and_clear_fpu();
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;
574 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
575 fpregs,
576 0, 32 * sizeof(u32));
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));
588 if (!ret) {
589 compat_ulong_t val;
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));
598 if (!ret)
599 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
600 35 * sizeof(u32), -1);
602 return ret;
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)
610 unsigned long *fpregs = task_thread_info(target)->fpregs;
611 unsigned long fprs;
612 int ret;
614 if (target == current)
615 save_and_clear_fpu();
617 fprs = task_thread_info(target)->fpsaved[0];
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;
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;
642 fprs |= (FPRS_FEF | FPRS_DL);
643 task_thread_info(target)->fpsaved[0] = fprs;
645 if (!ret)
646 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
647 34 * sizeof(u32), -1);
648 return ret;
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
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
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)
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
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)
687 #endif /* CONFIG_COMPAT */
689 const struct user_regset_view *task_user_regset_view(struct task_struct *task)
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;
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];
711 long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
712 compat_ulong_t caddr, compat_ulong_t cdata)
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;
723 pregs = (struct pt_regs32 __user *) addr;
724 fps = (struct compat_fps __user *) addr;
726 switch (request) {
727 case PTRACE_PEEKUSR:
728 ret = (addr != 0) ? -EIO : 0;
729 break;
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;
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;
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;
772 break;
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;
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;
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;
806 default:
807 ret = compat_ptrace_request(child, request, addr, data);
808 break;
811 return ret;
813 #endif /* CONFIG_COMPAT */
815 struct fps {
816 unsigned int regs[64];
817 unsigned long fsr;
820 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
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;
828 pregs = (struct pt_regs __user *) (unsigned long) addr;
829 fps = (struct fps __user *) (unsigned long) addr;
831 switch (request) {
832 case PTRACE_PEEKUSR:
833 ret = (addr != 0) ? -EIO : 0;
834 break;
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);
848 break;
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);
862 break;
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;
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;
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;
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;
898 default:
899 ret = ptrace_request(child, request, addr, data);
900 break;
903 return ret;
906 asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p)
908 /* do the secure computing check first */
909 secure_computing(regs->u_regs[UREG_G1]);
911 if (unlikely(current->audit_context) && syscall_exit_p) {
912 unsigned long tstate = regs->tstate;
913 int result = AUDITSC_SUCCESS;
915 if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
916 result = AUDITSC_FAILURE;
918 audit_syscall_exit(result, regs->u_regs[UREG_I0]);
921 if (!(current->ptrace & PT_PTRACED))
922 goto out;
924 if (!test_thread_flag(TIF_SYSCALL_TRACE))
925 goto out;
927 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
928 ? 0x80 : 0));
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
935 if (current->exit_code) {
936 send_sig(current->exit_code, current, 1);
937 current->exit_code = 0;
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]);