GDB基本操作
1.GDB是什么
GDB调试器可以运行你在程序运行的时候检查里面到底发生了什么?
GDB可以做一下的事情
-
启动你的程序,修改一些东西,从而影响程序运行的行为。
-
可以指定断点。程序执行到断点处会暂停执行。
-
当你的程序停掉时,你可以用它来观察发生了什么事情。
-
动态的改变你程序的执行环境,尝试修正bug。
GDB支持的语言
- Ada
- Assembly 汇编语言
- C
- C++
- D
- Fortran
- Go
- Objective-C
- OpenCL
- Modula-2
- Pascal
- Rust
2.GDB 安装
ubuntn16.04 安装GDB
sudo apt-get install gdb
查看GDB版本
gdb --version
3.GDB快速上手
test.c程序如下
//test.c
#include <stdio.h>
int main()
{
int arr[4]={1,2,3,4};
for(int i=0;i<4;i++)
{
printf("%d\n",arr[i]);
}
return 0;
}
编译命令
gcc -g test.c
注意这里的-g一定得加上,否则gcc生成的a.out无法被gdb调试
调试命令
gdb运行out文件
gdb a.out
在gdb环境中输入r或者run就可以执行a.out的内容
运行情况如下
此时在GDB环境下输入quit或者按键盘上的Ctrl+D退出GDB环境
gdb下打断点
b (break) + 函数名/行号
注意如果不知道第几行,可以在gdb环境下使用list命令查看带行号的源代码
info b可以查看断点的详细情况
n (next) 执行一行
运行情况如下
4.print和step
4.1 print 可以查看变量的值
p (print) + 变量名/变量的地址,通过查看数组的两个变量名的地址,可以确定int占几个字节
运行情况如下
4.2 step命令可以跳入另一个函数
//test1.c
#include <stdio.h>
void hello()
{
printf ("hello gdb\n");
}
int main()
{
int arr[4]={1,2,3,4};
for(int i=0;i<4;i++)
{
printf("%d\n",arr[i]);
}
hello();
return 0;
}
编译命令
gdb -g test1.c -o test1.out
运行情况如下
5.GDB小技巧
5.1 gdb环境中可以使用shell脚本
shell ls
shell cat test1.c 查看test1.c的内容
5.2 日志功能
set logging on 产生一个gdb.txt,里面记录了自己曾经用gdb干了什么
5.3 watchpoint 监视一个变量
使用p +&i取出变量i的地址
使用watch *+变量的地址
info watchpoint 查看watchpoint的具体信息
当i的值发生改变时,gdb会打印
Old Value=0
New Value=1
运行情况如下
5.4 如何控制for循环的循环次数
//test_for.c
#include <stdio.h>
int main()
{
int i;
int k=0;
for (i=0;i<10;i++)
{
k=i*i;
printf("tgj hss\n");
printf("hss tgj\n");
}
return 0;
}
编译如下
gcc -c test_for.c -o test_for.out
gdb 控制循环次数的指令
break + 行号 if i==5 面试时面到的问题,现在在搞明白,实在惭愧
运行情况如下
5.5 在循环中跳过for循环
gdb 跳过for循环的指令
until
情况如下
注意,until需在至少循环一次后在使用,如果一开始在for循环进行until并不会直接跳到return 0。
6.GDB调试非正常文件
6.1程序已经挂掉,调试core文件
//test_error.c
#include <stdio.h>
int main()
{
int *temp=NULL;
*temp=10;
return 0;
}
编译如下
gcc -g test_error.c -o test_error.out
运行此out时出现段错误,此时文件路径下并没有core文件,因为系统不会默认打开core文件,需要手动打开
ulimit -c unlimited
再次编译运行,此时在文件目录下出现core文件,gdb调用core文件
gdb ./test_error.out core
运行情况如下,此时会定位到哪里出现了问题
6.2调试正在运行的程序
//test_while.c
#include <stdio.h>
void test()
{
}
void test1()
{
int i=0;
i++;
}
int main()
{
while(1)
{
test();
test1();
}
return 0;
}
编译如下
gcc -g test_while.c -o test_while.out
在后台运行
./test_while.out & 回车后会在后台打印pid进程号
如果不小心忘记了进程号: ps -ef | grep test_while.out 查看时间最近的进程号
kill + 进程号,干掉进程
gdb调试正在运行的程序
gdb -p + 程序的进程号,如果出现报错,那么退出gdb环境,再次输入 sudo gdb -p +程序的进程号
出现以下的情况,就说明正确进入gdb环境了,接下来就可以进行正常的gdb指令操作了
注: 博文根据B站UP主的小姐姐在下小神仙改写。