2 * linux/arch/cris/kernel/ptrace.c
4 * Parts taken from the m68k port.
6 * Copyright (c) 2000, 2001 Axis Communications AB
11 * Revision 1.9 2003/10/01 11:34:23 aurer
12 * * Allow PTRACE_PEEKUSR and PTRACE_POKEUSR to access USP.
13 * * Removed nonsensical comment about ptrace behavior.
15 * Revision 1.8 2001/11/12 18:26:21 pkj
16 * Fixed compiler warnings.
18 * Revision 1.7 2001/09/26 11:53:49 bjornw
19 * PTRACE_DETACH works more simple in 2.4.10
21 * Revision 1.6 2001/07/25 16:08:47 bjornw
22 * PTRACE_ATTACH bulk moved into arch-independant code in 2.4.7
24 * Revision 1.5 2001/03/26 14:24:28 orjanf
25 * * Changed loop condition.
26 * * Added comment documenting non-standard ptrace behaviour.
28 * Revision 1.4 2001/03/20 19:44:41 bjornw
29 * Use the user_regs macro instead of thread.esp0
31 * Revision 1.3 2000/12/18 23:45:25 bjornw
32 * Linux/CRIS first version
37 #include <linux/kernel.h>
38 #include <linux/sched.h>
40 #include <linux/smp.h>
41 #include <linux/smp_lock.h>
42 #include <linux/errno.h>
43 #include <linux/ptrace.h>
44 #include <linux/user.h>
46 #include <asm/uaccess.h>
48 #include <asm/pgtable.h>
49 #include <asm/system.h>
50 #include <asm/processor.h>
53 * does not yet catch signals sent when the child dies.
54 * in exit.c or in signal.c.
57 /* determines which bits in DCCR the user has access to. */
58 /* 1 = access 0 = no access */
59 #define DCCR_MASK 0x0000001f /* XNZVC */
62 * Get contents of register REGNO in task TASK.
64 static inline long get_reg(struct task_struct *task, unsigned int regno)
66 /* USP is a special case, it's not in the pt_regs struct but
67 * in the tasks thread struct
71 return task->thread.usp;
72 else if (regno < PT_MAX)
73 return ((unsigned long *)user_regs(task))[regno];
79 * Write contents of register REGNO in task TASK.
81 static inline int put_reg(struct task_struct *task, unsigned int regno,
85 task->thread.usp = data;
86 else if (regno < PT_MAX)
87 ((unsigned long *)user_regs(task))[regno] = data;
94 * Called by kernel/ptrace.c when detaching..
96 * Make sure the single step bit is not set.
98 void ptrace_disable(struct task_struct *child)
100 /* Todo - pending singlesteps? */
103 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
105 struct task_struct *child;
110 if (request == PTRACE_TRACEME) {
111 /* are we already being traced? */
112 if (current->ptrace & PT_PTRACED)
114 /* set the ptrace bit in the process flags. */
115 current->ptrace |= PT_PTRACED;
120 read_lock(&tasklist_lock);
121 child = find_task_by_pid(pid);
123 get_task_struct(child);
124 read_unlock(&tasklist_lock);
128 if (pid == 1) /* you may not mess with init */
130 if (request == PTRACE_ATTACH) {
131 ret = ptrace_attach(child);
135 if (!(child->ptrace & PT_PTRACED))
137 if (child->state != TASK_STOPPED) {
138 if (request != PTRACE_KILL)
141 if (child->p_pptr != current)
145 /* when I and D space are separate, these will need to be fixed. */
146 case PTRACE_PEEKTEXT: /* read word at location addr. */
147 case PTRACE_PEEKDATA: {
151 copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
153 if (copied != sizeof(tmp))
155 ret = put_user(tmp,(unsigned long *) data);
159 /* read the word at location addr in the USER area. */
160 case PTRACE_PEEKUSR: {
164 if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
167 tmp = get_reg(child, addr >> 2);
168 ret = put_user(tmp, (unsigned long *)data);
172 /* when I and D space are separate, this will have to be fixed. */
173 case PTRACE_POKETEXT: /* write the word at location addr. */
174 case PTRACE_POKEDATA:
176 if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
181 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
183 if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
188 if (addr == PT_DCCR) {
189 /* don't allow the tracing process to change stuff like
190 * interrupt enable, kernel/user bit, dma enables etc.
193 data |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
195 if (put_reg(child, addr, data))
200 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
201 case PTRACE_CONT: /* restart after signal. */
203 if ((unsigned long) data > _NSIG)
205 if (request == PTRACE_SYSCALL)
206 child->ptrace |= PT_TRACESYS;
208 child->ptrace &= ~PT_TRACESYS;
209 child->exit_code = data;
210 /* TODO: make sure any pending breakpoint is killed */
211 wake_up_process(child);
216 * make the child exit. Best I can do is send it a sigkill.
217 * perhaps it should be put in the status that it wants to
222 if (child->state == TASK_ZOMBIE) /* already dead */
224 child->exit_code = SIGKILL;
225 /* TODO: make sure any pending breakpoint is killed */
226 wake_up_process(child);
229 case PTRACE_SINGLESTEP: /* set the trap flag. */
231 if ((unsigned long) data > _NSIG)
233 child->ptrace &= ~PT_TRACESYS;
235 /* TODO: set some clever breakpoint mechanism... */
237 child->exit_code = data;
238 /* give it a chance to run. */
239 wake_up_process(child);
244 ret = ptrace_detach(child, data);
247 case PTRACE_GETREGS: { /* Get all gp regs from the child. */
250 for (i = 0; i <= PT_MAX; i++) {
251 tmp = get_reg(child, i);
252 if (put_user(tmp, (unsigned long *) data)) {
256 data += sizeof(long);
262 case PTRACE_SETREGS: { /* Set all gp regs in the child. */
265 for (i = 0; i <= PT_MAX; i++) {
266 if (get_user(tmp, (unsigned long *) data)) {
272 tmp |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
274 put_reg(child, i, tmp);
275 data += sizeof(long);
286 free_task_struct(child);
292 asmlinkage void syscall_trace(void)
294 if ((current->ptrace & (PT_PTRACED | PT_TRACESYS)) !=
295 (PT_PTRACED | PT_TRACESYS))
297 /* TODO: make a way to distinguish between a syscall stop and SIGTRAP
298 * delivery like in the i386 port ?
300 current->exit_code = SIGTRAP;
301 current->state = TASK_STOPPED;
302 notify_parent(current, SIGCHLD);
305 * this isn't the same as continuing with a signal, but it will do
306 * for normal use. strace only continues with a signal if the
307 * stopping signal is not SIGTRAP. -brl
309 if (current->exit_code) {
310 send_sig(current->exit_code, current, 1);
311 current->exit_code = 0;