我有一个由另一个进程调用的进程,该进程由另一个进程调用,以此类似于ad nauseum。这是一个长工具链中的子进程。
此过程正在崩溃。
我想在gdb中捕获这个过程,以了解它崩溃的原因。但是,我能想到的唯一方法是:
ps -C <name process I want to catch>
并获取PID。这很麻烦,但通常可以胜任。问题是当前的故障运行得非常快,当我捕获PID并启动gdb时,它已经通过了故障点。
我想启动gdb而不是:
(gdb) attach <pid>
我想这样做:
(gdb) attach <process name when it launches>
有没有办法做到这一点?
我在linux上使用gdb 7.1
答案 0 :(得分:20)
这是我的脚本,名为gdbwait:
#!/bin/sh
progstr=$1
progpid=`pgrep -o $progstr`
while [ "$progpid" = "" ]; do
progpid=`pgrep -o $progstr`
done
gdb -ex continue -p $progpid
用法:
gdbwait my_program
当然可以写得更好,但Bourne shell脚本语法对我来说很痛苦,所以如果它有效,那么我就不管它了。 :) 如果新进程启动并且死得太快,请在您自己的程序中添加1秒的延迟以进行调试......
答案 1 :(得分:8)
在Mac OS X上,您可以使用:
(gdb) attach --waitfor <process-name>
但这有时也无法捕获退出非常快的进程。我不确定这是否支持其他平台。
答案 2 :(得分:5)
您可以附加到父进程并设置跟随分叉模式子。这将使分叉后的gdb调试子进程而不是父进程。 catch fork 也很有用。这将使gdb在每个fork之后停止。请参阅docs。
答案 3 :(得分:1)
不完全符合您的期望,但它可能会帮助您进行调试。
valgrind --trace-children=yes your_program
将检查并打印进程的所有子进程中的内存错误,包括堆栈跟踪和有关错误的一些细节(例如,在双重自由的情况下,您将获得第一个免费的堆栈跟踪)。
此外,您可能会使崩溃过程生成核心转储,并调试此验尸。请参阅this answer for details。
答案 4 :(得分:1)
我一直面临着与我正在尝试调试的问题类似的问题,我想出了一个使用ldpreload的解决方案,但在看到Joeys的回答后,我想我会先尝试一下。如果它对其他人有帮助,虽然这里的想法是:
创建一个LD_PRELOAD库来挂钩exec *调用(有很多关于如何执行此操作的指南,但如果我这样做,我将使用代码更新我的答案),检查通过exec时使用的路径*调用,如果它是我们的目标,那么将带有PID的消息输出到stderr并进入无限循环(使用睡眠以避免大量CPU使用)。然后你可以用gdb附加并修改循环中使用的寄存器来继续执行。
这可能涉及一些内联ASM,以确保编译器不会以难以突破的方式优化无限循环。更有说服力的方法是找到一种方法来检测gdb已附加然后触发断点(“asm(”int3“);”应该对后者进行操作)。
答案 5 :(得分:0)
Tom Tromey在GitHub上的gdb-helpers存储库中的程序之一是preattach
,它将使gdb附加到使用给定名称创建的下一个进程。它需要Linux systemtap程序。