【问题标题】:GDB is killing my inferior processGDB 正在杀死我的劣质进程
【发布时间】:2013-05-13 16:16:45
【问题描述】:

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 的服务器上运行它。无论是启用还是禁用超线程,我都会得到相同的结果。

【问题讨论】:

    标签: gdb kill-process


    【解决方案1】:

    在 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_tsi_signo 成员所指示的 SIGSEGV 吗? sigaction() 注册的信号处理函数的第一个参数是什么? (使用 PTRACE_SETSIGINFO 这两件事不太可能但并非不可能)
    • GDB 截获了内核发送给您的进程的信号,然后再次注入该信号,或者决定自己发送信号。尝试确定哪个。这可以通过在其自身下运行 GDB 并中断 killtkilltgkillptrace if $rdi == PTRACE_KILL(我知道这听起来很耗时)。

    【讨论】:

    • 感谢您帮助 scottt,但我不认为这本身就是一个 SIGSEGV。我不知道为什么,但正如您所指出的,si_signo 设置为 SIGSEGV,在这种情况下,鉴别器似乎是 si_code (=0)。而 _sigfault.si_addr 是假的——覆盖了 _kill.si_pid/si_uid。
    • @kingofmybones,你是如何注册你的信号处理程序的?你确定它是由 SIGKILL 触发的吗?这可以通过例如验证通过在 x86 上使用 __asm__("int $3") 进入 GDB,从信号处理程序获取堆栈跟踪。
    • 我正在使用一个应用程序框架,它有一个可扩展的信号处理框架(并且经过了很好的测试——这个应用程序已经存在了好几年并且被广泛使用)。我的处理程序只是挂钩到现有的信号处理框架,我无法具体解释它是如何向 Linux 注册的。
    • 但我可以验证 siginfo 字段是否如所述 - 我的信号处理程序获得数百万个 SIGSEGV (si_code != 0),在此之前 (SIGSEGV with si_code == 0) 出现在受保护区域中蓝色的。我在 GDB 中看到了这一点,它随后遇到了我设置的断点,以检查我的处理程序未处理的信号。
    • @kingofmybones,我在回答的最后给你一些新的建议。
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-18
      • 2012-07-04
      • 2017-02-05
      • 1970-01-01
      相关资源
      最近更新 更多