文章目录
- 1、gdb
- 1.1、运行
- 1.1.1、程序入参
 
- 1.2、断点及观察点
- 1.2.1、设置断点
- 1.2.2、禁用、删除断点
- 1.2.3、观察点
 
- 1.3、打印
- 1.3.1、设定打印参数
- 1.3.2、打印数据
- 1.3.3、自动打印
- 1.3.4、按照地址打印
 
 
linux下我现在接触到的常用调试工具如下.
- gbd
- gdbgui
- cmake-tools
gdb是最为通用的,普遍linux会自带gdb工具,使用简单,无额外需求.
gdbgui需要额外安装,且会占用处理器资源.
cmake-tools是使用vscode远程ssh设备时在vscode上安装的一个插件,必须用cmake组织管理代码且使用vscode时才可以使用该工具借助于vscode图形化界面进行debug,但相当占用处理器资源.
下面只介绍gdb具体使用方法.
1、gdb
安装方式.
sudo apt-get install gdb
使用方法
// 无参程序调用
gdb ./<exce>
// 有参程序调用
gdb ./<exce> <param>
exce即为代码编译出来的可执行文件.
正常执行后会出现如下界面.
 
注意,这个时候程序并没有开始运行.
如果程序带有入参,则
1.1、运行
运行常用相关指令见下表.
| 命令 | 简写形式 | 说明 | 
|---|---|---|
| run | r | 开始执行程序直到遇到 结束或者遇到断点等待下一个命令; | 
| start | st | 开始执行程序,在main函数中的第一条语句前停下 | 
| continue | c | 继续程序的运行,直到遇到下一个断点 | 
| next | n | 执行下一条语句,如果该语句为函数调用,不会进入函数内部执行(即不会一步步地调试函数内部语句) | 
| step | s | 执行下一条语句,如果该语句为函数调用,则进入函数执行第一条语句 | 
| finish | 直接执行完当前函数,返回到调用该函数的位置 | |
| quit | q | 推出gdb调试环境 | 
该部分比较简单,且都比较常用,不再复述.
1.1.1、程序入参
| 命令 | 简写形式 | 说明 | 
|---|---|---|
| set args | 设定运行时的参数 | |
| show args | 查看设定的运行参数 | 
1.2、断点及观察点
gdb支持如下几种断点,且断点可以在程序运行前设置.
- 普通断点,运行到该处就停止
- 条件断点,运行到该处后且符合设定条件才停止
- 临时断点,只生效一次的断点
观察点是运行中设置,而且只能是变量。
1.2.1、设置断点
| 命令 | 简写形式 | 说明 | 
|---|---|---|
| break | b | 设置断点 | 
| break if | b if | 条件断点,满足if后的条件后停止 | 
| tbreak | 临时断点,只生效一次 | 
断点有如下几种设置方法.
// 在指定文件的指定行号设定断点
b <file_name>:<file_line>
// 在指定文件的指定函数设定断点
b <file_name>:<fun_name>
// 根据条件设定断点
b <file_name>:<file_line> if <cond>  例如:x==0
临时断点和上述用法一样.
1.2.2、禁用、删除断点
| 命令 | 简写形式 | 说明 | 
|---|---|---|
| info b | 显示当前所有断点 | |
| d break | 删除指定断点 | |
| delete | d | 删除所有断点 | 
| disable b | 禁用指定断点 | |
| enable b | 使能制定断点 | 
想要禁用或者删除断点,需要先知道当前共有哪些断点.如下所示.

从左到右,分别是断点号,类型,使能状态,后面是断点具体位置.
禁用断点示例如下.对应的使能断点不在演示.

可以看到禁用断点2后,后面的Enb变为了n.代表断点被禁用不生效,但依旧存在.
使能断点,删除所有断点如下所示.
 
删除指定断点示例如下.

