GDB技巧:自定义.gdbinit和标准输出出错重定向 & 查看STL容器的自定义gdb命令集合
2011-04-21 15:41
1106 查看
GDB技巧:自定义.gdbinit和标准输出出错重定向 & 查看STL容器的自定义gdb命令集合
分类: 工具 2011-02-09 18:00
实用GDB技巧--自定义.gdbinit和标准输出出错重定向
2008 年 3 月 20 日
本文介绍了一个实用 gdb 调试技巧。 它结合实际例子,一步一步示意如何重定向 stderr 和 stdout 到 gdb窗口,使得查看应用程序的输出信息更为方便,从而提高调试者的工作效率。
简介
本文介绍了一个实用 gdb 调试技巧。 它结合实际例子,一步一步示意如何重定向 stderr 和 stdout 到 gdb窗口,使得查看应用程序的输出信息更为方便,从而提高调试者的工作效率。
问题
为了调试基于 Eclipse 的 Java 和 C++ 混合的应用程序时,通常同时使用 Eclipse 和 gdb 来分别调试 Java 和 C++ 代码。此时,被调试程序的标准输出( stdout )和标准错误输出( stderr )取决于这个该程序的启动方式。如果程序是在 Eclipse 的 IDE 环境下启动的,那默认情况下 stderr 和 stdout 都会输出在 Eclipse 的 console 窗口下,如果这时又需要用 gdb 来调试 C++ 的代码,那为了查看输出的调试信息,还不得不切换到另外一个窗口(比如 Eclipse 的 console窗口)去查看,然后再切回来继续调试,这是不是很不方便呢?
解决之道
下面本文将介绍个一个简单的方法用以重定向 stderr 和 stdout 到指定的目的地,包括正在使用的 gdb 窗口。
由于这个方法是基于 gdb 提供的基本而又强大的两个功能之上的,所以在介绍它之前,先简单介绍一下 gdb 的这两个功能。
使用 call 命令调用外部函数
GDB 提供的 call 命令允许调试者在当前函数调用栈的栈顶调用函数,犹如在被调试的程序中执行的一般。比如想关闭某个文件(文件描述符为 fd ),那只需要在 gdb 中输入:
(gdb) call (int)close(fd) |
利用 .gdbinit 来自定义 gdb 命令
GDB 在启动的时候会按一定的路径顺序(通常是先当前目录而后用户目录)寻找 .gdbinit 文件,一旦找到,就会自动执行里面的命令。这个功能允许用户把常用的一些命令放在这个文件里,这样就不用每次进入 gdb 后再去手动执行这些命令。事实上,.gdbinit 就是一个脚本,甚至可在里面把常用的若干 gdb命令序列定义成一个新命令,这样只要在 gdb 里面输入这个新命令就等于自动执行了被定义的那个命令序列。
另外,如果用户已经在 gdb 里后,再去修改 .gdbinit ,只要通过:
(gdb) source ~/.gdbinit |
重定向 stdout和 stderr
首先,打开一个终端窗口,先用 ps 命令查到所需进程的 pid 。
$ ps ax | grep HelloWorld(要调试的应用程序名) 13522 ?? S 134:47.01 /Users/yyq/projects/1210/HelloWorld 24730 p5 S+ 0:00.00 grep Notes |
接着,我们使 gdb 连接上这个应用程序。如下:
$ gdb –pid=13522 |
$gdb $atta 13522 |
可以试一下看看是不是输出信息不在 gdb 窗口中。
(gdb) call (void)printf(“/n Is this string printed on gdb window/n”) |
解决的方法如下:
先关闭 stdout ,和 stderr 对应的文件描述符。
(gdb) call (int)close(1) (gdb) call (int)close(2) |
(gdb) shell tty /dev/tty5 |
(gdb) p (int)open("/dev/ttyp1", 2) $1 = 1 (gdb) p (int)open("/dev/ttyp1", 2) $2 = 2 |
另外,如果把这里的 ”/dev/ttyp1” 替换成目标文件名,便可将 stderr 和 stdout 重定向到该文件。
接下来,重新执行如下命令:
(gdb) call (void)printf(“/n Is this string be printed on gdb window?/n”) Is this string be printed on gdb window? |
如果每次都要运行这么多命令,还是较为繁琐,此时可以利用 .gdbinit 来简化用户输入:把这一系列命令定义一个新命令,放到 .gdbinit 文件里,然后在 gdb 里执行这个命令便可。
关于在 .gdbinit 中定义 gdb 新命令的语法可以参考 dW 上其他的文章。下面就针对重定向问题,看 .gdbinit 是如何通过引入新命令来简化用户输入。其实, 只需在 .gdbinit 文件里,增加如下脚本:
def redirect call (void)close(1) call (void)close(2) call (int)open($arg0, 2) call (int)open($arg0, 2) end |
之后,当重启 gdb (或者运行 source~/.gdbinit ),并且连接到要调试的应用程序后. 用以下简单的两步就可达到重定向的目的:
第一步, 仍是得到这个 gdb 窗口所在的虚拟终端:
(gdb)shell tty /dev/ttyp3 |
(gdb)redirect("/dev/ttyp3") $1=1 $2=2 |
把下面这段脚本紧接添加到刚才 redirect 所对应的 end 后面
document redirect redirect("argument"), this is used to switch stderr and stdout to gdb window. The argument is the name of gdb window. end |
(gdb) help redirect this is used to switch stderr and stdout to gdb window. The argument is the name of gdb window. |
由于系统有时会对输入输出会进行缓存,因此有可能会碰到如下情况:执行了输出语句,但还是不见输出。尤其是在调试 Java/C++ 混合程序时容易发生这种情况,比如在 JNI 代码中的printf 就很可能被缓存后再输出。这种系统缓存机制很不利于调试程序,因为调试信息的及时输出很重要,很多时候要利用这些输出信息来判断程序的行为是否正常。
为了解决这个问题,可以调用 fflush:
(gdb)call (int)fflush(0)
这样所有的缓冲都会得到立刻刷新,包括 stdout 和 stderr . 调试者就能马上看到前面执行的输出的结果。
|
gdb的命令很丰富,功能也很多,巧妙地利用它们可以大大地提高调试者的工作效率。本文通过利用 gdb 的 call 命令和 .gdbinit 文件的扩展功能,提出了一个简单有效的方法, 用以重定向被调试程序的 stdout 和 stderr ,以及如何及时刷新显示输出结果。
GDB:GNU Project Debugger:从 GNU 软件的发源地获得有关该程序的更多信息。
逆向工程社区:访问这个网站以获得有关使用 GDB 来调试进程的更多信息,并为有兴趣了解程序如何工作的用户社区作出贡献。
GDB mannual
http://sourceware.org/gdb/current/onlinedocs/gdbint/
一个查看STL容器的自定义gdb命令集合
http://help.lockergnome.com/linux/GDB-capabilities-exploring-STL-classes--ftopict279673.html
或者见附件
|
# #
# STL GDB evaluators/views/utilities #
# #
##########################################
#
# 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 command
# std::map<T,T> -- via pmap command
# std::multimap<T,T> -- via pmap 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
#
##########################################################################
# #
# CopyRight @ 2008 - Dan C Marinescu - All Rights Reserved under GPL V3. #
# #
# Email: dan_c_marinescu DeleteThis @yahoo.com #
# #
##########################################################################
#
# 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
#
# 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 + 4
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 + 4
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 + 4)
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
#
# 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
#
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
http://blogold.chinaunix.net/u3/111274/showart.php?id=2162256
相关文章推荐
- 支持stl容器的gdb自定义命令
- Linux 技巧:重定向 stderr 和 stdout 输出到 gdb 窗口
- GDB教程详解&打印STL容器
- 使用dumpbin命令查看dll导出函数及重定向输出到文件(VS自带)
- 标准输出重定向加管道,获取system命令执行结果
- 配置GDB以支持查看stl容器数据
- 配置GDB以支持查看stl容器数据
- command > filename 2>&1 把标准输出和标准错误一起重定向到一个文件中
- 批处理: 关于cmd命令的重定向输出 2>&1
- [zz]bash标准输出、错误输出、重定向标准输出2>&1
- 【Linux调试技巧----标准输出重定向到文件】dup2和dup的妙用
- GDB中查看STL容器类的内容
- GDB对STL容器的查看
- C++/STL关联容器-集合-multiset&set的用法
- gdb 查看 STL 容器值
- GDB pretty printer: linux下用gdb调试c++时如何更好的查看STL容器值
- [ZZ]配置GDB以支持查看stl容器数据
- 关于cmd命令的重定向输出 2>&1
- Linux 技巧:重定向 stderr 和 stdout 输出到 gdb 窗口
- GDB中查看STL容器中数据的方法