1/*
2 * BK Id: SCCS/s.ptrace.c 1.14 01/17/02 23:05:50 paulus
3 */
4/*
5 *  linux/arch/ppc/kernel/ptrace.c
6 *
7 *  PowerPC version
8 *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
9 *
10 *  Derived from "arch/m68k/kernel/ptrace.c"
11 *  Copyright (C) 1994 by Hamish Macdonald
12 *  Taken from linux/kernel/ptrace.c and modified for M680x0.
13 *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
14 *
15 * Modified by Cort Dougan (cort@hq.fsmlabs.com)
16 * and Paul Mackerras (paulus@linuxcare.com.au).
17 *
18 * This file is subject to the terms and conditions of the GNU General
19 * Public License.  Please read the COPYING file for all license details.
20 */
21
22#include <linux/kernel.h>
23#include <linux/sched.h>
24#include <linux/mm.h>
25#include <linux/smp.h>
26#include <linux/smp_lock.h>
27#include <linux/errno.h>
28#include <linux/ptrace.h>
29#include <linux/user.h>
30
31#include <asm/uaccess.h>
32#include <asm/page.h>
33#include <asm/pgtable.h>
34#include <asm/system.h>
35
36/*
37 * Set of msr bits that gdb can change on behalf of a process.
38 */
39#define MSR_DEBUGCHANGE	(MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1)
40
41/*
42 * does not yet catch signals sent when the child dies.
43 * in exit.c or in signal.c.
44 */
45
46/*
47 * Get contents of register REGNO in task TASK.
48 */
49static inline unsigned long get_reg(struct task_struct *task, int regno)
50{
51	if (regno < sizeof(struct pt_regs) / sizeof(unsigned long)
52	    && task->thread.regs != NULL)
53		return ((unsigned long *)task->thread.regs)[regno];
54	return (0);
55}
56
57/*
58 * Write contents of register REGNO in task TASK.
59 */
60static inline int put_reg(struct task_struct *task, int regno,
61			  unsigned long data)
62{
63	if (regno <= PT_MQ && task->thread.regs != NULL) {
64		if (regno == PT_MSR)
65			data = (data & MSR_DEBUGCHANGE)
66				| (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
67		((unsigned long *)task->thread.regs)[regno] = data;
68		return 0;
69	}
70	return -EIO;
71}
72
73#ifdef CONFIG_ALTIVEC
74/*
75 * Get contents of AltiVec register state in task TASK
76 */
77static inline int get_vrregs(unsigned long *data, struct task_struct *task)
78{
79	int i, j;
80
81	if (!access_ok(VERIFY_WRITE, data, 133 * sizeof(unsigned long)))
82		return -EFAULT;
83
84	/* copy AltiVec registers VR[0] .. VR[31] */
85	for (i = 0; i < 32; i++)
86		for (j = 0; j < 4; j++, data++)
87			if (__put_user(task->thread.vr[i].u[j], data))
88				return -EFAULT;
89
90	/* copy VSCR */
91	for (i = 0; i < 4; i++, data++)
92		if (__put_user(task->thread.vscr.u[i], data))
93			return -EFAULT;
94
95        /* copy VRSAVE */
96	if (__put_user(task->thread.vrsave, data))
97		return -EFAULT;
98
99	return 0;
100}
101
102/*
103 * Write contents of AltiVec register state into task TASK.
104 */
105static inline int set_vrregs(struct task_struct *task, unsigned long *data)
106{
107	int i, j;
108
109	if (!access_ok(VERIFY_READ, data, 133 * sizeof(unsigned long)))
110		return -EFAULT;
111
112	/* copy AltiVec registers VR[0] .. VR[31] */
113	for (i = 0; i < 32; i++)
114		for (j = 0; j < 4; j++, data++)
115			if (__get_user(task->thread.vr[i].u[j], data))
116				return -EFAULT;
117
118	/* copy VSCR */
119	for (i = 0; i < 4; i++, data++)
120		if (__get_user(task->thread.vscr.u[i], data))
121			return -EFAULT;
122
123	/* copy VRSAVE */
124	if (__get_user(task->thread.vrsave, data))
125		return -EFAULT;
126
127	return 0;
128}
129#endif
130
131static inline void
132set_single_step(struct task_struct *task)
133{
134	struct pt_regs *regs = task->thread.regs;
135
136	if (regs != NULL)
137		regs->msr |= MSR_SE;
138}
139
140static inline void
141clear_single_step(struct task_struct *task)
142{
143	struct pt_regs *regs = task->thread.regs;
144
145	if (regs != NULL)
146		regs->msr &= ~MSR_SE;
147}
148
149/*
150 * Called by kernel/ptrace.c when detaching..
151 *
152 * Make sure single step bits etc are not set.
153 */
154void ptrace_disable(struct task_struct *child)
155{
156	/* make sure the single step bit is not set. */
157	clear_single_step(child);
158}
159
160int sys_ptrace(long request, long pid, long addr, long data)
161{
162	struct task_struct *child;
163	int ret = -EPERM;
164
165	lock_kernel();
166	if (request == PTRACE_TRACEME) {
167		/* are we already being traced? */
168		if (current->ptrace & PT_PTRACED)
169			goto out;
170		/* set the ptrace bit in the process flags. */
171		current->ptrace |= PT_PTRACED;
172		ret = 0;
173		goto out;
174	}
175	ret = -ESRCH;
176	read_lock(&tasklist_lock);
177	child = find_task_by_pid(pid);
178	if (child)
179		get_task_struct(child);
180	read_unlock(&tasklist_lock);
181	if (!child)
182		goto out;
183
184	ret = -EPERM;
185	if (pid == 1)		/* you may not mess with init */
186		goto out_tsk;
187
188	if (request == PTRACE_ATTACH) {
189		ret = ptrace_attach(child);
190		goto out_tsk;
191	}
192
193	ret = ptrace_check_attach(child, request == PTRACE_KILL);
194	if (ret < 0)
195		goto out_tsk;
196
197	switch (request) {
198	/* when I and D space are separate, these will need to be fixed. */
199	case PTRACE_PEEKTEXT: /* read word at location addr. */
200	case PTRACE_PEEKDATA: {
201		unsigned long tmp;
202		int copied;
203
204		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
205		ret = -EIO;
206		if (copied != sizeof(tmp))
207			break;
208		ret = put_user(tmp,(unsigned long *) data);
209		break;
210	}
211
212	/* read the word at location addr in the USER area. */
213	case PTRACE_PEEKUSR: {
214		unsigned long index, tmp;
215
216		ret = -EIO;
217		/* convert to index and check */
218		index = (unsigned long) addr >> 2;
219		if ((addr & 3) || index > PT_FPSCR)
220			break;
221
222		if (index < PT_FPR0) {
223			tmp = get_reg(child, (int) index);
224		} else {
225			if (child->thread.regs != NULL
226			    && child->thread.regs->msr & MSR_FP)
227				giveup_fpu(child);
228			tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0];
229		}
230		ret = put_user(tmp,(unsigned long *) data);
231		break;
232	}
233
234	/* If I and D space are separate, this will have to be fixed. */
235	case PTRACE_POKETEXT: /* write the word at location addr. */
236	case PTRACE_POKEDATA:
237		ret = 0;
238		if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
239			break;
240		ret = -EIO;
241		break;
242
243	/* write the word at location addr in the USER area */
244	case PTRACE_POKEUSR: {
245		unsigned long index;
246
247		ret = -EIO;
248		/* convert to index and check */
249		index = (unsigned long) addr >> 2;
250		if ((addr & 3) || index > PT_FPSCR)
251			break;
252
253		if (index == PT_ORIG_R3)
254			break;
255		if (index < PT_FPR0) {
256			ret = put_reg(child, index, data);
257		} else {
258			if (child->thread.regs != NULL
259			    && child->thread.regs->msr & MSR_FP)
260				giveup_fpu(child);
261			((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data;
262			ret = 0;
263		}
264		break;
265	}
266
267	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
268	case PTRACE_CONT: { /* restart after signal. */
269		ret = -EIO;
270		if ((unsigned long) data > _NSIG)
271			break;
272		if (request == PTRACE_SYSCALL)
273			child->ptrace |= PT_TRACESYS;
274		else
275			child->ptrace &= ~PT_TRACESYS;
276		child->exit_code = data;
277		/* make sure the single step bit is not set. */
278		clear_single_step(child);
279		wake_up_process(child);
280		ret = 0;
281		break;
282	}
283
284/*
285 * make the child exit.  Best I can do is send it a sigkill.
286 * perhaps it should be put in the status that it wants to
287 * exit.
288 */
289	case PTRACE_KILL: {
290		ret = 0;
291		if (child->state == TASK_ZOMBIE)	/* already dead */
292			break;
293		child->exit_code = SIGKILL;
294		/* make sure the single step bit is not set. */
295		clear_single_step(child);
296		wake_up_process(child);
297		break;
298	}
299
300	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
301		ret = -EIO;
302		if ((unsigned long) data > _NSIG)
303			break;
304		child->ptrace &= ~PT_TRACESYS;
305		set_single_step(child);
306		child->exit_code = data;
307		/* give it a chance to run. */
308		wake_up_process(child);
309		ret = 0;
310		break;
311	}
312
313	case PTRACE_DETACH:
314		ret = ptrace_detach(child, data);
315		break;
316
317#ifdef CONFIG_ALTIVEC
318	case PTRACE_GETVRREGS:
319		/* Get the child altivec register state. */
320		if (child->thread.regs->msr & MSR_VEC)
321			giveup_altivec(child);
322		ret = get_vrregs((unsigned long *)data, child);
323		break;
324
325	case PTRACE_SETVRREGS:
326		/* Set the child altivec register state. */
327		/* this is to clear the MSR_VEC bit to force a reload
328		 * of register state from memory */
329		if (child->thread.regs->msr & MSR_VEC)
330			giveup_altivec(child);
331		ret = set_vrregs(child, (unsigned long *)data);
332		break;
333#endif
334
335	default:
336		ret = -EIO;
337		break;
338	}
339out_tsk:
340	free_task_struct(child);
341out:
342	unlock_kernel();
343	return ret;
344}
345
346void syscall_trace(void)
347{
348	if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
349			!= (PT_PTRACED|PT_TRACESYS))
350		return;
351	current->exit_code = SIGTRAP;
352	current->state = TASK_STOPPED;
353	notify_parent(current, SIGCHLD);
354	schedule();
355	/*
356	 * this isn't the same as continuing with a signal, but it will do
357	 * for normal use.  strace only continues with a signal if the
358	 * stopping signal is not SIGTRAP.  -brl
359	 */
360	if (current->exit_code) {
361		send_sig(current->exit_code, current, 1);
362		current->exit_code = 0;
363	}
364}
365