signal(7)手册页说明无法捕获,阻止或忽略 SIGKILL 。但我刚观察到,在使用GDB附加到进程后,我无法再将 SIGKILL 发送到该进程(类似地,其他信号也无法传递)。但在我分离并退出GDB之后, SIGKILL 照常交付。
在我看来,GDB在附加时阻止了该信号(代表tracee),并在分离时解锁了它。但是,ptrace(2)手册页说:
在跟踪时,即使信号被忽略,每次传送信号时,tracee都会停止。 (例外情况是 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...
仅供参考,我在uname -r
使用CentOS-6u3和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)
。一台旧机......
任何想法都将受到赞赏; - )