1/*
2 *  linux/arch/ppc64/kernel/ptrace32.c
3 *
4 *  PowerPC version
5 *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
6 *
7 *  Derived from "arch/m68k/kernel/ptrace.c"
8 *  Copyright (C) 1994 by Hamish Macdonald
9 *  Taken from linux/kernel/ptrace.c and modified for M680x0.
10 *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
11 *
12 * Modified by Cort Dougan (cort@hq.fsmlabs.com)
13 * and Paul Mackerras (paulus@linuxcare.com.au).
14 *
15 * This file is subject to the terms and conditions of the GNU General
16 * Public License.  See the file README.legal in the main directory of
17 * this archive for more details.
18 */
19
20#include <linux/kernel.h>
21#include <linux/sched.h>
22#include <linux/mm.h>
23#include <linux/smp.h>
24#include <linux/smp_lock.h>
25#include <linux/errno.h>
26#include <linux/ptrace.h>
27#include <linux/user.h>
28
29#include <asm/uaccess.h>
30#include <asm/page.h>
31#include <asm/pgtable.h>
32#include <asm/system.h>
33
34/*
35 * Set of msr bits that gdb can change on behalf of a process.
36 */
37#define MSR_DEBUGCHANGE	(MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1)
38
39/*
40 * does not yet catch signals sent when the child dies.
41 * in exit.c or in signal.c.
42 */
43
44/*
45 * Get contents of register REGNO in task TASK.
46 */
47static inline unsigned long get_reg(struct task_struct *task, int regno)
48{
49	if (regno < sizeof(struct pt_regs) / sizeof(unsigned long))
50		return ((unsigned long *)task->thread.regs)[regno];
51	return (0);
52}
53
54/*
55 * Write contents of register REGNO in task TASK.
56 * (Put DATA into task TASK's register REGNO.)
57 */
58static inline int put_reg(struct task_struct *task, int regno, unsigned long data)
59{
60	if (regno < PT_SOFTE)
61  {
62		if (regno == PT_MSR)
63			data = (data & MSR_DEBUGCHANGE) | (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
64		((unsigned long *)task->thread.regs)[regno] = data;
65		return 0;
66	}
67	return -EIO;
68}
69
70static inline void
71set_single_step(struct task_struct *task)
72{
73	struct pt_regs *regs = task->thread.regs;
74	if (regs != NULL)
75		regs->msr |= MSR_SE;
76}
77
78static inline void
79clear_single_step(struct task_struct *task)
80{
81	struct pt_regs *regs = task->thread.regs;
82	if (regs != NULL)
83		regs->msr &= ~MSR_SE;
84}
85
86int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data)
87{
88	struct task_struct *child;
89	int ret = -EPERM;
90
91	lock_kernel();
92	if (request == PTRACE_TRACEME) {
93		/* are we already being traced? */
94		if (current->ptrace & PT_PTRACED)
95			goto out;
96		/* set the ptrace bit in the process flags. */
97		current->ptrace |= PT_PTRACED;
98		ret = 0;
99		goto out;
100	}
101	ret = -ESRCH;
102	read_lock(&tasklist_lock);
103	child = find_task_by_pid(pid);
104	if (child)
105		get_task_struct(child);
106	read_unlock(&tasklist_lock);
107	if (!child)
108		goto out;
109
110	ret = -EPERM;
111	if (pid == 1)		/* you may not mess with init */
112		goto out_tsk;
113
114	if (request == PTRACE_ATTACH) {
115		ret = ptrace_attach(child);
116		goto out_tsk;
117	}
118
119	ret = ptrace_check_attach(child, request == PTRACE_KILL);
120	if (ret < 0)
121		goto out_tsk;
122
123	switch (request) {
124	/* Read word at location ADDR */
125	/* when I and D space are separate, these will need to be fixed. */
126	case PTRACE_PEEKTEXT: /* read word at location addr. */
127	case PTRACE_PEEKDATA:
128	{
129		unsigned int  tmp_mem_value;
130		int copied;
131
132		copied = access_process_vm(child, addr, &tmp_mem_value, sizeof(tmp_mem_value), 0);
133		ret = -EIO;
134		if (copied != sizeof(tmp_mem_value))
135			break;
136		ret = put_user(tmp_mem_value, (u32*)data);  // copy 4 bytes of data into the user location specified by the 8 byte pointer in "data".
137		break;
138	}
139
140	/*
141	 * Read 4 bytes of the other process' storage
142	 *  data is a pointer specifying where the user wants the
143	 *	4 bytes copied into
144	 *  addr is a pointer in the user's storage that contains an 8 byte
145	 *	address in the other process of the 4 bytes that is to be read
146	 * (this is run in a 32-bit process looking at a 64-bit process)
147	 * when I and D space are separate, these will need to be fixed.
148	 */
149	case PPC_PTRACE_PEEKTEXT_3264:
150	case PPC_PTRACE_PEEKDATA_3264:
151	{
152		u32  tmp_mem_value;
153		int  copied;
154		u32* addrOthers;
155
156		ret = -EIO;
157
158		/* Get the addr in the other process that we want to read */
159		if (get_user(addrOthers, (u32**)addr) != 0)
160			break;
161
162		copied = access_process_vm(child, (u64)addrOthers, &tmp_mem_value, sizeof(tmp_mem_value), 0);
163		if (copied != sizeof(tmp_mem_value))
164			break;
165		ret = put_user(tmp_mem_value, (u32*)data);  // copy 4 bytes of data into the user location specified by the 8 byte pointer in "data".
166		break;
167	}
168
169	/* Read a register (specified by ADDR) out of the "user area" */
170	case PTRACE_PEEKUSR: {
171		int index;
172		unsigned int reg32bits;
173		unsigned long tmp_reg_value;
174
175		ret = -EIO;
176		/* convert to index and check */
177		index = (unsigned long) addr >> 2;
178		if ((addr & 3) || (index > PT_FPSCR32))
179			break;
180
181		if (index < PT_FPR0) {
182			tmp_reg_value = get_reg(child,  index);
183		} else {
184			if (child->thread.regs->msr & MSR_FP)
185				giveup_fpu(child);
186			/*
187			 * the user space code considers the floating point
188			 * to be an array of unsigned int (32 bits) - the
189			 * index passed in is based on this assumption.
190			 */
191			tmp_reg_value = ((unsigned int *)child->thread.fpr)[index - PT_FPR0];
192		}
193		reg32bits = tmp_reg_value;
194		ret = put_user(reg32bits, (u32*)data);  // copy 4 bytes of data into the user location specified by the 8 byte pointer in "data".
195		break;
196	}
197
198	/*
199	 * Read 4 bytes out of the other process' pt_regs area
200	 *  data is a pointer specifying where the user wants the
201	 *	4 bytes copied into
202	 *  addr is the offset into the other process' pt_regs structure
203	 *	that is to be read
204	 * (this is run in a 32-bit process looking at a 64-bit process)
205	 */
206	case PPC_PTRACE_PEEKUSR_3264: {
207		u32 index;
208		u32 reg32bits;
209		u64 tmp_reg_value;
210		u32 numReg;
211		u32 part;
212
213		ret = -EIO;
214		/* Determine which register the user wants */
215		index = (u64)addr >> 2;  /* Divide addr by 4 */
216		numReg = index / 2;
217		/* Determine which part of the register the user wants */
218		if (index % 2)
219			part = 1;  /* want the 2nd half of the register (right-most). */
220		else
221			part = 0;  /* want the 1st half of the register (left-most). */
222
223		/* Validate the input - check to see if address is on the wrong boundary or beyond the end of the user area */
224		if ((addr & 3) || numReg > PT_FPSCR)
225			break;
226
227		if (numReg >= PT_FPR0) {
228			if (child->thread.regs->msr & MSR_FP)
229				giveup_fpu(child);
230		        if (numReg == PT_FPSCR)
231			        tmp_reg_value = ((unsigned int *)child->thread.fpscr);
232		        else
233			        tmp_reg_value = ((unsigned long int *)child->thread.fpr)[numReg - PT_FPR0];
234		} else { /* register within PT_REGS struct */
235		    tmp_reg_value = get_reg(child, numReg);
236		}
237                reg32bits = ((u32*)&tmp_reg_value)[part];
238		ret = put_user(reg32bits, (u32*)data);  /* copy 4 bytes of data into the user location specified by the 8 byte pointer in "data". */
239		break;
240	}
241
242	/* Write the word at location ADDR */
243	/* If I and D space are separate, this will have to be fixed. */
244	case PTRACE_POKETEXT: /* write the word at location addr. */
245	case PTRACE_POKEDATA: {
246		unsigned int tmp_value_to_write;
247		tmp_value_to_write =  data;
248		ret = 0;
249		if (access_process_vm(child, addr, &tmp_value_to_write, sizeof(tmp_value_to_write), 1) == sizeof(tmp_value_to_write))
250			break;
251		ret = -EIO;
252		break;
253	}
254
255	/*
256	 * Write 4 bytes into the other process' storage
257	 *  data is the 4 bytes that the user wants written
258	 *  addr is a pointer in the user's storage that contains an
259	 *	8 byte address in the other process where the 4 bytes
260	 *	that is to be written
261	 * (this is run in a 32-bit process looking at a 64-bit process)
262	 * when I and D space are separate, these will need to be fixed.
263	 */
264	case PPC_PTRACE_POKETEXT_3264:
265	case PPC_PTRACE_POKEDATA_3264:
266	{
267		u32  tmp_value_to_write = data;
268		u32* addrOthers;
269		int  bytesWritten;
270
271		/* Get the addr in the other process that we want to write into */
272		ret = -EIO;
273		if (get_user(addrOthers,(u32**)addr) != 0)
274			break;
275		ret = 0;
276		bytesWritten = access_process_vm(child, (u64)addrOthers, &tmp_value_to_write, sizeof(tmp_value_to_write), 1);
277		if (bytesWritten == sizeof(tmp_value_to_write))
278			break;
279		ret = -EIO;
280		break;
281	}
282
283	/* Write DATA into location ADDR within the USER area  */
284	case PTRACE_POKEUSR: {
285		unsigned long index;
286
287		ret = -EIO;
288		/* convert to index and check */
289		index = (unsigned long) addr >> 2;
290		if ((addr & 3) || (index > PT_FPSCR32))
291			break;
292
293		if (index == PT_ORIG_R3)
294			break;
295		if (index < PT_FPR0) {
296			ret = put_reg(child, index, data);
297		} else {
298			if (child->thread.regs->msr & MSR_FP)
299				giveup_fpu(child);
300			/*
301			 * the user space code considers the floating point
302			 * to be an array of unsigned int (32 bits) - the
303			 * index passed in is based on this assumption.
304			 */
305			((unsigned int *)child->thread.fpr)[index - PT_FPR0] = data;
306			ret = 0;
307		}
308		break;
309	}
310
311	/*
312	 * Write 4 bytes into the other process' pt_regs area
313	 *  data is the 4 bytes that the user wants written
314	 *  addr is the offset into the other process' pt_regs structure
315	 *	that is to be written into
316	 * (this is run in a 32-bit process looking at a 64-bit process)
317	 */
318	case PPC_PTRACE_POKEUSR_3264: {
319		u32 index;
320		u32 numReg;
321
322		ret = -EIO;
323		/* Determine which register the user wants */
324		index = (u64)addr >> 2;  /* Divide addr by 4 */
325		numReg = index / 2;
326		/*
327		 * Validate the input - check to see if address is on the
328		 * wrong boundary or beyond the end of the user area
329		 */
330		if ((addr & 3) || (numReg > PT_FPSCR))
331			break;
332		/* Insure it is a register we let them change */
333		if ((numReg == PT_ORIG_R3)
334				|| ((numReg > PT_CCR) && (numReg < PT_FPR0)))
335			break;
336		if (numReg >= PT_FPR0) {
337			if (child->thread.regs->msr & MSR_FP)
338				giveup_fpu(child);
339		}
340		if (numReg == PT_MSR)
341			data = (data & MSR_DEBUGCHANGE)
342				| (child->thread.regs->msr & ~MSR_DEBUGCHANGE);
343		((u32*)child->thread.regs)[index] = data;
344		ret = 0;
345		break;
346	}
347
348	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
349	case PTRACE_CONT: { /* restart after signal. */
350		ret = -EIO;
351		if ((unsigned long) data > _NSIG)
352			break;
353		if (request == PTRACE_SYSCALL)
354			child->ptrace |= PT_TRACESYS;
355		else
356			child->ptrace &= ~PT_TRACESYS;
357		child->exit_code = data;
358		/* make sure the single step bit is not set. */
359		clear_single_step(child);
360		wake_up_process(child);
361		ret = 0;
362		break;
363	}
364
365	/*
366	 * make the child exit.  Best I can do is send it a sigkill.
367	 * perhaps it should be put in the status that it wants to
368	 * exit.
369	 */
370	case PTRACE_KILL: {
371		ret = 0;
372		if (child->state == TASK_ZOMBIE)	/* already dead */
373			break;
374		child->exit_code = SIGKILL;
375		/* make sure the single step bit is not set. */
376		clear_single_step(child);
377		wake_up_process(child);
378		break;
379	}
380
381	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
382		ret = -EIO;
383		if ((unsigned long) data > _NSIG)
384			break;
385		child->ptrace &= ~PT_TRACESYS;
386		set_single_step(child);
387		child->exit_code = data;
388		/* give it a chance to run. */
389		wake_up_process(child);
390		ret = 0;
391		break;
392	}
393
394	case PTRACE_DETACH:
395		ret = ptrace_detach(child, data);
396		break;
397
398	default:
399		ret = -EIO;
400		break;
401	}
402out_tsk:
403	free_task_struct(child);
404out:
405	unlock_kernel();
406	return ret;
407}
408