我正在尝试调试服务器应用程序,但我遇到了一些困难,打破了我需要的地方。该应用程序分为两部分:
- 服务器应用程序,它生成工作进程(而不是线程)来处理传入请求。服务器基本上会产生进程,这些进程将以先到先得的方式处理传入的请求。
- 服务器还以共享库的形式加载插件。共享库定义了服务器能够处理的大部分服务,因此大部分实际处理都是在这里完成的。
作为一个额外的乐趣,工作进程“重生”(即退出并生成一个新的工作进程),因此子进程的 PID 会定期更改。 -_-'
基本上,我需要调试在共享库中调用的服务,但我不知道要提前附加到哪个进程,因为它们会临时获取请求。到目前为止,附加到主进程并设置断点似乎不起作用。
是否有一种方法可以调试此共享库代码,而无需提前附加到进程?基本上我想调试调用相关函数的第一个进程。
目前我可能会尝试将工作进程的数量限制为 1 并且不重生,但最好知道将来如何处理这样的场景,特别是如果我想确保它在“发布”配置中仍然有效。
我正在 Linux 平台上运行,尝试使用 DDD 和 GDB 进行调试。
编辑:为了帮助说明我想要完成的任务,让我提供一个简短的概念证明。
#include <iostream>
#include <stdlib.h>
#include <unistd.h>
using namespace std;
int important_function( const int child_id )
{
cout << "IMPORTANT(" << child_id << ")" << endl;
}
void child_task( const int child_id )
{
const int delay = 10 - child_id;
cout << "Child " << child_id << " started. Waiting " << delay << " seconds..." << endl;
sleep(delay);
important_function(child_id);
exit(0);
}
int main( void )
{
const int children = 10;
for (int i = 0; i < 10; ++i)
{
pid_t pid = fork();
if (pid < 0) cout << "Fork " << i << "failed." << endl;
else if (pid == 0) child_task(i);
}
sleep(10);
return 0;
}
这个程序将 fork 10 个进程,这些进程在调用 important_function
之前都会休眠 10 - id 秒,这是我想在第一个调用子进程中调试的函数(这里应该是我 fork 的最后一个)。
将 follow-fork-mode 设置为 child 将使我能够跟踪到第一个子 fork ,这不是我想要的。我正在寻找第一个调用重要函数的 child 。
设置 detach-on-fork 关闭没有帮助,因为它会停止父进程,直到 fork 的子进程退出,然后再继续 fork 其他进程(一次一个,在最后一个进程退出后)。
在实际场景中,同样重要的是,我能够附加到已生成线程的已运行服务器应用程序,并停止在第一个调用该函数的应用程序上。
我不确定这是否可行,因为我还没有看到太多相关文档。基本上我想调试第一个应用程序来调用这行代码,无论它来自哪个进程。 (虽然只有我的应用程序进程会调用代码,但我的问题似乎可能更普遍:附加到调用代码的第一个进程,无论其来源是什么)。
最佳答案
您可以在 fork() 处设置断点,然后发出“继续”命令,直到主进程的下一步是生成您想要调试的子进程。此时,在要调试的函数处设置断点,然后向 gdb 发出“set follow-fork-mode child”命令。当您继续时,gdb 应该将您挂接到子进程中断点所在的函数处。
如果您发出命令“set detach-on-fork off”,gdb 将继续调试子进程。在库中遇到断点的进程应该在到达该断点时停止。问题是,当 detach-on-fork 关闭时,gdb 会停止所有启动时 fork 的子进程。我不知道有什么方法可以告诉它在 fork 后继续执行这些进程。
我认为解决这个问题的方法是写一个 gdb script切换到每个进程并发出继续命令。使用断点命中函数的进程应该停止。
一位同事针对让每个 child 继续下去的问题提供了另一种解决方案。您可以保留“detach-on-fork”,在每个子进程的入口点插入一条打印语句,打印出其进程 ID,然后给它一条语句,告诉它等待变量的更改,如下所示:
{
volatile int foo = 1;
printf("execute \"gdb -p %u\" in a new terminal\n", (unsigned)getpid());
printf("once GDB is loaded, give it the following commands:\n");
printf(" set variable foo = 0\n");
printf(" c\n");
while (foo == 1) __asm__ __volatile__ ("":::"memory");
}
然后,启动 gdb,启动主进程,并将输出通过管道传输到文件。使用 bash 脚本,您可以读取子进程的 ID,启动 gdb 的多个实例,将每个实例附加到不同的子进程之一,并通过清除变量“foo”来通知每个实例继续。
关于c++ - GDB/DDD : Debug shared library with multi-process application C/C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25812550/