1

見てください:

    (gdb) x/x $esp
       0xb720a621:  0x00000000
    (gdb) info register eflags
       eflags         0x200286  [ PF SF IF ID ]
    (gdb) x/5i $pc
    => 0x15a965d <tables+11901>:    popf   
       0x15a965e <tables+11902>:    mov    $0xd7fb0aa3,%ecx
       0x15a9663 <tables+11907>:    ret    $0x849d
       0x15a9666 <tables+11910>:    xor    (%ebx),%esi
       0x15a9668 <tables+11912>:    aam    $0x78
    (gdb) stepi
       0x015a965e in tables () from /usr/local/apache2/modules/libphp5.so
    (gdb) info register eflags
       eflags         0x202 [ IF ]
    (gdb) stepi
       0x015a9663 in tables () from /usr/local/apache2/modules/libphp5.so
    (gdb) info register eflags
       eflags         0x302 [ TF IF ]

次の命令の後にTFが設定される理由がわかりません。

4

1 に答える 1

1

カーネルのバグだと思います。シングルステップの場合、カーネルを設定TFする必要がありますが、ユーザーモードも変更されている可能性がありますTF。これを処理するために、カーネルは誰が設定したかを維持しようとしますTF

    /* Set TF on the kernel stack.. */
    regs->flags |= X86_EFLAGS_TF;

    /*
     * ..but if TF is changed by the instruction we will trace,
     * don't mark it as being "us" that set it, so that we
     * won't clear it by hand later.
     *
     * Note that if we don't actually execute the popf because
     * of a signal arriving right now or suchlike, we will lose
     * track of the fact that it really was "us" that set it.
     */
    if (is_setting_trap_flag(child, regs)) {
            clear_tsk_thread_flag(child, TIF_FORCED_TF);
            return 0;
    }

いくつかのコーナーケースがそれを追跡できなくなる可能性があることを認めていることに注意してください。さらに悪いことis_setting_trap_flagに、命令が変更されるかどうかだけがチェックさTFれ、実際に設定されているかどうかはチェックされません。

    switch (opcode[i]) {
    /* popf and iret */
    case 0x9d: case 0xcf:
            return 1;

そのためTF、クリアされている場合でも、ユーザー設定としてマークされます。カーネルによって次のように設定されている場合は、get_flagsマスクを試みます。TF

    /*
     * If the debugger set TF, hide it from the readout.
     */
    if (test_tsk_thread_flag(task, TIF_FORCED_TF))
            retval &= ~X86_EFLAGS_TF;

誤ってクリアされたためTIF_FORCED_TF、この条件は真ではありません。したがって、TFカーネルによってシングルステップ用に実際に設定された条件がデバッガーに返されます。

is_setting_trap_flagこれは、スタックでフラグの新しい値をチェックし、実際に設定されている1場合にのみ返されるように変更することで修正できると思います。TF

于 2012-12-21T15:02:59.200 に答える