Andy Niu �����ĵ�

Andy Niu

Andy Niu Help  1.0.0.0

变量

 gdb调试
 
 gdb调试之list
 
 gdb调试服务vru
 
 gdb打印vector的内容
 
 gdb打印stl的内容
 
 gdb查看崩溃信息
 
 gdb查看core堆栈,栈顶显示问号
 
 gdb在动态库上打断点出现错误
 

详细描述

变量说明

gdb在动态库上打断点出现错误
1、no source file named xxx
2、一种情况是动态库还没有加载进来
3、一种情况是因为找不到源文件,把需要的源文件拷贝到当前目录,
    或者获取拷贝到一个目录,使用directory指定源文件的搜索路径
gdb打印stl的内容
1、将下面的内容,保存到 ~/.gdbinit
#                                                                                                        
#   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: [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<>
#

define pvector
    if $argc == 0
        help pvector
    else
        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
    end
    if $argc == 1
        set $i = 0
        while $i < $size
            printf "elem[%u]: ", $i
            p *($arg0._M_impl._M_start + $i)
            set $i++
        end
    end
    if $argc == 2
        set $idx = $arg1
        if $idx < 0 || $idx > $size_max
            printf "idx1, idx2 are not in acceptable range: [0..%u].\n", $size_max
        else
            printf "elem[%u]: ", $idx
            p *($arg0._M_impl._M_start + $idx)
        end
    end
    if $argc == 3
      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
    if $argc > 0
        printf "Vector size = %u\n", $size
        printf "Vector capacity = %u\n", $capacity
        printf "Element "
        whatis $arg0._M_impl._M_start
    end
end

document pvector
    Prints std::vector<T> information.
    Syntax: pvector <vector> <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 typedef
    pvector v 0 - Prints element[idx] from vector
    pvector v 1 2 - Prints elements in range [idx1..idx2] from vector
end 

#
# std::list<>
#

define plist
    if $argc == 0
        help plist
    else
        set $head = &$arg0._M_impl._M_node
        set $current = $arg0._M_impl._M_node._M_next
        set $size = 0
        while $current != $head
            if $argc == 2
                printf "elem[%u]: ", $size
                p *($arg1*)($current + 1)
            end
            if $argc == 3
                if $size == $arg2
                    printf "elem[%u]: ", $size
                    p *($arg1*)($current + 1)
                end
            end
            set $current = $current._M_next
            set $size++
        end
        printf "List size = %u \n", $size
        if $argc == 1
            printf "List "
            whatis $arg0
            printf "Use plist <variable_name> <element_type> to see the elements in the list.\n"
        end
    end
end

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

define plist_member
    if $argc == 0
        help plist_member
    else
        set $head = &$arg0._M_impl._M_node
        set $current = $arg0._M_impl._M_node._M_next
        set $size = 0
        while $current != $head
            if $argc == 3
                printf "elem[%u]: ", $size
                p (*($arg1*)($current + 1)).$arg2
            end
            if $argc == 4
                if $size == $arg3
                    printf "elem[%u]: ", $size
                    p (*($arg1*)($current + 1)).$arg2
                end
            end
            set $current = $current._M_next
            set $size++
        end
        printf "List size = %u \n", $size
        if $argc == 1
            printf "List "
            whatis $arg0
            printf "Use plist_member <variable_name> <element_type> <member> to see the elements in the list.\n"
        end
    end
end

document plist_member
    Prints std::list<T> information.
    Syntax: plist <list> <T> <idx>: 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 l int member 2 - prints the third element in the list (if exists) and list size
end


#
# std::map and std::multimap
#

define pmap
    if $argc == 0
        help pmap
    else
        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
        if $argc == 1
            printf "Map "
            whatis $tree
            printf "Use pmap <variable_name> <left_element_type> <right_element_type> to see the elements in the map.\n"
        end
        if $argc == 3
            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
        if $argc == 4
            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
        if $argc == 5
            set $idx1 = $arg3
            set $idx2 = $arg4
            set $ElementsFound = 0
            while $i < $tree_size
                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
        printf "Map size = %u\n", $tree_size
    end
end

document pmap
    Prints 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 definition
    pmap m int int - prints all elements and map size
    pmap m int int 20 - prints the element(s) with left-value = 20 (if any) and map size
    pmap m int int 20 200 - prints the element(s) with left-value = 20 and right-value = 200 (if any) and map size
