LInux中调试器的使用(cgdb)

LInux中调试器的使用-gdb/cgdb

下面提供一个示例程序,便于使用 cgdb 调试时练习定位 bug。

#include <stdio.h>
int Sum(int s, int e)
{
int result = 0;
for(int i = s; i <= e; i++)
{
result += i;
}
return result;
}
int main()
{
int start = 1;
int end = 100;
printf("I will begin\n");
int n = Sum(start, end);
printf("running done, result is: [%d-%d]=%d\n", start, end, n);
return 0;
}

我们在 lesson8 文件夹中创建 mycmd.c 执行 gcc mycmd.c -o mycmd -std=c99 后, 生成 mycmd 文件。使用 gdb mycmd 命令进行调试。并输入 list 命令:

在这里插入图片描述

程序显示为 No symbol table is loaded. Use the "file" command. 这说明当前文件不具有调试功能。这是因为gcc默认是已release模式发布的,不包含调试信息。所以程序无法调试。

我们可以使用 readelf 扫描可执行文件,并读取可执行程序的二进制文件的构成段,然后查找有没有 debug 文件信息来确定是否有调试功能。

在这里插入图片描述

readelf -S mycmd | grep -i debug 使用readelf 读取文件信息,使用管道搜索debug关键词

如果没有debug信息,说明他无法调试。


**如何以debug模式发布:**在最后加上-g选项 gcc mycmd.c -o mycmd -std=c99 -g

再次使用 readelf 读取文件,可见:

在这里插入图片描述

说明此时文件为可调式文件,之后我们可以进行调试。

此时再次执行 gdb mycmd 指令, 运行 list 命令后,显示如下,此时说明文件已经变成了 debug 版本。

在这里插入图片描述

从图中可以看到,罗列出来的代码并没有从第一行开始,我们可以使用 l 0 从第一行开始罗列。


编写Makefile文件

我们可以对编译的过程优化一下,根据之前学过的知识,我们可以先编写Makefile文件, 然后使用 makemycmd.c 指令进行自动化编译。

touch Makefile 创建文件后, 使用 vim Makefile 指令打开编写如下代码:

mycmd: mycmd.c
    gcc -std=c99 -o $@ $^ -g
.PHONY: clean
clean:
	rm -f mycmd

-std=c99:严格使用 C99 标准。

-std=gnu99:使用 C99 标准并同时包含 GNU 扩展。

-g:生成调试信息。

-Wall:打开大部分常见的警告。

编写完成后,使用 make 指令运行 Makefile文件,自动化生成 mycmd 可执行二进制文件。然后进行调试。

如果你在 make 后,遇到如下问题:

在这里插入图片描述

这是因为,编译器默认使用了比 C99 更早的 C 语言标准(可能是 gnu89),导致出现如图错误。我们仅需在 Makefile中指定使用 c99标准进行编译即可。


选择更加可是化的调试器

使用 gdb 是有问题的,我们默认开不到代码,很不方便,因此我们推荐使用cgdb 来调试代码,这样我们不仅可以看到代码,还可以看到调试的信息。

使用 sudo yum install -y cgdb 命令(centos)来安装cgdb

使用 cgdb mycmd 命令开始调试,显示如下:

在这里插入图片描述

相比于gdb调试,界面看起来舒服太多了。

cgdb相关指令:

list/l 行号0: 查看代码
b行号: 打断点
info b: 查看断点
d 断点编号: 删除
b  + 文件名 :函数名   为某个文件中的某个函数打断点
删除断点的时候,需要按照断点的编号来进行删除
在一轮调试周期中,断点编号是线性递增的
r   表示运行
n/next  表示单步执行,不进入函数内部

在这里插入图片描述

注意:
按esc键可以让输入焦点进入到vi窗口,再按i键回到gdb窗口。
gbd启动调试的时候,只是开启了gbd,程序并没有运行起来。
r/run, 表示的是在gbd的场景中,启动我们自己的mycmd程序。
在没有断点情况下,r/run命令就是让我们的程序运行结束
断点的本质是:让程序运行到指定行后暂停。

cgbd中常见指令汇总

命令代码
list/l显示源代码,从上次位置在开始,每次列出10行
list/l 函数名列出指定函数的源代码
list/l 文件名:行号列出指定文件的源代码
r/run从程序开始连续执行
n/next单步执行,不进入函数内部
s/step单步执行,进入函数内部
break/b[文件名:] 行号在指定行号设置断点
break/b 函数名在函数开头设置断点
info break/b查看当前所有断点的信息
finish执行到当前函数返回,然后停止
print/p 表达式打印表达式
p变量打印指定便量的值
set var 便量=值修改变量的值
continue/c从当前位置开始连续执行程序
delete/d beakpoints n删除序号为n的断点
disable breakpoints禁用所有断点
enable breakpoints启用所有断点
info/i breakpoints查看当前设置的断点列表
display 变量跟踪指定变量的值(每次停止时)
undisplay 编号取消对指定变量编号的变量的跟踪显示
until x 行号执行到指定行号
backtrace/bt查看当前执行栈的局部变量值
info/i locals查看当前栈帧的局部变量值
quit退出GDB调试器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值