Blame view

arch/avr32/kernel/ptrace.c 9.25 KB
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
1
2
3
4
5
6
7
8
9
10
11
  /*
   * Copyright (C) 2004-2006 Atmel Corporation
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
  #undef DEBUG
  #include <linux/kernel.h>
  #include <linux/sched.h>
  #include <linux/mm.h>
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
12
13
14
15
16
17
18
19
20
21
22
  #include <linux/ptrace.h>
  #include <linux/errno.h>
  #include <linux/user.h>
  #include <linux/security.h>
  #include <linux/unistd.h>
  #include <linux/notifier.h>
  
  #include <asm/traps.h>
  #include <asm/uaccess.h>
  #include <asm/ocd.h>
  #include <asm/mmu_context.h>
1eeb66a1b   Christoph Hellwig   move die notifier...
23
  #include <linux/kdebug.h>
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
24
25
26
  
  static struct pt_regs *get_user_regs(struct task_struct *tsk)
  {
c9f4f06d3   Roman Zippel   wrap access to th...
27
  	return (struct pt_regs *)((unsigned long)task_stack_page(tsk) +
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
28
29
  				  THREAD_SIZE - sizeof(struct pt_regs));
  }
9e584fbbd   Peter Huewe   arch/avr32: fix b...
30
  void user_enable_single_step(struct task_struct *tsk)
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
31
  {
1d8393171   Christoph Hellwig   avr32: use generi...
32
33
  	pr_debug("user_enable_single_step: pid=%u, PC=0x%08lx, SR=0x%08lx
  ",
2507bc133   Haavard Skinnemoen   [AVR32] Follow th...
34
  		 tsk->pid, task_pt_regs(tsk)->pc, task_pt_regs(tsk)->sr);
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
35

2507bc133   Haavard Skinnemoen   [AVR32] Follow th...
36
37
38
39
40
41
42
43
44
45
46
47
48
  	/*
  	 * We can't schedule in Debug mode, so when TIF_BREAKPOINT is
  	 * set, the system call or exception handler will do a
  	 * breakpoint to enter monitor mode before returning to
  	 * userspace.
  	 *
  	 * The monitor code will then notice that TIF_SINGLE_STEP is
  	 * set and return to userspace with single stepping enabled.
  	 * The CPU will then enter monitor mode again after exactly
  	 * one instruction has been executed, and the monitor code
  	 * will then send a SIGTRAP to the process.
  	 */
  	set_tsk_thread_flag(tsk, TIF_BREAKPOINT);
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
49
50
  	set_tsk_thread_flag(tsk, TIF_SINGLE_STEP);
  }
