GDB在Popf后设置陷阱标志(可能有错误?)

GDB在Popf后设置陷阱标志(可能有错误?),gdb,Gdb,看一看: (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>: mo

看一看:

    (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 ]
(gdb)x/x$esp
0xb720a621:0x00000000
(gdb)信息寄存器eflags
eflags 0x200286[PF SF IF ID]
(gdb)x/5i$pc
=>0x15a965d:popf
0x15a965e:mov$0xd7fb0aa3,%ecx
0x15a9663:ret$0x849d
0x15a9666:xor(%ebx),%esi
0x15a9668:aam$0x78
(gdb)stepi
0x015a965e位于/usr/local/apache2/modules/libphp5.so的表()中
(gdb)信息寄存器eflags
eflags 0x202[如果]
(gdb)stepi
0x015a9663位于/usr/local/apache2/modules/libphp5.so的表()中
(gdb)信息寄存器eflags
eflags 0x302[TF IF]

不确定为什么在下一条指令之后设置TF。

我认为这是一个内核错误。当单步执行时,内核必须设置
TF
,但用户模式也可能正在修改
TF
。为了处理这个问题,内核试图维护设置
TF的用户:

/*在内核堆栈上设置TF*/
regs->flags |=X86\u EFLAGS\u TF;
/*
*..但如果TF被指令改变,我们将跟踪,
*不要把它标记为是“我们”设定的,这样我们
*以后不会用手清理的。
*
*请注意,如果我们没有实际执行popf,因为
*如果信号马上到达,我们就输了
*事实上是“我们”决定了这一切。
*/
如果(正在设置陷阱标志(子项、注册表)){
清除线程标志(子级,TIF强制);
返回0;
}
请注意,它甚至承认一些角落的情况可能会使它迷失方向。 更糟糕的是,
is\u setting\u trap\u flag
只检查指令是否会修改
TF
,而不检查指令是否实际设置了它:

开关(操作码[i]){
/*popf和iret*/
案例0x9d:案例0xcf:
返回1;
因此,即使已清除,它也会将
TF
标记为用户设置。在
get_flags
中,如果内核设置了
TF
,它将尝试屏蔽
TF
,如下所示:

/*
*如果调试器设置了TF,则将其从读数中隐藏。
*/
if(测试线程标志(任务,TIF强制)
retval&=~X86个字符集;
由于
TIF_FORCED\u TF
被错误清除,此条件将不为真,因此实际上由内核为单步执行设置的
TF
将返回到调试器


我认为可以通过修改
is\u setting\u trap\u flag
来解决这个问题,这样它就可以检查堆栈中标志的新值,并且只有在
TF
实际被设置时才返回
1

我认为这是一个内核错误。内核在单步执行时必须设置
TF
,但用户模式也可能正在修改
TF。为了处理这个问题,内核会尝试维护谁设置了
TF

/*在内核堆栈上设置TF*/
regs->flags |=X86\u EFLAGS\u TF;
/*
*..但如果TF被指令改变,我们将跟踪,
*不要把它标记为是“我们”设定的,这样我们
*以后不会用手清理的。
*
*请注意,如果我们没有实际执行popf,因为
*如果信号马上到达,我们就输了
*事实上是“我们”决定了这一切。
*/
如果(正在设置陷阱标志(子项、注册表)){
清除线程标志(子级,TIF强制);
返回0;
}
请注意,它甚至承认一些角落的情况可能会使它迷失方向。 更糟糕的是,
is\u setting\u trap\u flag
只检查指令是否会修改
TF
,而不检查指令是否实际设置了它:

开关(操作码[i]){
/*popf和iret*/
案例0x9d:案例0xcf:
返回1;
因此,即使已清除,它也会将
TF
标记为用户设置。在
get_flags
中,如果内核设置了
TF
,它将尝试屏蔽
TF
,如下所示:

/*
*如果调试器设置了TF,则将其从读数中隐藏。
*/
if(测试线程标志(任务,TIF强制)
retval&=~X86个字符集;
由于
TIF_FORCED\u TF
被错误清除,此条件将不为真,因此实际上由内核为单步执行设置的
TF
将返回到调试器

我认为这可以通过修改
is\u setting\u trap\u flag
来解决,这样它就可以检查堆栈中标志的新值,并且只有在
TF
实际被设置时才返回
1