我正在尝试调试一个程序,该程序经常导致GDB停止并在不处于断点时显示SIGTRAP。加载动态库和其他普通的东西时会发生这种情况。在我的断点最终被击中之前,有大约1000个发生,所以我手动“继续”所有这些无关的SIGTRAP是不可行的。但是如果我使用命令handle SIGTRAP nostop noprint
,那么GDB将不会停在我的断点处。
似乎必须有一种方法来教育GDB,以便它了解哪个SIGTRAP适合停止,哪个不利于停止。很明显,GDB知道它是否处于断点,因为输出非常可靠地不同:在断点处,它提到“断点”并显示断点号 - 但在任何其他SIGTRAP中,它只是说“SIGTRAP”。所以不是打印关于SIGTRAP的消息,我真的很喜欢GDB对自己说,“哇,这是一个SIGTRAP,这里没有断点 - 看着我,我要停下来打印一个完全破坏调试会话的无用的SIGTRAP消息!我只是静静地继续?“如果有人有办法,请告诉我。
答案 0 :(得分:4)
您可以设置catchpoints以捕获SIGTRAP信号并添加命令以决定是继续还是停止。在此处理程序中,您可以检查convenience variables,例如$_siginfo
,以了解信号的原因。
特别感兴趣的是$_siginfo.si_code
,其值取决于所传递的信号。 sigaction(2) Linux手册页描述了确切的关系。您可以通过编译程序或查找标题(在我的系统上使用标题SI_USER
)来查找SI_KERNEL
,/usr/include/bits/siginfo.h
等代码的数值。我遇到的一些值是:
SI_USER
SI_KERNEL
TRAP_TRACE
掌握了这些信息,这里有一个抓住SIGTRAP并打印原因的例子,然后继续:
catch signal SIGTRAP
commands
p $_siginfo.si_code
c
end
# Set another breakpoint for testing
break sleep
现在考虑这个睡眠时间为5秒的测试程序,然后在x86(-64)上触发调试陷阱:
#include <unistd.h>
int main(void) {
for (;;) {
sleep(5);
asm("int3");
}
return 0;
}
此程序一直在gdb
行停止int3
,因为信号被捕获(si_code
恰好是0x80,SI_KERNEL
),但随后指令再次重复。因此,要跳过此指令,必须递增程序计数器($pc
)。完成后,我了解了有关SIGTRAP
和si_code
的信息:
SI_KERNEL
)触发SIGTRAP。TRAP_TRACE
)的SIGTRAP(由于SIGTRAP
的抓点)。int3
指令使用代码128触发SIGTRAP。因此,您需要一些区分指令。以下是跳过int3
陷阱但仍保持断点正常的最终GDB命令:
catch signal SIGTRAP
commands
silent # do not print catchpoint hits
# ignore the int3 instruction (this address was looked up at
# the tracepoint using print $pc)
if $pc == 0x400568
set $pc++ # skip int3
c
end
# Ignore TRAP_TRACE that is used for breakpoints
if $_siginfo.si_code == 2
c
end
end
最后一点:SIGTRAP由调试器在内部使用,上面的内容可能过多。这是在Arch Linux上使用GDB 7.10进行测试的。