文章目录
- 一.背景知识
- 二.安装gdb
- 三.gdb的用法
- 使用须知
- gdb的常用指令
- 1.进入调试
- 2.退出调试操作
- 3.显示源代码
- 4.设置断点breakPoint
- 5.查看断点信息/禁用断点/开启断点/删除断点
- 6.运行程序,开始调试run
- 7.查看变量
- 8.其它重要命令
一.背景知识
- 程序的发布方式有两种,debug(调试)模式和release(发行)模式;
- Linux gcc/g++出来的二进制程序,默认是release模式;
- gdb是Linux中的调试器。用于debug版本代码的调试, 要使用gdb调试,必须在源代码生成二进制程序的时候, 加上
-g
选项
二.安装gdb
sudo yum install gdb //想直接安装就加上-y选项
三.gdb的用法
为了详细解析gdb的各种用法,我们先创建两个文件:test.c和Makefile文件,用于测试gdb。
以下分别是两个文件中的测试代码:
//test.c:我们用一个从1加到100的程序来测试gdb
#include<stdio.h>
int addToTop(int top)
{
printf("enter addToTop\n");
int sum=0;
for(int i=1;i<=top;i++)
{
sum+=i;
}
printf("quit addToTop\n");
return sum;
}
int main()
{
int top=100;
int ret=addToTop(top);
printf("ret:%d\n",ret);
return 0;
}
//Makefile(自动化构建项目的工具)
mytest:test.c //依赖test.c文件生成mytest可执行程序
gcc test.c -g -o mytest -std=c99 //注意这里加上了-g选项,也用上了c99标准
.PHONY:
make clean:
rm -f mytest
运行结果:
使用须知
程序的发布方式有两种:
- debug版本:程序本身会被加入更多的调试信息,以便于进行调试。
- release版本:不会添加任何调试信息,是不可调试的。
在Linux当中gcc/g++默认生成的可执行程序是release版本的,是不可被调试的。如果想生成debug版本,就需要在使用gcc/g++生成可执行程序时加上-g
选项。
我们可以使用readelf指令查看ELF格式的文件信息:
对同一份源代码分别生成其release版本和debug版本的可执行程序,debug版本发布的可执行程序的大小比release版本发布的可执行程序的大小要大一点,从上图我们可以看出debug版本中有debug信息,其原因就是以debug版本发布的可执行程序当中包含了更多的调试信息。
gdb的常用指令
1.进入调试
gdb [可执行程序] //在上述我们写的测试代码中,可执行程序命名为mytest
//所以接下来我们就以mytest为例
2.退出调试操作
ctrl+d 或 quit
3.显示源代码
list/l 行号:显示源代码,如果按换行键会接着上次显示的位置往下列,每次只显示10行
list/l 函数名:可以直接定位到函数名的位置
操作示例:
4.设置断点breakPoint
beak(b) 行号:在某行设置一个断点
b 函数名:在某个函数开头设置断点
操作示例:
意思是在源代码的第19行设置断点
意思是在源代码的addToTop函数开头设置断点,会自动识别到第5行(函数所在处)
5.查看断点信息/禁用断点/开启断点/删除断点
info b(break)
info b指令会显示出所有的断点,我们刚刚设置了两个断点,所以显示出了两个断点的信息,Num是断点的编号,Enb表示断点的状态,y表示断点正常使用,n表示断点已被禁用。
想要操作哪个断点不是看这个断点在代码中的行号,而是在断点列表的编号。
禁用断点:
disable [断点编号Num]
开启断点:
enable [断点编号Num]
删除断点:
d(delete) [断点编号] //不加断点编号,则删除所有已设置的断点
6.运行程序,开始调试run
运行程序后会在断点处停下,就跟我们在Windows下用vs编译器调试一样一样的。不设置断点的话,程序就直接跑完了,并输出结果。
r或run
7.查看变量
打印变量值:
p 变量名
跟踪查看一个变量(长显示):
display 变量名
取消对变量的跟踪(取消长显示):
undisplay 变量名
8.其它重要命令
set var i=100
:将某个变量设置成特定的值continue(或c)
:从一个断点处,直接运行到下一个断点处until 行号
:在函数内,进行指定位置跳转,执行完区间代码bt(或breaktrace)
:查看调用堆栈info (i)locals
:查看当前栈帧局部变量的值n或next
:逐过程执行代码s或stap
:逐语句执行代码,可以进入函数体内finish
:进入一个函数,只执行完该函数,就停下来,比如上述所例举的从1加到100的函数,如果我们这个时候还在执行for循环,我们直接输入finish,就可以直接指向完addToTop函数。print(p)
:打印表达式的值,通过表达式可以修改变量的值或者调用函数info
:查看gdb的使用手册