PageRenderTime 34ms CodeModel.GetById 14ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 0ms

/arch/ppc64/kernel/ptrace32.c

https://bitbucket.org/evzijst/gittest
C | 420 lines | 283 code | 45 blank | 92 comment | 63 complexity | 5c3de20cfcb24df1d31384203080aa2c MD5 | raw file
  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#include <linux/security.h>
 29
 30#include <asm/uaccess.h>
 31#include <asm/page.h>
 32#include <asm/pgtable.h>
 33#include <asm/system.h>
 34#include <asm/ptrace-common.h>
 35
 36/*
 37 * does not yet catch signals sent when the child dies.
 38 * in exit.c or in signal.c.
 39 */
 40
 41int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data)
 42{
 43	struct task_struct *child;
 44	int ret = -EPERM;
 45
 46	lock_kernel();
 47	if (request == PTRACE_TRACEME) {
 48		/* are we already being traced? */
 49		if (current->ptrace & PT_PTRACED)
 50			goto out;
 51		ret = security_ptrace(current->parent, current);
 52		if (ret)
 53			goto out;
 54		/* set the ptrace bit in the process flags. */
 55		current->ptrace |= PT_PTRACED;
 56		ret = 0;
 57		goto out;
 58	}
 59	ret = -ESRCH;
 60	read_lock(&tasklist_lock);
 61	child = find_task_by_pid(pid);
 62	if (child)
 63		get_task_struct(child);
 64	read_unlock(&tasklist_lock);
 65	if (!child)
 66		goto out;
 67
 68	ret = -EPERM;
 69	if (pid == 1)		/* you may not mess with init */
 70		goto out_tsk;
 71
 72	if (request == PTRACE_ATTACH) {
 73		ret = ptrace_attach(child);
 74		goto out_tsk;
 75	}
 76
 77	ret = ptrace_check_attach(child, request == PTRACE_KILL);
 78	if (ret < 0)
 79		goto out_tsk;
 80
 81	switch (request) {
 82	/* when I and D space are separate, these will need to be fixed. */
 83	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
 84	case PTRACE_PEEKDATA: {
 85		unsigned int tmp;
 86		int copied;
 87
 88		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
 89		ret = -EIO;
 90		if (copied != sizeof(tmp))
 91			break;
 92		ret = put_user(tmp, (u32 __user *)data);
 93		break;
 94	}
 95
 96	/*
 97	 * Read 4 bytes of the other process' storage
 98	 *  data is a pointer specifying where the user wants the
 99	 *	4 bytes copied into
100	 *  addr is a pointer in the user's storage that contains an 8 byte
101	 *	address in the other process of the 4 bytes that is to be read
102	 * (this is run in a 32-bit process looking at a 64-bit process)
103	 * when I and D space are separate, these will need to be fixed.
104	 */
105	case PPC_PTRACE_PEEKTEXT_3264:
106	case PPC_PTRACE_PEEKDATA_3264: {
107		u32 tmp;
108		int copied;
109		u32 __user * addrOthers;
110
111		ret = -EIO;
112
113		/* Get the addr in the other process that we want to read */
114		if (get_user(addrOthers, (u32 __user * __user *)addr) != 0)
115			break;
116
117		copied = access_process_vm(child, (u64)addrOthers, &tmp,
118				sizeof(tmp), 0);
119		if (copied != sizeof(tmp))
120			break;
121		ret = put_user(tmp, (u32 __user *)data);
122		break;
123	}
124
125	/* Read a register (specified by ADDR) out of the "user area" */
126	case PTRACE_PEEKUSR: {
127		int index;
128		unsigned long tmp;
129
130		ret = -EIO;
131		/* convert to index and check */
132		index = (unsigned long) addr >> 2;
133		if ((addr & 3) || (index > PT_FPSCR32))
134			break;
135
136		if (index < PT_FPR0) {
137			tmp = get_reg(child, index);
138		} else {
139			flush_fp_to_thread(child);
140			/*
141			 * the user space code considers the floating point
142			 * to be an array of unsigned int (32 bits) - the
143			 * index passed in is based on this assumption.
144			 */
145			tmp = ((unsigned int *)child->thread.fpr)[index - PT_FPR0];
146		}
147		ret = put_user((unsigned int)tmp, (u32 __user *)data);
148		break;
149	}
150  
151	/*
152	 * Read 4 bytes out of the other process' pt_regs area
153	 *  data is a pointer specifying where the user wants the
154	 *	4 bytes copied into
155	 *  addr is the offset into the other process' pt_regs structure
156	 *	that is to be read
157	 * (this is run in a 32-bit process looking at a 64-bit process)
158	 */
159	case PPC_PTRACE_PEEKUSR_3264: {
160		u32 index;
161		u32 reg32bits;
162		u64 tmp;
163		u32 numReg;
164		u32 part;
165
166		ret = -EIO;
167		/* Determine which register the user wants */
168		index = (u64)addr >> 2;
169		numReg = index / 2;
170		/* Determine which part of the register the user wants */
171		if (index % 2)
172			part = 1;  /* want the 2nd half of the register (right-most). */
173		else
174			part = 0;  /* want the 1st half of the register (left-most). */
175
176		/* Validate the input - check to see if address is on the wrong boundary or beyond the end of the user area */
177		if ((addr & 3) || numReg > PT_FPSCR)
178			break;
179
180		if (numReg >= PT_FPR0) {
181			flush_fp_to_thread(child);
182			tmp = ((unsigned long int *)child->thread.fpr)[numReg - PT_FPR0];
183		} else { /* register within PT_REGS struct */
184			tmp = get_reg(child, numReg);
185		} 
186		reg32bits = ((u32*)&tmp)[part];
187		ret = put_user(reg32bits, (u32 __user *)data);
188		break;
189	}
190
191	/* If I and D space are separate, this will have to be fixed. */
192	case PTRACE_POKETEXT: /* write the word at location addr. */
193	case PTRACE_POKEDATA: {
194		unsigned int tmp;
195		tmp = data;
196		ret = 0;
197		if (access_process_vm(child, addr, &tmp, sizeof(tmp), 1)
198				== sizeof(tmp))
199			break;
200		ret = -EIO;
201		break;
202	}
203
204	/*
205	 * Write 4 bytes into the other process' storage
206	 *  data is the 4 bytes that the user wants written
207	 *  addr is a pointer in the user's storage that contains an
208	 *	8 byte address in the other process where the 4 bytes
209	 *	that is to be written
210	 * (this is run in a 32-bit process looking at a 64-bit process)
211	 * when I and D space are separate, these will need to be fixed.
212	 */
213	case PPC_PTRACE_POKETEXT_3264:
214	case PPC_PTRACE_POKEDATA_3264: {
215		u32 tmp = data;
216		u32 __user * addrOthers;
217
218		/* Get the addr in the other process that we want to write into */
219		ret = -EIO;
220		if (get_user(addrOthers, (u32 __user * __user *)addr) != 0)
221			break;
222		ret = 0;
223		if (access_process_vm(child, (u64)addrOthers, &tmp,
224					sizeof(tmp), 1) == sizeof(tmp))
225			break;
226		ret = -EIO;
227		break;
228	}
229
230	/* write the word at location addr in the USER area */
231	case PTRACE_POKEUSR: {
232		unsigned long index;
233
234		ret = -EIO;
235		/* convert to index and check */
236		index = (unsigned long) addr >> 2;
237		if ((addr & 3) || (index > PT_FPSCR32))
238			break;
239
240		if (index == PT_ORIG_R3)
241			break;
242		if (index < PT_FPR0) {
243			ret = put_reg(child, index, data);
244		} else {
245			flush_fp_to_thread(child);
246			/*
247			 * the user space code considers the floating point
248			 * to be an array of unsigned int (32 bits) - the
249			 * index passed in is based on this assumption.
250			 */
251			((unsigned int *)child->thread.fpr)[index - PT_FPR0] = data;
252			ret = 0;
253		}
254		break;
255	}
256
257	/*
258	 * Write 4 bytes into the other process' pt_regs area
259	 *  data is the 4 bytes that the user wants written
260	 *  addr is the offset into the other process' pt_regs structure
261	 *	that is to be written into
262	 * (this is run in a 32-bit process looking at a 64-bit process)
263	 */
264	case PPC_PTRACE_POKEUSR_3264: {
265		u32 index;
266		u32 numReg;
267
268		ret = -EIO;
269		/* Determine which register the user wants */
270		index = (u64)addr >> 2;
271		numReg = index / 2;
272		/*
273		 * Validate the input - check to see if address is on the
274		 * wrong boundary or beyond the end of the user area
275		 */
276		if ((addr & 3) || (numReg > PT_FPSCR))
277			break;
278		/* Insure it is a register we let them change */
279		if ((numReg == PT_ORIG_R3)
280				|| ((numReg > PT_CCR) && (numReg < PT_FPR0)))
281			break;
282		if (numReg >= PT_FPR0) {
283			flush_fp_to_thread(child);
284		}
285		if (numReg == PT_MSR)
286			data = (data & MSR_DEBUGCHANGE)
287				| (child->thread.regs->msr & ~MSR_DEBUGCHANGE);
288		((u32*)child->thread.regs)[index] = data;
289		ret = 0;
290		break;
291	}
292
293	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
294	case PTRACE_CONT: { /* restart after signal. */
295		ret = -EIO;
296		if ((unsigned long) data > _NSIG)
297			break;
298		if (request == PTRACE_SYSCALL)
299			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
300		else
301			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
302		child->exit_code = data;
303		/* make sure the single step bit is not set. */
304		clear_single_step(child);
305		wake_up_process(child);
306		ret = 0;
307		break;
308	}
309
310	/*
311	 * make the child exit.  Best I can do is send it a sigkill.
312	 * perhaps it should be put in the status that it wants to
313	 * exit.
314	 */
315	case PTRACE_KILL: {
316		ret = 0;
317		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
318			break;
319		child->exit_code = SIGKILL;
320		/* make sure the single step bit is not set. */
321		clear_single_step(child);
322		wake_up_process(child);
323		break;
324	}
325
326	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
327		ret = -EIO;
328		if ((unsigned long) data > _NSIG)
329			break;
330		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
331		set_single_step(child);
332		child->exit_code = data;
333		/* give it a chance to run. */
334		wake_up_process(child);
335		ret = 0;
336		break;
337	}
338
339	case PTRACE_DETACH:
340		ret = ptrace_detach(child, data);
341		break;
342
343	case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
344		int i;
345		unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
346		unsigned int __user *tmp = (unsigned int __user *)addr;
347
348		for (i = 0; i < 32; i++) {
349			ret = put_user(*reg, tmp);
350			if (ret)
351				break;
352			reg++;
353			tmp++;
354		}
355		break;
356	}
357
358	case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
359		int i;
360		unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
361		unsigned int __user *tmp = (unsigned int __user *)addr;
362
363		for (i = 0; i < 32; i++) {
364			ret = get_user(*reg, tmp);
365			if (ret)
366				break;
367			reg++;
368			tmp++;
369		}
370		break;
371	}
372
373	case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
374		int i;
375		unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
376		unsigned int __user *tmp = (unsigned int __user *)addr;
377
378		flush_fp_to_thread(child);
379
380		for (i = 0; i < 32; i++) {
381			ret = put_user(*reg, tmp);
382			if (ret)
383				break;
384			reg++;
385			tmp++;
386		}
387		break;
388	}
389
390	case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
391		int i;
392		unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
393		unsigned int __user *tmp = (unsigned int __user *)addr;
394
395		flush_fp_to_thread(child);
396
397		for (i = 0; i < 32; i++) {
398			ret = get_user(*reg, tmp);
399			if (ret)
400				break;
401			reg++;
402			tmp++;
403		}
404		break;
405	}
406
407       case PTRACE_GETEVENTMSG:
408                ret = put_user(child->ptrace_message, (unsigned int __user *) data);
409                break;
410
411	default:
412		ret = ptrace_request(child, request, addr, data);
413		break;
414	}
415out_tsk:
416	put_task_struct(child);
417out:
418	unlock_kernel();
419	return ret;
420}