【问题标题】:Why can GDB mask tracee's SIGKILL when attaching to the tracee为什么GDB在附加到tracee时可以屏蔽tracee的SIGKILL
【发布时间】: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 仍在屏蔽这些信号......

标签: linux gdb signals ptrace


【解决方案1】:

$ ##### 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在另一个窗口中执行:

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

【讨论】:

  • 你知道GDB使用哪个信号来实现控制转移吗?通过控制转移,我的意思是,在被跟踪者执行一个函数并返回之后,会生成哪个信号以便 GDB 可以等待 *() 并再次夺取控制权?虽然很多人声称它不是 SIGTRAP ...
  • @walkerlala 这可能最好作为一个单独的问题提出。我知道,但是这个评论栏太短了;-)
猜你喜欢
  • 1970-01-01
  • 2019-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-22
  • 1970-01-01
相关资源
最近更新 更多