1 /*
2 * linux/arch/cris/kernel/ptrace.c
3 *
4 * Parts taken from the m68k port.
5 *
6 * Copyright (c) 2000, 2001 Axis Communications AB
7 *
8 * Authors: Bjorn Wesen
9 *
10 * $Log: ptrace.c,v $
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.
14 *
15 * Revision 1.8 2001/11/12 18:26:21 pkj
16 * Fixed compiler warnings.
17 *
18 * Revision 1.7 2001/09/26 11:53:49 bjornw
19 * PTRACE_DETACH works more simple in 2.4.10
20 *
21 * Revision 1.6 2001/07/25 16:08:47 bjornw
22 * PTRACE_ATTACH bulk moved into arch-independant code in 2.4.7
23 *
24 * Revision 1.5 2001/03/26 14:24:28 orjanf
25 * * Changed loop condition.
26 * * Added comment documenting non-standard ptrace behaviour.
27 *
28 * Revision 1.4 2001/03/20 19:44:41 bjornw
29 * Use the user_regs macro instead of thread.esp0
30 *
31 * Revision 1.3 2000/12/18 23:45:25 bjornw
32 * Linux/CRIS first version
33 *
34 *
35 */
36
37 #include <linux/kernel.h>
38 #include <linux/sched.h>
39 #include <linux/mm.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>
45
46 #include <asm/uaccess.h>
47 #include <asm/page.h>
48 #include <asm/pgtable.h>
49 #include <asm/system.h>
50 #include <asm/processor.h>
51
52 /*
53 * does not yet catch signals sent when the child dies.
54 * in exit.c or in signal.c.
55 */
56
57 /* determines which bits in DCCR the user has access to. */
58 /* 1 = access 0 = no access */
59 #define DCCR_MASK 0x0000001f /* XNZVC */
60
61 /*
62 * Get contents of register REGNO in task TASK.
63 */
get_reg(struct task_struct * task,unsigned int regno)64 static inline long get_reg(struct task_struct *task, unsigned int regno)
65 {
66 /* USP is a special case, it's not in the pt_regs struct but
67 * in the tasks thread struct
68 */
69
70 if (regno == PT_USP)
71 return task->thread.usp;
72 else if (regno < PT_MAX)
73 return ((unsigned long *)user_regs(task))[regno];
74 else
75 return 0;
76 }
77
78 /*
79 * Write contents of register REGNO in task TASK.
80 */
put_reg(struct task_struct * task,unsigned int regno,unsigned long data)81 static inline int put_reg(struct task_struct *task, unsigned int regno,
82 unsigned long data)
83 {
84 if (regno == PT_USP)
85 task->thread.usp = data;
86 else if (regno < PT_MAX)
87 ((unsigned long *)user_regs(task))[regno] = data;
88 else
89 return -1;
90 return 0;
91 }
92
93 /*
94 * Called by kernel/ptrace.c when detaching..
95 *
96 * Make sure the single step bit is not set.
97 */
ptrace_disable(struct task_struct * child)98 void ptrace_disable(struct task_struct *child)
99 {
100 /* Todo - pending singlesteps? */
101 }
102
sys_ptrace(long request,long pid,long addr,long data)103 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
104 {
105 struct task_struct *child;
106 int ret;
107
108 lock_kernel();
109 ret = -EPERM;
110 if (request == PTRACE_TRACEME) {
111 /* are we already being traced? */
112 if (current->ptrace & PT_PTRACED)
113 goto out;
114 /* set the ptrace bit in the process flags. */
115 current->ptrace |= PT_PTRACED;
116 ret = 0;
117 goto out;
118 }
119 ret = -ESRCH;
120 read_lock(&tasklist_lock);
121 child = find_task_by_pid(pid);
122 if (child)
123 get_task_struct(child);
124 read_unlock(&tasklist_lock);
125 if (!child)
126 goto out;
127 ret = -EPERM;
128 if (pid == 1) /* you may not mess with init */
129 goto out_tsk;
130 if (request == PTRACE_ATTACH) {
131 ret = ptrace_attach(child);
132 goto out_tsk;
133 }
134 ret = -ESRCH;
135 if (!(child->ptrace & PT_PTRACED))
136 goto out_tsk;
137 if (child->state != TASK_STOPPED) {
138 if (request != PTRACE_KILL)
139 goto out_tsk;
140 }
141 if (child->p_pptr != current)
142 goto out_tsk;
143
144 switch (request) {
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: {
148 unsigned long tmp;
149 int copied;
150
151 copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
152 ret = -EIO;
153 if (copied != sizeof(tmp))
154 break;
155 ret = put_user(tmp,(unsigned long *) data);
156 break;
157 }
158
159 /* read the word at location addr in the USER area. */
160 case PTRACE_PEEKUSR: {
161 unsigned long tmp;
162
163 ret = -EIO;
164 if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
165 break;
166
167 tmp = get_reg(child, addr >> 2);
168 ret = put_user(tmp, (unsigned long *)data);
169 break;
170 }
171
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:
175 ret = 0;
176 if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
177 break;
178 ret = -EIO;
179 break;
180
181 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
182 ret = -EIO;
183 if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
184 break;
185
186 addr >>= 2;
187
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.
191 */
192 data &= DCCR_MASK;
193 data |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
194 }
195 if (put_reg(child, addr, data))
196 break;
197 ret = 0;
198 break;
199
200 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
201 case PTRACE_CONT: /* restart after signal. */
202 ret = -EIO;
203 if ((unsigned long) data > _NSIG)
204 break;
205 if (request == PTRACE_SYSCALL)
206 child->ptrace |= PT_TRACESYS;
207 else
208 child->ptrace &= ~PT_TRACESYS;
209 child->exit_code = data;
210 /* TODO: make sure any pending breakpoint is killed */
211 wake_up_process(child);
212 ret = 0;
213 break;
214
215 /*
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
218 * exit.
219 */
220 case PTRACE_KILL:
221 ret = 0;
222 if (child->state == TASK_ZOMBIE) /* already dead */
223 break;
224 child->exit_code = SIGKILL;
225 /* TODO: make sure any pending breakpoint is killed */
226 wake_up_process(child);
227 break;
228
229 case PTRACE_SINGLESTEP: /* set the trap flag. */
230 ret = -EIO;
231 if ((unsigned long) data > _NSIG)
232 break;
233 child->ptrace &= ~PT_TRACESYS;
234
235 /* TODO: set some clever breakpoint mechanism... */
236
237 child->exit_code = data;
238 /* give it a chance to run. */
239 wake_up_process(child);
240 ret = 0;
241 break;
242
243 case PTRACE_DETACH:
244 ret = ptrace_detach(child, data);
245 break;
246
247 case PTRACE_GETREGS: { /* Get all gp regs from the child. */
248 int i;
249 unsigned long tmp;
250 for (i = 0; i <= PT_MAX; i++) {
251 tmp = get_reg(child, i);
252 if (put_user(tmp, (unsigned long *) data)) {
253 ret = -EFAULT;
254 break;
255 }
256 data += sizeof(long);
257 }
258 ret = 0;
259 break;
260 }
261
262 case PTRACE_SETREGS: { /* Set all gp regs in the child. */
263 int i;
264 unsigned long tmp;
265 for (i = 0; i <= PT_MAX; i++) {
266 if (get_user(tmp, (unsigned long *) data)) {
267 ret = -EFAULT;
268 break;
269 }
270 if (i == PT_DCCR) {
271 tmp &= DCCR_MASK;
272 tmp |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
273 }
274 put_reg(child, i, tmp);
275 data += sizeof(long);
276 }
277 ret = 0;
278 break;
279 }
280
281 default:
282 ret = -EIO;
283 break;
284 }
285 out_tsk:
286 free_task_struct(child);
287 out:
288 unlock_kernel();
289 return ret;
290 }
291
syscall_trace(void)292 asmlinkage void syscall_trace(void)
293 {
294 if ((current->ptrace & (PT_PTRACED | PT_TRACESYS)) !=
295 (PT_PTRACED | PT_TRACESYS))
296 return;
297 /* TODO: make a way to distinguish between a syscall stop and SIGTRAP
298 * delivery like in the i386 port ?
299 */
300 current->exit_code = SIGTRAP;
301 current->state = TASK_STOPPED;
302 notify_parent(current, SIGCHLD);
303 schedule();
304 /*
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
308 */
309 if (current->exit_code) {
310 send_sig(current->exit_code, current, 1);
311 current->exit_code = 0;
312 }
313 }
314