使用 gdb 检查标准容器 (std::map) 内容

Posted

技术标签:

【中文标题】使用 gdb 检查标准容器 (std::map) 内容【英文标题】:Inspecting standard container (std::map) contents with gdb 【发布时间】:2010-09-30 11:11:52 【问题描述】:

假设有这样的东西:

#include <map>
int main()
    std::map<int,int> m;
    m[1] = 2;
    m[2] = 4;
    return 0;

我希望能够检查从 gdb 运行程序的地图内容。 如果我尝试使用下标运算符,我会得到:

(gdb) p m[1]
Attempt to take address of value not located in memory.

使用 find 方法不会产生更好的结果:

(gdb) p m.find(1)
Cannot evaluate function -- may be inlined

有没有办法做到这一点?

【问题讨论】:

打印所有元素而不截断大地图:***.com/questions/47743215/… 更多“无法评估函数可能内联”的重点:***.com/questions/40633787/… 一般问题:c++ - How to pretty-print STL containers in GDB? - Stack Overflow 【参考方案1】:

此问题的现有答案非常已过时。由于 GDB 7.x 中内置的 Python 支持以及 GCC 附带的 libstdc++ 漂亮的打印机,它使用最近的 GCC 和 GDB 即可工作TM

对于 OP 的示例,我得到:

(gdb) print m
$1 = std::map with 2 elements = [1] = 2, [2] = 4

如果它不能自动运行,请查看 GDB wiki 的 STL Support 页面上的第一个要点。

您也可以为自己的类型编写 Python 漂亮的打印机,请参阅 GDB 手册中的 Pretty Printing。

【讨论】:

是的,但是其他问题作为重复的问题正在关闭,所以我希望它有最近的信息。 我正在使用 GDB 7.2 并且上面的作品......如果你有一个小集合。除了使用 STL 实现的内部结构外,我还没有找到任何方法从 4K 矢量打印元素 1543。 是的,在 GDB 7.2 和 icpc 编译器中我收到错误 Could not find operator[] 不幸的是,它并不是在所有发行版中都“正常工作”。在 Ubuntu 13.10 中默认没有安装它,并且有 problems when you try to install it manually @razeh、Fedora、RHEL(和 RHEL 克隆)。正在进行修复以使打印机也可以在 GDB 链接到 Python 3 的发行版上运行【参考方案2】:

我认为没有,至少在您的源代码经过优化等情况下不会。但是,gdb 有一些宏可以为您检查 STL 容器:

http://sourceware.org/ml/gdb/2008-02/msg00064.html

不过我不用这个,所以YMMV

【讨论】:

感谢您的链接;唯一的问题是宏依赖于 stl 库版本,我希望避免这种情况。 +1 像“plist foo std::string”这样的命令给出语法错误也有点令人沮丧。看来 value_type 不能包含任何标点符号。 我没试过,但如果这和 GDB 的其他部分一样,用单引号将带标点名称的名称括起来就可以了。 注意:这些脚本中的 std::map 功能假定为 32 位指针类型。对于 64 位机器,将文件中的“+ 4”替换为“+ 8”。 pvector 未在我的 gdb(版本 7.5.91.20130417-cvs-ubuntu)中定义。【参考方案3】:

总是很明显:定义您自己的测试函数...从 gdb 调用它。例如:

#define SHOW(X) cout << # X " = " << (X) << endl

void testPrint( map<int,int> & m, int i )

  SHOW( m[i] );
  SHOW( m.find(i)->first );


int
main()

    std::map<int,int> m;
    m[1] = 2;
    m[2] = 4;
    return 0;  // Line 15.

还有:

....
Breakpoint 1 at 0x400e08: file foo.C, line 15.
(gdb) run
Starting program: /tmp/z/qD 

Breakpoint 1, main () at qD.C:15
(gdb) call testPrint( m, 2)
m[i] = 4
(*m.find(i)).first = 2
(gdb) 

【讨论】:

只要进程正在运行。对于核心转储不是那么有用。 这是一个有用的建议,一般调试 GDB,而不仅仅是使用 STL。我为大量难以检索的数据保留了一个完整的 gdb 辅助函数库,例如write_cuda_array_as_image()。请注意,某些编译器会删除任何未调用的函数,因此我在 main 的“return 0;”之后调用每个辅助函数。还用 extern "C" 声明它们使得从 gdb 调用它们更容易。 @KyleSimek gcc 还支持` __attribute__((used))`,因此如果未使用,链接器不会丢弃符号【参考方案4】:

stl-views.gdb 曾经是最好的答案,但现在不是了。

这还没有集成到主线 GDB 中,但这是使用“archer-tromey-python”branch 得到的结果:

(gdb) list
1   #include <map>
2   int main()
3       std::map<int,int> m;
4       m[1] = 2;
5       m[2] = 4;
6       return 0;
7   
(gdb) break 6
Breakpoint 1 at 0x8048274: file map.cc, line 6.
(gdb) run

Breakpoint 1, main () at map.cc:6
6       return 0;
(gdb) print m
$1 = std::map with 2 elements = 
  [1] = 2,
  [2] = 4

(gdb) quit

【讨论】:

【参考方案5】:

尝试取消引用 STL 容器:在此页面上:http://www.yolinux.com/TUTORIALS/GDB-Commands.html

【讨论】:

这些看起来是生意! 它们实际上与上一个答案中的宏相同 :) 恐怕没有更简单的解决方案了。 命令是什么?你设法用大量不相关的信息在场外运行我们。我对“如何启动 GDB”和其他内容不感兴趣。【参考方案6】:

上面的答案很好用。如果您使用的是 stl-views.gdb,这是查看其中的地图和元素的正确方法。 让你的地图如下: std::map&lt;char, int&gt; myMap;

(gdb) pmap myMap char int

pmap &lt;variable_name&gt; &lt;left_element_type&gt; &lt;right_element_type&gt; 查看地图中的元素。

希望对您有所帮助。

【讨论】:

【参考方案7】:

您可以通过确保您的编译器在编译程序时使用 DWARF-2(或 3 或 4)调试信息来解决第二个问题 (Cannot evaluate function -- may be inlined)。 DWARF-2 包含内联信息,因此您应该能够使用您描述的任何一种方法来访问 std::map 容器的元素。

要使用 DWARF-2 调试信息进行编译,请将 -gdwarf-2 标志添加到您的编译命令中。

【讨论】:

嗯,知道一个函数被内联的位置并不能让 GDB 评估对该函数的调用; GDB 确实需要访问该函数的离线副本!

以上是关于使用 gdb 检查标准容器 (std::map) 内容的主要内容,如果未能解决你的问题,请参考以下文章

end() 返回的迭代器对于哪个标准容器(如果有)是持久的?

C ++标准中的矛盾?

如何在不插入的情况下检查 std::map 是不是包含键?

请教一个 C语言 字符串数组之间比较的算法,谢谢

在地图中存储标准地图

默认容器参数