您可以设置捕获点来捕获 SIGTRAP 信号并添加命令来决定是继续还是停止。在此处理程序中,您可以检查便利变量,例如$_siginfo
信号的原因。
特别有趣的是$_siginfo.si_code
,它的值取决于传递的信号。sigaction(2) Linux 手册页描述了确切的关系。您可以通过编译程序或查看标头(在我的系统上使用标头)来找到这些SI_USER
,等代码的数值。我遇到的一些价值观是:SI_KERNEL
/usr/include/bits/siginfo.h
- 0x00 (0):
SI_USER
- 0x80 (128):
SI_KERNEL
- 0x02 (2):
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
and的信息si_code
:
- 断点使用代码 128 ( ) 触发 SIGTRAP
SI_KERNEL
。
- 继续断点后,将
TRAP_TRACE
收到代码为 2 ( ) 的 SIGTRAP(因为 的捕获点SIGTRAP
)。
- 该
int3
指令使用代码 128 触发 SIGTRAP。因此,您需要一些东西来区分指令。
以下是最终的 GDB 命令,它们跳过了int3
陷阱并仍然保持断点功能:
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 测试的。