3. Linux调试器-gdb使用
3.1 背景
程序的发布方式有两种,debug
模式和release
模式
Linux gcc/g++
出来的二进制程序,默认是release
模式
要使用gdb
调试,必须在源代码生成二进制程序的时候, 加上 -g
选项
3.2 下载安装
debug
模式的代码可以被调试,release
模式的代码不可以被调试。
为什么一个可以被调试一个不可以被调试呢?
debug
模式的代码形成可执行程序的时候会有调试信息,而release
模式的代码没有。
我们可以先进入root
账户安装一下gdb
。
sudo apt update # 更新软件源
sudo apt install gdb # 安装gdb
然后验证
# 检查gdb版本
gdb --version
3.3 使用gdb查询
对于一个文件我们不知道是debug
还是release
,就可以使用gdb
来查询
我们先写一个Makefile
mycode:mycode.c
gcc -o $@ $^
.PHONY:clean
clean:
rm -f mycode
然后写一个mycode.c
的文件,里面写一个hello linux
然后编译,使用gdb
(No debugging symbols found in mycode)
意味着不是debug
版本的。
退出gdb
的话输入一个q
,回车就行了。
还有个命令readelf -S mycode
,可以读取
文件的二进制构成,可以看到里面没有debug
。
说明gcc
编译默认是release
编译的。
如果我们想要debug
编译可以改一下代码:
这里的-g
是使用debug
,前面的mycode-debug
是改个名字便于区分。
然后我们make
一下,
出现了这个信息。
3.4 开始使用
gdb binFile 退出: ctrl + d 或 quit 调试命令:
list/l 行号:显示binFile源代码,接着上次的位置往下列,每次列10行。
list/l 函数名:列出某个函数的源代码。
r或run:运行程序。
n 或 next:单条执行。
s或step:进入函数调用
break(b) 行号:在某一行设置断点
break 函数名:在某个函数开头设置断点
info break :查看断点信息。
finish:执行到当前函数返回,然后挺下来等待命令
print§:打印表达式的值,通过表达式可以修改变量的值或者调用函数
p 变量:打印变量值。
set var:修改变量的值
continue(或c):从当前位置开始连续而非单步执行程序
run(或r):从开始连续而非单步执行程序
delete breakpoints:删除所有断点
delete breakpoints n:删除序号为n的断点
disable breakpoints:禁用断点
enable breakpoints:启用断点
info(或i) breakpoints:参看当前设置了哪些断点
display 变量名:跟踪查看一个变量,每次停下来都显示它的值
undisplay:取消对先前设置的那些变量的跟踪
until X行号:跳至X行
breaktrace(或bt):查看各级函数调用及参数info(i) locals:查看当前栈帧局部变量的值
quit:退出gdb
mycode.c
#include <stdio.h>
int addToTop(int top)
{
int res=0;
int i=1;
for(;i<=top;i++)
{
res+=i;
}
return res;
}
int main(){
printf("debug begin\n");
int top=100;
int sum=addToTop(top);
printf("sum:%d\n",sum);
printf("debug end\n");
return 0;
}
执行编译生成的mycode-debug
文件:
输入命令进入交互模式
要调试首先要看到代码,我们可以输入list
或者l
不过这边只输出了10行,我们也可以使用list n
来显示一下:
也可以输完l 0
后回车,一次出现10行。
直接输入r
,因为没有断点就直接运行了。
我们一般可以打断点:
b 行号
这边打完断点怎么查呢?
可以使用info b
来查询。
怎么删除断点呢?
断点的删除可以使用:b 行号
来删除,要注意这里的行号是Num
这里的断点的行号。
这里的Enb
的值有y
和n
,y
就是启用断点,n
就是禁用断点。
如果我们想要看里面的i
,就可以使用p i
;如果我们想要看里面的i
的地址,就可以使用p &i
每次都这么输入比较麻烦,我们就可以使用display
。
display
变量名:跟踪查看一个变量,每次停下来都显示它的值。
如果我们想让自己从一个断点到另一个断点,就可以直接使用continue
(或c
)。
也可以禁用断点而不是删除断点:disable breakpoints