Blame view

arch/sh/kernel/ptrace_64.c 14.3 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
4b27c47cf   Paul Mundt   sh: syscall audit...
2
   * arch/sh/kernel/ptrace_64.c
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
   *
   * Copyright (C) 2000, 2001  Paolo Alberelli
dd76279b4   Paul Mundt   sh: Provide linux...
5
   * Copyright (C) 2003 - 2008  Paul Mundt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
8
9
10
11
12
13
   *
   * Started from SH3/4 version:
   *   SuperH version:   Copyright (C) 1999, 2000  Kaz Kojima & Niibe Yutaka
   *
   *   Original x86 implementation:
   *	By Ross Biro 1/23/92
   *	edited by Linus Torvalds
   *
4b27c47cf   Paul Mundt   sh: syscall audit...
14
15
16
   * This file is subject to the terms and conditions of the GNU General Public
   * License.  See the file "COPYING" in the main directory of this archive
   * for more details.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
21
22
  #include <linux/kernel.h>
  #include <linux/rwsem.h>
  #include <linux/sched.h>
  #include <linux/mm.h>
  #include <linux/smp.h>
d71415e88   Arnd Bergmann   sh: kill big kern...
23
  #include <linux/bitops.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
  #include <linux/errno.h>
  #include <linux/ptrace.h>
  #include <linux/user.h>
7ed20e1ad   Jesper Juhl   [PATCH] convert t...
27
  #include <linux/signal.h>
481bed454   Christoph Hellwig   [PATCH] consolida...
28
  #include <linux/syscalls.h>
4b27c47cf   Paul Mundt   sh: syscall audit...
29
  #include <linux/audit.h>
c4637d475   Paul Mundt   sh: seccomp support.
30
  #include <linux/seccomp.h>
ab99c733a   Paul Mundt   sh: Make syscall ...
31
  #include <linux/tracehook.h>
dd76279b4   Paul Mundt   sh: Provide linux...
32
33
  #include <linux/elf.h>
  #include <linux/regset.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
36
37
38
39
  #include <asm/io.h>
  #include <asm/uaccess.h>
  #include <asm/pgtable.h>
  #include <asm/system.h>
  #include <asm/processor.h>
  #include <asm/mmu_context.h>
fa43972fa   Paul Mundt   sh: fixup many sp...
40
  #include <asm/syscalls.h>
50387b3e1   Adrian Bunk   sh64: add missing...
41
  #include <asm/fpu.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42

