aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/traps.c
diff options
context:
space:
mode:
authorK.Prasad <prasad@linux.vnet.ibm.com>2009-06-01 14:14:08 -0400
committerFrederic Weisbecker <fweisbec@gmail.com>2009-06-02 16:46:58 -0400
commit08d68323d1f0c34452e614263b212ca556dae47f (patch)
treed020110151fe59d1b38eb17f7f40c43301677c81 /arch/x86/kernel/traps.c
parent0067f1297241ea567f2b22a455519752d70fcca9 (diff)
hw-breakpoints: modifying generic debug exception to use thread-specific debug registers
This patch modifies the breakpoint exception handler code to use the new abstract debug register names. [ fweisbec@gmail.com: fix conflict against kmemcheck ] [ Impact: refactor and cleanup x86 debug exception handler ] Original-patch-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: K.Prasad <prasad@linux.vnet.ibm.com> Reviewed-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Diffstat (limited to 'arch/x86/kernel/traps.c')
-rw-r--r--arch/x86/kernel/traps.c69
1 files changed, 24 insertions, 45 deletions
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index a1d288327ff0..de9913247dd0 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -529,73 +529,52 @@ asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs)
529dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) 529dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
530{ 530{
531 struct task_struct *tsk = current; 531 struct task_struct *tsk = current;
532 unsigned long condition; 532 unsigned long dr6;
533 int si_code; 533 int si_code;
534 534
535 get_debugreg(condition, 6); 535 get_debugreg(dr6, 6);
536 536
537 /* DR6 may or may not be cleared by the CPU */
538 set_debugreg(0, 6);
537 /* 539 /*
538 * The processor cleared BTF, so don't mark that we need it set. 540 * The processor cleared BTF, so don't mark that we need it set.
539 */ 541 */
540 clear_tsk_thread_flag(tsk, TIF_DEBUGCTLMSR); 542 clear_tsk_thread_flag(tsk, TIF_DEBUGCTLMSR);
541 tsk->thread.debugctlmsr = 0; 543 tsk->thread.debugctlmsr = 0;
542 544
543 if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code, 545 /* Store the virtualized DR6 value */
546 tsk->thread.debugreg6 = dr6;
547
548 if (notify_die(DIE_DEBUG, "debug", regs, dr6, error_code,
544 SIGTRAP) == NOTIFY_STOP) 549 SIGTRAP) == NOTIFY_STOP)
545 return; 550 return;
546 551
547 /* It's safe to allow irq's after DR6 has been saved */ 552 /* It's safe to allow irq's after DR6 has been saved */
548 preempt_conditional_sti(regs); 553 preempt_conditional_sti(regs);
549 554
550 /* Mask out spurious debug traps due to lazy DR7 setting */ 555 if (regs->flags & X86_VM_MASK) {
551 if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { 556 handle_vm86_trap((struct kernel_vm86_regs *) regs,
552 if (!tsk->thread.debugreg7) 557 error_code, 1);
553 goto clear_dr7; 558 return;
554 } 559 }
555 560
556#ifdef CONFIG_X86_32
557 if (regs->flags & X86_VM_MASK)
558 goto debug_vm86;
559#endif
560
561 /* Save debug status register where ptrace can see it */
562 tsk->thread.debugreg6 = condition;
563
564 /* 561 /*
565 * Single-stepping through TF: make sure we ignore any events in 562 * Single-stepping through system calls: ignore any exceptions in
566 * kernel space (but re-enable TF when returning to user mode). 563 * kernel space, but re-enable TF when returning to user mode.
564 *
565 * We already checked v86 mode above, so we can check for kernel mode
566 * by just checking the CPL of CS.
567 */ 567 */
568 if (condition & DR_STEP) { 568 if ((dr6 & DR_STEP) && !user_mode(regs)) {
569 if (!user_mode(regs)) 569 tsk->thread.debugreg6 &= ~DR_STEP;
570 goto clear_TF_reenable; 570 set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
571 regs->flags &= ~X86_EFLAGS_TF;
571 } 572 }
572 573 si_code = get_si_code(tsk->thread.debugreg6);
573 si_code = get_si_code(condition); 574 if (tsk->thread.debugreg6 & (DR_STEP | DR_TRAP_BITS))
574 /* Ok, finally something we can handle */ 575 send_sigtrap(tsk, regs, error_code, si_code);
575 send_sigtrap(tsk, regs, error_code, si_code);
576
577 /*
578 * Disable additional traps. They'll be re-enabled when
579 * the signal is delivered.
580 */
581clear_dr7:
582 set_debugreg(0, 7);
583 preempt_conditional_cli(regs); 576 preempt_conditional_cli(regs);
584 return;
585 577
586#ifdef CONFIG_X86_32
587debug_vm86:
588 /* reenable preemption: handle_vm86_trap() might sleep */
589 dec_preempt_count();
590 handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
591 conditional_cli(regs);
592 return;
593#endif
594
595clear_TF_reenable:
596 set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
597 regs->flags &= ~X86_EFLAGS_TF;
598 preempt_conditional_cli(regs);
599 return; 578 return;
600} 579}
601 580