在 GDB 中编译和注入代码:C++ 而不是 C

Compiling and injecting code in GDB: C++ rather than C

提问人:Robin Whittle 提问时间:2/8/2023 更新时间:2/11/2023 访问量:438

问:

我在 x86-64 Debian 11 上运行 gdb 10.1.90.20210103-git 和 gcc/g++ 10.2.1 20210110。我的 IDE 是 Codelite,它使用手动而不是 gdb 的机器界面,使我能够直接向 gdb 键入命令,并查看响应(可能会将响应复制到剪贴板)。这是当下级在点击中断后通过 gdb 控制台暂停时,该控制台位于 Codelite 的 Debugger > Output 窗格中。

我能够使用“在 GDB 中编译和注入代码”https://sourceware.org/gdb/current/onlinedocs/gdb#Compiling-and-Injecting-Code 中的说明来编译简单的 C 代码并使其在停止的下级环境中运行。例如:在下级中递增局部变量 int,我可以通过 Locals 或 Watch 窗格看到它。compile code blah++;

只要我指定了源文件的绝对路径,该命令就可以正常工作。compile file

我无法看到一个简单的 printf() 语句的控制台输出(到下级或 gdb 的控制台):'printf(“xxx”);',因为如果有这样的行,代码将无法编译

尽管使用并检查这些版本是否设置了这些版本,但我没有收到任何关于我尝试编译的任何错误消息或确认。set debug compileset debug compile-cplus-typesshow

blah 变量是一个整数,可以通过 C 代码和 gcc 访问。增加此值的能力是我的代码已编译并运行的唯一迹象。

我没有得到任何回应,所以我大概正在使用 gcc 进行编译。我确实下达了命令,但仍然没有回应或仅 C 的行为有任何变化。set/show compile gccset compile gcc /usr/bin/x86_64-linux-gnu-cpp-10show compile gcc

如果文件包含一行 C++,则无法编译该文件,该行在此类对象的向量中递增类对象的数据成员。如果代码包含 C++ 代码,我也无法编译代码,例如: 和/或 .#include <fstream>std::fstream oFile;

上面提到的 gdb 文档是通用的,但确实有 C 示例。

是否可以在 gdb 下编译 C++ 代码,将其注入到暂停的 inferior 环境中,使用任何版本的 gdb 和 gcc?

我热衷于使用这个 C++ 代码注入工具(如果存在)将大型复杂数据结构的内容转储到文件中,并修改其中的某些元素以帮助调试。

C++ Linux 编译 GDB Codelite

评论

1赞 Neil Butterworth 2/8/2023
至少,我会从问题空间中删除 Codelite,并从操作系统命令行执行所有操作。我还想说,您可能过于依赖调试器,而应该编写一些调试函数 - 但这只是我。
0赞 Robin Whittle 2/11/2023
谢谢@NeilButterworth。我能够通过使用“调用”或“打印”和转储函数来做我想做的事,转储函数是源代码的一部分。

答:

0赞 Robin Whittle 2/11/2023 #1

总结:GDB 的 C++ 编译和注入系统对我不起作用,并且据报道它有错误或无法正常工作。我只用单行 C 代码测试了这个命令,但它适用于这些命令。我能够运行我的函数,它编写一个文本转储文件,其中包含类对象数据成员向量的值,而下级在断点后暂停,方法是将其包含在源文件中并使用 GDB 或命令调用它,为其提供要转储的向量名称所需的输入参数。compileprintcall

我还没有尝试过单独使用 GDB,但目前我没有理由相信 Codelite 会干扰我通过 Codelite 的“调试器>输出”控制台与 GDB 进行通信的能力。

我写信给 GDB 开发者列表,并收到了我认为是消息灵通的回复。有人告诉我,根据受访者的经验,“C++插件的功能不是很好。它似乎也有一些错误并且经常崩溃。而且,似乎没有人在积极研究它。这与我迄今为止的经验是一致的。

也许更高版本的 GDB 会更好。然而,自 2017 年以来,库 https://github.com/gcc-mirror/gcc/commits/master/libcc1/libcp1.cc 的变化很小,自宣布引入以来,我找不到任何关于C++编译和注入 https://www.sourceware.org/gdb/news/ 的新工作的迹象:

GDB 8.3.1 发布于 2019-09-20,其中包含:“实验性支持编译和注入C++源代码到下级(需要 GCC 7.1 或更高版本,使用 libcp1.so 构建)”。

我的问题可能与没有这个库有关。我确实有 C 等效项:/usr/lib/x86_64-linux-gnu/libcc1.so.o。我在 Debian 软件包中找不到这样的库。我可以通过编译最新的 GCC/G++ 和 GDB 来做到这一点,但这非常令人生畏,涉及安装比我当前 Debian 安装更新的标准库,同时使这些库和更新的 G++ 和 GDB 可用于 Codelite 会话,但不会干扰机器上需要旧编译系统的其他软件。

受访者建议,与其在调试会话中编译和注入新代码,不如将其编写为库,并使用编译命令在调用它的纯 C 代码段上运行它。但是,出于我的目的,该函数需要传递一个或多个 C++ 构造,并且任何调用 C++ 函数的代码都是 C++ 代码,因此可能不会由 GDB 编译。

为了直接对类对象的数据成员的大型向量进行文本转储,我能够通过在现有源文件中编写这样的函数来成功,该文件还包含我正在调试的函数。然后我可以用 GDB 或命令调用它。我想如果调试功能在任何其他链接的源文件或链接库中,这将起作用。(也许有一种方法可以编写这样一个库,在下级停止时编译和链接它。printcall

我能够从调试会话中运行它,其中下级在某处停止,命令后跟函数名称,向量名称用括号括起来。不能有分号。我发现该命令更好,因为 GDB 会报告返回值,即“void”。我的函数使用C++结构(例如“<<”)来写入文本文件。printcallprint

在我的 C 函数的转储函数中调用导致当前目录在下级的终端窗口中输出。同样:。 尽职尽责地在下级的终端窗口跑了午夜指挥官。system("pwd")print system("pwd")print system("mc")

我更改了函数以返回一个字符串,GDB 在 GDB“调试器>输出”控制台中报告了该字符串。我添加了一行: - 但是在下级的终端窗口或 GDB 控制台中都没有出现任何内容。std::cout << "xyz";

我尝试使用 compile 命令以完全相同的方式调用我的转储函数,无论是否使用尾随分号,都没有产生任何结果。

我发现它适用于 C 和 C++ 代码,而“编译”仅适用于 C 代码。printcall

我尝试了整数、浮点数和字符串的数据成员,GDB 正确返回了它们的值。在末尾添加 a 会导致它返回原始整数值,但该值本身是递增的。print vvv[6].mmm++

当我尝试使用复合代码行时,在两个逻辑行之间使用分号,末尾有一个分号,没有分号,没有响应。print

GDB 开发人员列表不是支持请求的地方,但我不知道有更好的方法来了解该设施的状态。