2011-12-07
■[C++][boost][gdb] gdbでSTLやboostのコンテナの中身をわかりやすく表示
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 が存在するディレクトリ
https://github.com/ruediger/Boost-Pretty-Printer
をインストールすることで対応可能なようだ。
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
現在は積極的にメンテされていないようだが、この辺りはそうそう変わるものでもないだろう。暇があれば、いろいろ対応してフィードバックしてみようと思う。
というか、絶対どこかに既にあると思うのだが。。。
- 14 http://t.co/YxPYVMpo
- 4 http://longurl.org
- 4 http://t.co/qjXwuCyu
- 3 http://reader.livedoor.com/reader/
- 2 http://d.hatena.ne.jp/keywordblogmobile/V6
- 2 http://search.yahoo.co.jp/search?p=uq+1day+wimax&search.x=1&fr=bb_top_v2&tid=bb_top_v2&ei=UTF-8
- 2 http://t.co/oFzSo3ex
- 2 http://www.google.co.jp/url?sa=t&rct=j&q=自己遷移 内部遷移&source=web&cd=2&ved=0CCgQFjAB&url=http://d.hatena.ne.jp/redboltz/20110626/1309046959&ei=iGzgToKgJOmKmQWL88n7BA&usg=AFQjCNELM83
- 2 http://www.google.co.jp/url?sa=t&rct=j&q=qtruby&source=web&cd=3&ved=0CDAQFjAC&url=http://d.hatena.ne.jp/redboltz/20100715/1279204071&ei=vSDgTvPNN4r2mAX4hOWKBQ&usg=AFQjCNFfdlR3adC3YdWqEIpALMpYJFIyEg&sig2=5fHBZ0HawHGKeO8z7P9hug
- 2 http://www.google.co.jp/url?sa=t&rct=j&q=windows7 64bit 3.99gb使用可能&source=web&cd=3&sqi=2&ved=0CDYQFjAC&url=http://d.hatena.ne.jp/redboltz/20100131/1264897391&ei=4EfgToC1D6-WmQXd-vzwBA&usg=AFQjCNHuU9Pc9MrE69r
