函数源码 |
Source File:arch\x86\kernel\traps.c |
Create Date:2022-07-27 08:31:23 |
首页 | Copyright©Brick |
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 | /* * Our handling of the processor debug registers is non-trivial. * We do not clear them on entry and exit from the kernel. Therefore * it is possible to get a watchpoint trap here from inside the kernel. * However, the code in ./ptrace.c has ensured that the user can * only set watchpoints on userspace addresses. Therefore the in-kernel * watchpoint trap can only occur in code which is reading/writing * from user space. Such code must not hold kernel locks (since it * can equally take a page fault), therefore it is safe to call * force_sig_info even though that claims and releases locks. * * Code in ./signal.c ensures that the debug control register * is restored before we deliver any signal, and therefore that * user code runs with the correct debug control register even though * we clear it here. * * Being careful here means that we don't have to be as careful in a * lot of more complicated places (task switching can be a bit lazy * about restoring all the debug state, and ptrace doesn't have to * find every occurrence of the TF bit that could be saved away even * by user code) * * May run on IST stack. */ dotraplinkage void do_debug( struct pt_regs *regs, long error_code) { struct task_struct *tsk = current; int user_icebp = 0; unsigned long dr6; int si_code; ist_enter(regs); get_debugreg(dr6, 6); /* * The Intel SDM says: * * Certain debug exceptions may clear bits 0-3. The remaining * contents of the DR6 register are never cleared by the * processor. To avoid confusion in identifying debug * exceptions, debug handlers should clear the register before * returning to the interrupted task. * * Keep it simple: clear DR6 immediately. */ set_debugreg(0, 6); /* Filter out all the reserved bits which are preset to 1 */ dr6 &= ~DR6_RESERVED; /* * The SDM says "The processor clears the BTF flag when it * generates a debug exception." Clear TIF_BLOCKSTEP to keep * TIF_BLOCKSTEP in sync with the hardware BTF flag. */ clear_tsk_thread_flag(tsk, TIF_BLOCKSTEP); if (unlikely(!user_mode(regs) && (dr6 & DR_STEP) && is_sysenter_singlestep(regs))) { dr6 &= ~DR_STEP; if (!dr6) goto exit ; /* * else we might have gotten a single-step trap and hit a * watchpoint at the same time, in which case we should fall * through and handle the watchpoint. */ } /* * If dr6 has no reason to give us about the origin of this trap, * then it's very likely the result of an icebp/int01 trap. * User wants a sigtrap for that. */ if (!dr6 && user_mode(regs)) user_icebp = 1; /* Store the virtualized DR6 value */ tsk-> thread .debugreg6 = dr6; #ifdef CONFIG_KPROBES if (kprobe_debug_handler(regs)) goto exit ; #endif if (notify_die(DIE_DEBUG, "debug" , regs, ( long )&dr6, error_code, SIGTRAP) == NOTIFY_STOP) goto exit ; /* * Let others (NMI) know that the debug stack is in use * as we may switch to the interrupt stack. */ debug_stack_usage_inc(); /* It's safe to allow irq's after DR6 has been saved */ cond_local_irq_enable(regs); if (v8086_mode(regs)) { handle_vm86_trap(( struct kernel_vm86_regs *) regs, error_code, X86_TRAP_DB); cond_local_irq_disable(regs); debug_stack_usage_dec(); goto exit ; } if (WARN_ON_ONCE((dr6 & DR_STEP) && !user_mode(regs))) { /* * Historical junk that used to handle SYSENTER single-stepping. * This should be unreachable now. If we survive for a while * without anyone hitting this warning, we'll turn this into * an oops. */ tsk-> thread .debugreg6 &= ~DR_STEP; set_tsk_thread_flag(tsk, TIF_SINGLESTEP); regs->flags &= ~X86_EFLAGS_TF; } si_code = get_si_code(tsk-> thread .debugreg6); if (tsk-> thread .debugreg6 & (DR_STEP | DR_TRAP_BITS) || user_icebp) send_sigtrap(regs, error_code, si_code); cond_local_irq_disable(regs); debug_stack_usage_dec(); exit : ist_exit(regs); } |