Linux Audio

Check our new training course

Loading...
  1/*
  2 * ptrace for 32-bit processes running on a 64-bit kernel.
  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@samba.org).
 14 *
 15 * This file is subject to the terms and conditions of the GNU General
 16 * Public License.  See the file COPYING 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/errno.h>
 25#include <linux/ptrace.h>
 26#include <linux/regset.h>
 27#include <linux/user.h>
 28#include <linux/security.h>
 29#include <linux/signal.h>
 30#include <linux/compat.h>
 31
 32#include <asm/uaccess.h>
 33#include <asm/page.h>
 34#include <asm/pgtable.h>
 35#include <asm/switch_to.h>
 36
 37/*
 38 * does not yet catch signals sent when the child dies.
 39 * in exit.c or in signal.c.
 40 */
 41
 42/* Macros to workout the correct index for the FPR in the thread struct */
 43#define FPRNUMBER(i) (((i) - PT_FPR0) >> 1)
 44#define FPRHALF(i) (((i) - PT_FPR0) & 1)
 45#define FPRINDEX(i) TS_FPRWIDTH * FPRNUMBER(i) * 2 + FPRHALF(i)
 46
 47long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
 48			compat_ulong_t caddr, compat_ulong_t cdata)
 49{
 50	unsigned long addr = caddr;
 51	unsigned long data = cdata;
 52	int ret;
 53
 54	switch (request) {
 55	/*
 56	 * Read 4 bytes of the other process' storage
 57	 *  data is a pointer specifying where the user wants the
 58	 *	4 bytes copied into
 59	 *  addr is a pointer in the user's storage that contains an 8 byte
 60	 *	address in the other process of the 4 bytes that is to be read
 61	 * (this is run in a 32-bit process looking at a 64-bit process)
 62	 * when I and D space are separate, these will need to be fixed.
 63	 */
 64	case PPC_PTRACE_PEEKTEXT_3264:
 65	case PPC_PTRACE_PEEKDATA_3264: {
 66		u32 tmp;
 67		int copied;
 68		u32 __user * addrOthers;
 69
 70		ret = -EIO;
 71
 72		/* Get the addr in the other process that we want to read */
 73		if (get_user(addrOthers, (u32 __user * __user *)addr) != 0)
 74			break;
 75
 76		copied = access_process_vm(child, (u64)addrOthers, &tmp,
 77				sizeof(tmp), 0);
 78		if (copied != sizeof(tmp))
 79			break;
 80		ret = put_user(tmp, (u32 __user *)data);
 81		break;
 82	}
 83
 84	/* Read a register (specified by ADDR) out of the "user area" */
 85	case PTRACE_PEEKUSR: {
 86		int index;
 87		unsigned long tmp;
 88
 89		ret = -EIO;
 90		/* convert to index and check */
 91		index = (unsigned long) addr >> 2;
 92		if ((addr & 3) || (index > PT_FPSCR32))
 93			break;
 94
 95		CHECK_FULL_REGS(child->thread.regs);
 96		if (index < PT_FPR0) {
 97			ret = ptrace_get_reg(child, index, &tmp);
 98			if (ret)
 99				break;
100		} else {
101			flush_fp_to_thread(child);
102			/*
103			 * the user space code considers the floating point
104			 * to be an array of unsigned int (32 bits) - the
105			 * index passed in is based on this assumption.
106			 */
107			tmp = ((unsigned int *)child->thread.fp_state.fpr)
108				[FPRINDEX(index)];
109		}
110		ret = put_user((unsigned int)tmp, (u32 __user *)data);
111		break;
112	}
113  
114	/*
115	 * Read 4 bytes out of the other process' pt_regs area
116	 *  data is a pointer specifying where the user wants the
117	 *	4 bytes copied into
118	 *  addr is the offset into the other process' pt_regs structure
119	 *	that is to be read
120	 * (this is run in a 32-bit process looking at a 64-bit process)
121	 */
122	case PPC_PTRACE_PEEKUSR_3264: {
123		u32 index;
124		u32 reg32bits;
125		u64 tmp;
126		u32 numReg;
127		u32 part;
128
129		ret = -EIO;
130		/* Determine which register the user wants */
131		index = (u64)addr >> 2;
132		numReg = index / 2;
133		/* Determine which part of the register the user wants */
134		if (index % 2)
135			part = 1;  /* want the 2nd half of the register (right-most). */
136		else
137			part = 0;  /* want the 1st half of the register (left-most). */
138
139		/* Validate the input - check to see if address is on the wrong boundary
140		 * or beyond the end of the user area
141		 */
142		if ((addr & 3) || numReg > PT_FPSCR)
143			break;
144
145		CHECK_FULL_REGS(child->thread.regs);
146		if (numReg >= PT_FPR0) {
147			flush_fp_to_thread(child);
148			/* get 64 bit FPR */
149			tmp = child->thread.fp_state.fpr[numReg - PT_FPR0][0];
150		} else { /* register within PT_REGS struct */
151			unsigned long tmp2;
152			ret = ptrace_get_reg(child, numReg, &tmp2);
153			if (ret)
154				break;
155			tmp = tmp2;
156		} 
157		reg32bits = ((u32*)&tmp)[part];
158		ret = put_user(reg32bits, (u32 __user *)data);
159		break;
160	}
161
162	/*
163	 * Write 4 bytes into the other process' storage
164	 *  data is the 4 bytes that the user wants written
165	 *  addr is a pointer in the user's storage that contains an
166	 *	8 byte address in the other process where the 4 bytes
167	 *	that is to be written
168	 * (this is run in a 32-bit process looking at a 64-bit process)
169	 * when I and D space are separate, these will need to be fixed.
170	 */
171	case PPC_PTRACE_POKETEXT_3264:
172	case PPC_PTRACE_POKEDATA_3264: {
173		u32 tmp = data;
174		u32 __user * addrOthers;
175
176		/* Get the addr in the other process that we want to write into */
177		ret = -EIO;
178		if (get_user(addrOthers, (u32 __user * __user *)addr) != 0)
179			break;
180		ret = 0;
181		if (access_process_vm(child, (u64)addrOthers, &tmp,
182					sizeof(tmp), 1) == sizeof(tmp))
183			break;
184		ret = -EIO;
185		break;
186	}
187
188	/* write the word at location addr in the USER area */
189	case PTRACE_POKEUSR: {
190		unsigned long index;
191
192		ret = -EIO;
193		/* convert to index and check */
194		index = (unsigned long) addr >> 2;
195		if ((addr & 3) || (index > PT_FPSCR32))
196			break;
197
198		CHECK_FULL_REGS(child->thread.regs);
199		if (index < PT_FPR0) {
200			ret = ptrace_put_reg(child, index, data);
201		} else {
202			flush_fp_to_thread(child);
203			/*
204			 * the user space code considers the floating point
205			 * to be an array of unsigned int (32 bits) - the
206			 * index passed in is based on this assumption.
207			 */
208			((unsigned int *)child->thread.fp_state.fpr)
209				[FPRINDEX(index)] = data;
210			ret = 0;
211		}
212		break;
213	}
214
215	/*
216	 * Write 4 bytes into the other process' pt_regs area
217	 *  data is the 4 bytes that the user wants written
218	 *  addr is the offset into the other process' pt_regs structure
219	 *	that is to be written into
220	 * (this is run in a 32-bit process looking at a 64-bit process)
221	 */
222	case PPC_PTRACE_POKEUSR_3264: {
223		u32 index;
224		u32 numReg;
225
226		ret = -EIO;
227		/* Determine which register the user wants */
228		index = (u64)addr >> 2;
229		numReg = index / 2;
230
231		/*
232		 * Validate the input - check to see if address is on the
233		 * wrong boundary or beyond the end of the user area
234		 */
235		if ((addr & 3) || (numReg > PT_FPSCR))
236			break;
237		CHECK_FULL_REGS(child->thread.regs);
238		if (numReg < PT_FPR0) {
239			unsigned long freg;
240			ret = ptrace_get_reg(child, numReg, &freg);
241			if (ret)
242				break;
243			if (index % 2)
244				freg = (freg & ~0xfffffffful) | (data & 0xfffffffful);
245			else
246				freg = (freg & 0xfffffffful) | (data << 32);
247			ret = ptrace_put_reg(child, numReg, freg);
248		} else {
249			u64 *tmp;
250			flush_fp_to_thread(child);
251			/* get 64 bit FPR ... */
252			tmp = &child->thread.fp_state.fpr[numReg - PT_FPR0][0];
253			/* ... write the 32 bit part we want */
254			((u32 *)tmp)[index % 2] = data;
255			ret = 0;
256		}
257		break;
258	}
259
260	case PTRACE_GET_DEBUGREG: {
261#ifndef CONFIG_PPC_ADV_DEBUG_REGS
262		unsigned long dabr_fake;
263#endif
264		ret = -EINVAL;
265		/* We only support one DABR and no IABRS at the moment */
266		if (addr > 0)
267			break;
268#ifdef CONFIG_PPC_ADV_DEBUG_REGS
269		ret = put_user(child->thread.debug.dac1, (u32 __user *)data);
270#else
271		dabr_fake = (
272			(child->thread.hw_brk.address & (~HW_BRK_TYPE_DABR)) |
273			(child->thread.hw_brk.type & HW_BRK_TYPE_DABR));
274		ret = put_user(dabr_fake, (u32 __user *)data);
275#endif
276		break;
277	}
278
279	case PTRACE_GETREGS:	/* Get all pt_regs from the child. */
280		return copy_regset_to_user(
281			child, task_user_regset_view(current), 0,
282			0, PT_REGS_COUNT * sizeof(compat_long_t),
283			compat_ptr(data));
284
285	case PTRACE_SETREGS:	/* Set all gp regs in the child. */
286		return copy_regset_from_user(
287			child, task_user_regset_view(current), 0,
288			0, PT_REGS_COUNT * sizeof(compat_long_t),
289			compat_ptr(data));
290
291	case PTRACE_GETFPREGS:
292	case PTRACE_SETFPREGS:
293	case PTRACE_GETVRREGS:
294	case PTRACE_SETVRREGS:
295	case PTRACE_GETVSRREGS:
296	case PTRACE_SETVSRREGS:
297	case PTRACE_GETREGS64:
298	case PTRACE_SETREGS64:
299	case PTRACE_KILL:
300	case PTRACE_SINGLESTEP:
301	case PTRACE_DETACH:
302	case PTRACE_SET_DEBUGREG:
303	case PTRACE_SYSCALL:
304	case PTRACE_CONT:
305	case PPC_PTRACE_GETHWDBGINFO:
306	case PPC_PTRACE_SETHWDEBUG:
307	case PPC_PTRACE_DELHWDEBUG:
308		ret = arch_ptrace(child, request, addr, data);
309		break;
310
311	default:
312		ret = compat_ptrace_request(child, request, addr, data);
313		break;
314	}
315
316	return ret;
317}