2017-05-31 64 views
6

评价C++表达式调试时,我最近注意到,有GDB调试程序时,以评估“复杂”表述的能力,我想知道它是如何做到这一点。例如,用下面的代码:如何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动态进入其打印正确的值)和print v.at(2) == 3评估为真。

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

+1

目前还不清楚你希望得到什么样的答案。 Gdb能够在被调试程序的上下文中分析C和C++表达式,并且可以在二进制文件中包含调试信息的帮助下,也可以在可用时使用源代码。但是你已经知道了,而且这个场地的细节会很长。 –

+0

@JohnBollinger我想我将不得不“使用源”,但我想知道的是他们如何评估表达式。他们是在我编写并运行它时编译内联代码吗?他们是否有一个框架来在调试环境中实时评估C++?实质上,我想在调试器中重现这一点,我正在写这些调试器来评估断点处的表达式,这就是为什么我很好奇GDB如何执行它。谢谢! – llk

+0

你的问题似乎更关注于C++。我建议你删除C标签。 – tambre

回答

5

简短回答:它不编译代码。

龙答案:

  1. 你打电话print命令和在printcmd.c
  2. 它调用evaluate_expression,在eval.c定义,其通过读取目标存储器和计算它里面的gdb用于计算表达式发生程序标准操作员,否则使用call_function_by_hand
  3. call_function_by_hand定义于infcall.c。在调用时,该过程会暂停目标执行(有时不会,因此可能会使用此功能使多线程程序崩溃)。
  4. 将代码注入到正在调试的程序中。
  5. 通过读取内存来检索结果并在必要时取消暂停。

为了更好地理解,您可能会将注意力集中在call_function_by_hand的代码上。

注意:compile是与print/call不同的东西。

完整的答案:

在几天内,我可以写的GDB如何实现这个功能,进一步阅读了详细的分析。

6

,让我型喜欢的东西打印v.at(4);

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

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

+0

因此,GDB不会编译任何东西,而是运行现有代码的各个部分来评估表达式? GDB是否有一个库用来做这件事,或者它是以独立的方式完全编码的? – llk

+1

是的,在你发布的例子中。但它也可以编译和注入代码,请参阅https://sourceware.org/gdb/onlinedocs/gdb/Compiling-and-Injecting-Code.html#Compiling-and-Injecting-Code,但我没有使用过这个功能。 – ks1322