1d8393171   Christoph Hellwig   avr32: use generi...
51
52
53
54
  void user_disable_single_step(struct task_struct *child)
  {
  	/* XXX(hch): a no-op here seems wrong.. */
  }
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
55
56
57
58
59
60
61
62
  /*
   * Called by kernel/ptrace.c when detaching
   *
   * Make sure any single step bits, etc. are not set
   */
  void ptrace_disable(struct task_struct *child)
  {
  	clear_tsk_thread_flag(child, TIF_SINGLE_STEP);
2507bc133   Haavard Skinnemoen   [AVR32] Follow th...
63
  	clear_tsk_thread_flag(child, TIF_BREAKPOINT);
13b54a505   Haavard Skinnemoen   [AVR32] Enable de...
64
  	ocd_disable(child);
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
65
66
67
68
69
70
71
72
73
74
75
  }
  
  /*
   * Read the word at offset "offset" into the task's "struct user". We
   * actually access the pt_regs struct stored on the kernel stack.
   */
  static int ptrace_read_user(struct task_struct *tsk, unsigned long offset,
  			    unsigned long __user *data)
  {
  	unsigned long *regs;
  	unsigned long value;
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
76
77
78
79
80
81
82
83
84
85
86
  	if (offset & 3 || offset >= sizeof(struct user)) {
  		printk("ptrace_read_user: invalid offset 0x%08lx
  ", offset);
  		return -EIO;
  	}
  
  	regs = (unsigned long *)get_user_regs(tsk);
  
  	value = 0;
  	if (offset < sizeof(struct pt_regs))
  		value = regs[offset / sizeof(regs[0])];
2507bc133   Haavard Skinnemoen   [AVR32] Follow th...
87
88
89
  	pr_debug("ptrace_read_user(%s[%u], %#lx, %p) -> %#lx
  ",
  		 tsk->comm, tsk->pid, offset, data, value);
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
90
91
92
93
94
95
96
97
98
99
100
101
  	return put_user(value, data);
  }
  
  /*
   * Write the word "value" to offset "offset" into the task's "struct
   * user". We actually access the pt_regs struct stored on the kernel
   * stack.
   */
  static int ptrace_write_user(struct task_struct *tsk, unsigned long offset,
  			     unsigned long value)
  {
  	unsigned long *regs;
2507bc133   Haavard Skinnemoen   [AVR32] Follow th...
102
103
104
  	pr_debug("ptrace_write_user(%s[%u], %#lx, %#lx)
  ",
  			tsk->comm, tsk->pid, offset, value);
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
105
  	if (offset & 3 || offset >= sizeof(struct user)) {
2507bc133   Haavard Skinnemoen   [AVR32] Follow th...
106
107
  		pr_debug("  invalid offset 0x%08lx
  ", offset);
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
  		return -EIO;
  	}
  
  	if (offset >= sizeof(struct pt_regs))
  		return 0;
  
  	regs = (unsigned long *)get_user_regs(tsk);
  	regs[offset / sizeof(regs[0])] = value;
  
  	return 0;
  }
  
  static int ptrace_getregs(struct task_struct *tsk, void __user *uregs)
  {
  	struct pt_regs *regs = get_user_regs(tsk);
  
  	return copy_to_user(uregs, regs, sizeof(*regs)) ? -EFAULT : 0;
  }
  
  static int ptrace_setregs(struct task_struct *tsk, const void __user *uregs)
  {
  	struct pt_regs newregs;
  	int ret;
  
  	ret = -EFAULT;
  	if (copy_from_user(&newregs, uregs, sizeof(newregs)) == 0) {
  		struct pt_regs *regs = get_user_regs(tsk);
  
  		ret = -EINVAL;
  		if (valid_user_regs(&newregs)) {
  			*regs = newregs;
  			ret = 0;
  		}
  	}
  
  	return ret;
  }
9b05a69e0   Namhyung Kim   ptrace: change si...
145
146
  long arch_ptrace(struct task_struct *child, long request,
  		 unsigned long addr, unsigned long data)
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
147
  {
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
148
  	int ret;
9f29b8fb4   Namhyung Kim   ptrace: cleanup a...
149
  	void __user *datap = (void __user *) data;
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
150

5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
151
152
153
154
  	switch (request) {
  	/* Read the word at location addr in the child process */
  	case PTRACE_PEEKTEXT:
  	case PTRACE_PEEKDATA:
766473231   Alexey Dobriyan   PTRACE_PEEKDATA c...
155
  		ret = generic_ptrace_peekdata(child, addr, data);
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
156
157
158
  		break;
  
  	case PTRACE_PEEKUSR:
9f29b8fb4   Namhyung Kim   ptrace: cleanup a...
159
  		ret = ptrace_read_user(child, addr, datap);
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
160
161
162
163
164
  		break;
  
  	/* Write the word in data at location addr */
  	case PTRACE_POKETEXT:
  	case PTRACE_POKEDATA:
f284ce726   Alexey Dobriyan   PTRACE_POKEDATA c...
165
  		ret = generic_ptrace_pokedata(child, addr, data);
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
166
167
168
169
170
  		break;
  
  	case PTRACE_POKEUSR:
  		ret = ptrace_write_user(child, addr, data);
  		break;
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
171
  	case PTRACE_GETREGS:
9f29b8fb4   Namhyung Kim   ptrace: cleanup a...
172
  		ret = ptrace_getregs(child, datap);
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
173
174
175
  		break;
  
  	case PTRACE_SETREGS:
9f29b8fb4   Namhyung Kim   ptrace: cleanup a...
176
  		ret = ptrace_setregs(child, datap);
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
177
178
179
180
181
182
  		break;
  
  	default:
  		ret = ptrace_request(child, request, addr, data);
  		break;
  	}
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
183
184
185
186
187
  	return ret;
  }
  
  asmlinkage void syscall_trace(void)
  {
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
188
189
190
191
  	if (!test_thread_flag(TIF_SYSCALL_TRACE))
  		return;
  	if (!(current->ptrace & PT_PTRACED))
  		return;
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
  	/* The 0x80 provides a way for the tracing parent to
  	 * distinguish between a syscall stop and SIGTRAP delivery */
  	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
  				 ? 0x80 : 0));
  
  	/*
  	 * this isn't the same as continuing with a signal, but it
  	 * will do for normal use.  strace only continues with a
  	 * signal if the stopping signal is not SIGTRAP.  -brl
  	 */
  	if (current->exit_code) {
  		pr_debug("syscall_trace: sending signal %d to PID %u
  ",
  			 current->exit_code, current->pid);
  		send_sig(current->exit_code, current, 1);
  		current->exit_code = 0;
  	}
  }
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
210
  /*
2507bc133   Haavard Skinnemoen   [AVR32] Follow th...
211
212
213
214
215
216
217
218
219
220
221
222
223
   * debug_trampoline() is an assembly stub which will store all user
   * registers on the stack and execute a breakpoint instruction.
   *
   * If we single-step into an exception handler which runs with
   * interrupts disabled the whole time so it doesn't have to check for
   * pending work, its return address will be modified so that it ends
   * up returning to debug_trampoline.
   *
   * If the exception handler decides to store the user context and
   * enable interrupts after all, it will restore the original return
   * address and status register value. Before it returns, it will
   * notice that TIF_BREAKPOINT is set and execute a breakpoint
   * instruction.
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
224
   */
