使用GDB 调试STL方法

背景:

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

输出:

(gdb) p a

$1 = {

  static npos = 18446744073709551615,

  _M_dataplus = {

    > = {

     <__gnu_cxx::new_allocator> = {},},

    members ofstd::basic_string,std::allocator>::_Alloc_hider:

    _M_p = 0x50b028 "test"

  }

           }

打印一个vector v:

(gdb) p v

$2 = {

  >> = {

    _M_impl = {

      > = {

        <__gnu_cxx::new_allocator> ={}, },

      members ofstd::_Vector_base >::_Vector_impl:

      _M_start = 0x50b060,

      _M_finish = 0x50b068,

      _M_end_of_storage = 0x50b068

    }

  }, }

打印其中的某个元素:

(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 -- via pvector command
#       std::list -- via plist or plist_member command
#       std::map -- via pmap or pmap_member command
#       std::multimap -- via pmap or pmap_member command
#       std::set -- via pset command
#       std::multiset -- via pset command
#       std::deque -- via pdequeue command
#       std::stack -- via pstack command
#       std::queue -- via pqueue command
#       std::priority_queue -- via ppqueue command
#       std::bitset -- 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: [email protected] (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 - 1

	set $i = 0
	while $i < $size
		printf "elem[%u]: ", $i
		p *($arg0._M_impl._M_start + $i)
		set $i++
	end

	printf "Vector size = %u\n", $size
	printf "Vector capacity = %u\n", $capacity
	printf "Element "
	whatis $arg0._M_impl._M_start
end

#输出vector中指定索引位置的元素
define pvector_index
	set $idx = $arg1
    set $size = $arg0._M_impl._M_finish - $arg0._M_impl._M_start
    set $size_max = $size - 1

	if $idx < 0 || $idx > $size_max
		printf "idx is not in acceptable range: [0..%u].\n", $size_max
	else
		printf "elem[%u]: ", $idx
		p *($arg0._M_impl._M_start + $idx)
	end
end

#输出vector中指定索引范围内的元素
define pvector_range
    set $size = $arg0._M_impl._M_finish - $arg0._M_impl._M_start
    set $size_max = $size - 1
	printf "size_max[%u]: ", $size_max

	set $start_idx = $arg1
	set $stop_idx = $arg2
	if $start_idx > $stop_idx
	    set $tmp_idx = $start_idx
	    set $start_idx = $stop_idx
	    set $stop_idx = $tmp_idx
	end

	if $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_max
	else
	    set $i = $start_idx
		while $i <= $stop_idx
			printf "elem[%u]: ", $i
			p *($arg0._M_impl._M_start + $i)
			set $i++
		end
	end
end

define pvector_itr
	printf "iter: "
	p *($arg1*)($arg0._M_current)
end

document pvector
	Prints std::vector information.
	Syntax: pvector 
	Syntax: pvector_index   
    Syntax: pvector_range  
	Note: idx, idx1 and idx2 must be in acceptable range [0...size()-1].
	Examples:
	pvector v - Prints vector content, size, capacity and T typedef
	pvector_index v 0 - Prints element[idx] from vector
	pvector_range v 1 2 - Prints elements in range [idx1..idx2] from vector
	pvector_itr iter int - Prints itr 
end 

#
# std::list<>
#

define plist
	set $head = &$arg0._M_impl._M_node
	set $current = $arg0._M_impl._M_node._M_next
	set $size = 0
	while $current != $head
		set $current = $current._M_next
		set $size++
	end
	printf "List size = %u \n", $size
	printf "List "
	whatis $arg0
	printf "Use plist_all  plist_index  to see the elements in the list.\n"
end

#打印list中全部元素, 注意需要传入list中每个元素的类型
define plist_all
	set $head = &$arg0._M_impl._M_node
	set $current = $arg0._M_impl._M_node._M_next
	set $size = 0
	while $current != $head
		printf "elem[%u]: ", $size
        p *($arg1*)($current + 1)
		set $current = $current._M_next
		set $size++
	end
	printf "List size = %u \n", $size
end

#打印list中指定索引位置的元素(索引位置从0开始)
define plist_index
	set $head = &$arg0._M_impl._M_node
	set $current = $arg0._M_impl._M_node._M_next
	set $size = 0
	while $current != $head
		if $size == $arg2
			printf "elem[%u]: ", $size
			p *($arg1*)($current + 1)
		end

		set $current = $current._M_next
		set $size++
	end

	printf "List size = %u \n", $size
end

define plist_itr
	set $itr = $arg0
	printf "iter: "
	p *($arg1*)($itr._M_node+1)
end

document plist
	Prints std::list information.
	Syntax: plist   : Prints list size, if T defined all elements or just element at idx
	Examples:
	plist l - prints list size and definition
	plist_all l int - prints all elements and list size
	plist_index l int 2 - prints the third element in the list (if exists) and list size
	plist_iter iter int prints iterator 
end

#输出list中所有元素的某个成员 (plist_member l_pos pos x 1)
define plist_member 
	set $head = &$arg0._M_impl._M_node
	set $current = $arg0._M_impl._M_node._M_next
	set $size = 0
	while $current != $head
		printf "elem[%u]: ", $size
		p (*($arg1*)($current + 1)).$arg2
		set $current = $current._M_next
		set $size++
	end
end

#输出list中指定索引位置的某个成员 (plist_member_index l_pos pos x 1)
define plist_member_index
	set $head = &$arg0._M_impl._M_node
	set $current = $arg0._M_impl._M_node._M_next
	set $size = 0
	while $current != $head
		if $size == $arg3
			printf "elem[%u]: ", $size
			p (*($arg1*)($current + 1)).$arg2
		end
		set $current = $current._M_next
		set $size++
	end
end

document plist_member
	Prints std::list information.
	Syntax: plist_member   : Prints list size, if T defined all elements or just element at idx
	Examples:
	plist_member l int member - prints all elements and list size
	plist_member_index l int member 2 - prints the third element in the list (if exists) and list size
end

#
# std::map and std::multimap
#
# 输出map中元素的类型,与map size
define pmap
	set $tree = $arg0
	set $i = 0
	set $node = $tree._M_t._M_impl._M_header._M_left
	set $end = $tree._M_t._M_impl._M_header
	set $tree_size = $tree._M_t._M_impl._M_node_count
	printf "Map size = %u\n", $tree_size
	printf "Map "
	whatis $tree
	printf "Use pmap_all    to see the elements in the map.\n"
end

# 打印map中的所有元素 pmap_all mapStudent int string 
define pmap_all
	set $tree = $arg0
	set $i = 0
	set $node = $tree._M_t._M_impl._M_header._M_left
	set $end = $tree._M_t._M_impl._M_header
	set $tree_size = $tree._M_t._M_impl._M_node_count

	while $i < $tree_size
		set $value = (void *)($node + 1)
		printf "elem[%u].left: ", $i
		p *($arg1*)$value
		set $value = $value + sizeof($arg1)
		printf "elem[%u].right: ", $i
		p *($arg2*)$value
		if $node._M_right != 0
			set $node = $node._M_right
			while $node._M_left != 0
			    set $node = $node._M_left
		    end
		else
			set $tmp_node = $node._M_parent
			while $node == $tmp_node._M_right
				set $node = $tmp_node
				set $tmp_node = $tmp_node._M_parent
			end
			if $node._M_right != $tmp_node
				set $node = $tmp_node
			end
		end
		set $i++
	end
end

#打印map中左值为某个元素的匹配对与个数,pmap_left_match mapStudent int string 3
define pmap_left_match
	set $tree = $arg0
	set $i = 0
	set $node = $tree._M_t._M_impl._M_header._M_left
	set $end = $tree._M_t._M_impl._M_header
	set $tree_size = $tree._M_t._M_impl._M_node_count

	set $idx = $arg3
	set $ElementsFound = 0

	while $i < $tree_size
		set $value = (void *)($node + 1)
		if *($arg1*)$value == $idx
		    printf "elem[%u].left: ", $i
			p *($arg1*)$value
			set $value = $value + sizeof($arg1)
		    printf "elem[%u].right: ", $i
			p *($arg2*)$value
			set $ElementsFound++
	    end
		if $node._M_right != 0
			set $node = $node._M_right
			while $node._M_left != 0
				set $node = $node._M_left
		    end
		else
			set $tmp_node = $node._M_parent
			while $node == $tmp_node._M_right
				set $node = $tmp_node
				set $tmp_node = $tmp_node._M_parent
		    end
			if $node._M_right != $tmp_node
				set $node = $tmp_node
			end
		end
		set $i++
	end
	printf "Number of elements found = %u\n", $ElementsFound
end

# 打印左值和右值匹配的个数 pmap_left_right_match mappair int int 2 200 
define pmap_left_right_match
	set $tree = $arg0
	set $i = 0
	set $node = $tree._M_t._M_impl._M_header._M_left
	set $end = $tree._M_t._M_impl._M_header
	set $tree_size = $tree._M_t._M_impl._M_node_count

	set $idx1 = $arg3
	set $idx2 = $arg4
	set $ElementsFound = 0

	while $i < $tree_size
		printf "input[%u].left: ", $i
		set $value = (void *)($node + 1)
		set $valueLeft = *($arg1*)$value
		set $valueRight = *($arg2*)($value + sizeof($arg1))
		if $valueLeft == $idx1 && $valueRight == $idx2
			printf "elem[%u].left: ", $i
			p $valueLeft
			printf "elem[%u].right: ", $i
			p $valueRight
			set $ElementsFound++
		end
		if $node._M_right != 0
		    set $node = $node._M_right
		    while $node._M_left != 0
				set $node = $node._M_left
			end
		else
			set $tmp_node = $node._M_parent
			while $node == $tmp_node._M_right
				set $node = $tmp_node
				set $tmp_node = $tmp_node._M_parent
			end
			if $node._M_right != $tmp_node
				set $node = $tmp_node
		    end
		end
		set $i++
	end
	printf "Number of elements found = %u\n", $ElementsFound
end

# pmap_itr mapiter int int
define pmap_itr
	echo $arg0
	printf "->left: "
	p *($arg1*)($arg0._M_node+1)
	echo $arg0
	printf "->right: "
	p *($arg2*)((void*)($arg0._M_node+1)+sizeof($arg1))
end

document pmap
	Prints std::map or std::multimap information. Works for std::multimap as well.
	Syntax: pmap     : Prints map size, if T defined all elements or just element(s) with val(s)
	Examples:
	pmap m - prints map size and definition
	pmap_app m int int - prints all elements and map size
	pmap_left_match m int int 20 - prints the element(s) with left-value = 20 (if any) and map size
	pmap_left_right_match m int int 20 200 - prints the element(s) with left-value = 20 and right-value = 200 (if any) and map size
	pmap_itr itr int int - prints the iterator
end

define pmap_member
	set $tree = $arg0
	set $node = $tree._M_t._M_impl._M_header._M_left
	set $end = $tree._M_t._M_impl._M_header
	set $tree_size = $tree._M_t._M_impl._M_node_count
	while $i < $tree_size
		set $value = (void *)($node + 1)
		printf "elem[%u].left: ", $i
		p (*($arg1*)$value).$arg2
		set $value = $value + sizeof($arg1)
	    printf "elem[%u].right: ", $i
		p (*($arg3*)$value).$arg4
		if $node._M_right != 0
			set $node = $node._M_right
			while $node._M_left != 0
				set $node = $node._M_left
			end
		else
			set $tmp_node = $node._M_parent
			while $node == $tmp_node._M_right
				set $node = $tmp_node
				set $tmp_node = $tmp_node._M_parent
			end
			if $node._M_right != $tmp_node
				set $node = $tmp_node
			end
		end
		set $i++
	end
end

define pmap_member_left_match
	set $tree = $arg0
	set $node = $tree._M_t._M_impl._M_header._M_left
	set $end = $tree._M_t._M_impl._M_header
	set $tree_size = $tree._M_t._M_impl._M_node_count

	set $idx = $arg5
	set $ElementsFound = 0
	while $i < $tree_size
		set $value = (void *)($node + 1)
		if *($arg1*)$value == $idx
			printf "elem[%u].left: ", $i
			p (*($arg1*)$value).$arg2
		    set $value = $value + sizeof($arg1)
			printf "elem[%u].right: ", $i
			p (*($arg3*)$value).$arg4
			set $ElementsFound++
		end
		if $node._M_right != 0
			set $node = $node._M_right
			while $node._M_left != 0
				set $node = $node._M_left
			end
	    else
			set $tmp_node = $node._M_parent
			while $node == $tmp_node._M_right
				set $node = $tmp_node
			    set $tmp_node = $tmp_node._M_parent
			end
			if $node._M_right != $tmp_node
				set $node = $tmp_node
			end
		end
		set $i++
	end
	printf "Number of elements found = %u\n", $ElementsFound
end

document pmap_member
	Prints std::map or std::multimap information. Works for std::multimap as well.
	Syntax: pmap     : 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.member2
	pmap_member m class1 member1 class2 member2 lvalue - prints class1.member1 : class2.member2 where class1 == lvalue
end


#
# std::set and std::multiset
#

# 打印set的size与元素类型
define pset
	set $tree = $arg0
	set $i = 0
	set $node = $tree._M_t._M_impl._M_header._M_left
	set $end = $tree._M_t._M_impl._M_header
	set $tree_size = $tree._M_t._M_impl._M_node_count

	printf "Set size = %u\n", $tree_size
	printf "Set "
	whatis $tree
	printf "Use pset   to see the elements in the set.\n"
end

# 打印set中的所有元素, 需要传入输入数据类型
define pset_all
	set $tree = $arg0
	set $i = 0
	set $node = $tree._M_t._M_impl._M_header._M_left
	set $end = $tree._M_t._M_impl._M_header
	set $tree_size = $tree._M_t._M_impl._M_node_count

	while $i < $tree_size
		set $value = (void *)($node + 1)
		printf "elem[%u]: ", $i
		p *($arg1*)$value
		if $node._M_right != 0
			set $node = $node._M_right
			while $node._M_left != 0
				set $node = $node._M_left
			end
		else
			set $tmp_node = $node._M_parent
			while $node == $tmp_node._M_right
				set $node = $tmp_node
				set $tmp_node = $tmp_node._M_parent
			end
			if $node._M_right != $tmp_node
				set $node = $tmp_node
			end
		end
	    set $i++
	end
end

# 查询pset中某个元素的出现次数
define pset_match
	set $tree = $arg0
	set $i = 0
	set $node = $tree._M_t._M_impl._M_header._M_left
	set $end = $tree._M_t._M_impl._M_header
	set $tree_size = $tree._M_t._M_impl._M_node_count
	set $idx = $arg2

	set $ElementsFound = 0
	while $i < $tree_size
		set $value = (void *)($node + 1)
		if *($arg1*)$value == $idx
			printf "elem[%u]: ", $i
			p *($arg1*)$value
			set $ElementsFound++
		end
		if $node._M_right != 0
			set $node = $node._M_right
			while $node._M_left != 0
				set $node = $node._M_left
			end
		else
			set $tmp_node = $node._M_parent
			while $node == $tmp_node._M_right
			    set $node = $tmp_node
				set $tmp_node = $tmp_node._M_parent
		    end
			if $node._M_right != $tmp_node
				set $node = $tmp_node
			end
		end
		set $i++
	end
	printf "Number of elements found = %u\n", $ElementsFound
end

define pset_itr
	p *($arg1*)($arg0._M_node+1)
end

document pset
	Prints std::set or std::multiset information. Works for std::multiset as well.
	Syntax: pset   : Prints set size, if T defined all elements or just element(s) having val
	Examples:
	pset s - prints set size and definition
	pset_all s int - prints all elements and the size of s
	pset_match s int 20 - prints the element(s) with value = 20 (if any) and the size of s
	pset_itr itr int - prints the value of itr
end

#
# std::dequeue
#

define pdequeue
	set $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++
    end
	printf "Dequeue size = %u\n", $size
end

document pdequeue
	Prints std::dequeue information.
	Syntax: pdequeue : Prints dequeue size, if T defined all elements
	Deque 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 d
end

#
# std::stack
#

define pstack
	set $start_cur = $arg0.c._M_impl._M_start._M_cur
	set $finish_cur = $arg0.c._M_impl._M_finish._M_cur
	set $size = $finish_cur - $start_cur
    set $i = $size - 1
    while $i >= 0
        p *($start_cur + $i)
        set $i--
    end
	printf "Stack size = %u\n", $size
end

document pstack
	Prints std::stack information.
	Syntax: pstack : Prints all elements and size of the stack
	Stack 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 s
end

#
# std::queue
#

define pqueue
	set $start_cur = $arg0.c._M_impl._M_start._M_cur
	set $finish_cur = $arg0.c._M_impl._M_finish._M_cur
	set $size = $finish_cur - $start_cur
    set $i = 0
    while $i < $size
        p *($start_cur + $i)
        set $i++
    end
	printf "Queue size = %u\n", $size
end

document pqueue
	Prints std::queue information.
	Syntax: pqueue : Prints all elements and the size of the queue
	Queue 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 q
end



#
# std::priority_queue
#

define ppqueue
	set $size = $arg0.c._M_impl._M_finish - $arg0.c._M_impl._M_start
	set $capacity = $arg0.c._M_impl._M_end_of_storage - $arg0.c._M_impl._M_start
	set $i = $size - 1
	while $i >= 0
		p *($arg0.c._M_impl._M_start + $i)
		set $i--
	end
	printf "Priority queue size = %u\n", $size
	printf "Priority queue capacity = %u\n", $capacity
end

document ppqueue
	Prints std::priority_queue information.
	Syntax: ppqueue : Prints all elements, size and capacity of the priority_queue
	Priority_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 pq
end


#
# std::bitset
#

define pbitset
    p /t $arg0._M_w
end

document pbitset
	Prints std::bitset information.
	Syntax: pbitset : Prints all bits in bitset
	Example:
	pbitset b - prints all bits in b
end

#
# std::string
#

define pstring
	printf "String \t\t\t= \"%s\"\n", $arg0._M_data()
	printf "String size/length \t= %u\n", $arg0._M_rep()._M_length
	printf "String capacity \t= %u\n", $arg0._M_rep()._M_capacity
	printf "String ref-count \t= %d\n", $arg0._M_rep()._M_refcount
end

document pstring
	Prints std::string information.
	Syntax: pstring 
	Example:
	pstring s - Prints content, size/length, capacity and ref-count of string s
end 


#
# std::wstring
#

define pwstring
	call printf("WString \t\t= \"%ls\"\n", $arg0._M_data())
	printf "WString size/length \t= %u\n", $arg0._M_rep()._M_length
	printf "WString capacity \t= %u\n", $arg0._M_rep()._M_capacity
	printf "WString ref-count \t= %d\n", $arg0._M_rep()._M_refcount
end

document pwstring
	Prints std::wstring information.
	Syntax: pwstring 
	Example:
	pwstring s - Prints content, size/length, capacity and ref-count of wstring s
end 

#
# C++ related beautifiers (optional)
#

set print pretty on
set print object on
set print static-members on
set print vtbl on
set print demangle on
set demangle-style gnu-v3
set 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版本的问题。

你可能感兴趣的:(系统调试)