問題描述
如下列的程式碼:
std::vector<int> numbers; for (int i = 0; i < 4; i++) { numbers.push_back(i * 3); } std::map<std::string, std::string> contacts; contacts["john"] = "0987-654321"; contacts["mary"] = "";
在 gdb 中不易閱讀 numbers 和 contacts 的顯示結果:
(gdb) p numbers $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 = 0x6060 10, _M_finish = 0x606020, _M_end_of_storage = 0x606020}}, <No data fields>} (gdb) p contacts $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, std::basic_string<char, std::char_ traits<char>, std::allocator<char> > > > >> = {<__gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std ::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >> = {<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<char> >, bool>> = {<No data fields>}, <No data fields>}, _M_header = {_M_co lor = std::_S_red, _M_parent = 0x606080, _M_left = 0x606080, _M_right = 0x606120}, _M_node_count = 2}}}
解法一: 土法煉鋼
參考這篇的作法, 先取得目標位址再取值:
(gdb) p numbers $5 = {<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 = 0x60601 0, _M_finish = 0x606020, _M_end_of_storage = 0x606020}}, <No data fields>} (gdb) ptype numbers._M_impl type = struct std::_Vector_base<int, std::allocator<int> >::_Vector_impl : public std::allocator<int> { std::allocator<int>::pointer _M_start; std::allocator<int>::pointer _M_finish; std::allocator<int>::pointer _M_end_of_storage; public: void _Vector_impl(void); void _Vector_impl( const std::_Vector_base<int, std::allocator<int> >::_Vector_impl::_Tp_alloc_type &); } (gdb) ptype numbers._M_impl._M_start type = int * (gdb) p numbers._M_impl._M_start[1] $7 = 3 (gdb) p *(numbers._M_impl._M_start)@numbers.size() $12 = {0, 3, 6, 9}
先用 ptype 逐步了解各欄位的型別, 繼而找到儲存資料的欄位 numbers._M_impl._M_start。 由於 _M_start 是 int*, 倒數第二個指令直接取出 numbers[1] 的值, 最後一個指令則是用 print P@N 印出從位置 P 開始 N 筆資料。
嫌麻煩的話, 可以定義新的 gdb command:
(gdb) define pv Type commands for definition of "pv". End with a line saying just "end". >if $argc == 1 >p *($arg0._M_impl._M_start)@$arg0.size() >end >if $argc == 2 >p $arg0._M_impl._M_start[$arg1] >end >end (gdb) pv numbers $21 = {0, 3, 6, 9} (gdb) pv numbers 1 $22 = 3
將上述的 define pv ... end 寫入 /.gdbinit, 之後就不用重寫一次。
解法二: 使用別人寫好的 pretty-printers
土法煉鋼的目的是讓我們有辦法應付日後各種需求, 但是針對 STL 這種大家都有的需求, 已經有善心人士提供完整的套件了, 見 STLSupport - GDB Wiki 的第一點。
摘要作法如下:
$ cd /path/to/gdb_script/ $ svn co svn://gcc.gnu.org/svn/gcc/trunk/libstdc++-v3/python $ cat <<EOF >> ~/.gdbinit python import sys sys.path.insert(0, '/path/to/gdb_script/python') from libstdcxx.v6.printers import register_libstdcxx_printers register_libstdcxx_printers (None) end EOF
載入 pretty-printers 後, 輸出變數的結果如下:
(gdb) p numbers $1 = std::vector of length 4, capacity 4 = {0, 3, 6, 9} (gdb) p contacts $2 = std::map with 2 elements = {["john"] = "0987-654321", ["mary"] = ""}
有需要的時候, 也可以參考 python/libstdcxx/v6/printers.py 學習如何用 python 寫 gdb script。
沒有留言:
張貼留言