Linux基础知识(13)- GDB 调试器(一)| 安装配置和基本使用方法
GDB 调试器(GNU Symbolic Debugger),是 Linux 平台下最常用的一款程序调试器。GDB 编译器通常以 gdb 命令的形式在终端(Shell)中使用,它有很多选项。
GDB 调试器支持 C、C++、Go、Objective-C、OpenCL、Ada 等多种编程语言,实际场景中 GDB 更常用来调试 C 和 C++ 程序,虽然 Linux 平台下有很多能编写 C、C++ 代码的集成开发工具(IDE),但它们调试代码的能力往往都源自 GDB 调试器。
调试是开发流程中一个非常重要的环境,每个程序员都应具备调试代码的能力,对于 Linux C/C++ 开发,必须具备熟练使用 GDB 调试器的能力。
1. GDB 安装配置
1) CentOS 7.9 下安装
查看当前 GDB 版本:
$ gdb --version
-bash: gdb: command not foundg
注:表明当前系统没有安装 GDB。
基于 yum 安装:
$ sudo yum -y install gdb
... Running transaction Installing : gdb-7.6.1-120.el7.x86_64 1/1 Verifying : gdb-7.6.1-120.el7.x86_64 1/1 Installed: gdb.x86_64 0:7.6.1-120.el7 Complete!
$ gdb --version
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-120.el7 Copyright (C) 2013 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/>.
2) Ubuntu 20.04 下安装
查看当前 GDB 版本:
$ gdb --version
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2 Copyright (C) 2020 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.
注:表明当前系统已有 GDB。
2. 设置调试信息
GDB 的主要功能就是监控程序的执行流程。只有当源程序文件编译为可执行文件并执行时,并且该文件中必须包含必要的调试信息(比如代码所在的行号、包含程序中所有变量名称的列表(又称为符号表)等),GDB 才会有用。
在编译时需要使用 gcc/g++ -g 选项编译源文件,生成的可执行文件才能被 GDB 调试。
格式如下:
$ gcc -g test.c -o test
加上 -g 选项以后,gcc 在编译时做以下的操作:
(1) 创建调试符号表,符号表包含了程序中使用的变量名称的列表;
(2) 关闭所有的优化机制,以便程序执行过程中严格按照原来的 C 代码进行;
1) 创建 C 程序
$ cd ~/
$ vim test.c
#include <stdio.h> int main(int argc, char* argv[]) { if (argv[1] == NULL) { printf("Hello world - GDB\n"); } else { printf("Hello world - %s\n", argv[1]); } for (int i=0; i<5; i++ ) { printf("printf i=%d\n", i); } }
2)使用 gcc 编译(设置调试信息)
$ gcc -g test.c -o test
$ ./test
Hello world - GDB printf i=0 printf i=1 printf i=2 printf i=3 printf i=4
$ ./test "Message"
Hello world - Message printf i=0 printf i=1 printf i=2 printf i=3 printf i=4
3. GDB 加载程序
1)不带参数启动 GDB
$ cd ~/
$ gdb
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2 Copyright (C) 2020 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-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word". (gdb) file test Reading symbols from test ...
注:可以通过借助 GDB 内部的 file 子命令,则无需重启 GDB 就能指定要调试的目标程序文件。
2) 带参数启动 GDB
$ gdb test
... For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from test... (gdb)
# 使用 -q 参数,启动时不会打印 gdb 的默认信息
$ gdb -q test
Reading symbols from test... (gdb)
3)向被加载程序传递参数
(1) gdb 命令行使用 --args 传递参数
$ gdb -q --args test "Message2"
Reading symbols from test ... (gdb) run Starting program: /home/xxx/test Message2 Hello world - Message2 printf i=0 printf i=1 printf i=2 printf i=3 printf i=4 [Inferior 1 (process 5671) exited normally]
(2) 使用 GDB 内部的 set args 命令传递参数
$ gdb -q test
Reading symbols from test ... (gdb) set args "Message3" (gdb) run Starting program: /home/xxx/test "Message3" Hello world - Message3 printf i=0 printf i=1 printf i=2 printf i=3 printf i=4 [Inferior 1 (process 5679) exited normally]
(3)运行 GDB 内部的 run 命令(或 start 命令)时传递参数
$ gdb -q test
Reading symbols from test ... (gdb) run "Message4" Starting program: /home/xxx/test "Message4" Hello world - Message4 printf i=0 printf i=1 printf i=2 printf i=3 printf i=4 [Inferior 1 (process 5682) exited normally]
4. GDB 常用内部命令
命令 (缩写) | 描述 |
run (r) | 执行被调试的程序,在程序结束或者遇到断点处停止; |
start | 执行被调试的程序至 main() 主函数的起始位置,即在 main() 函数的第一行语句处停止执行(该行代码尚未执行); |
list (l) | 显示源程序代码的内容,包括各行代码所在的行号; |
break (b) | 在源代码指定的某一行设置断点,格式:b 空格 行号; |
continue (c) | 当程序在某一断点处停止后,用该指令可以继续执行,直至遇到断点或者程序结束; |
next (n) | 程序一行代码一行代码的执行; |
step (s) | 如果有调用函数,进入调用的函数内部;如果没有函数,和 next 命令的功能一样; |
until (u) | 使用 until 命令,可以运行程序直到退出循环体; |
until (u) n | n 为某一行代码的行号,该命令会使程序运行至第 n 行代码处停止; |
print (p) | 打印指定变量的值,格式:p 空格 变量; |
finish (fi) | 结束当前正在执行的函数,并在跳出函数后暂停程序的执行; |
return (return) | 结束当前调用函数并返回指定值,到上一层函数调用处停止程序执行; |
jump (j) | 使程序从当前要执行的代码处,直接跳转到指定位置处继续执行后续的代码; |
quit (q) | 终止调试。 |
1) 使用 run 命令运行被调试程序
$ gdb -q test
Reading symbols from test ... (gdb) r Starting program: /home/xxx/test Hello world - GDB printf i=0 printf i=1 printf i=2 printf i=3 printf i=4 [Inferior 1 (process 5690) exited normally] (gdb) r > a.txt Starting program: /home/xxx/test > a.txt [Inferior 1 (process 13070) exited normally]
注:把执行结果输出到 GDB 调试的工作目录下的 a.txt 文件,可以运行 (gdb) cd 命令改变调试的工作目录。
2) 使用 start 命令运行被调试程序
(gdb) start Temporary breakpoint 1 at 0x555555555169: file test.c, line 3. Starting program: /home/xxx/test Temporary breakpoint 1, main (argc=21845, argv=0x0) at test.c:3 3 int main(int argc, char* argv[]) { (gdb) c Continuing. Hello world - GDB printf i=0 printf i=1 printf i=2 printf i=3 printf i=4 [Inferior 1 (process 5694) exited normally]
注:start 命令会自动在 main 函数第一行加上零时断点, 运行 continue (c) 命令继续运行程序。
3) 使用 list 命令显示源程序代码的内容
(gdb) l 1 #include <stdio.h> 2 3 int main(int argc, char* argv[]) { 4 5 if (argv[1] == NULL) { 6 printf("Hello world - GDB\n"); 7 } else { 8 printf("Hello world - %s\n", argv[1]); 9 } 10 (gdb) 11 for (int i=0; i<5; i++ ) { 12 printf("printf i=%d\n", i); 13 } 14 } 15
通过回车键不断查看剩余代码。
4) 使用 quit 命令退出 GDB
(gdb) q