aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/traps.c')
-rw-r--r--arch/x86/kernel/traps.c73
1 files changed, 26 insertions, 47 deletions
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 5204332f475..ae04589a579 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -532,77 +532,56 @@ asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs)
532dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) 532dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
533{ 533{
534 struct task_struct *tsk = current; 534 struct task_struct *tsk = current;
535 unsigned long condition; 535 unsigned long dr6;
536 int si_code; 536 int si_code;
537 537
538 get_debugreg(condition, 6); 538 get_debugreg(dr6, 6);
539 539
540 /* Catch kmemcheck conditions first of all! */ 540 /* Catch kmemcheck conditions first of all! */
541 if (condition & DR_STEP && kmemcheck_trap(regs)) 541 if ((dr6 & DR_STEP) && kmemcheck_trap(regs))
542 return; 542 return;
543 543
544 /* DR6 may or may not be cleared by the CPU */
545 set_debugreg(0, 6);
544 /* 546 /*
545 * The processor cleared BTF, so don't mark that we need it set. 547 * The processor cleared BTF, so don't mark that we need it set.
546 */ 548 */
547 clear_tsk_thread_flag(tsk, TIF_DEBUGCTLMSR); 549 clear_tsk_thread_flag(tsk, TIF_DEBUGCTLMSR);
548 tsk->thread.debugctlmsr = 0; 550 tsk->thread.debugctlmsr = 0;
549 551
550 if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code, 552 /* Store the virtualized DR6 value */
551 SIGTRAP) == NOTIFY_STOP) 553 tsk->thread.debugreg6 = dr6;
554
555 if (notify_die(DIE_DEBUG, "debug", regs, PTR_ERR(&dr6), error_code,
556 SIGTRAP) == NOTIFY_STOP)
552 return; 557 return;
553 558
554 /* It's safe to allow irq's after DR6 has been saved */ 559 /* It's safe to allow irq's after DR6 has been saved */
555 preempt_conditional_sti(regs); 560 preempt_conditional_sti(regs);
556 561
557 /* Mask out spurious debug traps due to lazy DR7 setting */ 562 if (regs->flags & X86_VM_MASK) {
558 if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { 563 handle_vm86_trap((struct kernel_vm86_regs *) regs,
559 if (!tsk->thread.debugreg7) 564 error_code, 1);
560 goto clear_dr7; 565 return;
561 } 566 }
562 567
563#ifdef CONFIG_X86_32
564 if (regs->flags & X86_VM_MASK)
565 goto debug_vm86;
566#endif
567
568 /* Save debug status register where ptrace can see it */
569 tsk->thread.debugreg6 = condition;
570
571 /* 568 /*
572 * Single-stepping through TF: make sure we ignore any events in 569 * Single-stepping through system calls: ignore any exceptions in
573 * kernel space (but re-enable TF when returning to user mode). 570 * kernel space, but re-enable TF when returning to user mode.
571 *
572 * We already checked v86 mode above, so we can check for kernel mode
573 * by just checking the CPL of CS.
574 */ 574 */
575 if (condition & DR_STEP) { 575 if ((dr6 & DR_STEP) && !user_mode(regs)) {
576 if (!user_mode(regs)) 576 tsk->thread.debugreg6 &= ~DR_STEP;
577 goto clear_TF_reenable; 577 set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
578 regs->flags &= ~X86_EFLAGS_TF;
578 } 579 }
579 580 si_code = get_si_code(tsk->thread.debugreg6);
580 si_code = get_si_code(condition); 581 if (tsk->thread.debugreg6 & (DR_STEP | DR_TRAP_BITS))
581 /* Ok, finally something we can handle */ 582 send_sigtrap(tsk, regs, error_code, si_code);
582 send_sigtrap(tsk, regs, error_code, si_code);
583
584 /*
585 * Disable additional traps. They'll be re-enabled when
586 * the signal is delivered.
587 */
588clear_dr7:
589 set_debugreg(0, 7);
590 preempt_conditional_cli(regs); 583 preempt_conditional_cli(regs);
591 return;
592 584
593#ifdef CONFIG_X86_32
594debug_vm86:
595 /* reenable preemption: handle_vm86_trap() might sleep */
596 dec_preempt_count();
597 handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
598 conditional_cli(regs);
599 return;
600#endif
601
602clear_TF_reenable:
603 set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
604 regs->flags &= ~X86_EFLAGS_TF;
605 preempt_conditional_cli(regs);
606 return; 585 return;
607} 586}
608 587