使用GDB 调试STL方法

来源:互联网 发布:matlab导入excel数据 编辑:程序博客网 时间:2024/06/06 18:28

背景:

当我们用gdb调试stl时候,往往看到的是stl内部变量的值,比如打印一个string a

输出:

(gdb) p a

$1 = {

  static npos = 18446744073709551615,

  _M_dataplus = {

    <std::allocator<char>> = {

     <__gnu_cxx::new_allocator<char>> = {<No data fields>},<No data fields>},

    members ofstd::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Alloc_hider:

    _M_p = 0x50b028 "test"

  }

           }

打印一个vector v:

(gdb) p v

$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 ofstd::_Vector_base<int,std::allocator<int> >::_Vector_impl:

      _M_start = 0x50b060,

      _M_finish = 0x50b068,

      _M_end_of_storage = 0x50b068

    }

  }, <No datafields>}

打印其中的某个元素:

(gdb) p v[0]

One of the arguments you tried to pass to operator[] couldnot be converted to what the function wants.

 

(gdb) p v.at(0)

Cannot evaluate function -- may be inlined

 

当我们不熟悉stl内部实现的时候,这给我们调试问题带来了一些麻烦。

解决方案:

1) 使用gdb user define command

其实就是一些gdb语法实现一些宏,一个比较常用的是writen by Dan Marinescu 的dbinit_stl_views。内容参考如下:

    http://www.yolinux.com/TUTORIALS/src/dbinit_stl_views-1.03.txt

把上面文件写入.gdbinit,gdb启动的时候自动加载;一般来说这样就可以按照上面文档的说明接口调试stl,比如pvector pstring,但当我使用这些接口的时候,遇到下面的情况:

          


原因:我的gcc貌似不支持 $argc (所在的版本应该是支持的,可能是没有加某些编译选项,未找到原因),没想到更好的方案,如果不升级gcc,只能自己修改上面的接口,为多参数增加更多的宏定义;参考下面的源码:

 

