【发布时间】:2017-11-26 09:01:00
【问题描述】:
signal(7) 手册页说 SIGKILL 不能被捕获、阻止或忽略。但我只是观察到,在使用 GDB 附加到进程后,我无法再向该进程发送 SIGKILL (同样,也无法传递其他信号)。但在我分离并退出 GDB 后,SIGKILL 照常交付。
在我看来,GDB 在附加时(代表被跟踪者)阻塞了该信号,并在分离时解除了阻塞。但是,ptrace(2) 手册页说:
在被跟踪时,每次传递信号时,被跟踪者都会停止,即使该信号被忽略。 (一个例外是 SIGKILL,它具有通常的效果。)
那么为什么它会这样呢? GDB 使用了什么技巧?
这是一个简单的演示示例:
1.测试程序
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
/* Simple error handling functions */
#define handle_error_en(en, msg) \
do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
struct sigaction act;
void sighandler(int signum, siginfo_t *info, void *ptr) {
printf("Received signal: %d\n", signum);
printf("signal originate from pid[%d]\n", info->si_pid);
}
int
main(int argc, char *argv[])
{
printf("Pid of the current process: %d\n", getpid());
memset(&act, 0, sizeof(act));
act.sa_sigaction = sighandler;
act.sa_flags = SA_SIGINFO;
sigaction(SIGQUIT, &act, NULL);
while(1) {
;
}
return 0;
}
如果您尝试使用 SIGKILL(即使用kill -KILL ${pid})杀死该程序,它将按预期终止。如果您尝试发送 SIGQUIT(即使用 kill -QUIT ${pid}),那些 printf 语句将按预期执行。但是,如果您在发送信号之前将其与 GDB 连接,则不会发生任何事情:
$ ##### in shell 1 #####
$ gdb
(gdb) attach ${pid}
(gdb)
/* 现在 gdb 已成功附加,在另一个 shell 中:*/
$ #### in shell 2 ####
$ kill -QUIT ${pid} # nothing happen
$ kill -KILL ${pid} # again, nothing happen!
/* 现在 gdb 已分离 */
##### in shell 1 ####
(gdb) quit
/* 进程将收到 SIGKILL */
##### in shell 2 ####
$ Killed # the tracee receive **SIGKILL** eventually...
仅供参考,我使用的是 CentOS-6u3 和 uname -r 结果为 2.6.32_1-16-0-0。我的 GDB 版本是:GNU gdb (GDB) Red Hat Enterprise Linux (7.2-56.el6),我的 GCC 版本是:gcc (GCC) 3.4.6 20060404 (Red Hat 3.4.6-19.el6)。一台老机器……
任何想法将不胜感激;-)
【问题讨论】:
-
“最终”是指在 gdb 分离和 shell 报告进程被杀死之间存在一些延迟吗?
-
我很确定 GDB 没有使用任何技巧。你可能有一个损坏的内核。我怀疑你的结果会在不同的系统上重现。
-
@EmployedRussian 我正在使用 ptrace(2) 来实现与 GDB 类似的功能,但是信号处理变得一团糟,因为每次被跟踪者收到该信号时,它都会中断并且跟踪器会收到通知虚假地......所以我认为 GDB 是 在这里使用了一些技巧。你为什么这么肯定?你能澄清一下吗?
-
@MarkPlotnick 没有延迟。 gdb 分离和 shell 报告“已终止”之间没有延迟。但我没有实际衡量,所以很难说是否有任何延迟......
-
@EmployedRussian 我用 4.4.0 内核(Ubuntu 16.04 LTS)试试这个,结果是一样的,gdb 仍在屏蔽这些信号......