redboltzの日記 このページをアンテナに追加 RSSフィード

2011-12-07

[][][] gdbSTLboostのコンテナの中身をわかりやすく表示

VC++では、Debugger Visualizersによって、デバッガから、コンテナの中身をわかりやすく表示することが可能だ。

http://d.hatena.ne.jp/faith_and_brave/20100329/1269833173

gdbの場合はどうだろうか?

まず、STLのコンテナに関しては、

http://sourceware.org/gdb/wiki/STLSupport

インストールすることで対応可能なようだ。

インストール方法は、

svn co svn://gcc.gnu.org/svn/gcc/trunk/libstdc++-v3/python

を適当なディレクトリに配置し、以下の内容をホームディレクトリの.gdbinitに追記すればよい。.gdbinitが無ければ作ろう。

python
import sys
sys.path.insert(0, 'インストールしたディレクトリ*1')
from libstdcxx.v6.printers import register_libstdcxx_printers
register_libstdcxx_printers (None)
end
 *1 Makefile.am  Makefile.in  hook.in  libstdcxx が存在するディレクトリ

また、boostライブラリのコンテナやクラスに関しては、

https://github.com/ruediger/Boost-Pretty-Printer

インストールすることで対応可能なようだ。

インストール方法は先ほどのSTLのと同様に、

git clone git://github.com/ruediger/Boost-Pretty-Printer.git

を適当なディレクトリに配置し、以下を、.gdbinitに追記する。

python
import sys
sys.path.insert(0, 'インストールしたディレクトリ*2')
from boost.v1_40.printers import register_boost_printers
register_boost_printers(None)
end
 *2 README  boost  supported.txt が存在するディレクトリ

2011/12/08 追記

マヌケにも、デバッガで表示している対象ソースを書き忘れていたので追記


#include <list>
#include <map>

#include <boost/optional.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/variant.hpp>
#include <boost/ref.hpp>
#include <boost/unordered_map.hpp>

#include <memory>

int main() {
  std::list<int> l;
  l.push_back(3);
  l.push_back(4);
  l.push_back(5);

  std::map<std::string, double> m;
  m.insert(std::make_pair("abc", 1.23));
  m.insert(std::make_pair("hoge", 0.3));
  m.insert(std::make_pair("vw xy", 99));

  boost::shared_ptr<int> sp = boost::make_shared<int>(42);
  boost::variant<int, double, char> v = 5.2;
  int i = 10;
  boost::reference_wrapper<int> r(i);
  boost::unordered_map<std::string, int> u;
  u.insert(std::make_pair("bcd", 50));
  u.insert(std::make_pair("xyz", -9));
}

本ツールをインストールする前のgdbでのprint結果は、以下のような形となる。

