配置gdb调试时显示STL容器具体内容若干坑

上周四工作时领导发现我用户目录下的gdb竟然不能在调试时正常打印stl容器中的内容,然后在我目录下加了一份.gdbinit文件,内容很简单只有一行,如下。

1
set auto-load safe-path / 

然后就可以了,但后面我在自己云主机上也照做后,发现并不管用,于是开始一系列的尝试。

gdb版本更新

一开始我看工作环境gdb版本为9.2版本,我自己的机器上的是7.6版本,那么是不是版本原因呢?先更新试试!

下载更新新版本GDB

先去gdb官网 下载新版本的gdb源码,然后发现最新的是10.1版本,那就10.1好了。

下载好源码解压后,在gdb-10.1目录下新建一个build目录,然后执行

1
../configure

在build目录生成makefile,之后make然后make install即可,非root用户记得加上sudo。执行gdb --version即可查看到机器上的gdb版本变更为10.1了。

然后再试试,发现果然并不行- -。

Python脚本支持?

之后在网上一直查,发现7.0版本后的gdb打印stl容器功能其实是pretty-printer这个python脚本来提供的。通过在gdb中info pretty-printer查看是否有该脚本支持,尝试查看,果然没有。

设置pretty-printer

方法如下:

  1. 获得python脚本,建议使用gcc默认安装的

    1
    sudo find / -name "*libstdcxx*"
  2. 若本机查找不到python脚本,建议下载gcc对应版本源码包,相对目录如下

    1
    gcc-4.8.1/libstdc++-v3/python
  3. 也可直接下载最新版本

    1
    svn co svn://gcc.gnu.org/svn/gcc/trunk/libstdc++-v3/python
  4. 将如下代码添加到.gdbinit文件中(我自己的机器搜出来该python脚本位于 /usr/local/gcc/share/gcc-9.2.0/python/ 下,但是由于我的机器装东西装的比较乱,可能不止这一个目录有。。。)

    1
    2
    3
    4
    5
    6
    python
    import sys
    sys.path.insert(0, '/usr/local/gcc/share/gcc-9.2.0/python')
    from libstdcxx.v6.printers import register_libstdcxx_printers
    register_libstdcxx_printers (None)
    end

    设置好了在用户根目录.gdbinit文件中填入该脚本,直接在启动gdb时就报出了一个警告。完整的英文语句我有点忘记了,但意思是这个版本的gdb不支持python。

不支持python?这怎么可能,我搜出来的结果基本都是指向该功能需要由python来支持。

重新配置编译gdb源码

经尝试,gdb10.1(包括9.2)直接../configure是默认不会支持python功能的,我去啊= =。行吧那么重新来一遍

1
../configure --with-python="/usr/bin"

配置makefile文件时加上这个选项,路径为主机上python所在的目录。再次编译安装后,进入gdb界面,发现那条报错没有了!

成功打印!

令人高兴的是,加上python编译选项后gdb正确的打印出了我想要的东西,样子如下:

1
2
(gdb) p vec
$1 = std::vector of length 10, capacity 10 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

而原来是

1
2
3
4
(gdb) p vec
$1 = {<std::_Vector_base<int, std::allocator<int> >> = {
_M_impl = {<std::allocator<int>> = {<__gnu_cxx::new_allocator<int>> = {<No data fields>}, <No data fields>}, _M_start = 0x404010, _M_finish = 0x404038,
_M_end_of_storage = 0x404038}}, <No data fields>}

总结

虽然最后成功配置,但其实在这几天的踩坑中,还有很多细节可以记录

.gdbinit中的那段导入python的代码是否是必要的

我在删掉那段代码后,再次尝试是否可以正常打印stl容器内容,发现还是正常的(试过vector和set),但是使用info pretty-printer查看,结果和之前不太一样了

1
2
3
4
(gdb) info pretty-printer
global pretty-printers:
builtin
mpx_bound128

比之前少了很多,而之前是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
(gdb) info pretty-printer
global pretty-printers:
builtin
mpx_bound128
libstdc++-v6
__gnu_cxx::_Slist_iterator
__gnu_cxx::__8::_Slist_iterator
__gnu_cxx::__8::__normal_iterator
__gnu_cxx::__8::slist
__gnu_cxx::__normal_iterator
__gnu_cxx::slist
__gnu_debug::_Safe_iterator
std::_Deque_const_iterator
std::_Deque_iterator
std::_Fwd_list_const_iterator
std::_Fwd_list_iterator
std::_List_const_iterator
std::_List_iterator
std::shared_ptr
std::stack
std::tr1::shared_ptr
std::tr1::unordered_map
std::tr1::unordered_multimap
std::tr1::unordered_multiset
std::tr1::unordered_set
std::tr1::weak_ptr
std::tuple
std::unique_ptr
std::unordered_map
std::unordered_multimap
std::unordered_multiset
std::unordered_set
std::variant
std::vector
std::weak_ptr

这个我没去仔细查,最后我选择留下了那段导入脚本。

我机器gdb所依赖的库很奇怪

首先通过如下命令查看一个软件在linux上所依赖的库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@VM_0_12_centos ~]# which gdb
alias gdb='gdb -q'
/usr/local/bin/gdb
[root@VM_0_12_centos ~]# ldd /usr/local/bin/gdb
linux-vdso.so.1 => (0x00007ffe6c781000)
libncursesw.so.5 => /lib64/libncursesw.so.5 (0x00007f239664d000)
libtinfo.so.5 => /lib64/libtinfo.so.5 (0x00007f2396423000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f239621f000)
libpython2.7.so.1.0 => /lib64/libpython2.7.so.1.0 (0x00007f2395e53000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f2395c37000)
libutil.so.1 => /lib64/libutil.so.1 (0x00007f2395a34000)
libm.so.6 => /lib64/libm.so.6 (0x00007f2395732000)
libexpat.so.1 => /lib64/libexpat.so.1 (0x00007f2395508000)
libstdc++.so.6 => /usr/local/gcc/lib64/libstdc++.so.6 (0x00007f239512f000)
libgcc_s.so.1 => /usr/local/gcc/lib64/libgcc_s.so.1 (0x00007f2394f17000)
libc.so.6 => /lib64/libc.so.6 (0x00007f2394b4a000)
/lib64/ld-linux-x86-64.so.2 (0x00007f2396885000)

其他都很正常,唯独这句

libstdc++.so.6 => /usr/local/gcc/lib64/libstdc++.so.6 (0x00007f239512f000)

我也是现在写才发现。。。已经变正常了,之前他索引的是一个ycm插件下自带的libstdc++.so.6 ,这可能是gdb一开始没有索引默认gcc下的python脚本的原因(因为没报错)。在咨询过大佬同学后,让我查看机器的系统变量LD_LIBRARY_PATH,查询后发现就是那个错误的ycm地址。查询和修改语句

1
2
echo $LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/mypath

我先把它修改成空了,让软件先走系统默认的查询lib的路径。

后续发现在根目录下的.bashrc 文件,最后一句export LD_LIBRARY_PATH = 那个奇怪的位置。也就是这句话导致该变量异常。

在写这篇博文的时候才发现gdb所依赖的libstdc++.so.6库已经变成默认正常路径下的库了,难道linux软件依赖库是动态改变的?这一点后续可以确认考证下。

主要参考文章

打印STL容器中的内容