end


define pmap_member
    if $argc == 0
        help pmap_member
    else
        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
        if $argc == 1
            printf "Map "
            whatis $tree
            printf "Use pmap <variable_name> <left_element_type> <right_element_type> to see the elements in the map.\n"
        end
        if $argc == 5
            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
        if $argc == 6
            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
        printf "Map size = %u\n", $tree_size
    end
end

document pmap_member
    Prints 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.member2
    pmap_member m class1 member1 class2 member2 lvalue - prints class1.member1 : class2.member2 where class1 == lvalue
end


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

define pset
    if $argc == 0
        help pset
    else
        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
        if $argc == 1
            printf "Set "
            whatis $tree
            printf "Use pset <variable_name> <element_type> to see the elements in the set.\n"
        end
        if $argc == 2
            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
        if $argc == 3
            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
        printf "Set size = %u\n", $tree_size
    end
end

document pset
    Prints 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 val
    Examples:
    pset s - prints set size and definition
    pset s int - prints all elements and the size of s
    pset s int 20 - prints the element(s) with value = 20 (if any) and the size of s
end



#
# std::dequeue
#

define pdequeue
    if $argc == 0
        help pdequeue
    else
        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
end

document pdequeue
    Prints std::dequeue<T> information.
    Syntax: pdequeue <dequeue>: 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
    if $argc == 0
        help pstack
    else
        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
end

document pstack
    Prints std::stack<T> information.
    Syntax: pstack <stack>: 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
    if $argc == 0
        help pqueue
    else
        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
end

document pqueue
    Prints std::queue<T> information.
    Syntax: pqueue <queue>: 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
    if $argc == 0
        help ppqueue
    else
        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
end

document ppqueue
    Prints std::priority_queue<T> information.
    Syntax: ppqueue <priority_queue>: 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
    if $argc == 0
        help pbitset
    else
        p /t $arg0._M_w
    end
end

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



#
# std::string
#

define pstring
    if $argc == 0
        help pstring
    else
        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
end

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

#
# std::wstring
#

define pwstring
    if $argc == 0
        help pwstring
    else
        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
end

document pwstring
    Prints std::wstring information.
    Syntax: pwstring <wstring>
    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、然后就可以使用这些命令 pvector, plist, pmap, pset, pdequeue, pstack, pqueue, ppqueue, pbitset, pstring, pwstring
参见
gdb打印vector的内容
1、高版本的gdb可以打印出vector的内容,但是低版本的vector还不行。
2、怎么解决?
    我们知道vector内部是使用数组实现的,我们可以打印出来array地址的内容。
3、示例如下:
    [niu_zibin@localhost gdb]$ vi main.cpp
    
    1 #include <stdio.h>
    2 #include <vector.h>
    3 int main()
    4 {
    5         vector<int> aVec;
    6         aVec.push_back(1);
    7         aVec.push_back(2);
    8         aVec.push_back(3);
    9 
    10         return 0;
    11 }
    
    [niu_zibin@localhost gdb]$ g++ -g -o main main.cpp
    
    [niu_zibin@localhost gdb]$ gdb main
    (gdb) b 10 
    Breakpoint 1 at 0x804879b: file main.cpp, line 10.
    (gdb) r
    Starting program: /home/niu_zibin/test/gdb/main 
    
    Breakpoint 1, main () at main.cpp:10
    10              return 0;
    (gdb) p aVec
    $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 = 0x804b028, _M_finish = 0x804b034, _M_end_of_storage = 0x804b038}}, <No data fields>}
    (gdb) p *(0x804b028)
    $2 = 1
    (gdb) p *(0x804b028)@1
    $3 = {1}
    (gdb) p *(0x804b028)@2
    $4 = {1, 2}
    (gdb) p *(0x804b028)@3
    $5 = {1, 2, 3}
    (gdb) c
    Continuing.
    
    Program exited normally.
    (gdb) q
