现象
通过gdb att $keepalived_pid发起对当前运行keepalived的调试;
在放行keepalived继续执行后,想通过Ctrl+C按键中断执行,观察下被调试程序的当前内部状态,
 但是,在终端输入Ctrl+C后,导致keepalived被调试进程退出。
gdb无法对keepalived进行正常的调试交互!
结论先行
- gdb与- inferior process之间通过- ptrace系统调用,以及对- signal信号的拦截、传递进行调试交互过程
- 由终端触发的signal会首先被Kernel路由到inferior process,然后再被gdb截获
- Linux Kernel针对- inferior process信号存在特别的路由机制,会导致某些应用使用了特别信号捕获机制,例如,- sigwait or signalfd,并处理了- SIGINT信号,则不能被- gdb正常调试
缘由
以前就了解到,如果被调试程序使用到类似sigwait特殊的信号捕捉机制,将会导致gdb调试程序遇到麻烦,特别是无法正常使用Ctrl+C按键,中断暂停被调试程序,进行正常的交互操作。
最近遇到keepalived一些问题, 就想用调试的方法看看它的运行时逻辑,在这时就遭遇了现象一样的调试失败。
先搜索了下keepalived源码,并无sigwait的使用过程,因为以前看那篇介绍比较粗,不知道除了sigwait使用方式外,还有signalfd使用方式,也会导致GDB调试遭遇类似问题。
 而且,当时觉得keepalived作为比较出名的开源软件,应该不会不支持被调试,所以,并没有在第一时间发现原因。
分析
采用了分掘挖进的方法:
- 用不同的keepalived版本
- 用不同的linux部署环境、不同的gdb版本
来分析、验证这个问题,结果发现表象却出奇的一致!
最后,懒得继续研究下去其中到底为什么了,就向keepalived社区提出了Keeppalived不能被正常调试的issue。
社区解决方案
keepalived社区称之为Linux Kernel signal bug,但Linux社区保持这样的信号处理特性,有其原因。
最终,
keepalived社区用新增启动参数项--ignore-sigint来解决这个问题。
图解

 
参考
- Keeppalived不能被正常调试的issue
- 社区新增–ignore-sigint option的commit
- E文 Linux信号路由特殊机制导致GDB正常Ctrl+C却调试失败
- E文 调试的信号传递过程
- E文 GNU GDB 信号处理相关命令