2 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3 * Licensed under the GPL
6 #include "linux/audit.h"
7 #include "linux/ptrace.h"
8 #include "linux/sched.h"
9 #include "asm/uaccess.h"
10 #include "skas_ptrace.h"
14 void user_enable_single_step(struct task_struct
*child
)
16 child
->ptrace
|= PT_DTRACE
;
17 child
->thread
.singlestep_syscall
= 0;
19 #ifdef SUBARCH_SET_SINGLESTEPPING
20 SUBARCH_SET_SINGLESTEPPING(child
, 1);
24 void user_disable_single_step(struct task_struct
*child
)
26 child
->ptrace
&= ~PT_DTRACE
;
27 child
->thread
.singlestep_syscall
= 0;
29 #ifdef SUBARCH_SET_SINGLESTEPPING
30 SUBARCH_SET_SINGLESTEPPING(child
, 0);
35 * Called by kernel/ptrace.c when detaching..
37 void ptrace_disable(struct task_struct
*child
)
39 user_disable_single_step(child
);
42 extern int peek_user(struct task_struct
* child
, long addr
, long data
);
43 extern int poke_user(struct task_struct
* child
, long addr
, long data
);
45 long arch_ptrace(struct task_struct
*child
, long request
,
46 unsigned long addr
, unsigned long data
)
49 unsigned long __user
*p
= (void __user
*)data
;
53 /* read word at location addr. */
56 ret
= generic_ptrace_peekdata(child
, addr
, data
);
59 /* read the word at location addr in the USER area. */
61 ret
= peek_user(child
, addr
, data
);
64 /* write the word at location addr. */
67 ret
= generic_ptrace_pokedata(child
, addr
, data
);
70 /* write the word at location addr in the USER area */
72 ret
= poke_user(child
, addr
, data
);
76 case PTRACE_SYSEMU_SINGLESTEP
:
81 case PTRACE_GETREGS
: { /* Get all gp regs from the child. */
82 if (!access_ok(VERIFY_WRITE
, p
, MAX_REG_OFFSET
)) {
86 for ( i
= 0; i
< MAX_REG_OFFSET
; i
+= sizeof(long) ) {
87 __put_user(getreg(child
, i
), p
);
95 case PTRACE_SETREGS
: { /* Set all gp regs in the child. */
96 unsigned long tmp
= 0;
97 if (!access_ok(VERIFY_READ
, p
, MAX_REG_OFFSET
)) {
101 for ( i
= 0; i
< MAX_REG_OFFSET
; i
+= sizeof(long) ) {
103 putreg(child
, i
, tmp
);
110 #ifdef PTRACE_GETFPREGS
111 case PTRACE_GETFPREGS
: /* Get the child FPU state. */
112 ret
= get_fpregs(vp
, child
);
115 #ifdef PTRACE_SETFPREGS
116 case PTRACE_SETFPREGS
: /* Set the child FPU state. */
117 ret
= set_fpregs(vp
, child
);
120 case PTRACE_GET_THREAD_AREA
:
121 ret
= ptrace_get_thread_area(child
, addr
, vp
);
124 case PTRACE_SET_THREAD_AREA
:
125 ret
= ptrace_set_thread_area(child
, addr
, vp
);
128 case PTRACE_FAULTINFO
: {
130 * Take the info from thread->arch->faultinfo,
131 * but transfer max. sizeof(struct ptrace_faultinfo).
132 * On i386, ptrace_faultinfo is smaller!
134 ret
= copy_to_user(p
, &child
->thread
.arch
.faultinfo
,
135 sizeof(struct ptrace_faultinfo
)) ?
142 struct ptrace_ldt ldt
;
144 if (copy_from_user(&ldt
, p
, sizeof(ldt
))) {
150 * This one is confusing, so just punt and return -EIO for
157 #ifdef PTRACE_ARCH_PRCTL
158 case PTRACE_ARCH_PRCTL
:
159 /* XXX Calls ptrace on the host - needs some SMP thinking */
160 ret
= arch_prctl(child
, data
, (void __user
*) addr
);
164 ret
= ptrace_request(child
, request
, addr
, data
);
166 ret
= subarch_ptrace(child
, request
, addr
, data
);
173 static void send_sigtrap(struct task_struct
*tsk
, struct uml_pt_regs
*regs
,
178 memset(&info
, 0, sizeof(info
));
179 info
.si_signo
= SIGTRAP
;
180 info
.si_code
= TRAP_BRKPT
;
183 info
.si_addr
= UPT_IS_USER(regs
) ? (void __user
*) UPT_IP(regs
) : NULL
;
185 /* Send us the fake SIGTRAP */
186 force_sig_info(SIGTRAP
, &info
, tsk
);
190 * XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and
191 * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check
193 void syscall_trace(struct uml_pt_regs
*regs
, int entryexit
)
195 int is_singlestep
= (current
->ptrace
& PT_DTRACE
) && entryexit
;
198 if (unlikely(current
->audit_context
)) {
200 audit_syscall_entry(HOST_AUDIT_ARCH
,
201 UPT_SYSCALL_NR(regs
),
202 UPT_SYSCALL_ARG1(regs
),
203 UPT_SYSCALL_ARG2(regs
),
204 UPT_SYSCALL_ARG3(regs
),
205 UPT_SYSCALL_ARG4(regs
));
206 else audit_syscall_exit(AUDITSC_RESULT(UPT_SYSCALL_RET(regs
)),
207 UPT_SYSCALL_RET(regs
));
210 /* Fake a debug trap */
212 send_sigtrap(current
, regs
, 0);
214 if (!test_thread_flag(TIF_SYSCALL_TRACE
))
217 if (!(current
->ptrace
& PT_PTRACED
))
221 * the 0x80 provides a way for the tracing parent to distinguish
222 * between a syscall stop and SIGTRAP delivery
224 tracesysgood
= (current
->ptrace
& PT_TRACESYSGOOD
);
225 ptrace_notify(SIGTRAP
| (tracesysgood
? 0x80 : 0));
227 if (entryexit
) /* force do_signal() --> is_syscall() */
228 set_thread_flag(TIF_SIGPENDING
);
231 * this isn't the same as continuing with a signal, but it will do
232 * for normal use. strace only continues with a signal if the
233 * stopping signal is not SIGTRAP. -brl
235 if (current
->exit_code
) {
236 send_sig(current
->exit_code
, current
, 1);
237 current
->exit_code
= 0;