4、现在考虑,vector元素是自定义的类型,操作如下:
    [niu_zibin@localhost gdb]$ vi main.cpp 

    #include <stdio.h>
    #include <vector.h>
    #include <string.h>
    
    using namespace std;
    
    struct Person
    {
            int     _Age;
            string  _Name;
            Person(int age,string name)
            {
                    _Age = age;
                    _Name = name;
            }
    };
    
    int main()
    {
            Person p1(1,"Andy");
            Person p2(2,"Bill");
            Person p3(3,"Caroline");
    
            vector<Person> aVec;
            aVec.push_back(p1);
            aVec.push_back(p2);
            aVec.push_back(p3);
    
            return 0;
    }
    
    [niu_zibin@localhost gdb]$ g++ -g -o main main.cpp
    
    [niu_zibin@localhost gdb]$ gdb main
    (gdb) shell vi main.cpp
    
        1 #include <stdio.h>
        2 #include <vector.h>
        3 #include <string.h>
        4 
        5 using namespace std;
        6 
        7 struct Person
        8 {
        9         int     _Age;
        10         string  _Name;
        11         Person(int age,string name)
        12         {
        13                 _Age = age;
        14                 _Name = name;
        15         }
        16 };
        17 
        18 int main()
        19 {
        20         Person p1(1,"Andy");
        21         Person p2(2,"Bill");
        22         Person p3(3,"Caroline");
        23 
        24         vector<Person> aVec;
        25         aVec.push_back(p1);
        26         aVec.push_back(p2);
        27         aVec.push_back(p3);
        28 
        29         return 0;
        30 }
    (gdb) b 29
    Breakpoint 1 at 0x8048b14: file main.cpp, line 29.
    (gdb) r
    Starting program: /home/niu_zibin/test/gdb/main 
    warning: .dynamic section for "/lib/libc.so.6" is not at the expected address
    warning: difference appears to be caused by prelink, adjusting expectations
    
    Breakpoint 1, main () at main.cpp:29
    29              return 0;
    (gdb) p aVec
    $1 = {<std::_Vector_base<Person, std::allocator<Person> >> = {
        _M_impl = {<std::allocator<Person>> = {<__gnu_cxx::new_allocator<Person>> = {<No data fields>}, <No data fields>}, 
        _M_start = 0x804c080, _M_finish = 0x804c098, _M_end_of_storage = 0x804c0a0}}, <No data fields>}
    (gdb) p *(0x804c080)
    $2 = 1
    (gdb) p *(Person*)(0x804c080)
    $3 = {_Age = 1, _Name = {static npos = 4294967295, 
        _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, 
        _M_p = 0x804c014 "Andy"}}}
    (gdb) p *(Person*)(0x804c080)@1
    $4 = {{_Age = 1, _Name = {static npos = 4294967295, 
        _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, 
            _M_p = 0x804c014 "Andy"}}}}
    (gdb) p *(Person*)(0x804c080)@2
    $5 = {{_Age = 1, _Name = {static npos = 4294967295, 
        _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, 
            _M_p = 0x804c014 "Andy"}}}, {_Age = 2, _Name = {static npos = 4294967295, 
        _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, 
            _M_p = 0x804c02c "Bill"}}}}
    (gdb) p *(Person*)(0x804c080)@3
    $6 = {{_Age = 1, _Name = {static npos = 4294967295, 
        _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, 
            _M_p = 0x804c014 "Andy"}}}, {_Age = 2, _Name = {static npos = 4294967295, 
        _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, 
            _M_p = 0x804c02c "Bill"}}}, {_Age = 3, _Name = {static npos = 4294967295, 
        _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, 
            _M_p = 0x804c044 "Caroline"}}}}
    (gdb) c
    Continuing.
    
    Program exited normally.
    (gdb) q
gdb查看core堆栈,栈顶显示问号
1、使用gdb查看core文件的堆栈信息,使用bt(全称是backtrace回溯),栈顶显示为 ?? ()
2、这是怎么回事?
    bt会显示方法的调用堆栈,栈顶为 ?? () 说明是调用的方法找不到。
    比如:方法指针被设置为NULL,或者其他无效的值
3、模拟代码如下:
    int Sum(int a,int b)
    {
        return a+b;
    }
    
    int main()
    {
        int(*pFun)(int,int)=Sum;
        pFun=0; // 强制设置为0,然后调用
        // pFun=(int(*)(int,int))1234; 设置为无效的值,也是同样的道理。
        int c = pFun(1,2);
        return 0;
    }
