GDB正在扼杀我的劣质流程

时间:2013-05-13 16:16:45

标签: gdb kill-process

GDB正在杀死我的下级。劣势是一个长期(20-30分钟)的基准。 GDB和劣等都在我的uid下运行。运行一段时间然后使用s_sinfo_t实例调用我的信号处理程序,其中si_signo = 11,si_errno = 0和si_code = 0; _sifields._kill.si_pid =( gdb-pid ),_ sifields._kill.si_uid =( my-uid )。

我读到这个,因为GDB决定向我的下级进程发送一个kill信号。 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中的错误地址在受保护的内存范围内之后)。

但是,siScode为零的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

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

可能是劣质过程正在执行原始SIGSTOP的一些低级处理,并将其作为一个kill发送到链。但它是我不理解/想要消除的原始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 Core / 32 Thread Xeon,4x E7520,基于Nehalem的服务器上运行。无论是启用还是禁用超线程,我都会得到相同的结果。

2 个答案:

答案 0 :(得分:0)

在Linux下, si_signo = 11 表示这是传播 SIGSEGV 的GDB。有关信号编号,请参阅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并打破 kill tkill tgkill ptrace来实现,如果$ rdi == PTRACE_KILL < / strong>(听起来很费时间,我知道)。

答案 1 :(得分:0)

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