(gdb) p l
$1 = {<std::_List_base<int, std::allocator<int> >> = {_M_impl = {<std::allocator<std::_List_node<int> >> = {<__gnu_cxx::new_allocato\
r<std::_List_node<int> >> = {<No data fields>}, <No data fields>}, _M_node = {_M_next = 0x804d008, _M_prev = 0x804d028}}}, <No data \
fields>}
(gdb) p m
$2 = {_M_t = {_M_impl = {<std::allocator<std::_Rb_tree_node<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator\
<char> > const, double> > >> = {<__gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<std::basic_string<char, std::char_traits<char\
>, std::allocator<char> > const, double> > >> = {<No data fields>}, <No data fields>}, _M_key_compare = {<std::binary_function<std::\
basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<ch\
ar> >, bool>> = {<No data fields>}, <No data fields>}, _M_header = {_M_color = std::_S_red, _M_parent = 0x804d088, _M_left = 0x804d0\
50, _M_right = 0x804d0c0}, _M_node_count = 3}}}
(gdb) p sp
$1 = {px = 0x80530f4, pn = {pi_ = 0x80530e0}}
(gdb) p v
$2 = {which_ = 1, storage_ = {<boost::detail::aligned_storage::aligned_storage_imp<8u, 4u>> = {data_ = {buf = "\315\314\314\314\314\\
314\024@", align_ = {<No data fields>}}}, static size = <optimized out>, static alignment = <optimized out>}}
(gdb) p r
$3 = {t_ = 0xbffff168}
(gdb) p u
$4 = {table_ = {<boost::unordered_detail::hash_table<boost::unordered_detail::map<std::basic_string<char, std::char_traits<char>, st\
d::allocator<char> >, boost::hash<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::equal_to<std::basic\
_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::basic_string<char, std::char_traits<ch\
ar>, std::allocator<char> > const, int> > > >> = {<boost::unordered_detail::hash_buckets<std::allocator<std::pair<std::basic_string<\
char, std::char_traits<char>, std::allocator<char> > const, int> >, boost::unordered_detail::ungrouped>> = {buckets_ = 0x8053128, bu\
cket_count_ = 11, allocators_ = {<boost::details::compressed_pair_imp<std::allocator<boost::unordered_detail::hash_bucket<std::alloc\
ator<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> > > >, std::allocator<boost::unord\
ered_detail::hash_node<std::allocator<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> >\
, boost::unordered_detail::ungrouped> >, 3>> = {<std::allocator<boost::unordered_detail::hash_bucket<std::allocator<std::pair<std::b\
asic_string<char, std::char_traits<char>, std::allocator<char> > const, int> > > >> = {<__gnu_cxx::new_allocator<boost::unordered_de\
tail::hash_bucket<std::allocator<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> > > >>\
 = {<No data fields>}, <No data fields>}, <std::allocator<boost::unordered_detail::hash_node<std::allocator<std::pair<std::basic_str\
ing<char, std::char_traits<char>, std::allocator<char> > const, int> >, boost::unordered_detail::ungrouped> >> = {<__gnu_cxx::new_al\
locator<boost::unordered_detail::hash_node<std::allocator<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<c\
har> > const, int> >, boost::unordered_detail::ungrouped> >> = {<No data fields>}, <No data fields>}, <No data fields>}, <No data fi\
elds>}}, <boost::unordered_detail::hash_buffered_functions<boost::hash<std::basic_string<char, std::char_traits<char>, std::allocato\
r<char> > >, std::equal_to<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {current_ = false, funcs_ =\
 {{data_ = {buf = "!", align_ = 33 '!'}}, {data_ = {buf = "", align_ = 0 '\000'}}}}, size_ = 2, mlf_ = 1, cached_begin_bucket_ = 0x8\
05313c, max_load_ = 11}, <No data fields>}}

そして、インストール後はこんな風に変わる。

(gdb) p l
$1 = std::list = {
  [0] = 3,
  [1] = 4,
  [2] = 5
}
(gdb) p m
$2 = std::map with 3 elements = {
  ["abc"] = 1.23,
  ["hoge"] = 0.29999999999999999,
  ["vw xy"] = 99
}
(gdb) p sp
$1 = (boost::shared_ptr<int>) (count 1, weak count 1) 0x80530f4
(gdb) p v
$2 = (boost::variant<...>) which (1) = double value = 5.2000000000000002
(gdb) p r
$3 = (boost::reference_wrapper<int>) 10
(gdb) p u
$4 = {table_ = {<boost::unordered_detail::hash_table<boost::unordered_detail::map<std::basic_string<char, std::char_traits<char>, st\
d::allocator<char> >, boost::hash<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::equal_to<std::basic\
_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::basic_string<char, std::char_traits<ch\
ar>, std::allocator<char> > const, int> > > >> = {<boost::unordered_detail::hash_buckets<std::allocator<std::pair<std::basic_string<\
char, std::char_traits<char>, std::allocator<char> > const, int> >, boost::unordered_detail::ungrouped>> = {buckets_ = 0x8053128, bu\
cket_count_ = 11, allocators_ = {<boost::details::compressed_pair_imp<std::allocator<boost::unordered_detail::hash_bucket<std::alloc\
ator<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> > > >, std::allocator<boost::unord\
ered_detail::hash_node<std::allocator<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> >\
, boost::unordered_detail::ungrouped> >, 3>> = {<std::allocator<boost::unordered_detail::hash_bucket<std::allocator<std::pair<std::b\
asic_string<char, std::char_traits<char>, std::allocator<char> > const, int> > > >> = {<__gnu_cxx::new_allocator<boost::unordered_de\
tail::hash_bucket<std::allocator<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> > > >>\
 = {<No data fields>}, <No data fields>}, <std::allocator<boost::unordered_detail::hash_node<std::allocator<std::pair<std::basic_str\
ing<char, std::char_traits<char>, std::allocator<char> > const, int> >, boost::unordered_detail::ungrouped> >> = {<__gnu_cxx::new_al\
locator<boost::unordered_detail::hash_node<std::allocator<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<c\
har> > const, int> >, boost::unordered_detail::ungrouped> >> = {<No data fields>}, <No data fields>}, <No data fields>}, <No data fi\
elds>}}, <boost::unordered_detail::hash_buffered_functions<boost::hash<std::basic_string<char, std::char_traits<char>, std::allocato\
r<char> > >, std::equal_to<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {current_ = false, funcs_ =\
 {{data_ = {buf = "!", align_ = 33 '!'}}, {data_ = {buf = "", align_ = 0 '\000'}}}}, size_ = 2, mlf_ = 1, cached_begin_bucket_ = 0x8\
05313c, max_load_ = 11}, <No data fields>}}
(gdb) 

かなりわかりやすくなった。残念ながら、boost::unordered_mapには対応していないようだ。

boost/v1_40/printers.py を見ると何に対応しているのか分かる。

というか、これ、名前からして、1.40当時のものらしい。最新のものがあったりするのだろうか?ご存じの方いらっしゃいましたら教えて下さい。

さて、よく見たら、shared_ptrの内容もアドレス表示となっており、中身が見えていない。

$1 = (boost::shared_ptr<int>) (count 1, weak count 1) 0x80530f4

shared_ptrの整形は、以下の箇所で行われている。

https://github.com/ruediger/Boost-Pretty-Printer/blob/master/boost/v1_40/printers.py#L191

pxの参照外しした値を表示末尾に追加してみた。

@register_pretty_printer
class BoostSharedPtr:
    "Pretty Printer for boost::shared/weak_ptr/array (Boost.SmartPtr)"

    regex = re.compile('^boost::(weak|shared)_(ptr|array)<(.*)>$')
    @static
    def supports(typename):
        return BoostSharedPtr.regex.search(typename)  

    def __init__(self, typename, value):
        self.typename = typename
        self.value = value

    def to_string(self):
        if self.value['px'] == 0x0:
            return '(%s) %s' % (self.typename, self.value['px'])
        countobj = self.value['pn']['pi_'].dereference()
        refcount = countobj['use_count_']
        weakcount = countobj['weak_count_']
        return '(%s) (count %d, weak count %d) %s %s' % (self.typename,
                                                         refcount, weakcount,
                                                         self.value['px'],
                                                         self.value['px'].dereference())

その結果、以下のようにうまく表示されるようになった。

$1 = (boost::shared_ptr<int>) (count 1, weak count 1) 0x80530f4 42

現在は積極的にメンテされていないようだが、この辺りはそうそう変わるものでもないだろう。暇があれば、いろいろ対応してフィードバックしてみようと思う。

というか、絶対どこかに既にあると思うのだが。。。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証