2 * Copyright (C) 2000-2003, Axis Communications AB.
5 #include <linux/kernel.h>
6 #include <linux/sched.h>
9 #include <linux/smp_lock.h>
10 #include <linux/errno.h>
11 #include <linux/ptrace.h>
12 #include <linux/user.h>
14 #include <asm/uaccess.h>
16 #include <asm/pgtable.h>
17 #include <asm/system.h>
18 #include <asm/processor.h>
21 * Determines which bits in DCCR the user has access to.
22 * 1 = access, 0 = no access.
24 #define DCCR_MASK 0x0000001f /* XNZVC */
26 extern inline long get_reg(struct task_struct
*, unsigned int);
27 extern inline long put_reg(struct task_struct
*, unsigned int, unsigned long);
30 * Called by kernel/ptrace.c when detaching.
32 * Make sure the single step bit is not set.
35 ptrace_disable(struct task_struct
*child
)
37 /* Todo - pending singlesteps? */
41 * Note that this implementation of ptrace behaves differently from vanilla
42 * ptrace. Contrary to what the man page says, in the PTRACE_PEEKTEXT,
43 * PTRACE_PEEKDATA, and PTRACE_PEEKUSER requests the data variable is not
44 * ignored. Instead, the data variable is expected to point at a location
45 * (in user space) where the result of the ptrace call is written (instead of
49 sys_ptrace(long request
, long pid
, long addr
, long data
)
51 struct task_struct
*child
;
57 if (request
== PTRACE_TRACEME
) {
58 if (current
->ptrace
& PT_PTRACED
)
61 current
->ptrace
|= PT_PTRACED
;
67 read_lock(&tasklist_lock
);
68 child
= find_task_by_pid(pid
);
71 get_task_struct(child
);
73 read_unlock(&tasklist_lock
);
80 if (pid
== 1) /* Leave the init process alone! */
83 if (request
== PTRACE_ATTACH
) {
84 ret
= ptrace_attach(child
);
88 ret
= ptrace_check_attach(child
, request
== PTRACE_KILL
);
93 /* Read word at location address. */
95 case PTRACE_PEEKDATA
: {
99 copied
= access_process_vm(child
, addr
, &tmp
, sizeof(tmp
), 0);
102 if (copied
!= sizeof(tmp
))
105 ret
= put_user(tmp
,(unsigned long *) data
);
109 /* Read the word at location address in the USER area. */
110 case PTRACE_PEEKUSR
: {
114 if ((addr
& 3) || addr
< 0 || addr
> PT_MAX
<< 2)
117 tmp
= get_reg(child
, addr
>> 2);
118 ret
= put_user(tmp
, (unsigned long *)data
);
122 /* Write the word at location address. */
123 case PTRACE_POKETEXT
:
124 case PTRACE_POKEDATA
:
127 if (access_process_vm(child
, addr
, &data
, sizeof(data
), 1) == sizeof(data
))
133 /* Write the word at location address in the USER area. */
136 if ((addr
& 3) || addr
< 0 || addr
> PT_MAX
<< 2)
141 if (addr
== PT_DCCR
) {
142 /* don't allow the tracing process to change stuff like
143 * interrupt enable, kernel/user bit, dma enables etc.
146 data
|= get_reg(child
, PT_DCCR
) & ~DCCR_MASK
;
148 if (put_reg(child
, addr
, data
))
157 if ((unsigned long) data
> _NSIG
)
160 if (request
== PTRACE_SYSCALL
) {
161 set_tsk_thread_flag(child
, TIF_SYSCALL_TRACE
);
164 clear_tsk_thread_flag(child
, TIF_SYSCALL_TRACE
);
167 child
->exit_code
= data
;
169 /* TODO: make sure any pending breakpoint is killed */
170 wake_up_process(child
);
175 /* Make the child exit by sending it a sigkill. */
179 if (child
->state
== TASK_ZOMBIE
)
182 child
->exit_code
= SIGKILL
;
184 /* TODO: make sure any pending breakpoint is killed */
185 wake_up_process(child
);
188 /* Set the trap flag. */
189 case PTRACE_SINGLESTEP
:
192 if ((unsigned long) data
> _NSIG
)
195 clear_tsk_thread_flag(child
, TIF_SYSCALL_TRACE
);
197 /* TODO: set some clever breakpoint mechanism... */
199 child
->exit_code
= data
;
200 wake_up_process(child
);
205 ret
= ptrace_detach(child
, data
);
208 /* Get all GP registers from the child. */
209 case PTRACE_GETREGS
: {
213 for (i
= 0; i
<= PT_MAX
; i
++) {
214 tmp
= get_reg(child
, i
);
216 if (put_user(tmp
, (unsigned long *) data
)) {
221 data
+= sizeof(long);
228 /* Set all GP registers in the child. */
229 case PTRACE_SETREGS
: {
233 for (i
= 0; i
<= PT_MAX
; i
++) {
234 if (get_user(tmp
, (unsigned long *) data
)) {
241 tmp
|= get_reg(child
, PT_DCCR
) & ~DCCR_MASK
;
244 put_reg(child
, i
, tmp
);
245 data
+= sizeof(long);
253 ret
= ptrace_request(child
, request
, addr
, data
);
257 put_task_struct(child
);
263 void do_syscall_trace(void)
265 if (!test_thread_flag(TIF_SYSCALL_TRACE
))
268 if (!(current
->ptrace
& PT_PTRACED
))
271 /* the 0x80 provides a way for the tracing parent to distinguish
272 between a syscall stop and SIGTRAP delivery */
273 ptrace_notify(SIGTRAP
| ((current
->ptrace
& PT_TRACESYSGOOD
)
277 * This isn't the same as continuing with a signal, but it will do for
280 if (current
->exit_code
) {
281 send_sig(current
->exit_code
, current
, 1);
282 current
->exit_code
= 0;