• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* MN10300 Process tracing
2  *
3  * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
4  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5  * Modified by David Howells (dhowells@redhat.com)
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public Licence
9  * as published by the Free Software Foundation; either version
10  * 2 of the Licence, or (at your option) any later version.
11  */
12 #include <linux/kernel.h>
13 #include <linux/sched.h>
14 #include <linux/mm.h>
15 #include <linux/smp.h>
16 #include <linux/errno.h>
17 #include <linux/ptrace.h>
18 #include <linux/user.h>
19 #include <linux/regset.h>
20 #include <linux/elf.h>
21 #include <linux/tracehook.h>
22 #include <asm/uaccess.h>
23 #include <asm/pgtable.h>
24 #include <asm/processor.h>
25 #include <asm/cacheflush.h>
26 #include <asm/fpu.h>
27 #include <asm/asm-offsets.h>
28 
29 /*
30  * translate ptrace register IDs into struct pt_regs offsets
31  */
32 static const u8 ptrace_regid_to_frame[] = {
33 	[PT_A3 << 2]		= REG_A3,
34 	[PT_A2 << 2]		= REG_A2,
35 	[PT_D3 << 2]		= REG_D3,
36 	[PT_D2 << 2]		= REG_D2,
37 	[PT_MCVF << 2]		= REG_MCVF,
38 	[PT_MCRL << 2]		= REG_MCRL,
39 	[PT_MCRH << 2]		= REG_MCRH,
40 	[PT_MDRQ << 2]		= REG_MDRQ,
41 	[PT_E1 << 2]		= REG_E1,
42 	[PT_E0 << 2]		= REG_E0,
43 	[PT_E7 << 2]		= REG_E7,
44 	[PT_E6 << 2]		= REG_E6,
45 	[PT_E5 << 2]		= REG_E5,
46 	[PT_E4 << 2]		= REG_E4,
47 	[PT_E3 << 2]		= REG_E3,
48 	[PT_E2 << 2]		= REG_E2,
49 	[PT_SP << 2]		= REG_SP,
50 	[PT_LAR << 2]		= REG_LAR,
51 	[PT_LIR << 2]		= REG_LIR,
52 	[PT_MDR << 2]		= REG_MDR,
53 	[PT_A1 << 2]		= REG_A1,
54 	[PT_A0 << 2]		= REG_A0,
55 	[PT_D1 << 2]		= REG_D1,
56 	[PT_D0 << 2]		= REG_D0,
57 	[PT_ORIG_D0 << 2]	= REG_ORIG_D0,
58 	[PT_EPSW << 2]		= REG_EPSW,
59 	[PT_PC << 2]		= REG_PC,
60 };
61 
get_stack_long(struct task_struct * task,int offset)62 static inline int get_stack_long(struct task_struct *task, int offset)
63 {
64 	return *(unsigned long *)
65 		((unsigned long) task->thread.uregs + offset);
66 }
67 
68 static inline
put_stack_long(struct task_struct * task,int offset,unsigned long data)69 int put_stack_long(struct task_struct *task, int offset, unsigned long data)
70 {
71 	unsigned long stack;
72 
73 	stack = (unsigned long) task->thread.uregs + offset;
74 	*(unsigned long *) stack = data;
75 	return 0;
76 }
77 
78 /*
79  * retrieve the contents of MN10300 userspace general registers
80  */
genregs_get(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,void * kbuf,void __user * ubuf)81 static int genregs_get(struct task_struct *target,
82 		       const struct user_regset *regset,
83 		       unsigned int pos, unsigned int count,
84 		       void *kbuf, void __user *ubuf)
85 {
86 	const struct pt_regs *regs = task_pt_regs(target);
87 	int ret;
88 
89 	/* we need to skip regs->next */
90 	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
91 				  regs, 0, PT_ORIG_D0 * sizeof(long));
92 	if (ret < 0)
93 		return ret;
94 
95 	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
96 				  &regs->orig_d0, PT_ORIG_D0 * sizeof(long),
97 				  NR_PTREGS * sizeof(long));
98 	if (ret < 0)
99 		return ret;
100 
101 	return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
102 					NR_PTREGS * sizeof(long), -1);
103 }
104 
105 /*
106  * update the contents of the MN10300 userspace general registers
107  */
genregs_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)108 static int genregs_set(struct task_struct *target,
109 		       const struct user_regset *regset,
110 		       unsigned int pos, unsigned int count,
111 		       const void *kbuf, const void __user *ubuf)
112 {
113 	struct pt_regs *regs = task_pt_regs(target);
114 	unsigned long tmp;
115 	int ret;
116 
117 	/* we need to skip regs->next */
118 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
119 				 regs, 0, PT_ORIG_D0 * sizeof(long));
120 	if (ret < 0)
121 		return ret;
122 
123 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
124 				 &regs->orig_d0, PT_ORIG_D0 * sizeof(long),
125 				 PT_EPSW * sizeof(long));
126 	if (ret < 0)
127 		return ret;
128 
129 	/* we need to mask off changes to EPSW */
130 	tmp = regs->epsw;
131 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
132 				 &tmp, PT_EPSW * sizeof(long),
133 				 PT_PC * sizeof(long));
134 	tmp &= EPSW_FLAG_V | EPSW_FLAG_C | EPSW_FLAG_N | EPSW_FLAG_Z;
135 	tmp |= regs->epsw & ~(EPSW_FLAG_V | EPSW_FLAG_C | EPSW_FLAG_N |
136 			      EPSW_FLAG_Z);
137 	regs->epsw = tmp;
138 
139 	if (ret < 0)
140 		return ret;
141 
142 	/* and finally load the PC */
143 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
144 				 &regs->pc, PT_PC * sizeof(long),
145 				 NR_PTREGS * sizeof(long));
146 
147 	if (ret < 0)
148 		return ret;
149 
150 	return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
151 					 NR_PTREGS * sizeof(long), -1);
152 }
153 
154 /*
155  * retrieve the contents of MN10300 userspace FPU registers
156  */
fpuregs_get(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,void * kbuf,void __user * ubuf)157 static int fpuregs_get(struct task_struct *target,
158 		       const struct user_regset *regset,
159 		       unsigned int pos, unsigned int count,
160 		       void *kbuf, void __user *ubuf)
161 {
162 	const struct fpu_state_struct *fpregs = &target->thread.fpu_state;
163 	int ret;
164 
165 	unlazy_fpu(target);
166 
167 	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
168 				  fpregs, 0, sizeof(*fpregs));
169 	if (ret < 0)
170 		return ret;
171 
172 	return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
173 					sizeof(*fpregs), -1);
174 }
175 
176 /*
177  * update the contents of the MN10300 userspace FPU registers
178  */
fpuregs_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)179 static int fpuregs_set(struct task_struct *target,
180 		       const struct user_regset *regset,
181 		       unsigned int pos, unsigned int count,
182 		       const void *kbuf, const void __user *ubuf)
183 {
184 	struct fpu_state_struct fpu_state = target->thread.fpu_state;
185 	int ret;
186 
187 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
188 				 &fpu_state, 0, sizeof(fpu_state));
189 	if (ret < 0)
190 		return ret;
191 
192 	fpu_kill_state(target);
193 	target->thread.fpu_state = fpu_state;
194 	set_using_fpu(target);
195 
196 	return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
197 					 sizeof(fpu_state), -1);
198 }
199 
200 /*
201  * determine if the FPU registers have actually been used
202  */
fpuregs_active(struct task_struct * target,const struct user_regset * regset)203 static int fpuregs_active(struct task_struct *target,
204 			  const struct user_regset *regset)
205 {
206 	return is_using_fpu(target) ? regset->n : 0;
207 }
208 
209 /*
210  * Define the register sets available on the MN10300 under Linux
211  */
212 enum mn10300_regset {
213 	REGSET_GENERAL,
214 	REGSET_FPU,
215 };
216 
217 static const struct user_regset mn10300_regsets[] = {
218 	/*
219 	 * General register format is:
220 	 *	A3, A2, D3, D2, MCVF, MCRL, MCRH, MDRQ
221 	 *	E1, E0, E7...E2, SP, LAR, LIR, MDR
222 	 *	A1, A0, D1, D0, ORIG_D0, EPSW, PC
223 	 */
224 	[REGSET_GENERAL] = {
225 		.core_note_type	= NT_PRSTATUS,
226 		.n		= ELF_NGREG,
227 		.size		= sizeof(long),
228 		.align		= sizeof(long),
229 		.get		= genregs_get,
230 		.set		= genregs_set,
231 	},
232 	/*
233 	 * FPU register format is:
234 	 *	FS0-31, FPCR
235 	 */
236 	[REGSET_FPU] = {
237 		.core_note_type	= NT_PRFPREG,
238 		.n		= sizeof(struct fpu_state_struct) / sizeof(long),
239 		.size		= sizeof(long),
240 		.align		= sizeof(long),
241 		.get		= fpuregs_get,
242 		.set		= fpuregs_set,
243 		.active		= fpuregs_active,
244 	},
245 };
246 
247 static const struct user_regset_view user_mn10300_native_view = {
248 	.name		= "mn10300",
249 	.e_machine	= EM_MN10300,
250 	.regsets	= mn10300_regsets,
251 	.n		= ARRAY_SIZE(mn10300_regsets),
252 };
253 
task_user_regset_view(struct task_struct * task)254 const struct user_regset_view *task_user_regset_view(struct task_struct *task)
255 {
256 	return &user_mn10300_native_view;
257 }
258 
259 /*
260  * set the single-step bit
261  */
user_enable_single_step(struct task_struct * child)262 void user_enable_single_step(struct task_struct *child)
263 {
264 #ifndef CONFIG_MN10300_USING_JTAG
265 	struct user *dummy = NULL;
266 	long tmp;
267 
268 	tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw);
269 	tmp |= EPSW_T;
270 	put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp);
271 #endif
272 }
273 
274 /*
275  * make sure the single-step bit is not set
276  */
user_disable_single_step(struct task_struct * child)277 void user_disable_single_step(struct task_struct *child)
278 {
279 #ifndef CONFIG_MN10300_USING_JTAG
280 	struct user *dummy = NULL;
281 	long tmp;
282 
283 	tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw);
284 	tmp &= ~EPSW_T;
285 	put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp);
286 #endif
287 }
288 
ptrace_disable(struct task_struct * child)289 void ptrace_disable(struct task_struct *child)
290 {
291 	user_disable_single_step(child);
292 }
293 
294 /*
295  * handle the arch-specific side of process tracing
296  */
arch_ptrace(struct task_struct * child,long request,unsigned long addr,unsigned long data)297 long arch_ptrace(struct task_struct *child, long request,
298 		 unsigned long addr, unsigned long data)
299 {
300 	unsigned long tmp;
301 	int ret;
302 	unsigned long __user *datap = (unsigned long __user *) data;
303 
304 	switch (request) {
305 	/* read the word at location addr in the USER area. */
306 	case PTRACE_PEEKUSR:
307 		ret = -EIO;
308 		if ((addr & 3) || addr > sizeof(struct user) - 3)
309 			break;
310 
311 		tmp = 0;  /* Default return condition */
312 		if (addr < NR_PTREGS << 2)
313 			tmp = get_stack_long(child,
314 					     ptrace_regid_to_frame[addr]);
315 		ret = put_user(tmp, datap);
316 		break;
317 
318 		/* write the word at location addr in the USER area */
319 	case PTRACE_POKEUSR:
320 		ret = -EIO;
321 		if ((addr & 3) || addr > sizeof(struct user) - 3)
322 			break;
323 
324 		ret = 0;
325 		if (addr < NR_PTREGS << 2)
326 			ret = put_stack_long(child, ptrace_regid_to_frame[addr],
327 					     data);
328 		break;
329 
330 	case PTRACE_GETREGS:	/* Get all integer regs from the child. */
331 		return copy_regset_to_user(child, &user_mn10300_native_view,
332 					   REGSET_GENERAL,
333 					   0, NR_PTREGS * sizeof(long),
334 					   datap);
335 
336 	case PTRACE_SETREGS:	/* Set all integer regs in the child. */
337 		return copy_regset_from_user(child, &user_mn10300_native_view,
338 					     REGSET_GENERAL,
339 					     0, NR_PTREGS * sizeof(long),
340 					     datap);
341 
342 	case PTRACE_GETFPREGS:	/* Get the child FPU state. */
343 		return copy_regset_to_user(child, &user_mn10300_native_view,
344 					   REGSET_FPU,
345 					   0, sizeof(struct fpu_state_struct),
346 					   datap);
347 
348 	case PTRACE_SETFPREGS:	/* Set the child FPU state. */
349 		return copy_regset_from_user(child, &user_mn10300_native_view,
350 					     REGSET_FPU,
351 					     0, sizeof(struct fpu_state_struct),
352 					     datap);
353 
354 	default:
355 		ret = ptrace_request(child, request, addr, data);
356 		break;
357 	}
358 
359 	return ret;
360 }
361 
362 /*
363  * handle tracing of system call entry
364  * - return the revised system call number or ULONG_MAX to cause ENOSYS
365  */
syscall_trace_entry(struct pt_regs * regs)366 asmlinkage unsigned long syscall_trace_entry(struct pt_regs *regs)
367 {
368 	if (tracehook_report_syscall_entry(regs))
369 		/* tracing decided this syscall should not happen, so
370 		 * We'll return a bogus call number to get an ENOSYS
371 		 * error, but leave the original number in
372 		 * regs->orig_d0
373 		 */
374 		return ULONG_MAX;
375 
376 	return regs->orig_d0;
377 }
378 
379 /*
380  * handle tracing of system call exit
381  */
syscall_trace_exit(struct pt_regs * regs)382 asmlinkage void syscall_trace_exit(struct pt_regs *regs)
383 {
384 	tracehook_report_syscall_exit(regs, 0);
385 }
386