4 GDB 调试程序
GDB(GNU Debugger)是GNU项目的调试器,主要用于调试C、C++和其他编程语言编写的程序。它是开发过程中非常强大和重要的工具,尤其在定位、分析和修复程序中的问题时非常有用。以下是GDB的主要作用和功能:
1. 定位程序错误(调试)
实时调试:GDB可以在程序运行时暂停程序的执行,从而让开发者检查程序的内部状态(变量、寄存器、内存等),并逐步执行代码,以帮助找出程序中潜在的问题。
跟踪和分析崩溃:当程序发生崩溃时,GDB能够加载崩溃时生成的核心转储文件(core dump),分析崩溃时的代码状态,帮助开发者了解崩溃发生的原因。
2. 设置断点与观察点
断点(Breakpoints):开发者可以通过GDB在程序的特定代码行或函数上设置断点。当程序执行到断点处时,它会暂停,让开发者可以检查和分析程序的状态。
条件断点:可以在特定条件下暂停程序运行。例如,只有当某个变量的值满足特定条件时,程序才会在断点处暂停。
观察点(Watchpoints):观察点是一种特殊的断点,用于监视特定变量的值变化。当程序中的某个变量发生变化时,GDB会暂停程序并报告这一变化。
3. 逐步执行代码
单步执行(Step):GDB可以逐行执行程序,让开发者可以逐步查看每一行代码的效果,从而理解程序的执行逻辑。
跳过函数(Next):与单步执行不同的是,GDB还允许跳过当前的函数调用,而不进入函数内部执行,这对于快速调试大段代码非常有帮助。
继续执行(Continue):如果你不再需要查看逐行执行,可以让程序继续运行,直到下一个断点或程序终止。
4. 检查和修改变量值
查看变量值:GDB允许开发者在调试时查看变量的值,包括局部变量、全局变量以及类的成员变量。这在查找逻辑错误和调试复杂程序时非常有帮助。
修改变量值:除了查看变量,GDB还允许在程序运行时修改变量的值。开发者可以直接改变变量的值来模拟不同的执行路径,或修复运行时的错误。
5. 调用栈分析
查看调用栈(Backtrace):当程序暂停或崩溃时,GDB可以显示当前的调用栈,帮助开发者了解程序的执行路径,以及当前函数是由哪些函数调用的。
栈帧切换:GDB允许开发者在调用栈中自由切换,查看不同栈帧中的局部变量和参数。这对于分析深层次的调用链错误非常有帮助。
6. 多线程和多进程调试
调试多线程程序:GDB支持调试多线程程序,开发者可以查看和切换线程,检查每个线程的状态(如变量、堆栈等),并针对特定线程设置断点。
调试多进程程序:对于多进程程序,GDB可以在父进程和子进程之间进行切换,帮助开发者跟踪进程间的通信和状态变化。
7. 调试动态库和内存问题
调试共享库:GDB可以调试使用动态链接库(shared libraries)的程序。当程序使用的动态库出现问题时,GDB能够帮助跟踪并调试动态库的加载和执行情况。
调试内存问题:GDB可以配合其他工具(如Valgrind)帮助发现程序中的内存泄漏、未初始化的内存使用等问题。此外,开发者可以使用GDB手动检查和修改内存中的数据。
8. 自动化调试
脚本化调试:GDB允许用户编写调试脚本,以自动化调试任务。这对于重复性调试工作非常有用,比如在每次调试时都需要执行相同的命令。
记录调试会话:GDB可以记录调试会话,帮助开发者保存和回放调试过程,便于日后分析。
9. 核心转储分析(Core Dump Analysis)
加载和分析核心转储文件:当程序崩溃时,操作系统可能生成一个核心转储文件。GDB能够加载这个文件,并重现程序崩溃时的状态。开发者可以通过核心转储文件分析出崩溃的原因。
调试崩溃点:开发者可以使用GDB回溯崩溃时的调用栈,并检查程序崩溃时的内存、寄存器状态等。
10. 跨平台调试
远程调试:GDB可以用于调试运行在其他设备或远程系统上的程序。通过GDB的远程调试功能,可以在开发者的主机上调试运行在其他机器(如嵌入式设备)上的程序。这对嵌入式开发非常重要。
调试交叉编译程序:GDB支持交叉调试,即在一种架构上调试运行在另一种架构上的程序。通过远程GDB服务器,可以在不同平台上进行调试。
4.1 运行案例
#include <stdio.h>
/*冒泡排序算法*/
void BubbleSort(int *pData,int count)
{int temp,i,j;int flag = 0; //设定标志,如果第一次循环比较时没有发生交换,则说明数组是升序排序,不用排序,提前结束循环。for(i = 0;i < count;i++) { //外层循环控制循环次数for(j = 0;j < count-1-i;j++) { //内层循环控制每次循环里比较的次数
/*相邻数据进行比较,如果前面的大于后面的,则交换位置*/
if(pData[j] > pData[j+1]) { temp = pData[j];pData[j] = pData[j+1];pData[j+1] = temp;flag = 1;}}/*不需要排序的情况*/ if(0 == flag){ printf("No Sort\n");break; }}
}
int main(void)
{int i;int Data[10] = {7,23,12,4,33,21,2,17,13,9}; //初始化数组,定义数组内的数据个数BubbleSort(Data,); //调用函数实现排序算法
/* 向控制台循环输出6个排序过的数据*/for(i = 0;i < 10;i++) { printf("%d ",Data[i]);}printf("\n");return 0;
}
4.2 编译、运行
gcc -g -o test test.c
gdb test
4.3 gdb 指令
list: 查看代码
run : 运行程序
break : 插入代码
next: 下一个插入
step: 下一步
quit: 退出
print: 打印结果
backtrace : 查看当前调用的栈
set: 设置值
watch: 监视变量的值
4.4 运行结果
4.4.1 进入GDB
uptech@uptech-virtual-machine:/imx8/SRC/exp/01_basic/05_gdb/pc_gdb$ gdb test
GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-git
Copyright (C) 2018 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"...
Reading symbols from test...done.
(gdb)
4.4.2 插入断点
(gdb) break 26
Breakpoint 1 at 0x85e: file test.c, line 26.
插入断点,就可以利用run指令来运行程序。
4.4.3 进入子函数,利用step
(gdb) step
BubbleSort (pData=0x7fffffffca80, count=10) at test.c:6
6 int flag = 0;
(gdb) s
7 for(i = 0;i < count;i++) { //
(gdb) s
8 for(j = 0;j < count-1-i;j++) {
(gdb) s
9 if(pData[j] > pData[j+1]) {
(gdb) s
8 for(j = 0;j < count-1-i;j++) {
(gdb) s
9 if(pData[j] > pData[j+1]) {
(gdb) s
10 temp = pData[j];
(gdb) s
11 pData[j] = pData[j+1];
(gdb) s
12 pData[j+1] = temp;
(gdb) s
13 flag = 1;
(gdb) s
8 for(j = 0;j < count-1-i;j++) {
(gdb) print j
$1 = 1
(gdb) print pData[0]
$2 = 7
(gdb) print pData[1]
$3 = 12
(gdb) print i
$4 = 0
4.4.4 跳过子函数,用next
(gdb) next
27 BubbleSort(Data,10);
(gdb)
4.4.5 退出调试,用quit
(gdb) continue
Continuing.
2 4 7 9 12 13 17 21 23 33
[Inferior 1 (process 20355) exited normally]
(gdb) q
4.4.6 设置和打印
set x = 10 # 将变量 x 设置为 10
set y = 3.14 # 将浮点型变量 y 设置为 3.14
set z = "test" # 将字符数组变量 z 设置为 "test"print var # 打印变量 var 的值
4.4.7 监视变量的值
(gdb) watch x
(gdb) continue
每当 x 的值变化时,程序会暂停,并显示 x 的旧值和新值。