Linux学习(三)——gdb调试
基本命令
gdb 可执行文件名
b 函数名或行号
info breakpoints
delete
l 函数名或行号
r 表示运行
q 表示退出
bt 表示列出调用栈
p 变量名 (查看变量名的值)
p/d 变量名 (10进制查看)
p/x 变量名 (16进制查看)
s 表示单步执行,有函数时进函数
n 表示单步执行,有函数时跳过函数
c 表示跳到下一个断点
具体使用
首先写一个测试用的代码:
#include <stdio.h>
int func(int n)
{
int sum = 0, i;
for (i = 0; i < n; i++)
{
sum += i;
}
return sum;
}
void main()
{
unsigned int i;
long result;
int a[200];
for (i = 1; i < 100; ++i)
{
result += i;
a[i] = i;
}
printf("result[1-100] = %d\n", result);
printf("result[1-200] = %d\n", func(200));
}
在这段代码里面有个小错误,我们先编译一下看看
接下来,我们使用gdb进入调试:
接下来我们再使用 l main 命令来查看主函数
可以看到上述的图片中显示错误,无法执行该命令,这是因为我们之前编译过程没有加上调试的指令,现在我们用q退出,然后重新编译,这时加上 -g
gcc -g test.c -o test1
重新进入调试界面进行调试,可见成功查看了main函数
在main函数那里设置一个断点,在第18行也设置一个断点
**查看断点:**使用info breakpoints指令
**删除断点:**使用 delete 断点Num 的方法
通过r运行程序,通过n到下一步(这样无法进入到函数里面,如果想要进入到函数里面就使用s命令):
由上图可见在for循环中,执行了100次,显然我们无法真的执行100次,所以我们可以再设置一个断点, 然后用c指令就可以跳到下一个断点
我们再次进行调试,这时进入for循环中并查看result的值,很明显可以看到result的值不对劲,那么就是这里出了问题
在循环中i=50时打个断点的做法:
gdb段错误调试
代码:
#include <stdio.h>
int main(int argc, char *argv[])
{
char *p = NULL;
printf("input string:");
gets(p);
printf("string is:%s\n", p);
return 0;
}
这段代码有个很明显的错误,那就是尝试给指向空的空指针赋值。
这里编译一下就可以知道错误:
这时虽然有警告,但是仍然编译成功了,但是我们运行程序的时候就会发现错误:
这种错误是在告诉我们:
1、数组越界;
2、指针没有赋值;
3、通过指针直接访问内存
使用ulimit命令来帮助调试:
指令:
ulimit -c unlimited
如图所示,在使用了该指令后运行文件在提示段错误后会出现一个core文件,这里面就包含了一些文件崩溃的信息
GDB调试
我们先全部重新编译,重新运行一遍
接下来再启动gdb
使用bt查看详情,并把代码拿出来对比,可以看到在#1那一行显示了错误在哪,在#0那一行可以看出来_IO_gets指向的buf=0x0,即为空指针,明显错误。
多文件调试
这里用到之前makefile中写的几个文件
然后修改一下makefile文件(要让编译后的文件包含调试信息)
target=myProject
OBJ:=myadd.c mysub.c mymul.c
OBJ+=myProject.c
CC:=gcc
CFLAGS:=-c
$(target):$(OBJ)
$(CC) -g $^ -o $@
clean:
rm -f *.o $(target)
然后进入调试,在myAdd那里打个断点(可以看到多文件打断点成功)
接下来在myProject中的main函数和myadd.c的第5行打个断点(通过文件名:行数或函数名)
r一下试试