【问题标题】:Is there any way to tell gdb to wait for a process to start and attach to it?有没有办法告诉 gdb 等待进程启动并附加到它?
【发布时间】:2010-12-07 22:34:39
【问题描述】:

我有一个由另一个进程调用的进程,该进程由另一个进程调用,以此类推。它是一个长工具链中的子进程。

这个进程正在崩溃。

我想在 gdb 中捕获这个进程,以了解它为什么会崩溃。但是,我能想到的唯一方法是:

  1. 在命令行中启动原来的父进程。
  2. 轮询 ps -C <name process I want to catch> 并获取 PID。
  3. 启动 gdb,附加到该进程的 PID。

这很麻烦,但通常可以完成这项工作。问题是当前的故障运行非常快,当我捕获 PID 并启动 gdb 时,它已经通过了故障点。

我想启动 gdb 而不是:

(gdb) attach <pid>

我想做:

(gdb) attach <process name when it launches>

有什么办法吗?


我在 linux 上使用 gdb 7.1

【问题讨论】:

    标签: gdb


    【解决方案1】:

    这是我的脚本 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 秒延迟以进行调试...

    【讨论】:

    • 很高兴看到便携式解决方案!
    • my_program 部分可以是正则表达式,例如添加 $ 以匹配进程名称的尾随部分:)
    【解决方案2】:

    您可以附加到父进程并设置 follow-fork-mode 子进程。这将使 gdb 在分叉后调试子进程而不是父进程。 catch fork 也会很有用。这将使 gdb 在每次分叉后停止。见docs

    【讨论】:

    • 但是如果进程树很深(就像我的情况一样),这可能会变得非常乏味
    • @NathanFellman - 解决繁琐的一种方法可能是为 gdb 编写一些 Python 扩展代码,以自动执行此过程。它可以在每个捕获的分叉后唤醒,确定该分叉是否相关,如果不相关则继续。
    【解决方案3】:

    在 Mac OS X 上,您可以使用:

    (gdb) attach --waitfor <process-name>
    

    但这有时也无法捕获快速退出的进程。我不确定这是否在任何其他平台上受支持。

    GDB Release Notes for Mac OS X v10.5 WWDC Seed

    【讨论】:

    • 这就是我要找的。不幸的是,我的版本(7.2)似乎不支持它
    • 使用 gdb-apple: sudo port install gdb-apple
    【解决方案4】:

    不完全符合您的期望,但它可能会帮助您进行调试。

    valgrind --trace-children=yes your_program
    

    将检查并打印进程所有子进程中的内存错误,包括堆栈跟踪和有关错误的一些详细信息(例如,在双重释放的情况下,您将获得第一个释放的堆栈跟踪)。

    此外,您可以让崩溃的进程生成核心转储,并调试此事后分析。见this answer for details

    【讨论】:

      【解决方案5】:

      我在尝试调试的东西上遇到了类似的问题,我想出了一个使用 ldpreload 的解决方案,但在看到 Joeys 的回答后,我想我会先尝试一下。万一它对其他人有帮助,尽管这是这个想法:

      创建一个 LD_PRELOAD 库来挂钩 exec* 调用(有很多关于如何执行此操作的指南,但如果我这样做,我将使用代码更新我的答案),检查通过 exec 时使用的路径* 调用,如果它是我们的目标,则将带有 PID 的消息输出到 stderr 并进入无限循环(睡眠以避免大量 CPU 使用)。然后你可以附加 gdb 并修改循环中使用的寄存器以继续执行。

      这可能涉及一些内联 ASM,以确保编译器不会以难以摆脱的方式优化无限循环。一种更有说服力的方法是找到一种方法来检测 gdb 是否已附加,然后触发断点(“asm("int3");" 应该对后者起作用)。

      【讨论】:

        【解决方案6】:

        Tom Tromey 在 GitHub 上的 gdb-helpers 存储库中的一个程序是 preattach,这将使 gdb 附加到使用给定名称创建的下一个进程。它需要 Linux systemtap 程序。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-12-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-21
          • 2010-10-11
          • 1970-01-01
          相关资源
          最近更新 更多