• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* MN10300 Process tracing
2  *
3  * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
4  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5  * Modified by David Howells (dhowells@redhat.com)
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public Licence
9  * as published by the Free Software Foundation; either version
10  * 2 of the Licence, or (at your option) any later version.
11  */
12 #include <linux/kernel.h>
13 #include <linux/sched.h>
14 #include <linux/mm.h>
15 #include <linux/smp.h>
16 #include <linux/smp_lock.h>
17 #include <linux/errno.h>
18 #include <linux/ptrace.h>
19 #include <linux/user.h>
20 #include <asm/uaccess.h>
21 #include <asm/pgtable.h>
22 #include <asm/system.h>
23 #include <asm/processor.h>
24 #include <asm/cacheflush.h>
25 #include <asm/fpu.h>
26 #include <asm/asm-offsets.h>
27 
28 /*
29  * translate ptrace register IDs into struct pt_regs offsets
30  */
31 static const u8 ptrace_regid_to_frame[] = {
32 	[PT_A3 << 2]		= REG_A3,
33 	[PT_A2 << 2]		= REG_A2,
34 	[PT_D3 << 2]		= REG_D3,
35 	[PT_D2 << 2]		= REG_D2,
36 	[PT_MCVF << 2]		= REG_MCVF,
37 	[PT_MCRL << 2]		= REG_MCRL,
38 	[PT_MCRH << 2]		= REG_MCRH,
39 	[PT_MDRQ << 2]		= REG_MDRQ,
40 	[PT_E1 << 2]		= REG_E1,
41 	[PT_E0 << 2]		= REG_E0,
42 	[PT_E7 << 2]		= REG_E7,
43 	[PT_E6 << 2]		= REG_E6,
44 	[PT_E5 << 2]		= REG_E5,
45 	[PT_E4 << 2]		= REG_E4,
46 	[PT_E3 << 2]		= REG_E3,
47 	[PT_E2 << 2]		= REG_E2,
48 	[PT_SP << 2]		= REG_SP,
49 	[PT_LAR << 2]		= REG_LAR,
50 	[PT_LIR << 2]		= REG_LIR,
51 	[PT_MDR << 2]		= REG_MDR,
52 	[PT_A1 << 2]		= REG_A1,
53 	[PT_A0 << 2]		= REG_A0,
54 	[PT_D1 << 2]		= REG_D1,
55 	[PT_D0 << 2]		= REG_D0,
56 	[PT_ORIG_D0 << 2]	= REG_ORIG_D0,
57 	[PT_EPSW << 2]		= REG_EPSW,
58 	[PT_PC << 2]		= REG_PC,
59 };
60 
get_stack_long(struct task_struct * task,int offset)61 static inline int get_stack_long(struct task_struct *task, int offset)
62 {
63 	return *(unsigned long *)
64 		((unsigned long) task->thread.uregs + offset);
65 }
66 
67 /*
68  * this routine will put a word on the processes privileged stack.
69  * the offset is how far from the base addr as stored in the TSS.
70  * this routine assumes that all the privileged stacks are in our
71  * data space.
72  */
73 static inline
put_stack_long(struct task_struct * task,int offset,unsigned long data)74 int put_stack_long(struct task_struct *task, int offset, unsigned long data)
75 {
76 	unsigned long stack;
77 
78 	stack = (unsigned long) task->thread.uregs + offset;
79 	*(unsigned long *) stack = data;
80 	return 0;
81 }
82 
get_fpregs(struct fpu_state_struct * buf,struct task_struct * tsk)83 static inline unsigned long get_fpregs(struct fpu_state_struct *buf,
84 				       struct task_struct *tsk)
85 {
86 	return __copy_to_user(buf, &tsk->thread.fpu_state,
87 			      sizeof(struct fpu_state_struct));
88 }
89 
set_fpregs(struct task_struct * tsk,struct fpu_state_struct * buf)90 static inline unsigned long set_fpregs(struct task_struct *tsk,
91 				       struct fpu_state_struct *buf)
92 {
93 	return __copy_from_user(&tsk->thread.fpu_state, buf,
94 				sizeof(struct fpu_state_struct));
95 }
96 
fpsave_init(struct task_struct * task)97 static inline void fpsave_init(struct task_struct *task)
98 {
99 	memset(&task->thread.fpu_state, 0, sizeof(struct fpu_state_struct));
100 }
101 
102 /*
103  * make sure the single step bit is not set
104  */
ptrace_disable(struct task_struct * child)105 void ptrace_disable(struct task_struct *child)
106 {
107 #ifndef CONFIG_MN10300_USING_JTAG
108 	struct user *dummy = NULL;
109 	long tmp;
110 
111 	tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw);
112 	tmp &= ~EPSW_T;
113 	put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp);
114 #endif
115 }
116 
117 /*
118  * set the single step bit
119  */
ptrace_enable(struct task_struct * child)120 void ptrace_enable(struct task_struct *child)
121 {
122 #ifndef CONFIG_MN10300_USING_JTAG
123 	struct user *dummy = NULL;
124 	long tmp;
125 
126 	tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw);
127 	tmp |= EPSW_T;
128 	put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp);
129 #endif
130 }
131 
132 /*
133  * handle the arch-specific side of process tracing
134  */
arch_ptrace(struct task_struct * child,long request,long addr,long data)135 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
136 {
137 	struct fpu_state_struct fpu_state;
138 	int i, ret;
139 
140 	switch (request) {
141 	/* read the word at location addr. */
142 	case PTRACE_PEEKTEXT: {
143 		unsigned long tmp;
144 		int copied;
145 
146 		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
147 		ret = -EIO;
148 		if (copied != sizeof(tmp))
149 			break;
150 		ret = put_user(tmp, (unsigned long *) data);
151 		break;
152 	}
153 
154 	/* read the word at location addr. */
155 	case PTRACE_PEEKDATA: {
156 		unsigned long tmp;
157 		int copied;
158 
159 		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
160 		ret = -EIO;
161 		if (copied != sizeof(tmp))
162 			break;
163 		ret = put_user(tmp, (unsigned long *) data);
164 		break;
165 	}
166 
167 	/* read the word at location addr in the USER area. */
168 	case PTRACE_PEEKUSR: {
169 		unsigned long tmp;
170 
171 		ret = -EIO;
172 		if ((addr & 3) || addr < 0 ||
173 		    addr > sizeof(struct user) - 3)
174 			break;
175 
176 		tmp = 0;  /* Default return condition */
177 		if (addr < NR_PTREGS << 2)
178 			tmp = get_stack_long(child,
179 					     ptrace_regid_to_frame[addr]);
180 		ret = put_user(tmp, (unsigned long *) data);
181 		break;
182 	}
183 
184 	/* write the word at location addr. */
185 	case PTRACE_POKETEXT:
186 	case PTRACE_POKEDATA:
187 		if (access_process_vm(child, addr, &data, sizeof(data), 1) ==
188 		    sizeof(data))
189 			ret = 0;
190 		else
191 			ret = -EIO;
192 		break;
193 
194 		/* write the word at location addr in the USER area */
195 	case PTRACE_POKEUSR:
196 		ret = -EIO;
197 		if ((addr & 3) || addr < 0 ||
198 		    addr > sizeof(struct user) - 3)
199 			break;
200 
201 		ret = 0;
202 		if (addr < NR_PTREGS << 2)
203 			ret = put_stack_long(child, ptrace_regid_to_frame[addr],
204 					     data);
205 		break;
206 
207 		/* continue and stop at next (return from) syscall */
208 	case PTRACE_SYSCALL:
209 		/* restart after signal. */
210 	case PTRACE_CONT:
211 		ret = -EIO;
212 		if ((unsigned long) data > _NSIG)
213 			break;
214 		if (request == PTRACE_SYSCALL)
215 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
216 		else
217 			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
218 		child->exit_code = data;
219 		ptrace_disable(child);
220 		wake_up_process(child);
221 		ret = 0;
222 		break;
223 
224 		/*
225 		 * make the child exit
226 		 * - the best I can do is send it a sigkill
227 		 * - perhaps it should be put in the status that it wants to
228 		 *   exit
229 		 */
230 	case PTRACE_KILL:
231 		ret = 0;
232 		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
233 			break;
234 		child->exit_code = SIGKILL;
235 		clear_tsk_thread_flag(child, TIF_SINGLESTEP);
236 		ptrace_disable(child);
237 		wake_up_process(child);
238 		break;
239 
240 	case PTRACE_SINGLESTEP: /* set the trap flag. */
241 #ifndef CONFIG_MN10300_USING_JTAG
242 		ret = -EIO;
243 		if ((unsigned long) data > _NSIG)
244 			break;
245 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
246 		ptrace_enable(child);
247 		child->exit_code = data;
248 		wake_up_process(child);
249 		ret = 0;
250 #else
251 		ret = -EINVAL;
252 #endif
253 		break;
254 
255 	case PTRACE_DETACH:	/* detach a process that was attached. */
256 		ret = ptrace_detach(child, data);
257 		break;
258 
259 		/* Get all gp regs from the child. */
260 	case PTRACE_GETREGS: {
261 		unsigned long tmp;
262 
263 		if (!access_ok(VERIFY_WRITE, (unsigned *) data, NR_PTREGS << 2)) {
264 			ret = -EIO;
265 			break;
266 		}
267 
268 		for (i = 0; i < NR_PTREGS << 2; i += 4) {
269 			tmp = get_stack_long(child, ptrace_regid_to_frame[i]);
270 			__put_user(tmp, (unsigned long *) data);
271 			data += sizeof(tmp);
272 		}
273 		ret = 0;
274 		break;
275 	}
276 
277 	case PTRACE_SETREGS: { /* Set all gp regs in the child. */
278 		unsigned long tmp;
279 
280 		if (!access_ok(VERIFY_READ, (unsigned long *)data,
281 			       sizeof(struct pt_regs))) {
282 			ret = -EIO;
283 			break;
284 		}
285 
286 		for (i = 0; i < NR_PTREGS << 2; i += 4) {
287 			__get_user(tmp, (unsigned long *) data);
288 			put_stack_long(child, ptrace_regid_to_frame[i], tmp);
289 			data += sizeof(tmp);
290 		}
291 		ret = 0;
292 		break;
293 	}
294 
295 	case PTRACE_GETFPREGS: { /* Get the child FPU state. */
296 		if (is_using_fpu(child)) {
297 			unlazy_fpu(child);
298 			fpu_state = child->thread.fpu_state;
299 		} else {
300 			memset(&fpu_state, 0, sizeof(fpu_state));
301 		}
302 
303 		ret = -EIO;
304 		if (copy_to_user((void *) data, &fpu_state,
305 				 sizeof(fpu_state)) == 0)
306 			ret = 0;
307 		break;
308 	}
309 
310 	case PTRACE_SETFPREGS: { /* Set the child FPU state. */
311 		ret = -EFAULT;
312 		if (copy_from_user(&fpu_state, (const void *) data,
313 				   sizeof(fpu_state)) == 0) {
314 			fpu_kill_state(child);
315 			child->thread.fpu_state = fpu_state;
316 			set_using_fpu(child);
317 			ret = 0;
318 		}
319 		break;
320 	}
321 
322 	case PTRACE_SETOPTIONS: {
323 		if (data & PTRACE_O_TRACESYSGOOD)
324 			child->ptrace |= PT_TRACESYSGOOD;
325 		else
326 			child->ptrace &= ~PT_TRACESYSGOOD;
327 		ret = 0;
328 		break;
329 	}
330 
331 	default:
332 		ret = -EIO;
333 		break;
334 	}
335 
336 	return ret;
337 }
338 
339 /*
340  * notification of system call entry/exit
341  * - triggered by current->work.syscall_trace
342  */
do_syscall_trace(struct pt_regs * regs,int entryexit)343 asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
344 {
345 #if 0
346 	/* just in case... */
347 	printk(KERN_DEBUG "[%d] syscall_%lu(%lx,%lx,%lx,%lx) = %lx\n",
348 	       current->pid,
349 	       regs->orig_d0,
350 	       regs->a0,
351 	       regs->d1,
352 	       regs->a3,
353 	       regs->a2,
354 	       regs->d0);
355 	return;
356 #endif
357 
358 	if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
359 	    !test_thread_flag(TIF_SINGLESTEP))
360 		return;
361 	if (!(current->ptrace & PT_PTRACED))
362 		return;
363 
364 	/* the 0x80 provides a way for the tracing parent to distinguish
365 	   between a syscall stop and SIGTRAP delivery */
366 	ptrace_notify(SIGTRAP |
367 		      ((current->ptrace & PT_TRACESYSGOOD) &&
368 		       !test_thread_flag(TIF_SINGLESTEP) ? 0x80 : 0));
369 
370 	/*
371 	 * this isn't the same as continuing with a signal, but it will do
372 	 * for normal use.  strace only continues with a signal if the
373 	 * stopping signal is not SIGTRAP.  -brl
374 	 */
375 	if (current->exit_code) {
376 		send_sig(current->exit_code, current, 1);
377 		current->exit_code = 0;
378 	}
379 }
380