GDB如何在运行时评估C ++表达式

时间:2017-05-31 13:40:19

标签: c++ gdb expression

调试时,我最近注意到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后打印正确的值)和{ {1}}评估为真。

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

2 个答案:

答案 0 :(得分:8)

  

允许我输入print v.at(4);

之类的内容

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

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

答案 1 :(得分:7)

简答:它不编译代码。

长答案:

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

    注意:compileprint / call不同。

    完整答案:

    在几天之内,我可能会详细分析GDB如何实现此功能,以便进一步阅读。