0

GDB 正在杀死我的下等人。Inferior 是一个长时间运行(20-30 分钟)的基准测试。GDB和inferior都在我的uid下运行。运行良好一段时间然后我的信号处理程序使用 si_signo = 11、si_errno = 0 和 si_code = 0 的 siginfo_t 实例调用;_sifields._kill.si_pid = ( gdb-pid ),_sifields._kill.si_uid = ( my-uid )。

当 GDB 决定向我的劣质进程发送终止信号时,我读到了这篇文章。GDB在什么情况下会这样做?

这不是 SIGSEGV(尽管 si_signo 会建议它是),因为 si_code 为 0 并且 si_pid 和 si_uid 已设置)。我的劣势是具有自定义信号处理程序的多线程 C++ 应用程序,用于在应用程序遇到我为保护某些内存范围而设置的内存屏障时处理 GPF。当我在 GDB 下运行时,我设置了

handle SIGSEGV noprint

确保 GDB 将与内存屏障相关的 SIGSEGV 信号传递给我的应用程序进行处理。该部分似乎工作正常 - siginfo_t 结构中具有非零 si_code 的 SIGSEGV 得到正确处理(在验证 siginfo->_sifields.si_addr 中的故障地址在受保护的内存范围内之后)。

但是,据我所知,si_code 为零的 SIGSEGV 表明下级正在被杀死,并且覆盖 _sifields._sigfault 字段的 _sifields._kill 字段支持这种解释:GDB 正在杀死我的下级进程。

我只是不明白是什么导致 GDB 这样做。


对此的更新:看起来 GDB 正在向下级发送 SIGSTOP。如果我在失败点查看 $_siginfo,我会看到:

(gdb) p $_siginfo
$2 = {
  si_signo = 5,
  si_errno = 0,
  si_code = 128,
  _sifields = {
    _pad = {0, 0, -1054653696, 57, 97635496, 0, 5344160, 0, 47838328, 0, -154686444, 32767, 47838328, 0, 4514687, 0, 0, 0, 49642032, 0, 50016832, 0, 49599376, 1, 0, 0, 92410096, 0},
    _kill = {
      si_pid = 0,
      si_uid = 0
    },
    _timer = {
      si_tid = 0,
      si_overrun = 0,
      si_sigval = {
        sival_int = -1054653696,
        sival_ptr = 0x39c1234300
      }
    },
    _rt = {
      si_pid = 0,
      si_uid = 0,
      si_sigval = {
        sival_int = -1054653696,
        sival_ptr = 0x39c1234300
      }
    },
    _sigchld = {
      si_pid = 0,
      si_uid = 0,
      si_status = -1054653696,
      si_utime = 419341262248738873,
      si_stime = 22952992424591360
    },
    _sigfault = {
      si_addr = 0x0
    },
    _sigpoll = {
      si_band = 0,
      si_fd = -1054653696
    }
  }
}

但是我的信号处理程序看到了这一点(有点混淆* ——我在洁净室环境中工作):

(gdb) bt
#0  ***SignalHandler (signal=11, sigInfo=0x7fff280083f0, contextInfo=0x7fff280082c0) at ***signal.c:***
...
(gdb) setsig 0x7fff280083f0
[signo=11; code=0; addr=0xbb900007022] ((siginfo_t*) 0x7fff280083f0)
...
(gdb) p *((siginfo_t*) 0x7fff280083f0)
$4 = {
  si_signo = 11,
  si_errno = 0,
  si_code = 0,
  _sifields = {
    _pad = {28706, 3001, -515511096, 32767, -233916640, 32767, -228999566, 32767, 671122824, 32767, -468452105, 1927272, 1, 0, -515510808, 32767, 0, 32767, 37011703, 0, -515511024, 32767, 37011703, 32767, 2, 32767, 1000000000, 0},
    _kill = {
      si_pid = 28706,
      si_uid = 3001
    },
    _timer = {
      si_tid = 28706,
      si_overrun = 3001,
      si_sigval = {
        sival_int = -515511096,
        sival_ptr = 0x7fffe145ecc8
      }
    },
    _rt = {
      si_pid = 28706,
      si_uid = 3001,
      si_sigval = {
        sival_int = -515511096,
        sival_ptr = 0x7fffe145ecc8
      }
    },
    _sigchld = {
      si_pid = 28706,
      si_uid = 3001,
      si_status = -515511096,
      si_utime = 140737254438688,
      si_stime = 140737259355762
    },
    _sigfault = {
      si_addr = 0xbb900007022
    },
    _sigpoll = {
      si_band = 12889196884002,
      si_fd = -515511096
    }
  }
}
(gdb) shell ps -ef | grep gdb
***  28706 28704  0 Jun26 pts/17   00:00:02 /usr/bin/gdb -q ***
(gdb) shell echo $UID
3001

