aboutsummaryrefslogtreecommitdiffstats
path: root/arch/avr32/kernel/ptrace.c
diff options
context:
space:
mode:
authorHaavard Skinnemoen <hskinnemoen@atmel.com>2007-11-28 09:04:01 -0500
committerHaavard Skinnemoen <hskinnemoen@atmel.com>2007-12-07 08:54:46 -0500
commit2507bc1338e43eadfef5b604d2c47e4f8180718f (patch)
tree4bc3c14114ba96efb8e9e4f2c0925fb92b669a19 /arch/avr32/kernel/ptrace.c
parent8dfe8f29cd371affcc3c6b35658dc4bd95ee7b61 (diff)
[AVR32] Follow the rules when dealing with the OCD system
The current debug trap handling code does a number of things that are illegal according to the AVR32 Architecture manual. Most importantly, it may try to schedule from Debug Mode, thus clearing the D bit, which can lead to "undefined behaviour". It seems like this works in most cases, but several people have observed somewhat unstable behaviour when debugging programs, including soft lockups. So there's definitely something which is not right with the existing code. The new code will never schedule from Debug mode, it will always exit Debug mode with a "retd" instruction, and if something not running in Debug mode needs to do something debug-related (like doing a single step), it will enter debug mode through a "breakpoint" instruction. The monitor code will then return directly to user space, bypassing its own saved registers if necessary (since we don't actually care about the trapped context, only the one that came before.) This adds three instructions to the common exception handling code, including one branch. It does not touch super-hot paths like the TLB miss handler. Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
Diffstat (limited to 'arch/avr32/kernel/ptrace.c')
-rw-r--r--arch/avr32/kernel/ptrace.c271
1 files changed, 155 insertions, 116 deletions
diff --git a/arch/avr32/kernel/ptrace.c b/arch/avr32/kernel/ptrace.c
index 0de9a6eeb5bb..002369e44093 100644
--- a/arch/avr32/kernel/ptrace.c
+++ b/arch/avr32/kernel/ptrace.c
@@ -30,20 +30,22 @@ static struct pt_regs *get_user_regs(struct task_struct *tsk)
30 30
31static void ptrace_single_step(struct task_struct *tsk) 31static void ptrace_single_step(struct task_struct *tsk)
32{ 32{
33 pr_debug("ptrace_single_step: pid=%u, SR=0x%08lx\n", 33 pr_debug("ptrace_single_step: pid=%u, PC=0x%08lx, SR=0x%08lx\n",
34 tsk->pid, tsk->thread.cpu_context.sr); 34 tsk->pid, task_pt_regs(tsk)->pc, task_pt_regs(tsk)->sr);
35 if (!(tsk->thread.cpu_context.sr & SR_D)) {
36 /*
37 * Set a breakpoint at the current pc to force the
38 * process into debug mode. The syscall/exception
39 * exit code will set a breakpoint at the return
40 * address when this flag is set.
41 */
42 pr_debug("ptrace_single_step: Setting TIF_BREAKPOINT\n");
43 set_tsk_thread_flag(tsk, TIF_BREAKPOINT);
44 }
45 35
46 /* The monitor code will do the actual step for us */ 36 /*
37 * We can't schedule in Debug mode, so when TIF_BREAKPOINT is
38 * set, the system call or exception handler will do a
39 * breakpoint to enter monitor mode before returning to
40 * userspace.
41 *
42 * The monitor code will then notice that TIF_SINGLE_STEP is
43 * set and return to userspace with single stepping enabled.
44 * The CPU will then enter monitor mode again after exactly
45 * one instruction has been executed, and the monitor code
46 * will then send a SIGTRAP to the process.
47 */
48 set_tsk_thread_flag(tsk, TIF_BREAKPOINT);
47 set_tsk_thread_flag(tsk, TIF_SINGLE_STEP); 49 set_tsk_thread_flag(tsk, TIF_SINGLE_STEP);
48} 50}
49 51
@@ -55,23 +57,7 @@ static void ptrace_single_step(struct task_struct *tsk)
55void ptrace_disable(struct task_struct *child) 57void ptrace_disable(struct task_struct *child)
56{ 58{
57 clear_tsk_thread_flag(child, TIF_SINGLE_STEP); 59 clear_tsk_thread_flag(child, TIF_SINGLE_STEP);
58} 60 clear_tsk_thread_flag(child, TIF_BREAKPOINT);
59
60/*
61 * Handle hitting a breakpoint
62 */
63static void ptrace_break(struct task_struct *tsk, struct pt_regs *regs)
64{
65 siginfo_t info;
66
67 info.si_signo = SIGTRAP;
68 info.si_errno = 0;
69 info.si_code = TRAP_BRKPT;
70 info.si_addr = (void __user *)instruction_pointer(regs);
71
72 pr_debug("ptrace_break: Sending SIGTRAP to PID %u (pc = 0x%p)\n",
73 tsk->pid, info.si_addr);
74 force_sig_info(SIGTRAP, &info, tsk);
75} 61}
76 62
77/* 63/*
@@ -84,9 +70,6 @@ static int ptrace_read_user(struct task_struct *tsk, unsigned long offset,
84 unsigned long *regs; 70 unsigned long *regs;
85 unsigned long value; 71 unsigned long value;
86 72
87 pr_debug("ptrace_read_user(%p, %#lx, %p)\n",
88 tsk, offset, data);
89
90 if (offset & 3 || offset >= sizeof(struct user)) { 73 if (offset & 3 || offset >= sizeof(struct user)) {
91 printk("ptrace_read_user: invalid offset 0x%08lx\n", offset); 74 printk("ptrace_read_user: invalid offset 0x%08lx\n", offset);
92 return -EIO; 75 return -EIO;
@@ -98,6 +81,9 @@ static int ptrace_read_user(struct task_struct *tsk, unsigned long offset,
98 if (offset < sizeof(struct pt_regs)) 81 if (offset < sizeof(struct pt_regs))
99 value = regs[offset / sizeof(regs[0])]; 82 value = regs[offset / sizeof(regs[0])];
100 83
84 pr_debug("ptrace_read_user(%s[%u], %#lx, %p) -> %#lx\n",
85 tsk->comm, tsk->pid, offset, data, value);
86
101 return put_user(value, data); 87 return put_user(value, data);
102} 88}
103 89
@@ -111,8 +97,11 @@ static int ptrace_write_user(struct task_struct *tsk, unsigned long offset,
111{ 97{
112 unsigned long *regs; 98 unsigned long *regs;
113 99
100 pr_debug("ptrace_write_user(%s[%u], %#lx, %#lx)\n",
101 tsk->comm, tsk->pid, offset, value);
102
114 if (offset & 3 || offset >= sizeof(struct user)) { 103 if (offset & 3 || offset >= sizeof(struct user)) {
115 printk("ptrace_write_user: invalid offset 0x%08lx\n", offset); 104 pr_debug(" invalid offset 0x%08lx\n", offset);
116 return -EIO; 105 return -EIO;
117 } 106 }
118 107
@@ -155,9 +144,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
155{ 144{
156 int ret; 145 int ret;
157 146
158 pr_debug("arch_ptrace(%ld, %d, %#lx, %#lx)\n",
159 request, child->pid, addr, data);
160
161 pr_debug("ptrace: Enabling monitor mode...\n"); 147 pr_debug("ptrace: Enabling monitor mode...\n");
162 ocd_write(DC, ocd_read(DC) | (1 << OCD_DC_MM_BIT) 148 ocd_write(DC, ocd_read(DC) | (1 << OCD_DC_MM_BIT)
163 | (1 << OCD_DC_DBE_BIT)); 149 | (1 << OCD_DC_DBE_BIT));
@@ -241,20 +227,16 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
241 break; 227 break;
242 } 228 }
243 229
244 pr_debug("sys_ptrace returning %d (DC = 0x%08lx)\n",
245 ret, ocd_read(DC));
246 return ret; 230 return ret;
247} 231}
248 232
249asmlinkage void syscall_trace(void) 233asmlinkage void syscall_trace(void)
250{ 234{
251 pr_debug("syscall_trace called\n");
252 if (!test_thread_flag(TIF_SYSCALL_TRACE)) 235 if (!test_thread_flag(TIF_SYSCALL_TRACE))
253 return; 236 return;
254 if (!(current->ptrace & PT_PTRACED)) 237 if (!(current->ptrace & PT_PTRACED))
255 return; 238 return;
256 239
257 pr_debug("syscall_trace: notifying parent\n");
258 /* The 0x80 provides a way for the tracing parent to 240 /* The 0x80 provides a way for the tracing parent to
259 * distinguish between a syscall stop and SIGTRAP delivery */ 241 * distinguish between a syscall stop and SIGTRAP delivery */
260 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) 242 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
@@ -273,86 +255,143 @@ asmlinkage void syscall_trace(void)
273 } 255 }
274} 256}
275 257
276asmlinkage void do_debug_priv(struct pt_regs *regs)
277{
278 unsigned long dc, ds;
279 unsigned long die_val;
280
281 ds = ocd_read(DS);
282
283 pr_debug("do_debug_priv: pc = %08lx, ds = %08lx\n", regs->pc, ds);
284
285 if (ds & (1 << OCD_DS_SSS_BIT))
286 die_val = DIE_SSTEP;
287 else
288 die_val = DIE_BREAKPOINT;
289
290 if (notify_die(die_val, "ptrace", regs, 0, 0, SIGTRAP) == NOTIFY_STOP)
291 return;
292
293 if (likely(ds & (1 << OCD_DS_SSS_BIT))) {
294 extern void itlb_miss(void);
295 extern void tlb_miss_common(void);
296 struct thread_info *ti;
297
298 dc = ocd_read(DC);
299 dc &= ~(1 << OCD_DC_SS_BIT);
300 ocd_write(DC, dc);
301
302 ti = current_thread_info();
303 set_ti_thread_flag(ti, TIF_BREAKPOINT);
304
305 /* The TLB miss handlers don't check thread flags */
306 if ((regs->pc >= (unsigned long)&itlb_miss)
307 && (regs->pc <= (unsigned long)&tlb_miss_common)) {
308 ocd_write(BWA2A, sysreg_read(RAR_EX));
309 ocd_write(BWC2A, 0x40000001 | (get_asid() << 1));
310 }
311
312 /*
313 * If we're running in supervisor mode, the breakpoint
314 * will take us where we want directly, no need to
315 * single step.
316 */
317 if ((regs->sr & MODE_MASK) != MODE_SUPERVISOR)
318 set_ti_thread_flag(ti, TIF_SINGLE_STEP);
319 } else {
320 panic("Unable to handle debug trap at pc = %08lx\n",
321 regs->pc);
322 }
323}
324
325/* 258/*
326 * Handle breakpoints, single steps and other debuggy things. To keep 259 * debug_trampoline() is an assembly stub which will store all user
327 * things simple initially, we run with interrupts and exceptions 260 * registers on the stack and execute a breakpoint instruction.
328 * disabled all the time. 261 *
262 * If we single-step into an exception handler which runs with
263 * interrupts disabled the whole time so it doesn't have to check for
264 * pending work, its return address will be modified so that it ends
265 * up returning to debug_trampoline.
266 *
267 * If the exception handler decides to store the user context and
268 * enable interrupts after all, it will restore the original return
269 * address and status register value. Before it returns, it will
270 * notice that TIF_BREAKPOINT is set and execute a breakpoint
271 * instruction.
329 */ 272 */
330asmlinkage void do_debug(struct pt_regs *regs) 273extern void debug_trampoline(void);
331{
332 unsigned long dc, ds;
333 274
334 ds = ocd_read(DS); 275asmlinkage struct pt_regs *do_debug(struct pt_regs *regs)
335 pr_debug("do_debug: pc = %08lx, ds = %08lx\n", regs->pc, ds); 276{
277 struct thread_info *ti;
278 unsigned long trampoline_addr;
279 u32 status;
280 u32 ctrl;
281 int code;
282
283 status = ocd_read(DS);
284 ti = current_thread_info();
285 code = TRAP_BRKPT;
286
287 pr_debug("do_debug: status=0x%08x PC=0x%08lx SR=0x%08lx tif=0x%08lx\n",
288 status, regs->pc, regs->sr, ti->flags);
289
290 if (!user_mode(regs)) {
291 unsigned long die_val = DIE_BREAKPOINT;
292
293 if (status & (1 << OCD_DS_SSS_BIT))
294 die_val = DIE_SSTEP;
295
296 if (notify_die(die_val, "ptrace", regs, 0, 0, SIGTRAP)
297 == NOTIFY_STOP)
298 return regs;
299
300 if ((status & (1 << OCD_DS_SWB_BIT))
301 && test_and_clear_ti_thread_flag(
302 ti, TIF_BREAKPOINT)) {
303 /*
304 * Explicit breakpoint from trampoline or
305 * exception/syscall/interrupt handler.
306 *
307 * The real saved regs are on the stack right
308 * after the ones we saved on entry.
309 */
310 regs++;
311 pr_debug(" -> TIF_BREAKPOINT done, adjusted regs:"
312 "PC=0x%08lx SR=0x%08lx\n",
313 regs->pc, regs->sr);
314 BUG_ON(!user_mode(regs));
315
316 if (test_thread_flag(TIF_SINGLE_STEP)) {
317 pr_debug("Going to do single step...\n");
318 return regs;
319 }
320
321 /*
322 * No TIF_SINGLE_STEP means we're done
323 * stepping over a syscall. Do the trap now.
324 */
325 code = TRAP_TRACE;
326 } else if ((status & (1 << OCD_DS_SSS_BIT))
327 && test_ti_thread_flag(ti, TIF_SINGLE_STEP)) {
328
329 pr_debug("Stepped into something, "
330 "setting TIF_BREAKPOINT...\n");
331 set_ti_thread_flag(ti, TIF_BREAKPOINT);
332
333 /*
334 * We stepped into an exception, interrupt or
335 * syscall handler. Some exception handlers
336 * don't check for pending work, so we need to
337 * set up a trampoline just in case.
338 *
339 * The exception entry code will undo the
340 * trampoline stuff if it does a full context
341 * save (which also means that it'll check for
342 * pending work later.)
343 */
344 if ((regs->sr & MODE_MASK) == MODE_EXCEPTION) {
345 trampoline_addr
346 = (unsigned long)&debug_trampoline;
347
348 pr_debug("Setting up trampoline...\n");
349 ti->rar_saved = sysreg_read(RAR_EX);
350 ti->rsr_saved = sysreg_read(RSR_EX);
351 sysreg_write(RAR_EX, trampoline_addr);
352 sysreg_write(RSR_EX, (MODE_EXCEPTION
353 | SR_EM | SR_GM));
354 BUG_ON(ti->rsr_saved & MODE_MASK);
355 }
356
357 /*
358 * If we stepped into a system call, we
359 * shouldn't do a single step after we return
360 * since the return address is right after the
361 * "scall" instruction we were told to step
362 * over.
363 */
364 if ((regs->sr & MODE_MASK) == MODE_SUPERVISOR) {
365 pr_debug("Supervisor; no single step\n");
366 clear_ti_thread_flag(ti, TIF_SINGLE_STEP);
367 }
368
369 ctrl = ocd_read(DC);
370 ctrl &= ~(1 << OCD_DC_SS_BIT);
371 ocd_write(DC, ctrl);
372
373 return regs;
374 } else {
375 printk(KERN_ERR "Unexpected OCD_DS value: 0x%08x\n",
376 status);
377 printk(KERN_ERR "Thread flags: 0x%08lx\n", ti->flags);
378 die("Unhandled debug trap in kernel mode",
379 regs, SIGTRAP);
380 }
381 } else if (status & (1 << OCD_DS_SSS_BIT)) {
382 /* Single step in user mode */
383 code = TRAP_TRACE;
336 384
337 if (test_thread_flag(TIF_BREAKPOINT)) { 385 ctrl = ocd_read(DC);
338 pr_debug("TIF_BREAKPOINT set\n"); 386 ctrl &= ~(1 << OCD_DC_SS_BIT);
339 /* We're taking care of it */ 387 ocd_write(DC, ctrl);
340 clear_thread_flag(TIF_BREAKPOINT);
341 ocd_write(BWC2A, 0);
342 } 388 }
343 389
344 if (test_thread_flag(TIF_SINGLE_STEP)) { 390 pr_debug("Sending SIGTRAP: code=%d PC=0x%08lx SR=0x%08lx\n",
345 pr_debug("TIF_SINGLE_STEP set, ds = 0x%08lx\n", ds); 391 code, regs->pc, regs->sr);
346 if (ds & (1 << OCD_DS_SSS_BIT)) {
347 dc = ocd_read(DC);
348 dc &= ~(1 << OCD_DC_SS_BIT);
349 ocd_write(DC, dc);
350 392
351 clear_thread_flag(TIF_SINGLE_STEP); 393 clear_thread_flag(TIF_SINGLE_STEP);
352 ptrace_break(current, regs); 394 _exception(SIGTRAP, regs, code, instruction_pointer(regs));
353 } 395
354 } else { 396 return regs;
355 /* regular breakpoint */
356 ptrace_break(current, regs);
357 }
358} 397}