2507bc133   Haavard Skinnemoen   [AVR32] Follow th...
225
  extern void debug_trampoline(void);
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
226

2507bc133   Haavard Skinnemoen   [AVR32] Follow th...
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
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
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
  asmlinkage struct pt_regs *do_debug(struct pt_regs *regs)
  {
  	struct thread_info	*ti;
  	unsigned long		trampoline_addr;
  	u32			status;
  	u32			ctrl;
  	int			code;
  
  	status = ocd_read(DS);
  	ti = current_thread_info();
  	code = TRAP_BRKPT;
  
  	pr_debug("do_debug: status=0x%08x PC=0x%08lx SR=0x%08lx tif=0x%08lx
  ",
  			status, regs->pc, regs->sr, ti->flags);
  
  	if (!user_mode(regs)) {
  		unsigned long	die_val = DIE_BREAKPOINT;
  
  		if (status & (1 << OCD_DS_SSS_BIT))
  			die_val = DIE_SSTEP;
  
  		if (notify_die(die_val, "ptrace", regs, 0, 0, SIGTRAP)
  				== NOTIFY_STOP)
  			return regs;
  
  		if ((status & (1 << OCD_DS_SWB_BIT))
  				&& test_and_clear_ti_thread_flag(
  					ti, TIF_BREAKPOINT)) {
  			/*
  			 * Explicit breakpoint from trampoline or
  			 * exception/syscall/interrupt handler.
  			 *
  			 * The real saved regs are on the stack right
  			 * after the ones we saved on entry.
  			 */
  			regs++;
  			pr_debug("  -> TIF_BREAKPOINT done, adjusted regs:"
  					"PC=0x%08lx SR=0x%08lx
  ",
  					regs->pc, regs->sr);
  			BUG_ON(!user_mode(regs));
  
  			if (test_thread_flag(TIF_SINGLE_STEP)) {
  				pr_debug("Going to do single step...
  ");
  				return regs;
  			}
  
  			/*
  			 * No TIF_SINGLE_STEP means we're done
  			 * stepping over a syscall. Do the trap now.
  			 */
  			code = TRAP_TRACE;
  		} else if ((status & (1 << OCD_DS_SSS_BIT))
  				&& test_ti_thread_flag(ti, TIF_SINGLE_STEP)) {
  
  			pr_debug("Stepped into something, "
  					"setting TIF_BREAKPOINT...
  ");
  			set_ti_thread_flag(ti, TIF_BREAKPOINT);
  
  			/*
  			 * We stepped into an exception, interrupt or
  			 * syscall handler. Some exception handlers
  			 * don't check for pending work, so we need to
  			 * set up a trampoline just in case.
  			 *
  			 * The exception entry code will undo the
  			 * trampoline stuff if it does a full context
  			 * save (which also means that it'll check for
  			 * pending work later.)
  			 */
  			if ((regs->sr & MODE_MASK) == MODE_EXCEPTION) {
  				trampoline_addr
  					= (unsigned long)&debug_trampoline;
  
  				pr_debug("Setting up trampoline...
  ");
  				ti->rar_saved = sysreg_read(RAR_EX);
  				ti->rsr_saved = sysreg_read(RSR_EX);
  				sysreg_write(RAR_EX, trampoline_addr);
  				sysreg_write(RSR_EX, (MODE_EXCEPTION
  							| SR_EM | SR_GM));
  				BUG_ON(ti->rsr_saved & MODE_MASK);
  			}
  
  			/*
  			 * If we stepped into a system call, we
  			 * shouldn't do a single step after we return
  			 * since the return address is right after the
  			 * "scall" instruction we were told to step
  			 * over.
  			 */
  			if ((regs->sr & MODE_MASK) == MODE_SUPERVISOR) {
  				pr_debug("Supervisor; no single step
  ");
  				clear_ti_thread_flag(ti, TIF_SINGLE_STEP);
  			}
  
  			ctrl = ocd_read(DC);
  			ctrl &= ~(1 << OCD_DC_SS_BIT);
  			ocd_write(DC, ctrl);
  
  			return regs;
  		} else {
  			printk(KERN_ERR "Unexpected OCD_DS value: 0x%08x
  ",
  					status);
  			printk(KERN_ERR "Thread flags: 0x%08lx
  ", ti->flags);
  			die("Unhandled debug trap in kernel mode",
  					regs, SIGTRAP);
  		}
  	} else if (status & (1 << OCD_DS_SSS_BIT)) {
  		/* Single step in user mode */
  		code = TRAP_TRACE;
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
344

2507bc133   Haavard Skinnemoen   [AVR32] Follow th...
345
346
347
  		ctrl = ocd_read(DC);
  		ctrl &= ~(1 << OCD_DC_SS_BIT);
  		ocd_write(DC, ctrl);
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
348
  	}
2507bc133   Haavard Skinnemoen   [AVR32] Follow th...
349
350
351
  	pr_debug("Sending SIGTRAP: code=%d PC=0x%08lx SR=0x%08lx
  ",
  			code, regs->pc, regs->sr);
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
352

2507bc133   Haavard Skinnemoen   [AVR32] Follow th...
353
354
355
356
  	clear_thread_flag(TIF_SINGLE_STEP);
  	_exception(SIGTRAP, regs, code, instruction_pointer(regs));
  
  	return regs;
5f97f7f94   Haavard Skinnemoen   [PATCH] avr32 arc...
357
  }