【问题标题】:How does GDB evaluate C++ expressions at runtimeGDB 如何在运行时评估 C++ 表达式
【发布时间】:2017-05-31 13:40:18
【问题描述】:

在调试时,我最近注意到 GDB 能够在调试程序时评估“复杂”表达式,我想知道它是如何做到这一点的。例如,使用以下代码:

int main() {
    std::vector<int> v = {1, 2, 3};
    int k = 0;
    std::cin >> k;
    v.push_back(k);
    return v.at(0);
}

我能够编译程序 g++ -g myprogram.cpp 并在 GDB 中对其进行调试,这允许我输入诸如 print v.at(4); (在动态输入 k 后打印正确的值)和评估为 true 的 print v.at(2) == 3 .

我想知道 GDB 是如何做到这一点的。 This SO question 暗示它是“在内存中编译的”,但没有进一步详细说明,所以我想知道它是使用某种 JIT 来使这一切正常工作还是其他什么?他们是否在我输入和运行代码时内联编译代码?他们是否有一个框架可以在调试上下文中动态评估 C++?本质上,我想在我正在编写的调试器中重现这一点,以在断点处评估表达式,这就是为什么我很好奇 GDB 是如何做到的。

【问题讨论】:

  • 我不清楚你希望得到什么样的答案。 Gdb 能够在被调试程序的上下文中分析 C 和 C++ 表达式,在二进制文件中包含的调试信息的帮助下,也可能在源代码可用时使用。但是你已经知道了,对于这个场地来说,细节会很长。
  • @JohnBollinger 我想我必须“使用源代码”,但我想知道的是他们如何评估表达式。他们是否在我输入和运行代码时内联编译代码?他们是否有一个框架可以在调试上下文中动态评估 C++?本质上,我想在我正在编写的调试器中重现这一点,以在断点处评估表达式,这就是为什么我很好奇 GDB 是如何做到的。谢谢!
  • 您的问题似乎更侧重于 C++。我建议你删除 C 标签。
  • 我对 GDB 的源代码进行了一些调查。希望对您有所帮助。

标签: c++ gdb expression


【解决方案1】:

简答:它不编译代码。

长答案:

  1. 您调用print 命令,该过程发生在printcmd.c
  2. 它调用在eval.c 中定义的evaluate_expression,它通过读取目标内存并在gdb 中为标准运算符计算表达式来评估表达式,否则使用call_function_by_hand
  3. call_function_by_handinfcall.c 中定义。调用时,该过程会停止目标执行(有时不会,因此使用此功能可能会使多线程程序崩溃)。
  4. 将代码注入正在调试的程序中。
  5. 通过读取内存检索结果并在必要时取消暂停。

您可以关注call_function_by_hand的代码以便更好地理解。

注意:compileprint/call 不同。

【讨论】:

【解决方案2】:

这让我可以输入类似 print v.at(4);

gdb 可以调用编译成二进制文件的函数。这正是这里发生的事情。 gdb 调用std::vector 成员函数at() 并为您打印结果,请参阅documentation

另请注意,这是可能的,因为您在代码中使用了v.at(0)。如果您删除这部分代码,v.at() 将不会被实例化并且不会在生成的二进制文件中可用,因此 gdb 无法调用它。

【讨论】:

  • 所以 GDB 不编译任何东西,而是运行现有代码的部分来评估表达式?是否有 GDB 使用的库来执行此操作,还是完全以独立方式编码?
  • 是的,在您发布的示例中。但它也可以编译和注入代码,见sourceware.org/gdb/onlinedocs/gdb/…,虽然我没有使用过这个功能。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-15
相关资源
最近更新 更多