为什么GDB在附加到tracee时可以屏蔽tracee的SIGKILL

Why can GDB mask tracee's SIGKILL when attaching to the tracee

signal(7) 手册页说 SIGKILL 不能被捕获、阻止或忽略。但我只是观察到,在使用 GDB 附加到一个进程后,我无法再向该进程发送 SIGKILL(类似地,其他信号也无法传递)。但是在我分离并退出 GDB 之后,SIGKILL 照常交付。

在我看来,GDB 在附加时阻止了该信号(代表被跟踪者),并在分离时解除了阻止。但是,ptrace(2) 手册页说:

While being traced, the tracee will stop each time a signal is delivered, even if the signal is being ignored. (An exception is SIGKILL, which has its usual effect.)

那么为什么它会这样呢? 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)。一台旧机器...

任何想法将不胜感激;-)

$ ##### in shell 1 ##### $ gdb (gdb) attach ${pid} (gdb)

问题是,一旦 GDB 附加到 ${pid},劣质(正在调试)进程 不再 运行 -- 它是 已停止.

内核不会对它做任何事情,直到它继续(使用(gdb) continue命令),或者它不再被跟踪((gdb) detachquit).

如果您发出 continue(在 kill -QUIT 之前或之后),您将看到:

(gdb) c
Continuing.

kill -QUIT $pid 在另一个 shell:

中执行
Program received signal SIGQUIT, Quit.
main (argc=1, argv=0x7ffdcc9c1518) at t.c:35
35      }

(gdb) c
Continuing.
Received signal: 3
signal originate from pid[123419]

kill -KILL 在另一个 window:

中执行
Program terminated with signal SIGKILL, Killed.
The program no longer exists.
(gdb)