等待GDB附加调试。

22

我之前在1或2个项目中正常使用gdb,即调用gdb --args prog args。gdb在与我调试的程序相同的tty上运行。

然而,我最新的项目是修改dtach实用程序。这是一个像screen一样的程序,因此tty被重定向到其他位置,因此我必须使用gdb的附加功能。

使用gdb attach的问题显然是,您不能从一开始就进行附加,因为您需要先运行程序才能获取要附加到的pid。

有没有办法让程序在某个点等待,直到gdb被附加?

由于我使用的是cygwin,因此无法使用gdbserver。我也尝试过使用pause(),但当我尝试继续时,它只是挂起了。


我的错,邮件列表中抱怨gdbserver在cygwin上无法工作的消息是9年前的了。昨晚编译了它,它可以正常工作。由于在cygwin上使用情况有限,可能是因为cygwin仓库中没有包含gdbserver二进制文件。此外,还有一种潜在的方法可以使用gdb调试存根从程序开始进行挂钩。无论如何,感谢您的回答。 - rhlee
你可以查看 https://github.com/scottt/debugbreak。 - Jérôme Pouiller
我投票支持重新开放此问题,因为这是一个不同的问题,其答案与链接的重复问题不同。 - gsgx
3个回答

27

至少在LLDB中,使进程发送SIGSTOP给自己就可以解决问题。调试器继续命令将会发出SIGCONT。这个方法也应该适用于GDB。或者尝试使用SIGINT代替SIGSTOP

包含头文件

#include <signal.h>
#include <csignal> // or C++ style alternative
那么
raise(SIGSTOP)

gdb命令info signals会打印信号列表以及它们是否传递给程序。然后,您可以使用handle命令修改其行为。 - Julio Guerra
问题在于,如果调试器实际上在被调试程序到达此点之前附加并发送了 SIGCONT 信号,则该进程会被卡住。 - Ajay Brahmakshatriya
3
这对我在调试C程序时起了作用。我包含了 signal.h 并在源代码的适当位置插入了 raise(SIGSTOP),使用GDB运行程序,并使用GDB命令 signal SIGCONT 继续执行。比 sleep 方法更干净。 - Jay Douglass
对@JayDouglass答案的改进。如果有多个线程在运行,您可以使用“thread apply all signal SIGCONT”同时恢复所有线程。 - HKTonyLee

19

这是我解决这个问题的方法。我看到其他人也用过这个技巧。

选择一个希望程序停下来并等待您附加调试器的位置。对于大多数程序,这将是一开始的地方,但如果有一些初始化工作需要完成,您可能想要先完成它,然后再进行此操作。

放置类似于以下循环:

#ifdef DEBUG

int i = 0;

while (i == 0)
{
    usleep(100000);  // sleep for 0.1 seconds
}

#endif // DEBUG

一旦成功附加到进程,您可以使用调试器更改变量i的值,这会打破循环并允许正常执行继续。

将变量更改为1的gdb命令:set var i = 1

我经常做的另一件事:定义一个简短的函数称为nop(),它不执行任何操作。 然后在想要中断的任何地方插入对nop()的调用,并在nop()内放置断点。

注意:如果使用-O0构建调试版本,则编译器不会优化掉变量。 如果您需要此技巧与优化的构建配合使用,则需要将变量声明为volatile


1
有一个解决方案,您可以安装一个信号处理程序,该程序将设置“i”变量以跳出循环? - To1ne

1

一些平台可能会有等待调试器指令或陷阱。

更加可移植的方法是,您可以使程序等待某些外部满足的条件,例如连接到套接字或将某些数据写入FIFO。然后,您可以从第三个终端建立连接或发送虚拟数据。

或者,您可以在程序中放置一个无限循环,测试某些易失性变量的值,您可以使用调试器修改该变量的值以允许程序继续执行。

如果我没记错的话,您可以在Cygwin程序中使用Windows API,一些网络搜索似乎表明可以使用Windows API检测程序是否正在被调试,因此您可以循环直到返回结果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接