a74f7e041   Paul Mundt   sh: Wire up HAVE_...
43
44
  #define CREATE_TRACE_POINTS
  #include <trace/events/syscalls.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
  /* This mask defines the bits of the SR which the user is not allowed to
     change, which are everything except S, Q, M, PR, SZ, FR. */
  #define SR_MASK      (0xffff8cfd)
  
  /*
   * does not yet catch signals sent when the child dies.
   * in exit.c or in signal.c.
   */
  
  /*
   * This routine will get a word from the user area in the process kernel stack.
   */
  static inline int get_stack_long(struct task_struct *task, int offset)
  {
  	unsigned char *stack;
  
  	stack = (unsigned char *)(task->thread.uregs);
  	stack += offset;
  	return (*((int *)stack));
  }
  
  static inline unsigned long
  get_fpu_long(struct task_struct *task, unsigned long addr)
  {
  	unsigned long tmp;
  	struct pt_regs *regs;
  	regs = (struct pt_regs*)((unsigned char *)task + THREAD_SIZE) - 1;
  
  	if (!tsk_used_math(task)) {
  		if (addr == offsetof(struct user_fpu_struct, fpscr)) {
  			tmp = FPSCR_INIT;
  		} else {
  			tmp = 0xffffffffUL; /* matches initial value in fpu.c */
  		}
  		return tmp;
  	}
  
  	if (last_task_used_math == task) {
256b22ca6   Paul Mundt   sh: Have SH-5 pro...
83
  		enable_fpu();
61cc7b0a1   Matt Fleming   sh: Fix up FPU bu...
84
  		save_fpu(task);
256b22ca6   Paul Mundt   sh: Have SH-5 pro...
85
  		disable_fpu();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
  		last_task_used_math = 0;
  		regs->sr |= SR_FD;
  	}
3ef2932b8   Paul Mundt   sh64: Fix up the ...
89
  	tmp = ((long *)task->thread.xstate)[addr / sizeof(unsigned long)];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
  	return tmp;
  }
  
  /*
   * This routine will put a word into the user area in the process kernel stack.
   */
  static inline int put_stack_long(struct task_struct *task, int offset,
  				 unsigned long data)
  {
  	unsigned char *stack;
  
  	stack = (unsigned char *)(task->thread.uregs);
  	stack += offset;
  	*(unsigned long *) stack = data;
  	return 0;
  }
  
  static inline int
  put_fpu_long(struct task_struct *task, unsigned long addr, unsigned long data)
  {
  	struct pt_regs *regs;
  
  	regs = (struct pt_regs*)((unsigned char *)task + THREAD_SIZE) - 1;
  
  	if (!tsk_used_math(task)) {
d6db8888c   Paul Mundt   sh64: Use the sha...
115
  		init_fpu(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
  	} else if (last_task_used_math == task) {
256b22ca6   Paul Mundt   sh: Have SH-5 pro...
117
  		enable_fpu();
61cc7b0a1   Matt Fleming   sh: Fix up FPU bu...
118
  		save_fpu(task);
256b22ca6   Paul Mundt   sh: Have SH-5 pro...
119
  		disable_fpu();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
121
122
  		last_task_used_math = 0;
  		regs->sr |= SR_FD;
  	}
3ef2932b8   Paul Mundt   sh64: Fix up the ...
123
  	((long *)task->thread.xstate)[addr / sizeof(unsigned long)] = data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
125
  	return 0;
  }
c459dbf29   Paul Mundt   sh: ptrace single...
126
127
128
129
130
  void user_enable_single_step(struct task_struct *child)
  {
  	struct pt_regs *regs = child->thread.uregs;
  
  	regs->sr |= SR_SSTEP;	/* auto-resetting upon exception */
4b505db9c   Paul Mundt   sh64: fix tracing...
131
132
  
  	set_tsk_thread_flag(child, TIF_SINGLESTEP);
c459dbf29   Paul Mundt   sh: ptrace single...
133
134
135
136
  }
  
  void user_disable_single_step(struct task_struct *child)
  {
e311be521   Adrian Bunk   sh: fix ptrace_64...
137
  	struct pt_regs *regs = child->thread.uregs;
c459dbf29   Paul Mundt   sh: ptrace single...
138
  	regs->sr &= ~SR_SSTEP;
4b505db9c   Paul Mundt   sh64: fix tracing...
139
140
  
  	clear_tsk_thread_flag(child, TIF_SINGLESTEP);
c459dbf29   Paul Mundt   sh: ptrace single...
141
  }
481bed454   Christoph Hellwig   [PATCH] consolida...
142

dd76279b4   Paul Mundt   sh: Provide linux...
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
  static int genregs_get(struct task_struct *target,
  		       const struct user_regset *regset,
  		       unsigned int pos, unsigned int count,
  		       void *kbuf, void __user *ubuf)
  {
  	const struct pt_regs *regs = task_pt_regs(target);
  	int ret;
  
  	/* PC, SR, SYSCALL */
  	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  				  &regs->pc,
  				  0, 3 * sizeof(unsigned long long));
  
  	/* R1 -> R63 */
  	if (!ret)
  		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  					  regs->regs,
  					  offsetof(struct pt_regs, regs[0]),
  					  63 * sizeof(unsigned long long));
  	/* TR0 -> TR7 */
  	if (!ret)
  		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  					  regs->tregs,
  					  offsetof(struct pt_regs, tregs[0]),
  					  8 * sizeof(unsigned long long));
  
  	if (!ret)
  		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
  					       sizeof(struct pt_regs), -1);
  
  	return ret;
  }
  
  static int genregs_set(struct task_struct *target,
  		       const struct user_regset *regset,
  		       unsigned int pos, unsigned int count,
  		       const void *kbuf, const void __user *ubuf)
  {
  	struct pt_regs *regs = task_pt_regs(target);
  	int ret;
  
  	/* PC, SR, SYSCALL */
  	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  				 &regs->pc,
  				 0, 3 * sizeof(unsigned long long));
  
  	/* R1 -> R63 */
  	if (!ret && count > 0)
  		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  					 regs->regs,
  					 offsetof(struct pt_regs, regs[0]),
  					 63 * sizeof(unsigned long long));
  
  	/* TR0 -> TR7 */
  	if (!ret && count > 0)
  		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  					 regs->tregs,
  					 offsetof(struct pt_regs, tregs[0]),
  					 8 * sizeof(unsigned long long));
  
  	if (!ret)
  		ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
  						sizeof(struct pt_regs), -1);
  
  	return ret;
  }
  
  #ifdef CONFIG_SH_FPU
  int fpregs_get(struct task_struct *target,
  	       const struct user_regset *regset,
  	       unsigned int pos, unsigned int count,
  	       void *kbuf, void __user *ubuf)
  {
  	int ret;
  
  	ret = init_fpu(target);
  	if (ret)
  		return ret;
  
  	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
3ef2932b8   Paul Mundt   sh64: Fix up the ...
223
  				   &target->thread.xstate->hardfpu, 0, -1);
