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,
9 * Added Linux support -miguel (weird, eh?, the original code was meant
13 #include <linux/kernel.h>
14 #include <linux/sched.h>
16 #include <linux/errno.h>
17 #include <linux/export.h>
18 #include <linux/ptrace.h>
19 #include <linux/user.h>
20 #include <linux/smp.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/tracehook.h>
27 #include <trace/syscall.h>
28 #include <linux/compat.h>
29 #include <linux/elf.h>
30 #include <linux/context_tracking.h>
33 #include <asm/pgtable.h>
34 #include <linux/uaccess.h>
35 #include <asm/psrcompat.h>
36 #include <asm/visasm.h>
37 #include <asm/spitfire.h>
39 #include <asm/cpudata.h>
40 #include <asm/cacheflush.h>
42 #define CREATE_TRACE_POINTS
43 #include <trace/events/syscalls.h>
47 /* #define ALLOW_INIT_TRACING */
49 struct pt_regs_offset
{
54 #define REG_OFFSET_NAME(n, r) \
55 {.name = n, .offset = (PT_V9_##r)}
56 #define REG_OFFSET_END {.name = NULL, .offset = 0}
58 static const struct pt_regs_offset regoffset_table
[] = {
59 REG_OFFSET_NAME("g0", G0
),
60 REG_OFFSET_NAME("g1", G1
),
61 REG_OFFSET_NAME("g2", G2
),
62 REG_OFFSET_NAME("g3", G3
),
63 REG_OFFSET_NAME("g4", G4
),
64 REG_OFFSET_NAME("g5", G5
),
65 REG_OFFSET_NAME("g6", G6
),
66 REG_OFFSET_NAME("g7", G7
),
68 REG_OFFSET_NAME("i0", I0
),
69 REG_OFFSET_NAME("i1", I1
),
70 REG_OFFSET_NAME("i2", I2
),
71 REG_OFFSET_NAME("i3", I3
),
72 REG_OFFSET_NAME("i4", I4
),
73 REG_OFFSET_NAME("i5", I5
),
74 REG_OFFSET_NAME("i6", I6
),
75 REG_OFFSET_NAME("i7", I7
),
77 REG_OFFSET_NAME("tstate", TSTATE
),
78 REG_OFFSET_NAME("pc", TPC
),
79 REG_OFFSET_NAME("npc", TNPC
),
80 REG_OFFSET_NAME("y", Y
),
81 REG_OFFSET_NAME("lr", I7
),
87 * Called by kernel/ptrace.c when detaching..
89 * Make sure single step bits etc are not set.
91 void ptrace_disable(struct task_struct
*child
)
96 /* To get the necessary page struct, access_process_vm() first calls
97 * get_user_pages(). This has done a flush_dcache_page() on the
98 * accessed page. Then our caller (copy_{to,from}_user_page()) did
99 * to memcpy to read/write the data from that page.
101 * Now, the only thing we have to do is:
102 * 1) flush the D-cache if it's possible than an illegal alias
104 * 2) flush the I-cache if this is pre-cheetah and we did a write
106 void flush_ptrace_access(struct vm_area_struct
*vma
, struct page
*page
,
107 unsigned long uaddr
, void *kaddr
,
108 unsigned long len
, int write
)
110 BUG_ON(len
> PAGE_SIZE
);
112 if (tlb_type
== hypervisor
)
117 #ifdef DCACHE_ALIASING_POSSIBLE
118 /* If bit 13 of the kernel address we used to access the
119 * user page is the same as the virtual address that page
120 * is mapped to in the user's address space, we can skip the
123 if ((uaddr
^ (unsigned long) kaddr
) & (1UL << 13)) {
124 unsigned long start
= __pa(kaddr
);
125 unsigned long end
= start
+ len
;
126 unsigned long dcache_line_size
;
128 dcache_line_size
= local_cpu_data().dcache_line_size
;
130 if (tlb_type
== spitfire
) {
131 for (; start
< end
; start
+= dcache_line_size
)
132 spitfire_put_dcache_tag(start
& 0x3fe0, 0x0);
134 start
&= ~(dcache_line_size
- 1);
135 for (; start
< end
; start
+= dcache_line_size
)
136 __asm__
__volatile__(
137 "stxa %%g0, [%0] %1\n\t"
141 "i" (ASI_DCACHE_INVALIDATE
));
145 if (write
&& tlb_type
== spitfire
) {
146 unsigned long start
= (unsigned long) kaddr
;
147 unsigned long end
= start
+ len
;
148 unsigned long icache_line_size
;
150 icache_line_size
= local_cpu_data().icache_line_size
;
152 for (; start
< end
; start
+= icache_line_size
)
158 EXPORT_SYMBOL_GPL(flush_ptrace_access
);
160 static int get_from_target(struct task_struct
*target
, unsigned long uaddr
,
163 if (target
== current
) {
164 if (copy_from_user(kbuf
, (void __user
*) uaddr
, len
))
167 int len2
= access_process_vm(target
, uaddr
, kbuf
, len
,
175 static int set_to_target(struct task_struct
*target
, unsigned long uaddr
,
178 if (target
== current
) {
179 if (copy_to_user((void __user
*) uaddr
, kbuf
, len
))
182 int len2
= access_process_vm(target
, uaddr
, kbuf
, len
,
183 FOLL_FORCE
| FOLL_WRITE
);
190 static int regwindow64_get(struct task_struct
*target
,
191 const struct pt_regs
*regs
,
192 struct reg_window
*wbuf
)
194 unsigned long rw_addr
= regs
->u_regs
[UREG_I6
];
196 if (!test_thread_64bit_stack(rw_addr
)) {
197 struct reg_window32 win32
;
200 if (get_from_target(target
, rw_addr
, &win32
, sizeof(win32
)))
202 for (i
= 0; i
< 8; i
++)
203 wbuf
->locals
[i
] = win32
.locals
[i
];
204 for (i
= 0; i
< 8; i
++)
205 wbuf
->ins
[i
] = win32
.ins
[i
];
207 rw_addr
+= STACK_BIAS
;
208 if (get_from_target(target
, rw_addr
, wbuf
, sizeof(*wbuf
)))
215 static int regwindow64_set(struct task_struct
*target
,
216 const struct pt_regs
*regs
,
217 struct reg_window
*wbuf
)
219 unsigned long rw_addr
= regs
->u_regs
[UREG_I6
];
221 if (!test_thread_64bit_stack(rw_addr
)) {
222 struct reg_window32 win32
;
225 for (i
= 0; i
< 8; i
++)
226 win32
.locals
[i
] = wbuf
->locals
[i
];
227 for (i
= 0; i
< 8; i
++)
228 win32
.ins
[i
] = wbuf
->ins
[i
];
230 if (set_to_target(target
, rw_addr
, &win32
, sizeof(win32
)))
233 rw_addr
+= STACK_BIAS
;
234 if (set_to_target(target
, rw_addr
, wbuf
, sizeof(*wbuf
)))
246 static int genregs64_get(struct task_struct
*target
,
247 const struct user_regset
*regset
,
248 unsigned int pos
, unsigned int count
,
249 void *kbuf
, void __user
*ubuf
)
251 const struct pt_regs
*regs
= task_pt_regs(target
);
254 if (target
== current
)
257 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
259 0, 16 * sizeof(u64
));
260 if (!ret
&& count
&& pos
< (32 * sizeof(u64
))) {
261 struct reg_window window
;
263 if (regwindow64_get(target
, regs
, &window
))
265 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
272 /* TSTATE, TPC, TNPC */
273 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
280 unsigned long y
= regs
->y
;
282 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
289 ret
= user_regset_copyout_zero(&pos
, &count
, &kbuf
, &ubuf
,
290 36 * sizeof(u64
), -1);
296 static int genregs64_set(struct task_struct
*target
,
297 const struct user_regset
*regset
,
298 unsigned int pos
, unsigned int count
,
299 const void *kbuf
, const void __user
*ubuf
)
301 struct pt_regs
*regs
= task_pt_regs(target
);
304 if (target
== current
)
307 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
309 0, 16 * sizeof(u64
));
310 if (!ret
&& count
&& pos
< (32 * sizeof(u64
))) {
311 struct reg_window window
;
313 if (regwindow64_get(target
, regs
, &window
))
316 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
322 regwindow64_set(target
, regs
, &window
))
326 if (!ret
&& count
> 0) {
327 unsigned long tstate
;
330 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
335 /* Only the condition codes and the "in syscall"
336 * state can be modified in the %tstate register.
338 tstate
&= (TSTATE_ICC
| TSTATE_XCC
| TSTATE_SYSCALL
);
339 regs
->tstate
&= ~(TSTATE_ICC
| TSTATE_XCC
| TSTATE_SYSCALL
);
340 regs
->tstate
|= tstate
;
346 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
353 unsigned long y
= regs
->y
;
355 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
364 ret
= user_regset_copyin_ignore(&pos
, &count
, &kbuf
, &ubuf
,
365 36 * sizeof(u64
), -1);
370 static int fpregs64_get(struct task_struct
*target
,
371 const struct user_regset
*regset
,
372 unsigned int pos
, unsigned int count
,
373 void *kbuf
, void __user
*ubuf
)
375 const unsigned long *fpregs
= task_thread_info(target
)->fpregs
;
376 unsigned long fprs
, fsr
, gsr
;
379 if (target
== current
)
380 save_and_clear_fpu();
382 fprs
= task_thread_info(target
)->fpsaved
[0];
385 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
387 0, 16 * sizeof(u64
));
389 ret
= user_regset_copyout_zero(&pos
, &count
, &kbuf
, &ubuf
,
395 ret
= user_regset_copyout(&pos
, &count
,
401 ret
= user_regset_copyout_zero(&pos
, &count
,
407 if (fprs
& FPRS_FEF
) {
408 fsr
= task_thread_info(target
)->xfsr
[0];
409 gsr
= task_thread_info(target
)->gsr
[0];
415 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
420 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
425 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
431 ret
= user_regset_copyout_zero(&pos
, &count
, &kbuf
, &ubuf
,
432 35 * sizeof(u64
), -1);
437 static int fpregs64_set(struct task_struct
*target
,
438 const struct user_regset
*regset
,
439 unsigned int pos
, unsigned int count
,
440 const void *kbuf
, const void __user
*ubuf
)
442 unsigned long *fpregs
= task_thread_info(target
)->fpregs
;
446 if (target
== current
)
447 save_and_clear_fpu();
449 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
451 0, 32 * sizeof(u64
));
453 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
454 task_thread_info(target
)->xfsr
,
458 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
459 task_thread_info(target
)->gsr
,
463 fprs
= task_thread_info(target
)->fpsaved
[0];
464 if (!ret
&& count
> 0) {
465 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
471 fprs
|= (FPRS_FEF
| FPRS_DL
| FPRS_DU
);
472 task_thread_info(target
)->fpsaved
[0] = fprs
;
475 ret
= user_regset_copyin_ignore(&pos
, &count
, &kbuf
, &ubuf
,
476 35 * sizeof(u64
), -1);
480 static const struct user_regset sparc64_regsets
[] = {
486 * TSTATE, TPC, TNPC, Y
489 .core_note_type
= NT_PRSTATUS
,
491 .size
= sizeof(u64
), .align
= sizeof(u64
),
492 .get
= genregs64_get
, .set
= genregs64_set
501 .core_note_type
= NT_PRFPREG
,
503 .size
= sizeof(u64
), .align
= sizeof(u64
),
504 .get
= fpregs64_get
, .set
= fpregs64_set
508 static const struct user_regset_view user_sparc64_view
= {
509 .name
= "sparc64", .e_machine
= EM_SPARCV9
,
510 .regsets
= sparc64_regsets
, .n
= ARRAY_SIZE(sparc64_regsets
)
514 static int genregs32_get(struct task_struct
*target
,
515 const struct user_regset
*regset
,
516 unsigned int pos
, unsigned int count
,
517 void *kbuf
, void __user
*ubuf
)
519 const struct pt_regs
*regs
= task_pt_regs(target
);
520 compat_ulong_t __user
*reg_window
;
521 compat_ulong_t
*k
= kbuf
;
522 compat_ulong_t __user
*u
= ubuf
;
525 if (target
== current
)
529 count
/= sizeof(reg
);
532 for (; count
> 0 && pos
< 16; count
--)
533 *k
++ = regs
->u_regs
[pos
++];
535 reg_window
= (compat_ulong_t __user
*) regs
->u_regs
[UREG_I6
];
537 if (target
== current
) {
538 for (; count
> 0 && pos
< 32; count
--) {
539 if (get_user(*k
++, ®_window
[pos
++]))
543 for (; count
> 0 && pos
< 32; count
--) {
544 if (access_process_vm(target
,
556 for (; count
> 0 && pos
< 16; count
--) {
557 if (put_user((compat_ulong_t
) regs
->u_regs
[pos
++], u
++))
561 reg_window
= (compat_ulong_t __user
*) regs
->u_regs
[UREG_I6
];
563 if (target
== current
) {
564 for (; count
> 0 && pos
< 32; count
--) {
565 if (get_user(reg
, ®_window
[pos
++]) ||
570 for (; count
> 0 && pos
< 32; count
--) {
571 if (access_process_vm(target
,
578 if (access_process_vm(target
,
581 FOLL_FORCE
| FOLL_WRITE
)
592 reg
= tstate_to_psr(regs
->tstate
);
613 else if (put_user(reg
, u
++))
620 count
*= sizeof(reg
);
622 return user_regset_copyout_zero(&pos
, &count
, &kbuf
, &ubuf
,
623 38 * sizeof(reg
), -1);
626 static int genregs32_set(struct task_struct
*target
,
627 const struct user_regset
*regset
,
628 unsigned int pos
, unsigned int count
,
629 const void *kbuf
, const void __user
*ubuf
)
631 struct pt_regs
*regs
= task_pt_regs(target
);
632 compat_ulong_t __user
*reg_window
;
633 const compat_ulong_t
*k
= kbuf
;
634 const compat_ulong_t __user
*u
= ubuf
;
637 if (target
== current
)
641 count
/= sizeof(reg
);
644 for (; count
> 0 && pos
< 16; count
--)
645 regs
->u_regs
[pos
++] = *k
++;
647 reg_window
= (compat_ulong_t __user
*) regs
->u_regs
[UREG_I6
];
649 if (target
== current
) {
650 for (; count
> 0 && pos
< 32; count
--) {
651 if (put_user(*k
++, ®_window
[pos
++]))
655 for (; count
> 0 && pos
< 32; count
--) {
656 if (access_process_vm(target
,
661 FOLL_FORCE
| FOLL_WRITE
)
669 for (; count
> 0 && pos
< 16; count
--) {
670 if (get_user(reg
, u
++))
672 regs
->u_regs
[pos
++] = reg
;
675 reg_window
= (compat_ulong_t __user
*) regs
->u_regs
[UREG_I6
];
677 if (target
== current
) {
678 for (; count
> 0 && pos
< 32; count
--) {
679 if (get_user(reg
, u
++) ||
680 put_user(reg
, ®_window
[pos
++]))
684 for (; count
> 0 && pos
< 32; count
--) {
685 if (access_process_vm(target
,
692 if (access_process_vm(target
,
696 FOLL_FORCE
| FOLL_WRITE
)
705 unsigned long tstate
;
709 else if (get_user(reg
, u
++))
714 tstate
= regs
->tstate
;
715 tstate
&= ~(TSTATE_ICC
| TSTATE_XCC
| TSTATE_SYSCALL
);
716 tstate
|= psr_to_tstate_icc(reg
);
717 if (reg
& PSR_SYSCALL
)
718 tstate
|= TSTATE_SYSCALL
;
719 regs
->tstate
= tstate
;
742 count
*= sizeof(reg
);
744 return user_regset_copyin_ignore(&pos
, &count
, &kbuf
, &ubuf
,
745 38 * sizeof(reg
), -1);
748 static int fpregs32_get(struct task_struct
*target
,
749 const struct user_regset
*regset
,
750 unsigned int pos
, unsigned int count
,
751 void *kbuf
, void __user
*ubuf
)
753 const unsigned long *fpregs
= task_thread_info(target
)->fpregs
;
754 compat_ulong_t enabled
;
759 if (target
== current
)
760 save_and_clear_fpu();
762 fprs
= task_thread_info(target
)->fpsaved
[0];
763 if (fprs
& FPRS_FEF
) {
764 fsr
= task_thread_info(target
)->xfsr
[0];
771 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
773 0, 32 * sizeof(u32
));
776 ret
= user_regset_copyout_zero(&pos
, &count
, &kbuf
, &ubuf
,
780 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
788 val
= (enabled
<< 8) | (8 << 16);
789 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
796 ret
= user_regset_copyout_zero(&pos
, &count
, &kbuf
, &ubuf
,
797 35 * sizeof(u32
), -1);
802 static int fpregs32_set(struct task_struct
*target
,
803 const struct user_regset
*regset
,
804 unsigned int pos
, unsigned int count
,
805 const void *kbuf
, const void __user
*ubuf
)
807 unsigned long *fpregs
= task_thread_info(target
)->fpregs
;
811 if (target
== current
)
812 save_and_clear_fpu();
814 fprs
= task_thread_info(target
)->fpsaved
[0];
816 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
818 0, 32 * sizeof(u32
));
820 user_regset_copyin_ignore(&pos
, &count
, &kbuf
, &ubuf
,
823 if (!ret
&& count
> 0) {
827 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
832 val
= task_thread_info(target
)->xfsr
[0];
833 val
&= 0xffffffff00000000UL
;
835 task_thread_info(target
)->xfsr
[0] = val
;
839 fprs
|= (FPRS_FEF
| FPRS_DL
);
840 task_thread_info(target
)->fpsaved
[0] = fprs
;
843 ret
= user_regset_copyin_ignore(&pos
, &count
, &kbuf
, &ubuf
,
844 34 * sizeof(u32
), -1);
848 static const struct user_regset sparc32_regsets
[] = {
854 * PSR, PC, nPC, Y, WIM, TBR
857 .core_note_type
= NT_PRSTATUS
,
859 .size
= sizeof(u32
), .align
= sizeof(u32
),
860 .get
= genregs32_get
, .set
= genregs32_set
866 * FPU QUEUE COUNT (8-bit char)
867 * FPU QUEUE ENTRYSIZE (8-bit char)
868 * FPU ENABLED (8-bit char)
870 * FPU QUEUE (64 32-bit ints)
873 .core_note_type
= NT_PRFPREG
,
875 .size
= sizeof(u32
), .align
= sizeof(u32
),
876 .get
= fpregs32_get
, .set
= fpregs32_set
880 static const struct user_regset_view user_sparc32_view
= {
881 .name
= "sparc", .e_machine
= EM_SPARC
,
882 .regsets
= sparc32_regsets
, .n
= ARRAY_SIZE(sparc32_regsets
)
884 #endif /* CONFIG_COMPAT */
886 const struct user_regset_view
*task_user_regset_view(struct task_struct
*task
)
889 if (test_tsk_thread_flag(task
, TIF_32BIT
))
890 return &user_sparc32_view
;
892 return &user_sparc64_view
;
897 unsigned int regs
[32];
903 unsigned int insnaddr
;
908 long compat_arch_ptrace(struct task_struct
*child
, compat_long_t request
,
909 compat_ulong_t caddr
, compat_ulong_t cdata
)
911 const struct user_regset_view
*view
= task_user_regset_view(current
);
912 compat_ulong_t caddr2
= task_pt_regs(current
)->u_regs
[UREG_I4
];
913 struct pt_regs32 __user
*pregs
;
914 struct compat_fps __user
*fps
;
915 unsigned long addr2
= caddr2
;
916 unsigned long addr
= caddr
;
917 unsigned long data
= cdata
;
920 pregs
= (struct pt_regs32 __user
*) addr
;
921 fps
= (struct compat_fps __user
*) addr
;
925 ret
= (addr
!= 0) ? -EIO
: 0;
929 ret
= copy_regset_to_user(child
, view
, REGSET_GENERAL
,
934 ret
= copy_regset_to_user(child
, view
, REGSET_GENERAL
,
941 ret
= copy_regset_from_user(child
, view
, REGSET_GENERAL
,
946 ret
= copy_regset_from_user(child
, view
, REGSET_GENERAL
,
952 case PTRACE_GETFPREGS
:
953 ret
= copy_regset_to_user(child
, view
, REGSET_FP
,
958 ret
= copy_regset_to_user(child
, view
, REGSET_FP
,
963 if (__put_user(0, &fps
->flags
) ||
964 __put_user(0, &fps
->extra
) ||
965 __put_user(0, &fps
->fpqd
) ||
966 clear_user(&fps
->fpq
[0], 32 * sizeof(unsigned int)))
971 case PTRACE_SETFPREGS
:
972 ret
= copy_regset_from_user(child
, view
, REGSET_FP
,
977 ret
= copy_regset_from_user(child
, view
, REGSET_FP
,
983 case PTRACE_READTEXT
:
984 case PTRACE_READDATA
:
985 ret
= ptrace_readdata(child
, addr
,
986 (char __user
*)addr2
, data
);
993 case PTRACE_WRITETEXT
:
994 case PTRACE_WRITEDATA
:
995 ret
= ptrace_writedata(child
, (char __user
*) addr2
,
1004 if (request
== PTRACE_SPARC_DETACH
)
1005 request
= PTRACE_DETACH
;
1006 ret
= compat_ptrace_request(child
, request
, addr
, data
);
1012 #endif /* CONFIG_COMPAT */
1015 unsigned int regs
[64];
1019 long arch_ptrace(struct task_struct
*child
, long request
,
1020 unsigned long addr
, unsigned long data
)
1022 const struct user_regset_view
*view
= task_user_regset_view(current
);
1023 unsigned long addr2
= task_pt_regs(current
)->u_regs
[UREG_I4
];
1024 struct pt_regs __user
*pregs
;
1025 struct fps __user
*fps
;
1026 void __user
*addr2p
;
1029 pregs
= (struct pt_regs __user
*) addr
;
1030 fps
= (struct fps __user
*) addr
;
1031 addr2p
= (void __user
*) addr2
;
1034 case PTRACE_PEEKUSR
:
1035 ret
= (addr
!= 0) ? -EIO
: 0;
1038 case PTRACE_GETREGS64
:
1039 ret
= copy_regset_to_user(child
, view
, REGSET_GENERAL
,
1044 /* XXX doesn't handle 'y' register correctly XXX */
1045 ret
= copy_regset_to_user(child
, view
, REGSET_GENERAL
,
1052 case PTRACE_SETREGS64
:
1053 ret
= copy_regset_from_user(child
, view
, REGSET_GENERAL
,
1058 /* XXX doesn't handle 'y' register correctly XXX */
1059 ret
= copy_regset_from_user(child
, view
, REGSET_GENERAL
,
1066 case PTRACE_GETFPREGS64
:
1067 ret
= copy_regset_to_user(child
, view
, REGSET_FP
,
1073 case PTRACE_SETFPREGS64
:
1074 ret
= copy_regset_from_user(child
, view
, REGSET_FP
,
1080 case PTRACE_READTEXT
:
1081 case PTRACE_READDATA
:
1082 ret
= ptrace_readdata(child
, addr
, addr2p
, data
);
1089 case PTRACE_WRITETEXT
:
1090 case PTRACE_WRITEDATA
:
1091 ret
= ptrace_writedata(child
, addr2p
, addr
, data
);
1099 if (request
== PTRACE_SPARC_DETACH
)
1100 request
= PTRACE_DETACH
;
1101 ret
= ptrace_request(child
, request
, addr
, data
);
1108 asmlinkage
int syscall_trace_enter(struct pt_regs
*regs
)
1112 /* do the secure computing check first */
1113 secure_computing_strict(regs
->u_regs
[UREG_G1
]);
1115 if (test_thread_flag(TIF_NOHZ
))
1118 if (test_thread_flag(TIF_SYSCALL_TRACE
))
1119 ret
= tracehook_report_syscall_entry(regs
);
1121 if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT
)))
1122 trace_sys_enter(regs
, regs
->u_regs
[UREG_G1
]);
1124 audit_syscall_entry(regs
->u_regs
[UREG_G1
], regs
->u_regs
[UREG_I0
],
1125 regs
->u_regs
[UREG_I1
], regs
->u_regs
[UREG_I2
],
1126 regs
->u_regs
[UREG_I3
]);
1131 asmlinkage
void syscall_trace_leave(struct pt_regs
*regs
)
1133 if (test_thread_flag(TIF_NOHZ
))
1136 audit_syscall_exit(regs
);
1138 if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT
)))
1139 trace_sys_exit(regs
, regs
->u_regs
[UREG_I0
]);
1141 if (test_thread_flag(TIF_SYSCALL_TRACE
))
1142 tracehook_report_syscall_exit(regs
, 0);
1144 if (test_thread_flag(TIF_NOHZ
))
1149 * regs_query_register_offset() - query register offset from its name
1150 * @name: the name of a register
1152 * regs_query_register_offset() returns the offset of a register in struct
1153 * pt_regs from its name. If the name is invalid, this returns -EINVAL;
1155 int regs_query_register_offset(const char *name
)
1157 const struct pt_regs_offset
*roff
;
1159 for (roff
= regoffset_table
; roff
->name
!= NULL
; roff
++)
1160 if (!strcmp(roff
->name
, name
))
1161 return roff
->offset
;