如何在GDB中漂亮地打印STL容器?

61 人关注

I've followed the instructions on the GDB wiki 来安装用于查看STL容器的python pretty-printers。我的 ~/.gdbinit 现在看起来像这样。

python 
import sys 
sys.path.insert(0, '/opt/gdb_prettyprint/python') 
from libstdcxx.v6.printers import register_libstdcxx_printers 
register_libstdcxx_printers (None) 

然而,当我运行GDB并试图打印一个STL类型时,我得到了以下结果。

print myString
Python Exception <class 'gdb.error'> No type named std::basic_string<char>::_Rep.: 

有谁能给我们一些启示吗?我运行的是Ubuntu 12.04,它自带GDB 7.4。

4 个评论
这可能只是因为 C++ 库改变了其内部类型和成员变量,而 Python 模块没有跟上。
你能不能粘贴更多的信息,比如C++源代码、编译器选项等?我刚刚在Ubuntu 12.04上进行了测试,它对我来说是有效的。
在CEntOS 7上对我来说是有效的。有一个潜在的错误需要注意,就是在你启动gdb的时候。它可能会打印一个你可能错过的python错误。
( 广告 )对于默认的pretty-printers libstdcxx ,我有一些不喜欢的地方,所以 我做了一些修改 .
c++
linux
debugging
stl
gdb
Nick Hutchinson
Nick Hutchinson
发布于 2012-07-23
10 个回答
Ciro Santilli OurBigBook.com
Ciro Santilli OurBigBook.com
发布于 2022-12-01
已采纳
0 人赞同

It just works on Ubuntu 17.04

现在,Debian似乎终于正确地整合了东西。

main.cpp

