5

我正在使用gdb非常方便的多重劣质支持来调试进程树:

(gdb) set detach-on-fork off
(gdb) set schedule-multiple on
(gdb) set follow-fork-mode parent
(gdb) break PostgresMain
(gdb) break PostmasterMain

现在需要让事情继续运行,直到我在一些尚未生成的次等中遇到未来的断点之一。

但是,gdb每当劣质正常退出时,似乎“有用”的暂停,或者至少阻止清理劣质,以便其父级wait()可以返回:

(gdb) c
[New process 16505]
process 16505 is executing new program: /home/craig/pg/bdr/bin/pg_config
Reading symbols from /home/craig/pg/bdr/bin/pg_config...done.
[Inferior 2 (process 16505) exited normally]
(gdb) info inferior
  Num  Description       Executable        
* 2    <null>            /home/craig/pg/bdr/bin/pg_config 
  1    process 16501     /usr/bin/make     
(gdb) inferior 1
[Switching to inferior 1 [process 16501] (/usr/bin/make)]
[Switching to thread 1 (process 16501)] 
#0  0x0000003bc68bc502 in __libc_wait (stat_loc=0x7fffffffbc78) at ../sysdeps/unix/sysv/linux/wait.c:30
30          return INLINE_SYSCALL (wait4, 4, WAIT_ANY, stat_loc, 0,
(gdb)

所以我不得不无休止地:

(gdb) inferior 1
(gdb) c

继续。大约 70 次,在我在一个孩子的一个孩子的一个孩子的孩子中击中所需的断点之前。

认为正在发生的事情是gdb将进程退出视为停止事件,并且由于non-stop设置为off(默认值)它会在一个线程停止时停止所有劣等线程中的所有线程。但是,这个劣势已经终止了,它不是一个正常的停止事件,所以你不能只是cont它,你必须先切换到另一个进程。

有什么方法可以阻止 gdb 在每个劣质出口处暂停吗?我本来希望follow-fork-mode parentschedule-multiple on做到这一点,但gdb似乎仍然想在劣等退出时停下来。

我想我正在寻找类似“skip proc-exit”的东西,或者我可以更改处理程序策略的虚拟信号,这样它就不会停止。


set non-stop on似乎它应该是正确的答案,但我怀疑它被多个劣等者打破了。

如果我使用non-stop on,那么在第一次退出陷阱之后,gdb的内部状态表明低级 1 正在运行:

(gdb) info inferior
  Num  Description       Executable        
* 1    process 20540     /usr/bin/make     
(gdb) info thread
  Id   Target Id         Frame 
* 1    process 20540 "make" (running)
(gdb) cont
Continuing.
Cannot execute this command while the selected thread is running.

但内核认为它被阻止ptrace_stop

$ ps -o "cmd,wchan" -p 20540
CMD                         WCHAN
/usr/bin/make check         ptrace_stop

......它没有进展,直到gdb被分离,或者它被杀死。进程的信号将被忽略,并且interrupt无效gdb


GNU gdb (GDB) Fedora 7.7.1-18.fc20在 x86_64 上使用。

4

2 回答 2

4

偶然发现一篇顺便引用它的帖子后,我发现缺少的魔法就set target-async on在旁边set non-stop on

正如预期的那样,不间断模式意味着 gdb 不会在劣质退出时停止一切。target-async需要使其在 gdb 7.7 上实际正常工作;这是 7.8 的默认设置。

所以完整的咒语是:

set detach-on-fork off
set schedule-multiple on
set follow-fork-mode parent
set non-stop on
set target-async on

对于 7.8,删除target-async on并添加set print symbol-loading off.

于 2014-11-27T04:36:17.760 回答
1

以下对 gdb 的 Python 扩展将在每次停止后切换回第一个下级并恢复执行。

感觉就像一个彻底的黑客攻击,但它确实有效。当一个进程退出时,它会设置一个标志,表明它在退出时停止,然后切换到原始进程。gdb然后将停止执行,传递一个停止事件。我们检查停止是否是由我们的停止事件引起的,如果是,我们立即继续。

该代码还设置了我正在使用的断点和多进程设置,所以我可以只source thescript.pyrun.

gdb.execute("set python print-stack full")
gdb.execute("set detach-on-fork off")
gdb.execute("set schedule-multiple on")
gdb.execute("set follow-fork-mode parent")

gdb.execute("set breakpoint pending on")
gdb.execute("break PostgresMain")
gdb.execute("break PostmasterMain")
gdb.execute("set breakpoint pending off")

def do_continue():
    gdb.execute("continue")

def exit_handler(event):
    global my_stop_request
    has_threads = [ inferior.num for inferior in gdb.inferiors() if inferior.threads() ]
    if has_threads:
        has_threads.sort()
        gdb.execute("inferior %d" % has_threads[0])
        my_stop_request = True

gdb.events.exited.connect(exit_handler)

def stop_handler(event):
    global my_stop_request
    if isinstance(event, gdb.SignalEvent):
        pass
    elif isinstance(event, gdb.BreakpointEvent):
        pass
    elif my_stop_request:
        my_stop_request = False
        gdb.post_event(do_continue)

gdb.events.stop.connect(stop_handler)

一定有比这更简单的方法。它很丑。

于 2014-11-26T06:26:22.650 回答