4、运行产生core文件
    [root@localhost niu5]# g++ -g -o main main.cpp
    [root@localhost niu5]# ulimit -c unlimited
    [root@localhost niu5]# ./main
    Segmentation fault (core dumped)
5、查看core文件,显示栈顶为?? ()
    [root@localhost niu5]# gdb main core.31041.main 
    GNU gdb (GDB) Red Hat Enterprise Linux (7.0.1-23.el5)
    Copyright (C) 2009 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
    and "show warranty" for details.
    This GDB was configured as "i386-redhat-linux-gnu".
    For bug reporting instructions, please see:
    <http://www.gnu.org/software/gdb/bugs/>...
    Reading symbols from /home/niu5/main...done.
    Reading symbols from /usr/lib/libstdc++.so.6...(no debugging symbols found)...done.
    Loaded symbols for /usr/lib/libstdc++.so.6
    Reading symbols from /lib/libm.so.6...(no debugging symbols found)...done.
    Loaded symbols for /lib/libm.so.6
    Reading symbols from /lib/libgcc_s.so.1...(no debugging symbols found)...done.
    Loaded symbols for /lib/libgcc_s.so.1
    Reading symbols from /lib/libc.so.6...(no debugging symbols found)...done.
    Loaded symbols for /lib/libc.so.6
    Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done.
    Loaded symbols for /lib/ld-linux.so.2
    Core was generated by `./main'.
    Program terminated with signal 11, Segmentation fault.
    #0  0x00000000 in ?? ()
    (gdb) bt
    #0  0x00000000 in ?? ()
    #1  0x08048463 in main () at main.cpp:10
gdb查看崩溃信息
1、gdb常常用于查看崩溃信息,如下:
    [root@localhost vru]# gdb vru_main core.10504.vru_main
2、常用的命名
    info thread
    thread apply 1 bt
    thread apply all bt
3、常见的coredump原因
    Signal 4(SIGILL)
        SIGILL信号是cpu在发现非法指令之后发出一个异常,然后由负责处理该异常的内核的ISR对含有这个非法指令的进程发出的。
        程序收到这个信号,一般就是报告 illegal instruction 错误信息。可能导致的原因:
        版本不一致, 比如依赖的共享库接口变了,但你仍在使用老版本的库,问题的现象通常是诡异。
        而且你觉得不可能挂的地方,而通常是挂在你对依赖库的调用之处。简单点说就是头文件更新了,但库文件还没有更新。
        一个非常常见的原因是:崩溃的上下文,存在把string当成int,进行打印。
        这种情况,采用排除法,注释掉会崩溃的代码,缩小范围,找到问题。
    Signal 6(SIGABRT)
        New失败:内存泄露造成内存不够
        Delete失败:多次delete同一块内存
        应用程序抛出的异常
    Signal 11(SIGSEGV)
        多为内存越界,访问已经被delete掉的内存
    Signal 13(SIGPIPE)
        写已经被删除的文件,写对方已经关闭的socket
4、更多的崩溃信号,如下:
    编号为1-31的信号为传统UNIX支持的信号,是不可靠信号(非实时的)。
    编号为32-63的信号是后来扩充的,称做可靠信号(实时信号)。
    不可靠信号和可靠信号的区别在于前者不支持排队,可能会造成信号丢失,而后者不会。
    下面我们对编号小于SIGRTMIN的信号进行讨论。
    1) SIGHUP
        本信号在用户终端连接(正常或非正常)结束时发出, 通常是在终端的控制进程结束时, 通知同一session内的各个作业,
        这时它们与控制终端不再关联。登录Linux时,系统会分配给登录用户一个终端(Session)。
        在这个终端运行的所有程序,包括前台进程组和后台进程组,一般都属于这个Session。当用户退出Linux登录时,
        前台进程组和后台有对终端输出的进程将会收到SIGHUP信号。这个信号的默认操作为终止进程,
        因此前台进程组和后台有终端输出的进程就会中止。不过可以捕获这个信号,比如wget能捕获SIGHUP信号,并忽略它,
        这样就算退出了Linux登录,wget也能继续下载。
        此外,对于与终端脱离关系的守护进程,这个信号用于通知它重新读取配置文件。
    2) SIGINT
        程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出,用于通知前台进程组终止进程。
    3) SIGQUIT
        和SIGINT类似, 但由QUIT字符(通常是Ctrl-\)来控制. 进程在因收到SIGQUIT退出时会产生core文件, 
        在这个意义上类似于一个程序错误信号。
    4) SIGILL
        执行了非法指令. 通常是因为可执行文件本身出现错误, 或者试图执行数据段. 堆栈溢出时也有可能产生这个信号。
    5) SIGTRAP
        由断点指令或其它trap指令产生. 由debugger使用。
    6) SIGABRT
        调用abort函数生成的信号。
    7) SIGBUS
        非法地址, 包括内存地址对齐(alignment)出错。比如访问一个四个字长的整数, 
        但其地址不是4的倍数。它与SIGSEGV的区别在于后者是由于对合法存储地址的非法访问触发的
        (如访问不属于自己存储空间或只读存储空间)。
    8) SIGFPE
        在发生致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢出及除数为0等其它所有的算术的错误。
    9) SIGKILL
        用来立即结束程序的运行. 本信号不能被阻塞、处理和忽略。如果管理员发现某个进程终止不了,可尝试发送这个信号。
    10) SIGUSR1
        留给用户使用
    11) SIGSEGV
        试图访问未分配给自己的内存, 或试图往没有写权限的内存地址写数据.
    12) SIGUSR2
        留给用户使用
    13) SIGPIPE
        管道破裂。这个信号通常在进程间通信产生,比如采用FIFO(管道)通信的两个进程,读管道没打开或者意外终止就往管道写,
        写进程会收到SIGPIPE信号。此外用Socket通信的两个进程,写进程在写Socket的时候,读进程已经终止。
    14) SIGALRM
        时钟定时信号, 计算的是实际的时间或时钟时间. alarm函数使用该信号.
    15) SIGTERM
        程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和处理。通常用来要求程序自己正常退出,
        shell命令kill缺省产生这个信号。如果进程终止不了,我们才会尝试SIGKILL。
    17) SIGCHLD
        子进程结束时, 父进程会收到这个信号。如果父进程没有处理这个信号,也没有等待(wait)子进程,子进程虽然终止,
        但是还会在内核进程表中占有表项,这时的子进程称为僵尸进程。这种情况我们应该避免
        (父进程或者忽略SIGCHILD信号,或者捕捉它,或者wait它派生的子进程,或者父进程先终止,
        这时子进程的终止自动由init进程来接管)。
    18) SIGCONT
        让一个停止(stopped)的进程继续执行. 本信号不能被阻塞。
        可以用一个handler来让程序在由stopped状态变为继续执行时完成特定的工作。例如, 重新显示提示符
    19) SIGSTOP
        停止(stopped)进程的执行. 注意它和terminate以及interrupt的区别:该进程还未结束, 只是暂停执行。
        本信号不能被阻塞, 处理或忽略.
    20) SIGTSTP
        停止进程的运行, 但该信号可以被处理和忽略. 用户键入SUSP字符时(通常是Ctrl-Z)发出这个信号
    21) SIGTTIN
        当后台作业要从用户终端读数据时, 该作业中的所有进程会收到SIGTTIN信号. 缺省时这些进程会停止执行.
    22) SIGTTOU
        类似于SIGTTIN, 但在写终端(或修改终端模式)时收到.
    23) SIGURG
        有"紧急"数据或out-of-band数据到达socket时产生.
    24) SIGXCPU
        超过CPU时间资源限制. 这个限制可以由getrlimit/setrlimit来读取/改变。
    25) SIGXFSZ
        当进程企图扩大文件以至于超过文件大小资源限制。
    26) SIGVTALRM
        虚拟时钟信号. 类似于SIGALRM, 但是计算的是该进程占用的CPU时间.
    27) SIGPROF
        类似于SIGALRM/SIGVTALRM, 但包括该进程用的CPU时间以及系统调用的时间.
    28) SIGWINCH
        窗口大小改变时发出.
    29) SIGIO
        文件描述符准备就绪, 可以开始进行输入/输出操作.
    30) SIGPWR
        Power failure
    31) SIGSYS
        非法的系统调用。
    在以上列出的信号中,
    程序不可捕获、阻塞或忽略的信号有:SIGKILL,SIGSTOP
    不能恢复至默认动作的信号有:SIGILL,SIGTRAP
    默认会导致进程流产的信号有:SIGABRT,SIGBUS,SIGFPE,SIGILL,SIGIOT,SIGQUIT,SIGSEGV,SIGTRAP,SIGXCPU,SIGXFSZ
    默认会导致进程退出的信号有:SIGALRM,SIGHUP,SIGINT,SIGKILL,SIGPIPE,SIGPOLL,SIGPROF,SIGSYS,SIGTERM,SIGUSR1,SIGUSR2,SIGVTALRM
    默认会导致进程停止的信号有:SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU
    默认进程忽略的信号有:SIGCHLD,SIGPWR,SIGURG,SIGWINCH
    此外,SIGIO在SVR4是退出,在4.3BSD中是忽略;SIGCONT在进程挂起时是继续,否则是忽略,不能被阻塞
gdb调试
1、准备工作
    编译调试版本的可执行程序(gcc加上-g参数即可,注意不要调试加-O相关的选项)
2、gdb调试方式
    冷启动
        gdb program         e.g., gdb ./cs
        gdb –p pid          e.g., gdb –p `pidof cs`
        gdb program core    e.g., gdb ./cs core.xxx
    热启动
        (gdb) attach pid    e.g., (gdb) attach 2313
    命令行参数
        gdb program --args arglist
        (gdb) set args arglist
        (gdb) run arglist
3、在gdb中调用shell命名,如下:
    (gdb) shell vi main.cpp
    进入vi 
    输入 :exit 退出vi
    注意:有些shell命名执行完毕就返回了,这种情况不需要exit
4、设置断点
    (gdb) break function: 在函数funtion入口处设置断点
    (gdb) break linenum: 在当前源文件的第linenum行处设置断点
    (gdb) break filename:linenum: 在名为filename的源文件的第linenum行处设置断点
    (gdb) break filename:function: 在名为filename的源文件中的function函数入口处设置断点
    比如:
    (gdb) break foo1
    (gdb) break 17
5、查看断点信息
    (gdb) info break
    Num     Type           Disp Enb Address    What
    1       breakpoint     keep y   0x080483fa in foo1() at main.cpp:5
    2       breakpoint     keep y   0x08048425 in foo3() at main.cpp:17
6、断点禁用启用
    (gdb) info break
    Num     Type           Disp Enb Address    What
    1       breakpoint     keep y   0x080483fa in foo1() at main.cpp:5
    2       breakpoint     keep y   0x08048425 in foo3() at main.cpp:17
    (gdb) disable break 1
    (gdb) info break
    Num     Type           Disp Enb Address    What
    1       breakpoint     keep n   0x080483fa in foo1() at main.cpp:5
    2       breakpoint     keep y   0x08048425 in foo3() at main.cpp:17
    (gdb) enable break 1
    (gdb) info break
    Num     Type           Disp Enb Address    What
    1       breakpoint     keep y   0x080483fa in foo1() at main.cpp:5
    2       breakpoint     keep y   0x08048425 in foo3() at main.cpp:17
7、删除断点
    (gdb) info break
    Num     Type           Disp Enb Address    What
    1       breakpoint     keep y   0x080483fa in foo1() at main.cpp:5
    2       breakpoint     keep y   0x08048425 in foo3() at main.cpp:17
    (gdb) delete break 1-2
    (gdb) info break
8、调试
    n step over 
    s step into
    c next break
9、打印,如下:
    (gdb) p a3
    $1 = 3
    (gdb) set print pretty 
    (gdb) p a3
    $2 = 3
10、转到堆栈
    (gdb) f 1
    #1  0x08048449 in main () at main.cpp:24
    24              foo3();
11、gdb 寄存器,如下:
    (gdb) info register
    eax            0xbfffead4       -1073747244
    ecx            0xbfffea50       -1073747376
    edx            0x1      1
    ebx            0x80aff4 8433652
    esp            0xbfffea24       0xbfffea24
    ebp            0xbfffea38       0xbfffea38
    esi            0x6c5ca0 7101600
    edi            0x0      0
    eip            0x8048405        0x8048405 <main()+17>
    eflags         0x286    [ PF SF IF ]
    cs             0x73     115
    ss             0x7b     123
    ds             0x7b     123
    es             0x7b     123
    fs             0x0      0
    gs             0x33     51
gdb调试之list
1、列出某一行的上下文:
    (gdb) list 8
    3       int foo1(int a)
    4       {
    5               return a+1;
    6       }
    7
    8
    9       int main()
    10      {
    11              int a = 7;
    12              int b= foo1(a);
2、列出行的范围:
    (gdb) list 7,14
    7
    8
    9       int main()
    10      {
    11              int a = 7;
    12              int b= foo1(a);
    13              return b;
    14      }
3、列出方法的上下文:
    (gdb) list foo1
    1       #include <stdio.h>
    2
    3       int foo1(int a)
    4       {
    5               return a+1;
    6       }
    7
    8
    9       int main()
    10      {
4、list是针对当前文件,一般是main.cpp,也可以指定其他cpp文件,对应的位置前面加上xxx.cpp,如下:
    (gdb) list main.cpp:8
    (gdb) list main.cpp:7,14
    (gdb) list main.cpp:foo1
5、特别注意:list能列出源代码,必须满足条件,当前环境下有cpp文件。
    如果没有cpp文件,报错 xxx.cpp: No such file or directory.
    也就是说,在设备A编译程序,然后把编译后的结果拷贝到设备B,在设备B上进行gdb,list不能列出源代码。怎么办?
    解决办法是:从设备A把cpp文件拷贝到设备B的当前目录下。
gdb调试服务vru
1、gdb ./vru_start.sh 用法是错误的
    [root@localhost vru]# gdb ./vru_start.sh 用法是错误的,添加断点错误如下:
    (gdb) b 2
    No symbol table is loaded.  Use the "file" command.
2、正确的用法:
    [root@localhost vru]# export LD_LIBRARY_PATH=../common:./:$LD_LIBRARY_PATH
    [root@localhost vru]# gdb ./vru_main
    (gdb) set args -f vru_linux.xml 
    (gdb) r
3、另外一种办法,找到进程Id,先下断点,再continue,然后p
    如下:
    [root@localhost vru]# gdb -p 24847
    (gdb) b src/VruMaster.cpp:528
    Breakpoint 1 at 0x80d33b0: file src/VruMaster.cpp, line 528.
    (gdb) c
    Continuing.
    [Switching to Thread 0xb097eb70 (LWP 24884)]
    
    Breakpoint 1, VruMaster::HandlePlan (this=0x93c6578) at src/VruMaster.cpp:528
    528     src/VruMaster.cpp: No such file or directory.
            in src/VruMaster.cpp
    (gdb) p ttpConfig
4、设置断点
    (gdb) info b
    No breakpoints or watchpoints.
    (gdb) b 6
    Breakpoint 8 at 0x80a6718: file src/VruApp.cpp, line 9. (2 locations)
    (gdb) b VruMaster.cpp:236
    Breakpoint 9 at 0x80d4649: file src/VruMaster.cpp, line 236.
    (gdb) b src/VruMaster.cpp:238
    Breakpoint 10 at 0x80d465b: file src/VruMaster.cpp, line 238.
    (gdb) b ./src/VruMaster.cpp:246
    No source file named ./src/VruMaster.cpp.
    Make breakpoint pending on future shared library load? (y or [n]) [answered N; input not from terminal]
    (gdb) b src/VruMaster.cpp:246
    Breakpoint 11 at 0x80d46f6: file src/VruMaster.cpp, line 246.
    (gdb) info b
    Num     Type           Disp Enb Address    What
    8       breakpoint     keep y   <MULTIPLE> 
    8.1                         y     0x080a6718 in __tcf_2(void*) at src/VruApp.cpp:9
    8.2                         y     0x080a6845 in __static_initialization_and_destruction_0(int, int) at src/VruApp.cpp:9
    9       breakpoint     keep y   0x080d4649 in VruMaster::logoutDeviceEvent() at src/VruMaster.cpp:236
    10      breakpoint     keep y   0x080d465b in VruMaster::logoutDeviceEvent() at src/VruMaster.cpp:238
    11      breakpoint     keep y   0x080d46f6 in VruMaster::logoutDeviceEvent() at src/VruMaster.cpp:246
    注意:b ./src/VruMaster.cpp:246 这种用法是错误的。
Copyright (c) 2015~2016, Andy Niu @All rights reserved. By Andy Niu Edit.