c++ - GDB/DDD : Debug shared library with multi-process application C/C++

标签 c++ c gdb multiprocessing

我正在尝试调试服务器应用程序,但我遇到了一些困难,打破了我需要的地方。该应用程序分为两部分:

  • 服务器应用程序,它生成工作进程(而不是线程)来处理传入请求。服务器基本上会产生进程,这些进程将以先到先得的方式处理传入的请求。
  • 服务器还以共享库的形式加载插件。共享库定义了服务器能够处理的大部分服务,因此大部分实际处理都是在这里完成的。

作为一个额外的乐趣,工作进程“重生”(即退出并生成一个新的工作进程),因此子进程的 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/

相关文章:

c++ - QT C++ 传递 Widgets 到函数

c - 如何在 C 中不访问此变量?

c - 在 IPv4 客户端/服务器应用程序中添加对 IPv6 的支持 - sin6_flowinfo 和 sin6_scope_id 字段?

c - 无法在 C 中打开文件

c++ - 访问短信收件箱

c++ - std::thread 构造函数中的可移动参数 (Visual C++ 2012)

c++ - 我有一个没有调试信息的发布二进制文件,它是用 gcc 构建的,有源代码

c++ - gdb vector 尝试获取不在内存中的地址

c++ - 为什么我不应该在这个简单的函数中使用 `const`?

c++ - 如何使用 gdb 调试 SIGTRAP?