函数源码

Linux Kernel

v5.5.9

Brick Technologies Co., Ltd

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);
}