1.2.3、观察点
观察点是当变量变化即停止的一种调试手段.
| 命令 | 简写形式 | 说明 | 
|---|---|---|
| info b | 利用此方式也可以查看watch信息,也可以使用 info watch | |
| watch | 只有当被监控变量(表达式)的值发生改变,程序才会停止运行 | |
| rwatch | 只要程序中出现读取目标变量(表达式)的值的操作,程序就会停止运行 | |
| awatch | 只要程序中出现读取目标变量(表达式)的值或者改变值的操作,程序就会停止运行 | 
cond可以是变量也可以是表达式.
我只用过变量.以变量说明
struct test{char name[16];uint32_t age;
};
struct test data = {0};
struct *p = &test_data;
-  watch data当data里任意一个数据发生改变即刻停止
-  watch data.age当data内的age发生改变时停止
-  watch *p同watch data
-  watch p当p指向内容发生变化时即刻停止
watch设定观察点的方式有两种,默认为1.
- 硬件观察点
- 软件观察点
以RK3568举例,实际使用中发现最多只能建立2个硬件观察点,后续在使用watch后,会出现如下提示.
Hardware watchpoint num: Could not insert watchpoint
使用如下指令强制GDB调试器建立软件观察点.
set can-use-hw-watchpoints 0
awatch 和 rwatch 命令只能设置硬件观察点,如果系统不支持或者借助如上命令禁用,则 GDB 调试器会打印如下信息:
Expression cannot be implemented with read/access watchpoint.
备注:软件观察点会导致程序执行效率变低
1.3、打印
1.3.1、设定打印参数
| 命令 | 简写形式 | 说明 | 
|---|---|---|
| set print elements | 设定打印长度 | |
| show print elements | 显示打印长度 | |
| set print pretty on | 打开换行打印 | 
打印信息过长时,信息显示不全,可以使用set print elements进行设定显示长度.
打印结构体时,默认不换行,使用set print pretty on可以将结构体成员变量换行显示如下所示.
其中红框内的是默认打印方式,下面的是打开换行打印后的显示效果.

1.3.2、打印数据
| 命令 | 简写形式 | 说明 | 
|---|---|---|
| print/ | p | 打印数据 | 
| ptype <var_name> | 查看变量数据类型 | 
简单介绍如下几种简单的使用方式.
int a = 1;
int *p_a = &a;
char name[32] = "name";p a   打印变量a值
p p_a  打印p_a存储的地址,即a的地址
p *p_a  打印p_a存储地址的所存储的数据
p name  打印name中的字符串值
p name[<idx>]@<len>  打印数组name从idx索引处len长度的数据
p ++a  打印++a的值,此时程序内a的值也将发生变化
p <fun(<param>)> 将参数传入函数中,直接调用函数并打印返回值
如果想要数据按照指定的方式打印,则需要用到参数.参数常用值
| fmt | 功能 | 
|---|---|
| /x | 十六进制的形式打印 | 
| /d | 有符号,十进制形式打印证书 | 
| /u | 无符号,十进制形式打印证书 | 
| /o | 八进制打印 | 
| /t | 二进制打印 | 
| /f | 浮点数打印 | 
| /c | 字符打印 | 
| /s | 字符串打印 | 
如下所示.
p/x a             以十六进制形式打印a变量
p/s name		  以字符串形式打印name数组存储的数据
p/x name[0]@10    以十六进制形式挨个打印name数组从0到len-1索引的数据
如果当前断点在C文件,此时想查看A文件的非局部变量的值,可以通过如下方式.
p <file_name>::<var_name>
可通过下列命令打印变量的类型
ptype <var_name>
1.3.3、自动打印
上述print指令需要用户每次都输入才会执行打印功能.如果想要程序一停止就打印数据可以使用display功能.
| 命令 | 简写形式 | 说明 | 
|---|---|---|
| display | ||
| info display | 查看自动显示的信息,包含信息编号 | |
| disable display | 失能自动输出,num代表信息编号 num可以为多个,比如 disable display 2 3 4也可以为一个范围,比如 disable display 2-4 | |
| enable display | 使能自动输出,num代表信息编号 num可以为多个,比如 enable display 2 3 4也可以为一个范围,比如 enable display 2-4 | |
| delete display | d display | 删除输出, num代表信息编号,同 undisplay <num>num可以为多个,比如 disable display 2 3 4也可以为一个范围,比如 disable display 2-4 | 
display所有用法同print基本一致.
1.3.4、按照地址打印
| 命令 | 简写形式 | 说明 | 
|---|---|---|
| x/<n/f/u> | 按照nfu三个参数的配置打印addr出的数据 | 
其中,n、f、u的含义如下.
| 名称 | 含义 | 
|---|---|
| n | 正整数,从addr开始,打印n个长度的数据 | 
| f | 打印形式,o是8进制,u是无符号10进制,t是二进制,c是字符,s是字符串等,参考print打印形式 | 
| u | 表示从当前地址往后请求的字节数,即一个长度的单位,默认为4字节,b表示单字节,h表示双字节,w表示四字 节,g表示八字节。 | 
x/16xb: 打印0地址处16个长度单位的数据,每个单位长度为一个字节,共计16个字节数据以16形式打印.