dd76279b4   Paul Mundt   sh: Provide linux...
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
  }
  
  static int fpregs_set(struct task_struct *target,
  		       const struct user_regset *regset,
  		       unsigned int pos, unsigned int count,
  		       const void *kbuf, const void __user *ubuf)
  {
  	int ret;
  
  	ret = init_fpu(target);
  	if (ret)
  		return ret;
  
  	set_stopped_child_used_math(target);
  
  	return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
3ef2932b8   Paul Mundt   sh64: Fix up the ...
240
  				  &target->thread.xstate->hardfpu, 0, -1);
dd76279b4   Paul Mundt   sh: Provide linux...
241
242
243
244
245
246
247
248
  }
  
  static int fpregs_active(struct task_struct *target,
  			 const struct user_regset *regset)
  {
  	return tsk_used_math(target) ? regset->n : 0;
  }
  #endif
eaaaeef39   Paul Mundt   sh: Add kprobe-ba...
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
  const struct pt_regs_offset regoffset_table[] = {
  	REG_OFFSET_NAME(pc),
  	REG_OFFSET_NAME(sr),
  	REG_OFFSET_NAME(syscall_nr),
  	REGS_OFFSET_NAME(0),
  	REGS_OFFSET_NAME(1),
  	REGS_OFFSET_NAME(2),
  	REGS_OFFSET_NAME(3),
  	REGS_OFFSET_NAME(4),
  	REGS_OFFSET_NAME(5),
  	REGS_OFFSET_NAME(6),
  	REGS_OFFSET_NAME(7),
  	REGS_OFFSET_NAME(8),
  	REGS_OFFSET_NAME(9),
  	REGS_OFFSET_NAME(10),
  	REGS_OFFSET_NAME(11),
  	REGS_OFFSET_NAME(12),
  	REGS_OFFSET_NAME(13),
  	REGS_OFFSET_NAME(14),
  	REGS_OFFSET_NAME(15),
  	REGS_OFFSET_NAME(16),
  	REGS_OFFSET_NAME(17),
  	REGS_OFFSET_NAME(18),
  	REGS_OFFSET_NAME(19),
  	REGS_OFFSET_NAME(20),
  	REGS_OFFSET_NAME(21),
  	REGS_OFFSET_NAME(22),
  	REGS_OFFSET_NAME(23),
  	REGS_OFFSET_NAME(24),
  	REGS_OFFSET_NAME(25),
  	REGS_OFFSET_NAME(26),
  	REGS_OFFSET_NAME(27),
  	REGS_OFFSET_NAME(28),
  	REGS_OFFSET_NAME(29),
  	REGS_OFFSET_NAME(30),
  	REGS_OFFSET_NAME(31),
  	REGS_OFFSET_NAME(32),
  	REGS_OFFSET_NAME(33),
  	REGS_OFFSET_NAME(34),
  	REGS_OFFSET_NAME(35),
  	REGS_OFFSET_NAME(36),
  	REGS_OFFSET_NAME(37),
  	REGS_OFFSET_NAME(38),
  	REGS_OFFSET_NAME(39),
  	REGS_OFFSET_NAME(40),
  	REGS_OFFSET_NAME(41),
  	REGS_OFFSET_NAME(42),
  	REGS_OFFSET_NAME(43),
  	REGS_OFFSET_NAME(44),
  	REGS_OFFSET_NAME(45),
  	REGS_OFFSET_NAME(46),
  	REGS_OFFSET_NAME(47),
  	REGS_OFFSET_NAME(48),
  	REGS_OFFSET_NAME(49),
  	REGS_OFFSET_NAME(50),
  	REGS_OFFSET_NAME(51),
  	REGS_OFFSET_NAME(52),
  	REGS_OFFSET_NAME(53),
  	REGS_OFFSET_NAME(54),
  	REGS_OFFSET_NAME(55),
  	REGS_OFFSET_NAME(56),
  	REGS_OFFSET_NAME(57),
  	REGS_OFFSET_NAME(58),
  	REGS_OFFSET_NAME(59),
  	REGS_OFFSET_NAME(60),
  	REGS_OFFSET_NAME(61),
  	REGS_OFFSET_NAME(62),
  	REGS_OFFSET_NAME(63),
  	TREGS_OFFSET_NAME(0),
  	TREGS_OFFSET_NAME(1),
  	TREGS_OFFSET_NAME(2),
  	TREGS_OFFSET_NAME(3),
  	TREGS_OFFSET_NAME(4),
  	TREGS_OFFSET_NAME(5),
  	TREGS_OFFSET_NAME(6),
  	TREGS_OFFSET_NAME(7),
  	REG_OFFSET_END,
  };