#include <map>
#include <utility>
#include <vector>
int main() {
    std::vector<int> v;
    v.push_back(0);
    v.push_back(1);
    v.push_back(2);
    std::map<int,int> m;
    m.insert(std::make_pair(0, 0));
    m.insert(std::make_pair(1, -1));
    m.insert(std::make_pair(2, -2));

Compile:

g++ -O0 -ggdb3 -o main.out -std=c++98 main.cpp

Outcome:

(gdb) p v
$1 = std::vector of length 3, capacity 4 = {0, 1, 2}
(gdb) p m
$2 = std::map with 3 elements = {[0] = 0, [1] = -1, [2] = -2}

我们可以看到,这台漂亮的打印机安装有。

(gdb) info pretty-printer

其中包含以下几句话。

global pretty-printers:
  objfile /usr/lib/x86_64-linux-gnu/libstdc++.so.6 pretty-printers:
  libstdc++-v6
    std::map
    std::vector

打印机是由文件提供的。

/usr/share/gcc-7/python/libstdcxx/v6/printers.py

它与主C++库包libstdc++6一起出现,位于GCC源代码中的libstdc++-v3/python/libstdcxx下。 https://github.com/gcc-mirror/gcc/blob/releases/gcc-6.3.0/libstdc%2B%2B-v3/python/libstdcxx/v6/printers.py#L244

TODO:GDB是如何找到这个文件的,这是最后的疑惑,它不在我的Python路径中。python -c "import sys; print('\n'.join(sys.path))"所以它一定是在某个地方被硬编码了?

请看如何定义一个自定义的toString方法并调用它。用GDB打印C++类对象

检查优化代码中的特定元素

上次我检查的时候是很难的,你会得到 "无法评估函数--可能是内嵌的"C++, STL, GDB: 无法评估可能内联的函数

在未经优化的代码上,它是有效的。用gdb检查标准容器(std::map)的内容

@Evg 我还没有进一步研究它。它对我有用,只是我不知道具体是怎么做的。如果你发现了细节,请告诉我。
关于TODO(来自 gcc.gnu.org/legacy-ml/libstdc++/2009-02/msg00056.html ): gdb在读取objfile时可以自动加载打印机。gdb寻找一个文件,该文件是objfile的真实名称,并加上"-gdb.py";例如,libstdc++.so.6.0.11-gdb.py。
Fei
Fei
发布于 2022-12-01
0 人赞同

你可以用以下方法试试 GDB宏 (把它附加到你的 ~/.gdbinit 文件)来打印STL容器类型的数据,甚至其数据成员。 https://gist.github.com/3978082

bartgol
bartgol
发布于 2022-12-01
0 人赞同

我跑到这个问题上,在试图弄清它的时候撞到了这个页面。我最终解决了这个问题,我认为这值得分享我的经验。

我使用gcc-5.2,所以我从svn repo下载了gcc-5-branch版本的pretty printer。然而,我不得不做这两个修改。

  • 在编辑 ~/.gdbinit 文件时,建议添加的内容是

    python
    import sys
    sys.path.insert(0, '/home/bartgol/.gdb/gdb_printers/python')
    from libstdcxx.v6.printers import register_libstdcxx_printers
    register_libstdcxx_printers (None)
    

    然而,我不得不对register_libstdcxx_printers (None)这一行进行注释,因为我一直收到一个错误,告诉我libstdcxx_printers已经被注册了。显然,它们是在导入阶段注册的。

  • I had to edit the printers.py file for std::set and std::map. Since the type _Rep_type is private in both. In particular, I replace the routine children in std::map and std::set with the corresponding one in the version of pretty printer from the gcc-4_6-branch version on the svn repo. Got no error ever since, and stuff prints out nicely now.
  • Hope this helps.

  • Ruslan
    我在Ubuntu 18.04上用自定义编译的GDB和来自 ubuntu-toolchain-r/test repo的gcc-9工作。我只是把路径改成了 /usr/share/gcc-9/python/
    Bingfeng
    Bingfeng
    发布于 2022-12-01
    0 人赞同

    检查你的gcc版本。如果它小于4.7,你需要使用另一个print.py文件。从以下地方获取该文件 http://gcc.gnu.org/svn/gcc/branches/gcc-4_6-branch/libstdc++-v3/python/ .

    Scott Yang
    Scott Yang
    发布于 2022-12-01
    0 人赞同

    中列出的方法,而不是在 the link you mentioned ,你可以试试这个脚本 here ,

    具体做法如下。

    1) 下载脚本到 /your/path 。将其命名为一些名称,例如: your_name.conf

    2) 在主目录中添加一个 ~/.gdbinit 文件,如果你没有这个文件。

    3) Add a line source /your/path/your_name.conf to your ~/.gdbinit .

    4) Restart gdb. Try pvector

    你可以通过 help pvector 等命令找到帮助信息。

    pvector vec 5      # Prints element[5] in vec
    pvector vec 5 10   # Prints elements in range [5, 10] in vec. (5, 6, 7, 8, 9, 10)
    

    FYI, the script在gdb中增加了几个命令(pvectorplistpmap等),其功能是打印STL的元素。它还增加了print pretty,产生了像这样的漂亮格式。

    另外,如果你想知道STL的元素在gdb中到底是如何被访问的,只需阅读命令的代码。代码中没有什么秘密。^_^

    向量是由._M_impl._M_start访问的。

    p vec._M_impl._M_start + 4 # prints vec[4]

    Manuel Núñez
    Manuel Núñez
    发布于 2022-12-01
    0 人赞同

    如果你在Python异常后面输入 info type _Rep ,gdb会告知你加载的类与_Rep相匹配。这个列表可以帮助你找到为什么Python找不到你的 std::string class

    我刚刚遇到了你的问题,在我的案例中是intel c编译器,icc,他破坏了相当多的印刷。特别是 std::string 的不合格的icc名称导致。

    std::basic_string<char, std::char_traits<char>, std::allocator<char> >::std::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Rep;
    

    但漂亮的打印机正在寻找不合格的gcc名称。

    std::basic_string<char, std::char_traits<char>, std::allocator<char>::_Rep;
    

    为了解决我的问题,我所做的是修改printers.py中的StdStringPrinter类,在typeename中加入不合格的字符串名称,在gdb中查找。替换了这一行。

    reptype = gdb.lookup_type (str (realtype) + '::_Rep').pointer ()
    

    with this:

    reptype = gdb.lookup_type (str (realtype) + '::' + str (realtype) + '::_Rep').pointer ()
    

    有了从info type中获得的列表,你可以修复你的漂亮的打印机,使它们正常工作。

    Omnifarious
    Omnifarious
    发布于 2022-12-01
    0 人赞同

    我认为你使用的是一个非GNU的STL库,或者可能是一个非常老的GCC libstdc++ 。在我的编译器上,一个正常的STL字符串的类型是。 std::basic_string<char, std::char_traits<char>, std::allocator<char> > 。请注意,这不是 std::basic_string<char>

    Python代码中就有这样的内容。

    reptype = gdb.lookup_type (str (realtype) + '::_Rep').pointer ()
    

    这查找了一个::Rep的嵌套类型,不管基础字符串类型实际上是什么。错误信息表明,你所使用的那个奇怪的库的字符串类实际上没有一个::Rep的嵌套类型。

    Ans
    Ans
    发布于 2022-12-01
    0 人赞同

    像你上面所说的错误通常出现在程序是LLVM-build(由 clang 编译),而你试图用 gdb (应该用于GCC-build程序)来调试它。 理论上,LLVM-build程序可以由 gdb 来调试,反之亦然。但是 为了避免上述问题,如果你使用 clang ,你应该使用 lldb ,如果你使用 g++ ,应该使用 gdb

    Yotam
    Yotam
    发布于 2022-12-01
    0 人赞同

    类似于 enter link description here 在~/.gdbinit中为我工作。

    python
    import sys
    sys.path.insert(0, '/usr/share/gcc-8/python')
    from libstdcxx.v6.printers import register_libstdcxx_printers
    register_libstdcxx_printers (None)
        
    Cole
    Cole
    发布于 2022-12-01
    0 人赞同

    我的系统也有这个问题。

    对我来说,修复方法是以下几点

    在~/.gdbinit中

    python
    import sys
    sys.path.insert(0, '<path/to/gcc/dir>/GCCcore/9.3.0/share/gcc-9.3.0/python/')
    exec(open("<path/to/gcc/dir>/GCCcore/9.3.0/lib64/libstdc++.so.6.0.28-gdb.py").read())
    

    问题是,包含漂亮打印机的python文件夹并不是python搜索path的一部分(就像你通常需要将你的python模块位置添加到$PYTHONPATH一样)。 第一个命令完成了这个任务。 接下来的问题是,现在需要加载漂亮的打印机。 在我的系统中,GCC在GCCcore/9.3.0/lib64/libstdc++.so.6.0.28-gdb.py中提供了一个这样做的脚本。第二个命令 "source "了这个脚本,它将加载打印机。

    在进行这一修改之前,我还得到了以下错误。

    warning: File "<path/to/gcc/dir>/GCCcore/9.3.0/lib64/libstdc++.so.6.0.28-gdb.py" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load".