所以我的信号处理程序看到一个 siginfo_t 结构体,si_signo 11 (SIGSEGV)、si_code = 0 (kill)、si_pid = 28706 (gdb) 和 si_user = 3001 (me)。GDB 报告 si_signo = 5 (SIGSTOP) 的 siginfo_t。

可能是劣质进程正在对原始 SIGSTOP 执行一些低级处理,并将其作为终止发送到链上。但这是我不理解/想要消除的原始 SIGSTOP。

我应该补充一点,在开始下级之前我正在设置以下指令(无论是否设置了句柄 SIGSTOP 指令都没有区别):

handle SIGSEGV noprint
handle SIGSTOP nostop print ignore

这是否说明了问题?这是要了我的命。另外,如果这里没有见解,任何人都可以建议其他可能有助于将其发布到的论坛吗?

(gdb) show version
GNU gdb (GDB) Red Hat Enterprise Linux (7.1-29.el6_0.1)
Copyright (C) 2010 Free Software Foundation, Inc.

我在 1.8GHz 16 核/32 线程 Xeon、4x E7520、基于 Nehalem 的服务器上运行它。无论是启用还是禁用超线程,我都会得到相同的结果。

4

2 回答 2

0

我在使用 gdb 7.4 的不同程序上遇到了完全相同的问题。我升级到 gdb 7.9 ---相同的机器和内核版本---并且问题消失了。在另一台机器上,gdb 7.7 也可以工作。我的猜测是该问题已在 gdb 7.5-7.7 中修复。

于 2015-03-10T10:01:16.173 回答
0

在 Linux 下,si_signo = 11表示这是 GDB 传播的SIGSEGV。有关信号编号,请参见signal(7)

尝试:

(gdb) handle SIGSEGV nopass
Signal        Stop  Print   Pass to program Description
SIGSEGV       Yes   Yes     No              Segmentation fault

尝试将您使用sigaction()注册的信号处理函数的第三个参数转换为(ucontext *)并转储 CPU 寄存器。特别是指令指针可以提供一些线索:

#include <ucontext.h>

int my_sigsegv_handler(int signo, siginfo_t *info, void *context)
{
    ucontext *u = (ucontext *)context;
    /* dump u->uc_mtext.gregs[REG_RIP] o REG_EIP */
}

然后将指令指针传递给GDB 中的info addr

要真正了解正在发生的事情,我会尝试确定:

  • 您的进程究竟看到了哪个信号,它是由siginfo_t的si_signo成员指示的SIGSEGV吗?sigaction()注册的信号处理函数的第一个参数是什么?(使用 PTRACE_SETSIGINFO 这两件事不太可能但并非不可能)
  • GDB 要么截获内核发送给你的进程的信号,然后再次注入信号,要么决定自己发送信号。尝试确定哪个。这可以通过在其自身下运行 GDB 并在$rdi == PTRACE_KILL时中断killtkilltgkill和ptrace 来完成(我知道这听起来很耗时)。
于 2013-05-13T16:43:35.933 回答