本文目的是通过在Ubuntu系统18.04上使用gdb调试器调试C语言程序,在调试的过程中深入了解gdb调试器的用法并且熟练掌握Linux系统下gdb调试器的使用。
目录
(一)初识gdb
1.gdb简介
- GDB : GNU Debugger,是GNU工程为GNU操作系统开发的调试器,但它的使用不局限于GNU操作系统, GDB可以运行在UNIX、Linux甚至Microsoft Windows。GDB可以调试C、C++、Objective-C、Pascal、Ada等语言编写的程序;被调试的程序可以跟GDB运行于同一台电脑,也可运行于不同电脑。
- GDB的功能:
(1)设置断点使程序停住
(2)监视或修改程序中变量的值
(3)跟踪代码执行过程
2.启动gdb
- 编译时添加调试信息
程序要能被调试,必须包含调试信息。编译程序时,通过gcc的-g选项为程序添加调试信息。命令如下:gcc –g –o hello hello.c
或者gcc -g hello.c -o hello
(这里以hello.c为例) - gdb调试程序
使用命令gdb hello
即可进行该程序的调试
3.gdb相关命令
命令 | 作用 |
---|---|
file | 装入想要调试的可执行文件。 |
kill | 终止正在调试的程序。 |
list | 列出产生执行文件的源代码的一部分。 |
next | 执行一行源代码但不进入函数内部。 |
step | 执行一行源代码而且进入函数内部。 |
run | 执行当前被调试的程序。 |
continue | 继续运行程序。 |
quit | 终止gdb。 |
watch | 使你能监视一个变量的值而不管它何时被改变。 |
backtrace | 栈跟踪,查出代码被谁调用。 |
查看变量的值。 | |
make | 使你能不退出gdb就可以重新产生可执行文件。 |
shell | 使你能不离开gdb就执行UNIX shell命令。 |
whatis | 显示变量或函数类型。 |
break | 在代码里设断点,这将使程序执行到这里时被挂起。 |
info break | 显示当前断点清单,包括到达断点处的次数等。 |
info files | 显示被调试文件的详细信息。 |
info func | 显示所有的函数名称。 |
info local | 显示当函数中的局部变量信息。 |
info prog | 显示被调试程序的执行状态。 |
delete [n] | 删除第n个断点。 |
disable[n] | 关闭第n个断点。 |
enable[n] | 开启第n个断点。 |
ptype | 显示结构定义。 |
set variable | 设置变量的值。 |
call name(args) | 调用并执行名为name,参数为args的函数。 |
Finish | 终止当前函数并输出返回值。 |
return value | 停止当前函数并返回value给调用者。 |
(二)执行程序时出错
1.源程序
- RevertNum.c
#include<stdio.h>
void ShowRevertNum(int Num)
{
while(Num>10)
{
printf("%d",Num%10);
Num/=10;
}
printf("%d\n",Num);
}
int main()
{
int n;
printf("Please input a number:");
scanf("%d",&n);
printf("After Revert:");
ShowRevertNum(n);
return 0;
}
- Seg_Demo.c
#include<stdio.h>
int main()
{
int *p=0;
*p=1;
return 0;
}
2.遇到的问题
- 编译生成的RevertNum倒序输出程序在输入100时出错
- 编译生成的Seg_Demo程序执行时显示段错误
(二)gdb调试解决问题
1.gdb调试RevertNum程序
-
首先,生成可调试的程序(命令:
gcc -g RevertNum.c -o RevertNum
)
-
其次,进入调试(命令:
gdb RevertNum
)
-
显示源程序代码,便于设置断点调试程序(命令:
list
或者l
)
-
设置并查看断点
- 设置断点命令:
break n
或者b n
,n为需要设置断点所在行数
- 查看已设置断点命令:
info b
- 设置断点命令:
-
执行程序
- 由于设置了断点,因此程序运行到断点时会停下来方便调试。
- 分析程序错误的原因:
这里我设置了三个断点,分别在第5、8、10行处。程序运行到第一个断点处Num的值为100;再次运行直接跳到第三个断点处时Num的值仍为100,;再次运行程序结束,输出为After Revert:100。为什么程序没有在第二个断点处停下来?原因是程序没有执行while循环里的语句,当传入的参数等于100时不满足该语句,因此不会执行while循环里的语句。 - 修改方法:
将该while(Num>10)
改为while(Num>=10)
即可。
- 由于设置了断点,因此程序运行到断点时会停下来方便调试。
2.gdb调试Seg_Demo内存出错的程序
- 首先和上面一样,生成可调试的程序Seg_Demo
- Linux中,程序崩溃时,一般会产生core文件,记录进程退出前的状态,调试段错误问题,借助于该文件,可快速定位问题。
- 可按如下步骤生成和使用core文件
(1)让系统产生core文件ulimit –c num #设定core文件容量(num为数字,为0是不产生core文件)
(3)gdb配合core文件,定位问题。命令:gdb 程序名 core文件名
- 产生core文件
- 可按如下步骤生成和使用core文件
- 其次,开始调试
- 使用命令
l
显示源代码 - 使用命令
b n
(n为需要设置的断点行数)设置断点 - 使用命令
info b
查看断点
- 使用命令
- gdb执行命令
r
时显示如下错误
- 继续调试该程序
调试时显示整型指针p的地址为0x0,而该地址一般不允许访问,因此造成了内存错误。
- 参考解决方法
给整型指针p分配地址,这样一般就不会出现内存错误的问题了。当然,这也有其他的方法,大家可以去自行探索。#include<stdio.h> #include<stdlib.h> int main() { int *p; p=malloc(sizeof(int)); *p=1; free(p); return 0; }
(三)总结
通过在Ubuntu系统使用gdb调试器对C程序进行调试,我发现Linux操作系统与windows系统调试程序完全是不一样的体验。gdb调试器让我对于底层C语言的调试有了更加清楚的认识,而windows系统上的IDE虽然方便了调试,但却看不见C语言的底层调试时如何完成的,这也是gdb调试程序的好处之一。希望自己在以后gdb的使用中可以了解得更加深入。