为什么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) detach
或 quit
).
如果您发出 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)
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) detach
或 quit
).
如果您发出 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)