1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 1992 Ross Biro
7  * Copyright (C) Linus Torvalds
8  * Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle
9  * Copyright (C) 1996 David S. Miller
10  * Copyright (C) 2000 Ulf Carlsson
11  *
12  * At this time Linux/MIPS64 only supports syscall tracing, even for 32-bit
13  * binaries.
14  */
15 #include <linux/config.h>
16 #include <linux/kernel.h>
17 #include <linux/sched.h>
18 #include <linux/mm.h>
19 #include <linux/errno.h>
20 #include <linux/ptrace.h>
21 #include <linux/smp.h>
22 #include <linux/smp_lock.h>
23 #include <linux/user.h>
24 
25 #include <asm/cpu.h>
26 #include <asm/fpu.h>
27 #include <asm/mipsregs.h>
28 #include <asm/pgtable.h>
29 #include <asm/page.h>
30 #include <asm/system.h>
31 #include <asm/uaccess.h>
32 #include <asm/bootinfo.h>
33 
34 /*
35  * Called by kernel/ptrace.c when detaching..
36  *
37  * Make sure single step bits etc are not set.
38  */
ptrace_disable(struct task_struct * child)39 void ptrace_disable(struct task_struct *child)
40 {
41 	/* Nothing to do.. */
42 }
43 
44 /*
45  * Tracing a 32-bit process with a 64-bit strace and vice versa will not
46  * work.  I don't know how to fix this.
47  */
sys32_ptrace(int request,int pid,int addr,int data)48 asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
49 {
50 	struct task_struct *child;
51 	int ret;
52 
53 	lock_kernel();
54 	ret = -EPERM;
55 	if (request == PTRACE_TRACEME) {
56 		/* are we already being traced? */
57 		if (current->ptrace & PT_PTRACED)
58 			goto out;
59 		/* set the ptrace bit in the process flags. */
60 		current->ptrace |= PT_PTRACED;
61 		ret = 0;
62 		goto out;
63 	}
64 	ret = -ESRCH;
65 	read_lock(&tasklist_lock);
66 	child = find_task_by_pid(pid);
67 	if (child)
68 		get_task_struct(child);
69 	read_unlock(&tasklist_lock);
70 	if (!child)
71 		goto out;
72 
73 	ret = -EPERM;
74 	if (pid == 1)		/* you may not mess with init */
75 		goto out_tsk;
76 
77 	if (request == PTRACE_ATTACH) {
78 		ret = ptrace_attach(child);
79 		goto out_tsk;
80 	}
81 
82 	ret = ptrace_check_attach(child, request == PTRACE_KILL);
83 	if (ret < 0)
84 		goto out_tsk;
85 
86 	switch (request) {
87 	/* when I and D space are separate, these will need to be fixed. */
88 	case PTRACE_PEEKTEXT: /* read word at location addr. */
89 	case PTRACE_PEEKDATA: {
90 		unsigned int tmp;
91 		int copied;
92 
93 		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
94 		ret = -EIO;
95 		if (copied != sizeof(tmp))
96 			break;
97 		ret = put_user(tmp, (unsigned int *) (unsigned long) data);
98 		break;
99 	}
100 
101 	/* read the word at location addr in the USER area. */
102 	case PTRACE_PEEKUSR: {
103 		struct pt_regs *regs;
104 		unsigned int tmp;
105 
106 		regs = (struct pt_regs *) ((unsigned long) child +
107 			KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
108 		ret = 0;
109 
110 		switch (addr) {
111 		case 0 ... 31:
112 			tmp = regs->regs[addr];
113 			break;
114 		case FPR_BASE ... FPR_BASE + 31:
115 			if (child->used_math) {
116 				unsigned long long *fregs;
117 				fregs = (unsigned long long *)get_fpu_regs(child);
118 				/*
119 				 * The odd registers are actually the high
120 				 * order bits of the values stored in the even
121 				 * registers - unless we're using r2k_switch.S.
122 				 */
123 				if (addr & 1)
124 					tmp = (unsigned long) (fregs[((addr & ~1) - 32)] >> 32);
125 				else
126 					tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff);
127 			} else {
128 				tmp = -1;	/* FP not yet used  */
129 			}
130 			break;
131 		case PC:
132 			tmp = regs->cp0_epc;
133 			break;
134 		case CAUSE:
135 			tmp = regs->cp0_cause;
136 			break;
137 		case BADVADDR:
138 			tmp = regs->cp0_badvaddr;
139 			break;
140 		case MMHI:
141 			tmp = regs->hi;
142 			break;
143 		case MMLO:
144 			tmp = regs->lo;
145 			break;
146 		case FPC_CSR:
147 			if (cpu_has_fpu)
148 				tmp = child->thread.fpu.hard.control;
149 			else
150 				tmp = child->thread.fpu.soft.sr;
151 			break;
152 		case FPC_EIR: { /* implementation / version register */
153 			unsigned long flags;
154 			__save_flags(flags);
155 			__enable_fpu();
156 			__asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
157 			__restore_flags(flags);
158 			break;
159 		}
160 		default:
161 			tmp = 0;
162 			ret = -EIO;
163 			goto out_tsk;
164 		}
165 		ret = put_user(tmp, (unsigned *) (unsigned long) data);
166 		break;
167 		}
168 	/* when I and D space are separate, this will have to be fixed. */
169 	case PTRACE_POKETEXT: /* write the word at location addr. */
170 	case PTRACE_POKEDATA:
171 		ret = 0;
172 		if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
173 			break;
174 		ret = -EIO;
175 		break;
176 
177 	case PTRACE_POKEUSR: {
178 		struct pt_regs *regs;
179 		ret = 0;
180 		regs = (struct pt_regs *) ((unsigned long) child +
181 			KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
182 
183 		switch (addr) {
184 		case 0 ... 31:
185 			regs->regs[addr] = data;
186 			break;
187 		case FPR_BASE ... FPR_BASE + 31: {
188 			unsigned long long *fregs;
189 			fregs = (unsigned long long *)get_fpu_regs(child);
190 			if (!child->used_math) {
191 				/* FP not yet used  */
192 				memset(&child->thread.fpu.hard, ~0,
193 				       sizeof(child->thread.fpu.hard));
194 				child->thread.fpu.hard.control = 0;
195 			}
196 			/*
197 			 * The odd registers are actually the high order bits
198 			 * of the values stored in the even registers - unless
199 			 * we're using r2k_switch.S.
200 			 */
201 			if (addr & 1) {
202 				fregs[(addr & ~1) - FPR_BASE] &= 0xffffffff;
203 				fregs[(addr & ~1) - FPR_BASE] |= ((unsigned long long) data) << 32;
204 			} else {
205 				fregs[addr - FPR_BASE] &= ~0xffffffffLL;
206 				/* Must cast, lest sign extension fill upper
207 				   bits!  */
208 				fregs[addr - FPR_BASE] |= (unsigned int)data;
209 			}
210 			break;
211 		}
212 		case PC:
213 			regs->cp0_epc = data;
214 			break;
215 		case MMHI:
216 			regs->hi = data;
217 			break;
218 		case MMLO:
219 			regs->lo = data;
220 			break;
221 		case FPC_CSR:
222 			if (cpu_has_fpu)
223 				child->thread.fpu.hard.control = data;
224 			else
225 				child->thread.fpu.soft.sr = data;
226 			break;
227 		default:
228 			/* The rest are not allowed. */
229 			ret = -EIO;
230 			break;
231 		}
232 		break;
233 		}
234 	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
235 	case PTRACE_CONT: { /* restart after signal. */
236 		ret = -EIO;
237 		if ((unsigned int) data > _NSIG)
238 			break;
239 		if (request == PTRACE_SYSCALL)
240 			child->ptrace |= PT_TRACESYS;
241 		else
242 			child->ptrace &= ~PT_TRACESYS;
243 		child->exit_code = data;
244 		wake_up_process(child);
245 		ret = 0;
246 		break;
247 	}
248 
249 /*
250  * make the child exit.  Best I can do is send it a sigkill.
251  * perhaps it should be put in the status that it wants to
252  * exit.
253  */
254 	case PTRACE_KILL: {
255 		if (child->state == TASK_ZOMBIE)	/* already dead */
256 			break;
257 		child->exit_code = SIGKILL;
258 		wake_up_process(child);
259 		break;
260 	}
261 
262 	case PTRACE_DETACH: /* detach a process that was attached. */
263 		ret = ptrace_detach(child, data);
264 		break;
265 
266 	case PTRACE_SETOPTIONS: {
267 		if (data & PTRACE_O_TRACESYSGOOD)
268 			child->ptrace |= PT_TRACESYSGOOD;
269 		else
270 			child->ptrace &= ~PT_TRACESYSGOOD;
271 		ret = 0;
272 		break;
273 	}
274 
275 	default:
276 		ret = -EIO;
277 		break;
278 	}
279 
280 out_tsk:
281 	free_task_struct(child);
282 out:
283 	unlock_kernel();
284 	return ret;
285 }
286 
sys_ptrace(long request,long pid,long addr,long data)287 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
288 {
289 	struct task_struct *child;
290 	int ret;
291 
292 	lock_kernel();
293 #if 0
294 	printk("ptrace(r=%d,pid=%d,addr=%08lx,data=%08lx)\n",
295 	       (int) request, (int) pid, (unsigned long) addr,
296 	       (unsigned long) data);
297 #endif
298 	ret = -EPERM;
299 	if (request == PTRACE_TRACEME) {
300 		/* are we already being traced? */
301 		if (current->ptrace & PT_PTRACED)
302 			goto out;
303 		/* set the ptrace bit in the process flags. */
304 		current->ptrace |= PT_PTRACED;
305 		ret = 0;
306 		goto out;
307 	}
308 	ret = -ESRCH;
309 	read_lock(&tasklist_lock);
310 	child = find_task_by_pid(pid);
311 	if (child)
312 		get_task_struct(child);
313 	read_unlock(&tasklist_lock);
314 	if (!child)
315 		goto out;
316 
317 	ret = -EPERM;
318 	if (pid == 1)		/* you may not mess with init */
319 		goto out_tsk;
320 
321 	if (request == PTRACE_ATTACH) {
322 		ret = ptrace_attach(child);
323 		goto out_tsk;
324 	}
325 
326 	ret = ptrace_check_attach(child, request == PTRACE_KILL);
327 	if (ret < 0)
328 		goto out_tsk;
329 
330 	switch (request) {
331 	/* when I and D space are separate, these will need to be fixed. */
332 	case PTRACE_PEEKTEXT: /* read word at location addr. */
333 	case PTRACE_PEEKDATA: {
334 		unsigned long tmp;
335 		int copied;
336 
337 		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
338 		ret = -EIO;
339 		if (copied != sizeof(tmp))
340 			break;
341 		ret = put_user(tmp,(unsigned long *) data);
342 		break;
343 	}
344 
345 	/* read the word at location addr in the USER area. */
346 	case PTRACE_PEEKUSR: {
347 		struct pt_regs *regs;
348 		unsigned long tmp;
349 
350 		regs = (struct pt_regs *) ((unsigned long) child +
351 			KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
352 		ret = 0;
353 
354 		switch (addr) {
355 		case 0 ... 31:
356 			tmp = regs->regs[addr];
357 			break;
358 		case FPR_BASE ... FPR_BASE + 31:
359 			if (child->used_math) {
360 				unsigned long *fregs = get_fpu_regs(child);
361 				tmp = fregs[addr - FPR_BASE];
362 			} else {
363 				tmp = -EIO;
364 			}
365 			break;
366 		case PC:
367 			tmp = regs->cp0_epc;
368 			break;
369 		case CAUSE:
370 			tmp = regs->cp0_cause;
371 			break;
372 		case BADVADDR:
373 			tmp = regs->cp0_badvaddr;
374 			break;
375 		case MMHI:
376 			tmp = regs->hi;
377 			break;
378 		case MMLO:
379 			tmp = regs->lo;
380 			break;
381 		case FPC_CSR:
382 			if (cpu_has_fpu)
383 				tmp = child->thread.fpu.hard.control;
384 			else
385 				tmp = child->thread.fpu.soft.sr;
386 			break;
387 		case FPC_EIR: { /* implementation / version register */
388 			unsigned long flags;
389 			__save_flags(flags);
390 			__enable_fpu();
391 			__asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
392 			__restore_flags(flags);
393 			break;
394 		}
395 		default:
396 			tmp = 0;
397 			ret = -EIO;
398 			goto out_tsk;
399 		}
400 		ret = put_user(tmp, (unsigned long *) data);
401 		break;
402 		}
403 	/* when I and D space are separate, this will have to be fixed. */
404 	case PTRACE_POKETEXT: /* write the word at location addr. */
405 	case PTRACE_POKEDATA:
406 		ret = 0;
407 		if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
408 			break;
409 		ret = -EIO;
410 		break;
411 
412 	case PTRACE_POKEUSR: {
413 		struct pt_regs *regs;
414 		ret = 0;
415 		regs = (struct pt_regs *) ((unsigned long) child +
416 			KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
417 
418 		switch (addr) {
419 		case 0 ... 31:
420 			regs->regs[addr] = data;
421 			break;
422 		case FPR_BASE ... FPR_BASE + 31: {
423 			unsigned long *fregs = get_fpu_regs(child);
424 			if (!child->used_math) {
425 				/* FP not yet used  */
426 				memset(&child->thread.fpu.hard, ~0,
427 				       sizeof(child->thread.fpu.hard));
428 				child->thread.fpu.hard.control = 0;
429 			}
430 			fregs[addr - FPR_BASE] = data;
431 			break;
432 		}
433 		case PC:
434 			regs->cp0_epc = data;
435 			break;
436 		case MMHI:
437 			regs->hi = data;
438 			break;
439 		case MMLO:
440 			regs->lo = data;
441 			break;
442 		case FPC_CSR:
443 			if (cpu_has_fpu)
444 				child->thread.fpu.hard.control = data;
445 			else
446 				child->thread.fpu.soft.sr = data;
447 			break;
448 		default:
449 			/* The rest are not allowed. */
450 			ret = -EIO;
451 			break;
452 		}
453 		break;
454 		}
455 	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
456 	case PTRACE_CONT: { /* restart after signal. */
457 		ret = -EIO;
458 		if ((unsigned long) data > _NSIG)
459 			break;
460 		if (request == PTRACE_SYSCALL)
461 			child->ptrace |= PT_TRACESYS;
462 		else
463 			child->ptrace &= ~PT_TRACESYS;
464 		child->exit_code = data;
465 		wake_up_process(child);
466 		ret = 0;
467 		break;
468 	}
469 
470 /*
471  * make the child exit.  Best I can do is send it a sigkill.
472  * perhaps it should be put in the status that it wants to
473  * exit.
474  */
475 	case PTRACE_KILL: {
476 		if (child->state == TASK_ZOMBIE)	/* already dead */
477 			break;
478 		child->exit_code = SIGKILL;
479 		wake_up_process(child);
480 		break;
481 	}
482 
483 	case PTRACE_DETACH: /* detach a process that was attached. */
484 		ret = ptrace_detach(child, data);
485 		break;
486 
487 	case PTRACE_SETOPTIONS: {
488 		if (data & PTRACE_O_TRACESYSGOOD)
489 			child->ptrace |= PT_TRACESYSGOOD;
490 		else
491 			child->ptrace &= ~PT_TRACESYSGOOD;
492 		ret = 0;
493 		break;
494 	}
495 
496 	default:
497 		ret = -EIO;
498 		break;
499 	}
500 
501 out_tsk:
502 	free_task_struct(child);
503 out:
504 	unlock_kernel();
505 	return ret;
506 }
507 
syscall_trace(void)508 asmlinkage void syscall_trace(void)
509 {
510 	if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
511 	    != (PT_PTRACED|PT_TRACESYS))
512 		return;
513 
514 	/* The 0x80 provides a way for the tracing parent to distinguish
515 	   between a syscall stop and SIGTRAP delivery */
516 	current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
517 	                                ? 0x80 : 0);
518 	current->state = TASK_STOPPED;
519 	notify_parent(current, SIGCHLD);
520 	schedule();
521 	/*
522 	 * this isn't the same as continuing with a signal, but it will do
523 	 * for normal use.  strace only continues with a signal if the
524 	 * stopping signal is not SIGTRAP.  -brl
525 	 */
526 	if (current->exit_code) {
527 		send_sig(current->exit_code, current, 1);
528 		current->exit_code = 0;
529 	}
530 }
531