【Linux系统编程】调试器-gdb/cgdb
【Linux系统编程】调试器-gdb/cgdb
- 1. Debug和Release
- 2. gdb/cgdb基本命令和使用
- 2.1 list/l 命令
- 2.2 break/b、info break/b、delete/d breakpoints
- 2.3 r/run、n/next、s/step
- 2.4 print/p、display、undisplay、until
- 2.5 finish、continue/c
- 2.6 disable breakpoints、 enable breakpoints
- 2.7 set var
- 2.8 watch
- 2.9 条件断点
1. Debug和Release
gdb/cgdb是一个强大的调试工具,支持多种编程语言,主要用于C/C++程序调试。
我们以下面的代码为例去认识gdb/cgdb。
// mycmd.c
#include <stdio.h>//int flag = 0; // 故意错误
//int flag = -1;
int flag = 1;int Sum(int s, int e)
{int result = 0;int i = s;for(; i <= e; i++){result += i;}return result * flag;
}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;
}
我们用gcc去直接编译该代码生成的二进制程序是Release版本的。
我们用命令readelf -S mycmd | grep -i debug去检查可执行文件或目标文件(即mycmd)中是否包含调试信息,以及调试信息的详细情况。
发现mycmd中没有任何调试信息。
要想让gcc编译mycmd.c生成debug版本的二进制程序要加-g选项
gcc -g mycmd.c -o mycmd-debug
发现mycmd-debug确实有调试信息。

而且从文件大小也能看出mycmd-debug确实有调试信息。

既然gdb是调试器,那么分别对mycmd和mycmd-debug用gdb调试,也能看出来mycmd是没有调试信息的。

2. gdb/cgdb基本命令和使用
2.1 list/l 命令
list/l 行号 :显示源代码,从上次位置开始,每次列出10行
list/l 函数名 :列出指定函数的源代码
list/l ⽂件名:⾏号 :列出指定⽂件的源代码

quit:退出gdb

是不是感觉如果通过list查看行号,然后调试的话特别麻烦?
所以可以使用cgdb,cgdb和gdb的命令是完全一样的。不同的是cgdb可以直接看着代码去调试。


2.2 break/b、info break/b、delete/d breakpoints
break/b [文件名]:行号 :在指定⾏号设置断点
break/b 函数名 :在函数开头设置断点
info break/b :查看当前所有断点的信息

delete/d breakpoints :删除所有断点
delete/d breakpoints n :删除序号为n的断点
注意:删除时 n 指的是序号,不是行号

2.3 r/run、n/next、s/step
r/run :从程序开始连续执⾏
n/next :单步执⾏,不进⼊函数内部
s/step :单步执⾏,进⼊函数内部

2.4 print/p、display、undisplay、until
print/p 表达式 :打印表达式的值
p 变量 :打印指定变量的值
display 变量名 :跟踪显示指定变量的值(每次停⽌时)
undisplay 编号 :取消对指定编号的变量的跟踪显示
until 行号 执⾏到指定⾏号
什么命令也不输入直接执行,会执行上次输入的命令

2.5 finish、continue/c
finish :执⾏到当前函数返回,然后停⽌
continue/c :从当前位置开始连续执⾏程序

2.6 disable breakpoints、 enable breakpoints
disable breakpoints :禁用所有断点
enable breakpoints :启用所有断点

为什么不直接删除断点,而选择禁用断点,防止此次调试debug未彻底,以便以后再次debug。
2.7 set var
set var 变量=值 :修改变量的值
为了更好地演示,先把flag从1改成0
// mycmd.c
#include <stdio.h>int flag = 0; // 故意错误
//int flag = -1;
//int flag = 1;int Sum(int s, int e)
{int result = 0;int i = s;for(; i <= e; i++){result += i;}return result * flag;
}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;
}
改完后发现1~100的和为0,假如我们不知道是flag导致的错误,此时我们要用cgdb进行调试。

我们调试到这里,发现是因为flag=0,导致的函数返回值为0,进而导致输出结果为0,我们如果结束调试把flag改为1再测试程序是否正确的话太慢了,所以可以用命令set var flag=1,在调试中让flag=1,观察结果是否正确,加快了调试效率。

发现结果正确,所以得出结论是因为flag错误而导致的程序结果错误。

2.8 watch
执行时监视⼀个表达式(如变量)的值。如果监视的表达式在程序运行期间的值发⽣变化,GDB会暂停程序的执行,并通知使⽤者。
如果你有⼀些变量不应该修改,但是你怀疑它修改导致了问题,你可以watch它,如果变化了,就会通知你.

2.9 条件断点
添加条件断点
b 行号/文件名:行号/函数名 if 条件

给已经存在的断点新增条件
condition 编号 条件

