Tuesday, May 5, 2015

STL pretty print support in gdb

I program in C/C++ for a long time, it's really hateful to debug C++ programs with STL containers in gdb, but yeah, who doesn't use STL?

gdb always prints lots of useless stuffs from a container.

$ g++ -std=c++11 foo.cc -g
$ gdb -q ./a.out
Reading symbols from ./a.out...done.

(^q^) l
1 #include <vector>
2
3 int main (void) {
4    std::vector<int> v = {1, 2, 3, 4, 5};
5    return 0;
6 }

(^q^) b 5
Breakpoint 1 at 0x40082c: file foo.cc, line 5.

(^q^) r
Starting program: /tmp/a.out 

Breakpoint 1, main () at foo.cc:5
5    return 0;

(^q^) p
$2 = {
  <std::_Vector_base<int, std::allocator<int> >> = {
    _M_impl = {
      <std::allocator<int>> = {
        <__gnu_cxx::new_allocator<int>> = {<No data fields>}, <No data fields>}, 
      members of std::_Vector_base<int, std::allocator<int> >::_Vector_impl: 
      _M_start = 0x602010, 
      _M_finish = 0x602024, 
      _M_end_of_storage = 0x602024
    }
  }, <No data fields>}

(^q^) 



And we're able to use a very tricky way to print that out.


(^q^) p *(v._M_impl._M_start)@(v._M_impl._M_finish - v._M_impl._M_start)
$22 =   {[0] = 1,
  [1] = 2,
  [2] = 3,
  [3] = 4,
  [4] = 5}

(^q^) 

A container is a "container", we don't care the implementation details, what we care about is the data.

With the pretty printer, we're able to print a container out like this:

(^q^) p v
$1 = std::vector of length 5, capacity 5 = {
  [0] = 1,
  [1] = 2,
  [2] = 3,
  [3] = 4,
  [4] = 5
}


According to the gdb wiki, the gdb python pretty printer is supported since 7.0. https://sourceware.org/gdb/wiki/STLSupport

Download the latest python script from gcc.gnu.org
---
mkdir ~/.gdb
cd ~/.gdb
svn co svn://gcc.gnu.org/svn/gcc/trunk/libstdc++-v3/python
---

put the following stuffs appended to your ~/.gdbinit
---
python
import sys
sys.path.insert(0, '/home/xatier/.gdb/python')
import libstdcxx.v6
end
---

Note, we only need to import the lib, let __init__.py do the magic ;-)

Done!


If you really want to dig up the implementation details, use " p /r "


(^q^) p /r v
$1 = {
  <std::_Vector_base<int, std::allocator<int> >> = {
    _M_impl = {
      <std::allocator<int>> = {
        <__gnu_cxx::new_allocator<int>> = {<No data fields>}, <No data fields>}, 
      members of std::_Vector_base<int, std::allocator<int> >::_Vector_impl: 
      _M_start = 0x602010, 
      _M_finish = 0x602024, 
      _M_end_of_storage = 0x602024
    }
  }, <No data fields>}

(^q^)


Actually this python script will be installed and automatically loaded in Archlinux once you install gcc/gcc-multilib.


$ pacman -Ql gcc-multilib | grep libstd
gcc-multilib /usr/lib/libstdc++.a
gcc-multilib /usr/lib32/libstdc++.a
gcc-multilib /usr/share/gcc-4.9.2/python/libstdcxx/
gcc-multilib /usr/share/gcc-4.9.2/python/libstdcxx/__init__.py
gcc-multilib /usr/share/gcc-4.9.2/python/libstdcxx/v6/
gcc-multilib /usr/share/gcc-4.9.2/python/libstdcxx/v6/__init__.py
gcc-multilib /usr/share/gcc-4.9.2/python/libstdcxx/v6/printers.py
gcc-multilib /usr/share/gdb/auto-load/usr/lib/libstdc++.so.6.0.20-gdb.py


If you're using other distros like Debian, that should be here, but not auto-loaded by default :(

$ apt-file list gcc | grep libstd
gcc-snapshot: /usr/lib/gcc-snapshot/share/gcc-4.9.0/python/libstdcxx/__init__.py
gcc-snapshot: /usr/lib/gcc-snapshot/share/gcc-4.9.0/python/libstdcxx/v6/__init__.py
gcc-snapshot: /usr/lib/gcc-snapshot/share/gcc-4.9.0/python/libstdcxx/v6/printers.py


Happy debugging C++! (^q^)

No comments:

Post a Comment