简单的gdb调试
gdb是类unix下注明的调试工具,和gcc组成了程序的两把利刃。本文档主要阐述两个内容:
- 安装gdb
- 调试
安装
我们使用的环境是CentOS,使用RedHat的用户一样,同时假设已经安装好了gcc和g++。
[root$localhost ~]$ yum install -y gdb
安装完成后,使用gdb查看是否已经安装成功。
[root$localhost ~]$ gdb -v
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-90.el6)
Copyright (C) 2010 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 "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
调试
调试之前,我们先得编写一个hello,world的C++代码。
简单的c++代码
#include "iostream"
int main(int argc, char** argv)
{
std::cout<<"hello, world!"<<std::endl;
return 0;
}
保存命名为main.cpp。
最简单的编译和运行
[root$localhost ~]$ g++ test.cpp
[root$localhost ~]$ ls
a.out main.cpp
其中a.out是根据main.cpp自动生成的可执行文件。但是这样一个可执行文件不能进行gdb的调试,
如果强行调试,会出现如下结果:
[zoujing@localhost test]$ gdb a.out
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-90.el6)
Copyright (C) 2010 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 "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/zoujing/test/a.out...(no debugging symbols found)...done.
(gdb) b main
Breakpoint 1 at 0x400818
(gdb) r
Starting program: /home/zoujing/test/a.out
Breakpoint 1, 0x0000000000400818 in main ()
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.192.el6.x86_64 libgcc-4.4.7-17.el6.x86_64 libstdc++-4.4.7-17.el6.x86_64
(gdb)
带调试信息的编译和运行
[root$localhost ~]$ g++ -g test.cpp
[root$localhost ~]$ ls
a.out main.cpp
a.out会替换之前的文件。这时,a.out里面会包含调试信息。如果比较之前的文件,通过readelf -h 查看a.out文件,我们可以看到两者的差异。
带有调试信息的输出:
[zoujing@localhost test]$ readelf a.out -h
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x400730
Start of program headers: 64 (bytes into file)
Start of section headers: 31136 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 8
Size of section headers: 64 (bytes)
Number of section headers: 37
Section header string table index: 34
不带调试信息的输出:
[zoujing@localhost test]$ readelf -h a.release
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x400730
Start of program headers: 64 (bytes into file)
Start of section headers: 3648 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 8
Size of section headers: 64 (bytes)
Number of section headers: 30
Section header string table index: 27
我们可以很轻易的看出来,带调试信息的Number of section headers比不带调试信息的多了7个,同时Section header string table index比不带调试信息的多了7个。这多出来的就是debug的符号信息。可以了解readelf继续查看相关信息,在.symtab(.symtab是符号表)里面会看到待调试的比不带调试的确实多了一部分信息。
下面的是具体的调试信息:
[zoujing@localhost test]$ gdb a.out
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-90.el6)
Copyright (C) 2010 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 "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/zoujing/test/a.out...done.
(gdb) b main
Breakpoint 1 at 0x400823: file main.cpp, line 5.
(gdb) r
Starting program: /home/zoujing/test/a.out
Breakpoint 1, main (argc=1, argv=0x7fffffffe918) at main.cpp:5
5 std::cout<<"hello, world!"<<std::endl;
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.192.el6.x86_64 libgcc-4.4.7-17.el6.x86_64 libstdc++-4.4.7-17.el6.x86_64
(gdb) l
1 #include "iostream"
2
3 int main(int argc, char** argv)
4 {
5 std::cout<<"hello, world!"<<std::endl;
6 return 0;
7 }
8
9
(gdb)
命令讲解
gdb file
表示调试这个file文件。
b
表示断点break
。gdb支持函数断点,例如我们例子里面的main函数(不需要带参数)b main
,也可以b + 行数
,比如,我需要调试main函数里面的输出语言,我们可以b 5
。
l
表示显示当前代码list
。gdb支持显示任意行的代码,比如我想显示第5行的,我可以l 5
。
结语
gdb还有很多其他功能,和强大的gcc搭配,编译出的代码运行效率非常高,而且调试非常方便。