现象
通过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 信号处理相关命令