xref: /openbmc/linux/arch/sh/kernel/ptrace_32.c (revision 82ced6fd)
1 /*
2  * SuperH process tracing
3  *
4  * Copyright (C) 1999, 2000  Kaz Kojima & Niibe Yutaka
5  * Copyright (C) 2002 - 2008  Paul Mundt
6  *
7  * Audit support by Yuichi Nakamura <ynakam@hitachisoft.jp>
8  *
9  * This file is subject to the terms and conditions of the GNU General Public
10  * License.  See the file "COPYING" in the main directory of this archive
11  * for more details.
12  */
13 #include <linux/kernel.h>
14 #include <linux/sched.h>
15 #include <linux/mm.h>
16 #include <linux/smp.h>
17 #include <linux/errno.h>
18 #include <linux/ptrace.h>
19 #include <linux/user.h>
20 #include <linux/slab.h>
21 #include <linux/security.h>
22 #include <linux/signal.h>
23 #include <linux/io.h>
24 #include <linux/audit.h>
25 #include <linux/seccomp.h>
26 #include <linux/tracehook.h>
27 #include <linux/elf.h>
28 #include <linux/regset.h>
29 #include <asm/uaccess.h>
30 #include <asm/pgtable.h>
31 #include <asm/system.h>
32 #include <asm/processor.h>
33 #include <asm/mmu_context.h>
34 #include <asm/syscalls.h>
35 #include <asm/fpu.h>
36 
37 /*
38  * This routine will get a word off of the process kernel stack.
39  */
40 static inline int get_stack_long(struct task_struct *task, int offset)
41 {
42 	unsigned char *stack;
43 
44 	stack = (unsigned char *)task_pt_regs(task);
45 	stack += offset;
46 	return (*((int *)stack));
47 }
48 
49 /*
50  * This routine will put a word on the process kernel stack.
51  */
52 static inline int put_stack_long(struct task_struct *task, int offset,
53 				 unsigned long data)
54 {
55 	unsigned char *stack;
56 
57 	stack = (unsigned char *)task_pt_regs(task);
58 	stack += offset;
59 	*(unsigned long *) stack = data;
60 	return 0;
61 }
62 
63 void user_enable_single_step(struct task_struct *child)
64 {
65 	/* Next scheduling will set up UBC */
66 	if (child->thread.ubc_pc == 0)
67 		ubc_usercnt += 1;
68 
69 	child->thread.ubc_pc = get_stack_long(child,
70 				offsetof(struct pt_regs, pc));
71 
72 	set_tsk_thread_flag(child, TIF_SINGLESTEP);
73 }
74 
75 void user_disable_single_step(struct task_struct *child)
76 {
77 	clear_tsk_thread_flag(child, TIF_SINGLESTEP);
78 
79 	/*
80 	 * Ensure the UBC is not programmed at the next context switch.
81 	 *
82 	 * Normally this is not needed but there are sequences such as
83 	 * singlestep, signal delivery, and continue that leave the
84 	 * ubc_pc non-zero leading to spurious SIGTRAPs.
85 	 */
86 	if (child->thread.ubc_pc != 0) {
87 		ubc_usercnt -= 1;
88 		child->thread.ubc_pc = 0;
89 	}
90 }
91 
92 /*
93  * Called by kernel/ptrace.c when detaching..
94  *
95  * Make sure single step bits etc are not set.
96  */
97 void ptrace_disable(struct task_struct *child)
98 {
99 	user_disable_single_step(child);
100 }
101 
102 static int genregs_get(struct task_struct *target,
103 		       const struct user_regset *regset,
104 		       unsigned int pos, unsigned int count,
105 		       void *kbuf, void __user *ubuf)
106 {
107 	const struct pt_regs *regs = task_pt_regs(target);
108 	int ret;
109 
110 	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
111 				  regs->regs,
112 				  0, 16 * sizeof(unsigned long));
113 	if (!ret)
114 		/* PC, PR, SR, GBR, MACH, MACL, TRA */
115 		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
116 					  &regs->pc,
117 					  offsetof(struct pt_regs, pc),
118 					  sizeof(struct pt_regs));
119 	if (!ret)
120 		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
121 					       sizeof(struct pt_regs), -1);
122 
123 	return ret;
124 }
125 
126 static int genregs_set(struct task_struct *target,
127 		       const struct user_regset *regset,
128 		       unsigned int pos, unsigned int count,
129 		       const void *kbuf, const void __user *ubuf)
130 {
131 	struct pt_regs *regs = task_pt_regs(target);
132 	int ret;
133 
134 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
135 				 regs->regs,
136 				 0, 16 * sizeof(unsigned long));
137 	if (!ret && count > 0)
138 		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
139 					 &regs->pc,
140 					 offsetof(struct pt_regs, pc),
141 					 sizeof(struct pt_regs));
142 	if (!ret)
143 		ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
144 						sizeof(struct pt_regs), -1);
145 
146 	return ret;
147 }
148 
149 #ifdef CONFIG_SH_FPU
150 int fpregs_get(struct task_struct *target,
151 	       const struct user_regset *regset,
152 	       unsigned int pos, unsigned int count,
153 	       void *kbuf, void __user *ubuf)
154 {
155 	int ret;
156 
157 	ret = init_fpu(target);
158 	if (ret)
159 		return ret;
160 
161 	if ((boot_cpu_data.flags & CPU_HAS_FPU))
162 		return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
163 					   &target->thread.fpu.hard, 0, -1);
164 
165 	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
166 				   &target->thread.fpu.soft, 0, -1);
167 }
168 
169 static int fpregs_set(struct task_struct *target,
170 		       const struct user_regset *regset,
171 		       unsigned int pos, unsigned int count,
172 		       const void *kbuf, const void __user *ubuf)
173 {
174 	int ret;
175 
176 	ret = init_fpu(target);
177 	if (ret)
178 		return ret;
179 
180 	set_stopped_child_used_math(target);
181 
182 	if ((boot_cpu_data.flags & CPU_HAS_FPU))
183 		return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
184 					  &target->thread.fpu.hard, 0, -1);
185 
186 	return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
187 				  &target->thread.fpu.soft, 0, -1);
188 }
189 
190 static int fpregs_active(struct task_struct *target,
191 			 const struct user_regset *regset)
192 {
193 	return tsk_used_math(target) ? regset->n : 0;
194 }
195 #endif
196 
197 #ifdef CONFIG_SH_DSP
198 static int dspregs_get(struct task_struct *target,
199 		       const struct user_regset *regset,
200 		       unsigned int pos, unsigned int count,
201 		       void *kbuf, void __user *ubuf)
202 {
203 	const struct pt_dspregs *regs =
204 		(struct pt_dspregs *)&target->thread.dsp_status.dsp_regs;
205 	int ret;
206 
207 	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs,
208 				  0, sizeof(struct pt_dspregs));
209 	if (!ret)
210 		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
211 					       sizeof(struct pt_dspregs), -1);
212 
213 	return ret;
214 }
215 
216 static int dspregs_set(struct task_struct *target,
217 		       const struct user_regset *regset,
218 		       unsigned int pos, unsigned int count,
219 		       const void *kbuf, const void __user *ubuf)
220 {
221 	struct pt_dspregs *regs =
222 		(struct pt_dspregs *)&target->thread.dsp_status.dsp_regs;
223 	int ret;
224 
225 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, regs,
226 				 0, sizeof(struct pt_dspregs));
227 	if (!ret)
228 		ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
229 						sizeof(struct pt_dspregs), -1);
230 
231 	return ret;
232 }
233 
234 static int dspregs_active(struct task_struct *target,
235 			  const struct user_regset *regset)
236 {
237 	struct pt_regs *regs = task_pt_regs(target);
238 
239 	return regs->sr & SR_DSP ? regset->n : 0;
240 }
241 #endif
242 
243 /*
244  * These are our native regset flavours.
245  */
246 enum sh_regset {
247 	REGSET_GENERAL,
248 #ifdef CONFIG_SH_FPU
249 	REGSET_FPU,
250 #endif
251 #ifdef CONFIG_SH_DSP
252 	REGSET_DSP,
253 #endif
254 };
255 
256 static const struct user_regset sh_regsets[] = {
257 	/*
258 	 * Format is:
259 	 *	R0 --> R15
260 	 *	PC, PR, SR, GBR, MACH, MACL, TRA
261 	 */
262 	[REGSET_GENERAL] = {
263 		.core_note_type	= NT_PRSTATUS,
264 		.n		= ELF_NGREG,
265 		.size		= sizeof(long),
266 		.align		= sizeof(long),
267 		.get		= genregs_get,
268 		.set		= genregs_set,
269 	},
270 
271 #ifdef CONFIG_SH_FPU
272 	[REGSET_FPU] = {
273 		.core_note_type	= NT_PRFPREG,
274 		.n		= sizeof(struct user_fpu_struct) / sizeof(long),
275 		.size		= sizeof(long),
276 		.align		= sizeof(long),
277 		.get		= fpregs_get,
278 		.set		= fpregs_set,
279 		.active		= fpregs_active,
280 	},
281 #endif
282 
283 #ifdef CONFIG_SH_DSP
284 	[REGSET_DSP] = {
285 		.n		= sizeof(struct pt_dspregs) / sizeof(long),
286 		.size		= sizeof(long),
287 		.align		= sizeof(long),
288 		.get		= dspregs_get,
289 		.set		= dspregs_set,
290 		.active		= dspregs_active,
291 	},
292 #endif
293 };
294 
295 static const struct user_regset_view user_sh_native_view = {
296 	.name		= "sh",
297 	.e_machine	= EM_SH,
298 	.regsets	= sh_regsets,
299 	.n		= ARRAY_SIZE(sh_regsets),
300 };
301 
302 const struct user_regset_view *task_user_regset_view(struct task_struct *task)
303 {
304 	return &user_sh_native_view;
305 }
306 
307 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
308 {
309 	struct user * dummy = NULL;
310 	unsigned long __user *datap = (unsigned long __user *)data;
311 	int ret;
312 
313 	switch (request) {
314 	/* read the word at location addr in the USER area. */
315 	case PTRACE_PEEKUSR: {
316 		unsigned long tmp;
317 
318 		ret = -EIO;
319 		if ((addr & 3) || addr < 0 ||
320 		    addr > sizeof(struct user) - 3)
321 			break;
322 
323 		if (addr < sizeof(struct pt_regs))
324 			tmp = get_stack_long(child, addr);
325 		else if (addr >= (long) &dummy->fpu &&
326 			 addr < (long) &dummy->u_fpvalid) {
327 			if (!tsk_used_math(child)) {
328 				if (addr == (long)&dummy->fpu.fpscr)
329 					tmp = FPSCR_INIT;
330 				else
331 					tmp = 0;
332 			} else
333 				tmp = ((long *)&child->thread.fpu)
334 					[(addr - (long)&dummy->fpu) >> 2];
335 		} else if (addr == (long) &dummy->u_fpvalid)
336 			tmp = !!tsk_used_math(child);
337 		else
338 			tmp = 0;
339 		ret = put_user(tmp, datap);
340 		break;
341 	}
342 
343 	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
344 		ret = -EIO;
345 		if ((addr & 3) || addr < 0 ||
346 		    addr > sizeof(struct user) - 3)
347 			break;
348 
349 		if (addr < sizeof(struct pt_regs))
350 			ret = put_stack_long(child, addr, data);
351 		else if (addr >= (long) &dummy->fpu &&
352 			 addr < (long) &dummy->u_fpvalid) {
353 			set_stopped_child_used_math(child);
354 			((long *)&child->thread.fpu)
355 				[(addr - (long)&dummy->fpu) >> 2] = data;
356 			ret = 0;
357 		} else if (addr == (long) &dummy->u_fpvalid) {
358 			conditional_stopped_child_used_math(data, child);
359 			ret = 0;
360 		}
361 		break;
362 
363 	case PTRACE_GETREGS:
364 		return copy_regset_to_user(child, &user_sh_native_view,
365 					   REGSET_GENERAL,
366 					   0, sizeof(struct pt_regs),
367 					   (void __user *)data);
368 	case PTRACE_SETREGS:
369 		return copy_regset_from_user(child, &user_sh_native_view,
370 					     REGSET_GENERAL,
371 					     0, sizeof(struct pt_regs),
372 					     (const void __user *)data);
373 #ifdef CONFIG_SH_FPU
374 	case PTRACE_GETFPREGS:
375 		return copy_regset_to_user(child, &user_sh_native_view,
376 					   REGSET_FPU,
377 					   0, sizeof(struct user_fpu_struct),
378 					   (void __user *)data);
379 	case PTRACE_SETFPREGS:
380 		return copy_regset_from_user(child, &user_sh_native_view,
381 					     REGSET_FPU,
382 					     0, sizeof(struct user_fpu_struct),
383 					     (const void __user *)data);
384 #endif
385 #ifdef CONFIG_SH_DSP
386 	case PTRACE_GETDSPREGS:
387 		return copy_regset_to_user(child, &user_sh_native_view,
388 					   REGSET_DSP,
389 					   0, sizeof(struct pt_dspregs),
390 					   (void __user *)data);
391 	case PTRACE_SETDSPREGS:
392 		return copy_regset_from_user(child, &user_sh_native_view,
393 					     REGSET_DSP,
394 					     0, sizeof(struct pt_dspregs),
395 					     (const void __user *)data);
396 #endif
397 #ifdef CONFIG_BINFMT_ELF_FDPIC
398 	case PTRACE_GETFDPIC: {
399 		unsigned long tmp = 0;
400 
401 		switch (addr) {
402 		case PTRACE_GETFDPIC_EXEC:
403 			tmp = child->mm->context.exec_fdpic_loadmap;
404 			break;
405 		case PTRACE_GETFDPIC_INTERP:
406 			tmp = child->mm->context.interp_fdpic_loadmap;
407 			break;
408 		default:
409 			break;
410 		}
411 
412 		ret = 0;
413 		if (put_user(tmp, datap)) {
414 			ret = -EFAULT;
415 			break;
416 		}
417 		break;
418 	}
419 #endif
420 	default:
421 		ret = ptrace_request(child, request, addr, data);
422 		break;
423 	}
424 
425 	return ret;
426 }
427 
428 static inline int audit_arch(void)
429 {
430 	int arch = EM_SH;
431 
432 #ifdef CONFIG_CPU_LITTLE_ENDIAN
433 	arch |= __AUDIT_ARCH_LE;
434 #endif
435 
436 	return arch;
437 }
438 
439 asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
440 {
441 	long ret = 0;
442 
443 	secure_computing(regs->regs[0]);
444 
445 	if (test_thread_flag(TIF_SYSCALL_TRACE) &&
446 	    tracehook_report_syscall_entry(regs))
447 		/*
448 		 * Tracing decided this syscall should not happen.
449 		 * We'll return a bogus call number to get an ENOSYS
450 		 * error, but leave the original number in regs->regs[0].
451 		 */
452 		ret = -1L;
453 
454 	if (unlikely(current->audit_context))
455 		audit_syscall_entry(audit_arch(), regs->regs[3],
456 				    regs->regs[4], regs->regs[5],
457 				    regs->regs[6], regs->regs[7]);
458 
459 	return ret ?: regs->regs[0];
460 }
461 
462 asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
463 {
464 	int step;
465 
466 	if (unlikely(current->audit_context))
467 		audit_syscall_exit(AUDITSC_RESULT(regs->regs[0]),
468 				   regs->regs[0]);
469 
470 	step = test_thread_flag(TIF_SINGLESTEP);
471 	if (step || test_thread_flag(TIF_SYSCALL_TRACE))
472 		tracehook_report_syscall_exit(regs, step);
473 }
474