#                                                                                                        #   STL GDB evaluators/views/utilities - 1.03##   The new GDB commands:                                                         #     are entirely non instrumental                                             #     do not depend on any "inline"(s) - e.g. size(), [], etc#       are extremely tolerant to debugger settings#                                                                                 #   This file should be "included" in .gdbinit as following:#   source stl-views.gdb or just paste it into your .gdbinit file##   The following STL containers are currently supported:##       std::vector<T> -- via pvector command#       std::list<T> -- via plist or plist_member command#       std::map<T,T> -- via pmap or pmap_member command#       std::multimap<T,T> -- via pmap or pmap_member command#       std::set<T> -- via pset command#       std::multiset<T> -- via pset command#       std::deque<T> -- via pdequeue command#       std::stack<T> -- via pstack command#       std::queue<T> -- via pqueue command#       std::priority_queue<T> -- via ppqueue command#       std::bitset<n> -- via pbitset command#       std::string -- via pstring command#       std::widestring -- via pwstring command##   The end of this file contains (optional) C++ beautifiers#   Make sure your debugger supports $argc##   Simple GDB Macros writen by Dan Marinescu (H-PhD) - License GPL#   Inspired by intial work of Tom Malnar, #     Tony Novac (PhD) / Cornell / Stanford,#     Gilad Mishne (PhD) and Many Many Others.#   Contact: dan_c_marinescu@yahoo.com (Subject: STL)##   Modified to work with g++ 4.3 by Anders Elton#   Also added _member functions, that instead of printing the entire class in map, prints a member.## std::vector<>## 输出vector中的全部元素,size, capacity, 元素类型define pvector    set $size = $arg0._M_impl._M_finish - $arg0._M_impl._M_start    set $capacity = $arg0._M_impl._M_end_of_storage - $arg0._M_impl._M_start    set $size_max = $size - 1set $i = 0while $i < $sizeprintf "elem[%u]: ", $ip *($arg0._M_impl._M_start + $i)set $i++endprintf "Vector size = %u\n", $sizeprintf "Vector capacity = %u\n", $capacityprintf "Element "whatis $arg0._M_impl._M_startend#输出vector中指定索引位置的元素define pvector_indexset $idx = $arg1    set $size = $arg0._M_impl._M_finish - $arg0._M_impl._M_start    set $size_max = $size - 1if $idx < 0 || $idx > $size_maxprintf "idx is not in acceptable range: [0..%u].\n", $size_maxelseprintf "elem[%u]: ", $idxp *($arg0._M_impl._M_start + $idx)endend#输出vector中指定索引范围内的元素define pvector_range    set $size = $arg0._M_impl._M_finish - $arg0._M_impl._M_start    set $size_max = $size - 1printf "size_max[%u]: ", $size_maxset $start_idx = $arg1set $stop_idx = $arg2if $start_idx > $stop_idx    set $tmp_idx = $start_idx    set $start_idx = $stop_idx    set $stop_idx = $tmp_idxendif $start_idx < 0 || $stop_idx < 0 || $start_idx > $size_max || $stop_idx > $size_max    printf "idx1, idx2 are not in acceptable range: [0..%u].\n", $size_maxelse    set $i = $start_idxwhile $i <= $stop_idxprintf "elem[%u]: ", $ip *($arg0._M_impl._M_start + $i)set $i++endendenddefine pvector_itrprintf "iter: "p *($arg1*)($arg0._M_current)enddocument pvectorPrints std::vector<T> information.Syntax: pvector <vector>Syntax: pvector_index <vector> <idx1>     Syntax: pvector_range <idx1> <idx2>Note: idx, idx1 and idx2 must be in acceptable range [0..<vector>.size()-1].Examples:pvector v - Prints vector content, size, capacity and T typedefpvector_index v 0 - Prints element[idx] from vectorpvector_range v 1 2 - Prints elements in range [idx1..idx2] from vectorpvector_itr iter int - Prints itr end ## std::list<>#define plistset $head = &$arg0._M_impl._M_nodeset $current = $arg0._M_impl._M_node._M_nextset $size = 0while $current != $headset $current = $current._M_nextset $size++endprintf "List size = %u \n", $sizeprintf "List "whatis $arg0printf "Use plist_all <variable_name> plist_index <element_type> to see the elements in the list.\n"end#打印list中全部元素, 注意需要传入list中每个元素的类型define plist_allset $head = &$arg0._M_impl._M_nodeset $current = $arg0._M_impl._M_node._M_nextset $size = 0while $current != $headprintf "elem[%u]: ", $size        p *($arg1*)($current + 1)set $current = $current._M_nextset $size++endprintf "List size = %u \n", $sizeend#打印list中指定索引位置的元素(索引位置从0开始)define plist_indexset $head = &$arg0._M_impl._M_nodeset $current = $arg0._M_impl._M_node._M_nextset $size = 0while $current != $headif $size == $arg2printf "elem[%u]: ", $sizep *($arg1*)($current + 1)endset $current = $current._M_nextset $size++endprintf "List size = %u \n", $sizeenddefine plist_itrset $itr = $arg0printf "iter: "p *($arg1*)($itr._M_node+1)enddocument plistPrints std::list<T> information.Syntax: plist <list> <T> <idx>: Prints list size, if T defined all elements or just element at idxExamples:plist l - prints list size and definitionplist_all l int - prints all elements and list sizeplist_index l int 2 - prints the third element in the list (if exists) and list sizeplist_iter iter int prints iterator end#输出list中所有元素的某个成员 (plist_member l_pos pos x 1)define plist_member set $head = &$arg0._M_impl._M_nodeset $current = $arg0._M_impl._M_node._M_nextset $size = 0while $current != $headprintf "elem[%u]: ", $sizep (*($arg1*)($current + 1)).$arg2set $current = $current._M_nextset $size++endend#输出list中指定索引位置的某个成员 (plist_member_index l_pos pos x 1)define plist_member_indexset $head = &$arg0._M_impl._M_nodeset $current = $arg0._M_impl._M_node._M_nextset $size = 0while $current != $headif $size == $arg3printf "elem[%u]: ", $sizep (*($arg1*)($current + 1)).$arg2endset $current = $current._M_nextset $size++endenddocument plist_memberPrints std::list<T> information.Syntax: plist_member <list> <T> <idx>: Prints list size, if T defined all elements or just element at idxExamples:plist_member l int member - prints all elements and list sizeplist_member_index l int member 2 - prints the third element in the list (if exists) and list sizeend## std::map and std::multimap## 输出map中元素的类型,与map sizedefine pmapset $tree = $arg0set $i = 0set $node = $tree._M_t._M_impl._M_header._M_leftset $end = $tree._M_t._M_impl._M_headerset $tree_size = $tree._M_t._M_impl._M_node_countprintf "Map size = %u\n", $tree_sizeprintf "Map "whatis $treeprintf "Use pmap_all <variable_name> <left_element_type> <right_element_type> to see the elements in the map.\n"end# 打印map中的所有元素 pmap_all mapStudent int string define pmap_allset $tree = $arg0set $i = 0set $node = $tree._M_t._M_impl._M_header._M_leftset $end = $tree._M_t._M_impl._M_headerset $tree_size = $tree._M_t._M_impl._M_node_countwhile $i < $tree_sizeset $value = (void *)($node + 1)printf "elem[%u].left: ", $ip *($arg1*)$valueset $value = $value + sizeof($arg1)printf "elem[%u].right: ", $ip *($arg2*)$valueif $node._M_right != 0set $node = $node._M_rightwhile $node._M_left != 0    set $node = $node._M_left    endelseset $tmp_node = $node._M_parentwhile $node == $tmp_node._M_rightset $node = $tmp_nodeset $tmp_node = $tmp_node._M_parentendif $node._M_right != $tmp_nodeset $node = $tmp_nodeendendset $i++endend#打印map中左值为某个元素的匹配对与个数,pmap_left_match mapStudent int string 3define pmap_left_matchset $tree = $arg0set $i = 0set $node = $tree._M_t._M_impl._M_header._M_leftset $end = $tree._M_t._M_impl._M_headerset $tree_size = $tree._M_t._M_impl._M_node_countset $idx = $arg3set $ElementsFound = 0while $i < $tree_sizeset $value = (void *)($node + 1)if *($arg1*)$value == $idx    printf "elem[%u].left: ", $ip *($arg1*)$valueset $value = $value + sizeof($arg1)    printf "elem[%u].right: ", $ip *($arg2*)$valueset $ElementsFound++    endif $node._M_right != 0set $node = $node._M_rightwhile $node._M_left != 0set $node = $node._M_left    endelseset $tmp_node = $node._M_parentwhile $node == $tmp_node._M_rightset $node = $tmp_nodeset $tmp_node = $tmp_node._M_parent    endif $node._M_right != $tmp_nodeset $node = $tmp_nodeendendset $i++endprintf "Number of elements found = %u\n", $ElementsFoundend# 打印左值和右值匹配的个数 pmap_left_right_match mappair int int 2 200 define pmap_left_right_matchset $tree = $arg0set $i = 0set $node = $tree._M_t._M_impl._M_header._M_leftset $end = $tree._M_t._M_impl._M_headerset $tree_size = $tree._M_t._M_impl._M_node_countset $idx1 = $arg3set $idx2 = $arg4set $ElementsFound = 0while $i < $tree_sizeprintf "input[%u].left: ", $iset $value = (void *)($node + 1)set $valueLeft = *($arg1*)$valueset $valueRight = *($arg2*)($value + sizeof($arg1))if $valueLeft == $idx1 && $valueRight == $idx2printf "elem[%u].left: ", $ip $valueLeftprintf "elem[%u].right: ", $ip $valueRightset $ElementsFound++endif $node._M_right != 0    set $node = $node._M_right    while $node._M_left != 0set $node = $node._M_leftendelseset $tmp_node = $node._M_parentwhile $node == $tmp_node._M_rightset $node = $tmp_nodeset $tmp_node = $tmp_node._M_parentendif $node._M_right != $tmp_nodeset $node = $tmp_node    endendset $i++endprintf "Number of elements found = %u\n", $ElementsFoundend# pmap_itr mapiter int intdefine pmap_itrecho $arg0printf "->left: "p *($arg1*)($arg0._M_node+1)echo $arg0printf "->right: "p *($arg2*)((void*)($arg0._M_node+1)+sizeof($arg1))enddocument pmapPrints std::map<TLeft and TRight> or std::multimap<TLeft and TRight> information. Works for std::multimap as well.Syntax: pmap <map> <TtypeLeft> <TypeRight> <valLeft> <valRight>: Prints map size, if T defined all elements or just element(s) with val(s)Examples:pmap m - prints map size and definitionpmap_app m int int - prints all elements and map sizepmap_left_match m int int 20 - prints the element(s) with left-value = 20 (if any) and map sizepmap_left_right_match m int int 20 200 - prints the element(s) with left-value = 20 and right-value = 200 (if any) and map sizepmap_itr itr int int - prints the iteratorenddefine pmap_memberset $tree = $arg0set $node = $tree._M_t._M_impl._M_header._M_leftset $end = $tree._M_t._M_impl._M_headerset $tree_size = $tree._M_t._M_impl._M_node_countwhile $i < $tree_sizeset $value = (void *)($node + 1)printf "elem[%u].left: ", $ip (*($arg1*)$value).$arg2set $value = $value + sizeof($arg1)    printf "elem[%u].right: ", $ip (*($arg3*)$value).$arg4if $node._M_right != 0set $node = $node._M_rightwhile $node._M_left != 0set $node = $node._M_leftendelseset $tmp_node = $node._M_parentwhile $node == $tmp_node._M_rightset $node = $tmp_nodeset $tmp_node = $tmp_node._M_parentendif $node._M_right != $tmp_nodeset $node = $tmp_nodeendendset $i++endenddefine pmap_member_left_matchset $tree = $arg0set $node = $tree._M_t._M_impl._M_header._M_leftset $end = $tree._M_t._M_impl._M_headerset $tree_size = $tree._M_t._M_impl._M_node_countset $idx = $arg5set $ElementsFound = 0while $i < $tree_sizeset $value = (void *)($node + 1)if *($arg1*)$value == $idxprintf "elem[%u].left: ", $ip (*($arg1*)$value).$arg2    set $value = $value + sizeof($arg1)printf "elem[%u].right: ", $ip (*($arg3*)$value).$arg4set $ElementsFound++endif $node._M_right != 0set $node = $node._M_rightwhile $node._M_left != 0set $node = $node._M_leftend    elseset $tmp_node = $node._M_parentwhile $node == $tmp_node._M_rightset $node = $tmp_node    set $tmp_node = $tmp_node._M_parentendif $node._M_right != $tmp_nodeset $node = $tmp_nodeendendset $i++endprintf "Number of elements found = %u\n", $ElementsFoundenddocument pmap_memberPrints std::map<TLeft and TRight> or std::multimap<TLeft and TRight> information. Works for std::multimap as well.Syntax: pmap <map> <TtypeLeft> <TypeRight> <valLeft> <valRight>: Prints map size, if T defined all elements or just element(s) with val(s)Examples:pmap_member m class1 member1 class2 member2 - prints class1.member1 : class2.member2pmap_member m class1 member1 class2 member2 lvalue - prints class1.member1 : class2.member2 where class1 == lvalueend## std::set and std::multiset## 打印set的size与元素类型define psetset $tree = $arg0set $i = 0set $node = $tree._M_t._M_impl._M_header._M_leftset $end = $tree._M_t._M_impl._M_headerset $tree_size = $tree._M_t._M_impl._M_node_countprintf "Set size = %u\n", $tree_sizeprintf "Set "whatis $treeprintf "Use pset <variable_name> <element_type> to see the elements in the set.\n"end# 打印set中的所有元素, 需要传入输入数据类型define pset_allset $tree = $arg0set $i = 0set $node = $tree._M_t._M_impl._M_header._M_leftset $end = $tree._M_t._M_impl._M_headerset $tree_size = $tree._M_t._M_impl._M_node_countwhile $i < $tree_sizeset $value = (void *)($node + 1)printf "elem[%u]: ", $ip *($arg1*)$valueif $node._M_right != 0set $node = $node._M_rightwhile $node._M_left != 0set $node = $node._M_leftendelseset $tmp_node = $node._M_parentwhile $node == $tmp_node._M_rightset $node = $tmp_nodeset $tmp_node = $tmp_node._M_parentendif $node._M_right != $tmp_nodeset $node = $tmp_nodeendend    set $i++endend# 查询pset中某个元素的出现次数define pset_matchset $tree = $arg0set $i = 0set $node = $tree._M_t._M_impl._M_header._M_leftset $end = $tree._M_t._M_impl._M_headerset $tree_size = $tree._M_t._M_impl._M_node_countset $idx = $arg2set $ElementsFound = 0while $i < $tree_sizeset $value = (void *)($node + 1)if *($arg1*)$value == $idxprintf "elem[%u]: ", $ip *($arg1*)$valueset $ElementsFound++endif $node._M_right != 0set $node = $node._M_rightwhile $node._M_left != 0set $node = $node._M_leftendelseset $tmp_node = $node._M_parentwhile $node == $tmp_node._M_right    set $node = $tmp_nodeset $tmp_node = $tmp_node._M_parent    endif $node._M_right != $tmp_nodeset $node = $tmp_nodeendendset $i++endprintf "Number of elements found = %u\n", $ElementsFoundenddefine pset_itrp *($arg1*)($arg0._M_node+1)enddocument psetPrints std::set<T> or std::multiset<T> information. Works for std::multiset as well.Syntax: pset <set> <T> <val>: Prints set size, if T defined all elements or just element(s) having valExamples:pset s - prints set size and definitionpset_all s int - prints all elements and the size of spset_match s int 20 - prints the element(s) with value = 20 (if any) and the size of spset_itr itr int - prints the value of itrend## std::dequeue#define pdequeueset $size = 0    set $start_cur = $arg0._M_impl._M_start._M_cur    set $start_last = $arg0._M_impl._M_start._M_last    set $start_stop = $start_last    while $start_cur != $start_stop        p *$start_cur        set $start_cur++        set $size++    end    set $finish_first = $arg0._M_impl._M_finish._M_first    set $finish_cur = $arg0._M_impl._M_finish._M_cur    set $finish_last = $arg0._M_impl._M_finish._M_last    if $finish_cur < $finish_last        set $finish_stop = $finish_cur    else        set $finish_stop = $finish_last    end    while $finish_first != $finish_stop        p *$finish_first        set $finish_first++        set $size++    endprintf "Dequeue size = %u\n", $sizeenddocument pdequeuePrints std::dequeue<T> information.Syntax: pdequeue <dequeue>: Prints dequeue size, if T defined all elementsDeque elements are listed "left to right" (left-most stands for front and right-most stands for back)Example:pdequeue d - prints all elements and size of dend## std::stack#define pstackset $start_cur = $arg0.c._M_impl._M_start._M_curset $finish_cur = $arg0.c._M_impl._M_finish._M_curset $size = $finish_cur - $start_cur    set $i = $size - 1    while $i >= 0        p *($start_cur + $i)        set $i--    endprintf "Stack size = %u\n", $sizeenddocument pstackPrints std::stack<T> information.Syntax: pstack <stack>: Prints all elements and size of the stackStack elements are listed "top to buttom" (top-most element is the first to come on pop)Example:pstack s - prints all elements and the size of send## std::queue#define pqueueset $start_cur = $arg0.c._M_impl._M_start._M_curset $finish_cur = $arg0.c._M_impl._M_finish._M_curset $size = $finish_cur - $start_cur    set $i = 0    while $i < $size        p *($start_cur + $i)        set $i++    endprintf "Queue size = %u\n", $sizeenddocument pqueuePrints std::queue<T> information.Syntax: pqueue <queue>: Prints all elements and the size of the queueQueue elements are listed "top to bottom" (top-most element is the first to come on pop)Example:pqueue q - prints all elements and the size of qend## std::priority_queue#define ppqueueset $size = $arg0.c._M_impl._M_finish - $arg0.c._M_impl._M_startset $capacity = $arg0.c._M_impl._M_end_of_storage - $arg0.c._M_impl._M_startset $i = $size - 1while $i >= 0p *($arg0.c._M_impl._M_start + $i)set $i--endprintf "Priority queue size = %u\n", $sizeprintf "Priority queue capacity = %u\n", $capacityenddocument ppqueuePrints std::priority_queue<T> information.Syntax: ppqueue <priority_queue>: Prints all elements, size and capacity of the priority_queuePriority_queue elements are listed "top to buttom" (top-most element is the first to come on pop)Example:ppqueue pq - prints all elements, size and capacity of pqend## std::bitset#define pbitset    p /t $arg0._M_wenddocument pbitsetPrints std::bitset<n> information.Syntax: pbitset <bitset>: Prints all bits in bitsetExample:pbitset b - prints all bits in bend## std::string#define pstringprintf "String \t\t\t= \"%s\"\n", $arg0._M_data()printf "String size/length \t= %u\n", $arg0._M_rep()._M_lengthprintf "String capacity \t= %u\n", $arg0._M_rep()._M_capacityprintf "String ref-count \t= %d\n", $arg0._M_rep()._M_refcountenddocument pstringPrints std::string information.Syntax: pstring <string>Example:pstring s - Prints content, size/length, capacity and ref-count of string send ## std::wstring#define pwstringcall printf("WString \t\t= \"%ls\"\n", $arg0._M_data())printf "WString size/length \t= %u\n", $arg0._M_rep()._M_lengthprintf "WString capacity \t= %u\n", $arg0._M_rep()._M_capacityprintf "WString ref-count \t= %d\n", $arg0._M_rep()._M_refcountenddocument pwstringPrints std::wstring information.Syntax: pwstring <wstring>Example:pwstring s - Prints content, size/length, capacity and ref-count of wstring send ## C++ related beautifiers (optional)#set print pretty onset print object onset print static-members onset print vtbl onset print demangle onset demangle-style gnu-v3set print sevenbit-strings off

但是缺陷,我们需要自己记忆很多的命令,不支持内嵌类型

 

2)使用python pretty-printers

Gdb 7.0 加入python脚本支持,可以使用python pretty-printers显示stl内容,pretty-printers使用方法:

https://access.redhat.com/site/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Developer_Guide/debuggingprettyprinters.html

 

具体使用:

1)安装gdb.7以上版本(需要安装过python的机器):

./configure--prefix=/home/users/liufeng01/bin/gdb/--with-python=/home/users/liufeng01/python/

2)通过svn下载python libstdc++ printers:

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

3)在.gdbinit中添加:

         python

         import sys

         sys.path.insert(0,'/home/maude/gdb_printers/python')

         from libstdcxx.v6.printers importregister_libstdcxx_printers

         register_libstdcxx_printers (None)

         end

 直接可以通过 p 打印vectorstring等内容,p /r 可以打印原来 print打印的内容。

 Pretty print是个看似完美的解决方案,但是但是在我的测试机器上对list与map的支持还有问题,可能是stl版本的问题。
原创粉丝点击