dd76279b4   Paul Mundt   sh: Provide linux...
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
  /*
   * These are our native regset flavours.
   */
  enum sh_regset {
  	REGSET_GENERAL,
  #ifdef CONFIG_SH_FPU
  	REGSET_FPU,
  #endif
  };
  
  static const struct user_regset sh_regsets[] = {
  	/*
  	 * Format is:
  	 *	PC, SR, SYSCALL,
  	 *	R1 --> R63,
  	 *	TR0 --> TR7,
  	 */
  	[REGSET_GENERAL] = {
  		.core_note_type	= NT_PRSTATUS,
  		.n		= ELF_NGREG,
  		.size		= sizeof(long long),
  		.align		= sizeof(long long),
  		.get		= genregs_get,
  		.set		= genregs_set,
  	},
  
  #ifdef CONFIG_SH_FPU
  	[REGSET_FPU] = {
  		.core_note_type	= NT_PRFPREG,
  		.n		= sizeof(struct user_fpu_struct) /
  				  sizeof(long long),
  		.size		= sizeof(long long),
  		.align		= sizeof(long long),
  		.get		= fpregs_get,
  		.set		= fpregs_set,
  		.active		= fpregs_active,
  	},
  #endif
  };
  
  static const struct user_regset_view user_sh64_native_view = {
  	.name		= "sh64",
  	.e_machine	= EM_SH,
  	.regsets	= sh_regsets,
  	.n		= ARRAY_SIZE(sh_regsets),
  };
  
  const struct user_regset_view *task_user_regset_view(struct task_struct *task)
  {
  	return &user_sh64_native_view;
  }
