Content
1. at后面的一堆字符串代表什么?
2. 为什么没有单步进入(step in)_Rb_tree_insert_and_rebalance函数?
3. 如何通过目标文件.o或者可执行文件得知是否有debugging information?
4. 如何单步调试没有debugging information的函数?
0. 引子
上次写了使用GDB调试RB-tree的几个问题讨论了几个问题,但关于at后面字符串的讨论是错误的,特在此进行更正,希望不要误导读者。并向已经读过该文并被误导或有疑惑的读者致以诚挚的歉意,同时也谢谢这些读者对本blog的支持。
一点心得:虽然笔者讨论的问题并不是什么科学,只是简单的技术问题,但也应该本着实事求是的精神,改正自己的错误,对读者负责,实际上也是对自己负责。看来,“科学是严谨的”在技术问题上也是适用的,技术也应该严谨,也应该认真。
言归正传,首先更正这个错误。
1. at后面的一堆字符串代表什么?
at后面的一堆字符串是一个整体,并没有什么前半部分和后半部分。这个整体代表的是一个绝对路径。例如,
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/new
其中的..表示当前目录的父目录。
因此,
/usr/lib/gcc/i386-redhat-linux/4.1.2/..表示/usr/lib/gcc/i386-redhat-linux
/usr/lib/gcc/i386-redhat-linux/4.1.2/../..表示/usr/lib/gcc
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../..表示/usr/lib
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../..表示/usr
因此,
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/new
就是/usr/include/c++/4.1.2/new,是一个绝对路径。
其中,/usr/lib/gcc/i386-redhat-linux/4.1.2是在gcc-4.1.2安装时就确定的。
如果同时安装了多个版本的gcc,如下所示。
# ls /usr/lib/gcc/i486-linux-gnu
4.4 4.4.0 4.4.1
# ls /usr/include/c++
4.4 4.4.0 4.4.1
/usr/lib/gcc/i486-linux-gnu/4.4/../../../../include/c++/4.4/new
/usr/lib/gcc/i486-linux-gnu/4.4.0/../../../../include/c++/4.4.0/new
/usr/lib/gcc/i486-linux-gnu/4.4.1/../../../../include/c++/4.4.1/new
2. 为什么没有单步进入(step in)_Rb_tree_insert_and_rebalance函数?
要回答这个问题,我们可以参考gdb的官方文档,如下。
Warning: If you use the step command while control is within a function that was compiled without debugging information, execution proceeds until control reaches a function that does have debugging information. Likewise, it will not step into a function which is compiled without debugging information. To step through functions without debugging information, use the stepi command, described below. ()
前半部分说明,如果在一个没有debugging information的函数中是用step命令,程序会一直运行到某个有debugging information的函数才停止。
另外,划线句子说明,如果某个函数没有debugging information,在使用step命令时不能进入该函数内部;那么这个命题的逆反命题也一定是成立的。即如果能step进入某个函数,则该函数一定有debugging information。
实际上,这也解释了使用GDB调试RB-tree的几个问题中的问题,即本标题的问题。
函数std::_Rb_tree, std::less, std::allocator >::_M_insert()在stl_tree.h中,有debugging information,而函数_Rb_tree_insert_and_rebalance所在的文件在编译时被编译成tree.o并链接到动态库libstdc++.so,
第 2 页 如何通过目标文件
3. 如何通过目标文件.o或者可执行文件得知是否有debugging information?
可通过如下命令查看debugguing information。
objdump -g filename
objdump -h filename(查看有无debug section)
nm -l filename
重新编译gcc-4.1.2的源文件,观看结果。
# cd /mnt/hgfs/edisk/opensource/gcc-4.1.2/libstdc++-v3/src
# g++ -o tre //without debugging information
# objdump -h tree.o
tree.o: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .group 00000008 00000000 00000000 00000034 2**2
CONTENTS, READONLY, EXCLUDE, GROUP, LINK_ONCE_DISCARD
1 .group 00000008 00000000 00000000 0000003c 2**2
CONTENTS, READONLY, EXCLUDE, GROUP, LINK_ONCE_DISCARD
2 .group 00000008 00000000 00000000 00000044 2**2
CONTENTS, READONLY, EXCLUDE, GROUP, LINK_ONCE_DISCARD
3 .text 00000952 00000000 00000000 0000004c 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
4 .data 00000000 00000000 00000000 000009a0 2**2
CONTENTS, ALLOC, LOAD, DATA
5 .bss 00000000 00000000 00000000 000009a0 2**2
ALLOC
6 .text._ZNSt18_Rb_tree_node_base10_S_minimumEPS_ 00000022 00000000 00000000 000009a0 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
7 .text._ZNSt18_Rb_tree_node_base10_S_maximumEPS_ 00000022 00000000 00000000 000009c2 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
8 .text._ZSt4swapISt14_Rb_tree_colorEvRT_S2_ 00000022 00000000 00000000 000009e4 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
ment 00000024 00000000 00000000 00000a06 2**0
CONTENTS, READONLY
10 .note.GNU-stack 00000000 00000000 00000000 00000a2a 2**0
CONTENTS, READONLY
11 .eh_frame 0000016c 00000000 00000000 00000a2c 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
# cd /mnt/hgfs/edisk/opensource/gcc-4.1.2/libstdc++-v3/src
# g++ -g -o tre //with debugging information
# objdump -h tree.d.o
tree.d.o: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .group 00000008 00000000 00000000 00000034 2**2
CONTENTS, READONLY, EXCLUDE, GROUP, LINK_ONCE_DISCARD
1 .group 00000008 00000000 00000000 0000003c 2**2
CONTENTS, READONLY, EXCLUDE, GROUP, LINK_ONCE_DISCARD
2 .group 00000008 00000000 00000000 00000044 2**2
CONTENTS, READONLY, EXCLUDE, GROUP, LINK_ONCE_DISCARD
3 .text 00000952 00000000 00000000 0000004c 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
4 .data 00000000 00000000 00000000 000009a0 2**2
CONTENTS, ALLOC, LOAD, DATA
5 .bss 00000000 00000000 00000000 000009a0 2**2
ALLOC
6 .debug_abbrev 000001d0 00000000 00000000 000009a0 2**0
CONTENTS, READONLY, DEBUGGING
7 .debug_info 000006fd 00000000 00000000 00000b70 2**0
CONTENTS, RELOC, READONLY, DEBUGGING
8 .debug_line 00000258 00000000 00000000 0000126d 2**0
CONTENTS, RELOC, READONLY, DEBUGGING
9 .text._ZNSt18_Rb_tree_node_base10_S_minimumEPS_ 00000022 00000000 00000000 000014c5 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
10 .text._ZNSt18_Rb_tree_node_base10_S_maximumEPS_ 00000022 00000000 00000000 000014e7 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
11 .text._ZSt4swapISt14_Rb_tree_colorEvRT_S2_ 00000022 00000000 00000000 00001509 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
12 .debug_loc 00000210 00000000 00000000 0000152b 2**0
CONTENTS, RELOC, READONLY, DEBUGGING
13 .debug_pubnames 0000019d 00000000 00000000 0000173b 2**0
CONTENTS, RELOC, READONLY, DEBUGGING
14 .debug_aranges 00000038 00000000 00000000 000018d8 2**0
CONTENTS, RELOC, READONLY, DEBUGGING
15 .debug_ranges 00000070 00000000 00000000 00001910 2**0
CONTENTS, RELOC, READONLY, DEBUGGING
16 .debug_str 00000533 00000000 00000000 00001980 2**0
CONTENTS, READONLY, DEBUGGING
ment 00000024 00000000 00000000 00001eb3 2**0
CONTENTS, READONLY
18 .note.GNU-stack 00000000 00000000 00000000 00001ed7 2**0
CONTENTS, READONLY
19 .eh_frame 0000016c 00000000 00000000 00001ed8 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
以下是nm命令的结果。
-l, –line-numbers Use debugging information to find a filename and
line number for each symbol
# cd /mnt/hgfs/edisk/opensource/gcc-4.1.2/libstdc++-v3/src
# nm -l tree.o
00000000 W _ZNSt18_Rb_tree_node_base10_S_maximumEPS_
00000000 W _ZNSt18_Rb_tree_node_base10_S_minimumEPS_
0000011a T _ZSt18_Rb_tree_decrementPKSt18_Rb_tree_node_base
00000088 T _ZSt18_Rb_tree_decrementPSt18_Rb_tree_node_base
00000075 T _ZSt18_Rb_tree_incrementPKSt18_Rb_tree_node_base
00000000 T _ZSt18_Rb_tree_incrementPSt18_Rb_tree_node_base
00000910 T _ZSt20_Rb_tree_black_countPKSt18_Rb_tree_node_baseS1_
0000012d T _ZSt20_Rb_tree_rotate_leftPSt18_Rb_tree_node_baseRS0_
000001ba T _ZSt21_Rb_tree_rotate_rightPSt18_Rb_tree_node_baseRS0_
0000046f T _ZSt28_Rb_tree_rebalance_for_erasePSt18_Rb_tree_node_baseRS_
00000247 T _ZSt29_Rb_tree_insert_and_rebalancebPSt18_Rb_tree_node_baseS0_RS_
00000000 W _ZSt4swapISt14_Rb_tree_colorEvRT_S2_
U __gxx_personality_v0
# cd /mnt/hgfs/edisk/opensource/gcc-4.1.2/libstdc++-v3/src
# nm -l tree.d.o //tree.d.o有debugging information
00000000 W _ZNSt18_Rb_tree_node_base10_S_maximumEPS_ /usr/include/c++/4.4/bits/stl_tree.h:112
00000000 W _ZNSt18_Rb_tree_node_base10_S_minimumEPS_ /usr/include/c++/4.4/bits/stl_tree.h:98
0000011a T _ZSt18_Rb_tree_decrementPKSt18_Rb_tree_node_base /mnt/hgfs/edisk/opensource/gcc-4.1.2/libstdc++-v3/src/:119
00000088 T _ZSt18_Rb_tree_decrementPSt18_Rb_tree_node_base /mnt/hgfs/edisk/opensource/gcc-4.1.2/libstdc++-v3/src/:93
00000075 T _ZSt18_Rb_tree_incrementPKSt18_Rb_tree_node_base /mnt/hgfs/edisk/opensource/gcc-4.1.2/libstdc++-v3/src/:87
00000000 T _ZSt18_Rb_tree_incrementPSt18_Rb_tree_node_base /mnt/hgfs/edisk/opensource/gcc-4.1.2/libstdc++-v3/src/:64
00000910 T _ZSt20_Rb_tree_black_countPKSt18_Rb_tree_node_baseS1_ /mnt/hgfs/edisk/opensource/gcc-4.1.2/libstdc++-v3/src/:416
0000012d T _ZSt20_Rb_tree_rotate_leftPSt18_Rb_tree_node_baseRS0_ /mnt/hgfs/edisk/opensource/gcc-4.1.2/libstdc++-v3/src/:126
000001ba T _ZSt21_Rb_tree_rotate_rightPSt18_Rb_tree_node_baseRS0_ /mnt/hgfs/edisk/opensource/gcc-4.1.2/libstdc++-v3/src/:147
0000046f T _ZSt28_Rb_tree_rebalance_for_erasePSt18_Rb_tree_node_baseRS_ /mnt/hgfs/edisk/opensource/gcc-4.1.2/libstdc++-v3/src/:259
00000247 T _ZSt29_Rb_tree_insert_and_rebalancebPSt18_Rb_tree_node_baseS0_RS_ /mnt/hgfs/edisk/opensource/gcc-4.1.2/libstdc++-v3/src/:170
00000000 W _ZSt4swapISt14_Rb_tree_colorEvRT_S2_ /usr/include/c++/4.4/bits/move.h:76
# c++filt _ZSt29_Rb_tree_insert_and_rebalancebPSt18_Rb_tree_node_baseS0_RS_
std::_Rb_tree_insert_and_rebalance(bool, std::_Rb_tree_node_base*, std::_Rb_tree_node_base*, std::_Rb_tree_node_base&)
从以上结果可以看出,在tree.d.o中,每个函数都有对应的调试信息,例如在源文件()中的行号。
第 3 页 debugging information的函数
4. 如何单步调试没有debugging information的函数?
由第2个问题,可知,可以通过stepi命令直接调试汇编代码。如使用GDB调试RB-tree的几个问题一文2.(4)所示。
stepi
stepi arg
si
Execute one machine instruction, then stop and return to the debugger.
It is often useful to do `display/i $pc’ when stepping by machine instructions. This makes GDB automatically display the next instruction to be executed, each time your program stops. See section Automatic display.
An argument is a repeat count, as in step. ()
Reference
objdump的manual页
nm的manual页
Technorati 标签: STL, RB-tree, 红黑树, GDB
如果发现错了,一定要止步.