9b05a69e0   Namhyung Kim   ptrace: change si...
378
379
  long arch_ptrace(struct task_struct *child, long request,
  		 unsigned long addr, unsigned long data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
  	int ret;
9e1cb2061   Namhyung Kim   ptrace: cleanup a...
382
  	unsigned long __user *datap = (unsigned long __user *) data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
  	switch (request) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
386
387
388
389
390
391
392
393
394
395
396
  	/* read the word at location addr in the USER area. */
  	case PTRACE_PEEKUSR: {
  		unsigned long tmp;
  
  		ret = -EIO;
  		if ((addr & 3) || addr < 0)
  			break;
  
  		if (addr < sizeof(struct pt_regs))
  			tmp = get_stack_long(child, addr);
  		else if ((addr >= offsetof(struct user, fpu)) &&
  			 (addr <  offsetof(struct user, u_fpvalid))) {
9e1cb2061   Namhyung Kim   ptrace: cleanup a...
397
  			unsigned long index;
c49b6ecf0   Phil Edworthy   sh: Fix ptrace fp...
398
399
400
  			ret = init_fpu(child);
  			if (ret)
  				break;
9e1cb2061   Namhyung Kim   ptrace: cleanup a...
401
402
  			index = addr - offsetof(struct user, fpu);
  			tmp = get_fpu_long(child, index);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
404
405
406
407
  		} else if (addr == offsetof(struct user, u_fpvalid)) {
  			tmp = !!tsk_used_math(child);
  		} else {
  			break;
  		}
9e1cb2061   Namhyung Kim   ptrace: cleanup a...
408
  		ret = put_user(tmp, datap);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
410
  		break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
  	case PTRACE_POKEUSR:
                  /* write the word at location addr in the USER area. We must
                     disallow any changes to certain SR bits or u_fpvalid, since
                     this could crash the kernel or result in a security
                     loophole. */
  		ret = -EIO;
  		if ((addr & 3) || addr < 0)
  			break;
  
  		if (addr < sizeof(struct pt_regs)) {
  			/* Ignore change of top 32 bits of SR */
  			if (addr == offsetof (struct pt_regs, sr)+4)
  			{
  				ret = 0;
  				break;
  			}
  			/* If lower 32 bits of SR, ignore non-user bits */
  			if (addr == offsetof (struct pt_regs, sr))
  			{
  				long cursr = get_stack_long(child, addr);
  				data &= ~(SR_MASK);
  				data |= (cursr & SR_MASK);
  			}
  			ret = put_stack_long(child, addr, data);
  		}
  		else if ((addr >= offsetof(struct user, fpu)) &&
  			 (addr <  offsetof(struct user, u_fpvalid))) {
9e1cb2061   Namhyung Kim   ptrace: cleanup a...
438
  			unsigned long index;
c49b6ecf0   Phil Edworthy   sh: Fix ptrace fp...
439
440
441
  			ret = init_fpu(child);
  			if (ret)
  				break;
9e1cb2061   Namhyung Kim   ptrace: cleanup a...
442
443
  			index = addr - offsetof(struct user, fpu);
  			ret = put_fpu_long(child, index, data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444
445
  		}
  		break;
dd76279b4   Paul Mundt   sh: Provide linux...
446
447
448
449
  	case PTRACE_GETREGS:
  		return copy_regset_to_user(child, &user_sh64_native_view,
  					   REGSET_GENERAL,
  					   0, sizeof(struct pt_regs),
9e1cb2061   Namhyung Kim   ptrace: cleanup a...
450
  					   datap);
dd76279b4   Paul Mundt   sh: Provide linux...
451
452
453
454
  	case PTRACE_SETREGS:
  		return copy_regset_from_user(child, &user_sh64_native_view,
  					     REGSET_GENERAL,
  					     0, sizeof(struct pt_regs),
9e1cb2061   Namhyung Kim   ptrace: cleanup a...
455
  					     datap);
dd76279b4   Paul Mundt   sh: Provide linux...
456
457
458
459
460
  #ifdef CONFIG_SH_FPU
  	case PTRACE_GETFPREGS:
  		return copy_regset_to_user(child, &user_sh64_native_view,
  					   REGSET_FPU,
  					   0, sizeof(struct user_fpu_struct),
9e1cb2061   Namhyung Kim   ptrace: cleanup a...
461
  					   datap);
dd76279b4   Paul Mundt   sh: Provide linux...
462
463
464
465
  	case PTRACE_SETFPREGS:
  		return copy_regset_from_user(child, &user_sh64_native_view,
  					     REGSET_FPU,
  					     0, sizeof(struct user_fpu_struct),
9e1cb2061   Namhyung Kim   ptrace: cleanup a...
466
  					     datap);
dd76279b4   Paul Mundt   sh: Provide linux...
467
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
469
470
471
  	default:
  		ret = ptrace_request(child, request, addr, data);
  		break;
  	}
dd76279b4   Paul Mundt   sh: Provide linux...
472

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473
474
  	return ret;
  }
9b05a69e0   Namhyung Kim   ptrace: change si...
475
476
  asmlinkage int sh64_ptrace(long request, long pid,
  			   unsigned long addr, unsigned long data)
481bed454   Christoph Hellwig   [PATCH] consolida...
477
  {
481bed454   Christoph Hellwig   [PATCH] consolida...
478
  #define WPC_DBRMODE 0x0d104008
d71415e88   Arnd Bergmann   sh: kill big kern...
479
  	static unsigned long first_call;
481bed454   Christoph Hellwig   [PATCH] consolida...
480

d71415e88   Arnd Bergmann   sh: kill big kern...
481
  	if (!test_and_set_bit(0, &first_call)) {
481bed454   Christoph Hellwig   [PATCH] consolida...
482
483
484
485
486
487
488
489
490
491
  		/* Set WPC.DBRMODE to 0.  This makes all debug events get
  		 * delivered through RESVEC, i.e. into the handlers in entry.S.
  		 * (If the kernel was downloaded using a remote gdb, WPC.DBRMODE
  		 * would normally be left set to 1, which makes debug events get
  		 * delivered through DBRVEC, i.e. into the remote gdb's
  		 * handlers.  This prevents ptrace getting them, and confuses
  		 * the remote gdb.) */
  		printk("DBRMODE set to 0 to permit native debugging
  ");
  		poke_real_address_q(WPC_DBRMODE, 0);
481bed454   Christoph Hellwig   [PATCH] consolida...
492
  	}
481bed454   Christoph Hellwig   [PATCH] consolida...
493
494
495
  
  	return sys_ptrace(request, pid, addr, data);
  }
9e5e21170   Paul Mundt   sh: Fix up the au...
496
497
498
499
500
501
502
503
504
505
506
507
508
  static inline int audit_arch(void)
  {
  	int arch = EM_SH;
  
  #ifdef CONFIG_64BIT
  	arch |= __AUDIT_ARCH_64BIT;
  #endif
  #ifdef CONFIG_CPU_LITTLE_ENDIAN
  	arch |= __AUDIT_ARCH_LE;
  #endif
  
  	return arch;
  }
ab99c733a   Paul Mundt   sh: Make syscall ...
509
  asmlinkage long long do_syscall_trace_enter(struct pt_regs *regs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
  {
ab99c733a   Paul Mundt   sh: Make syscall ...
511
  	long long ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512

c4637d475   Paul Mundt   sh: seccomp support.
513
  	secure_computing(regs->regs[9]);
ab99c733a   Paul Mundt   sh: Make syscall ...
514
515
516
517
518
519
520
521
  	if (test_thread_flag(TIF_SYSCALL_TRACE) &&
  	    tracehook_report_syscall_entry(regs))
  		/*
  		 * Tracing decided this syscall should not happen.
  		 * We'll return a bogus call number to get an ENOSYS
  		 * error, but leave the original number in regs->regs[0].
  		 */
  		ret = -1LL;
4b27c47cf   Paul Mundt   sh: syscall audit...
522

a74f7e041   Paul Mundt   sh: Wire up HAVE_...
523
524
  	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
  		trace_sys_enter(regs, regs->regs[9]);
ab99c733a   Paul Mundt   sh: Make syscall ...
525
  	if (unlikely(current->audit_context))
9e5e21170   Paul Mundt   sh: Fix up the au...
526
  		audit_syscall_entry(audit_arch(), regs->regs[1],
4b27c47cf   Paul Mundt   sh: syscall audit...
527
528
  				    regs->regs[2], regs->regs[3],
  				    regs->regs[4], regs->regs[5]);
ab99c733a   Paul Mundt   sh: Make syscall ...
529
530
531
532
533
534
  
  	return ret ?: regs->regs[9];
  }
  
  asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
  {
4b505db9c   Paul Mundt   sh64: fix tracing...
535
  	int step;
ab99c733a   Paul Mundt   sh: Make syscall ...
536
537
538
  	if (unlikely(current->audit_context))
  		audit_syscall_exit(AUDITSC_RESULT(regs->regs[9]),
  				   regs->regs[9]);
a74f7e041   Paul Mundt   sh: Wire up HAVE_...
539
540
  	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
  		trace_sys_exit(regs, regs->regs[9]);
4b505db9c   Paul Mundt   sh64: fix tracing...
541
542
543
  	step = test_thread_flag(TIF_SINGLESTEP);
  	if (step || test_thread_flag(TIF_SYSCALL_TRACE))
  		tracehook_report_syscall_exit(regs, step);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
  }
  
  /* Called with interrupts disabled */
  asmlinkage void do_single_step(unsigned long long vec, struct pt_regs *regs)
  {
  	/* This is called after a single step exception (DEBUGSS).
  	   There is no need to change the PC, as it is a post-execution
  	   exception, as entry.S does not do anything to the PC for DEBUGSS.
  	   We need to clear the Single Step setting in SR to avoid
  	   continually stepping. */
  	local_irq_enable();
  	regs->sr &= ~SR_SSTEP;
  	force_sig(SIGTRAP, current);
  }
  
  /* Called with interrupts disabled */
a4ae2b2b1   Paul Mundt   sh64: Fixup build...
560
  BUILD_TRAP_HANDLER(breakpoint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
  {
a4ae2b2b1   Paul Mundt   sh64: Fixup build...
562
  	TRAP_HANDLER_DECL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
564
565
566
567
568
569
570
571
572
573
574
575
576
  	/* We need to forward step the PC, to counteract the backstep done
  	   in signal.c. */
  	local_irq_enable();
  	force_sig(SIGTRAP, current);
  	regs->pc += 4;
  }
  
  /*
   * Called by kernel/ptrace.c when detaching..
   *
   * Make sure single step bits etc are not set.
   */
  void ptrace_disable(struct task_struct *child)
  {
c459dbf29   Paul Mundt   sh: ptrace single...
577
  	user_disable_single_step(child);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
  }