GDB——Linux下的调试工具

GDB安装

  1. 使用`yum
1yum install gdb -y
  1. 使用scl
1scl enable devtoolset-9

使用GDB调试

使用GDB调试指定文件

  1. 生成支持gdb调试的二进制文件
1gcc -g -o main main.c #添加-g参数来支持gdb调试
2
3#更推荐使用下面的方式使用gdb
4gcc -Og -o main main.c #-O参数指定1-4级的优化级别,默认为1
  1. 使用gdb启动二进制文件
1gdb main

image.png
看到(gdb)就代表gdb启动成功了

不指定文件调试GDB

直接执行命令gdb使用file指令指定当前要修改的文件

1gdb -q 									# -q means quiet,disable the notify info
2(gdb) file <target-file>

参数传递

  1. 启动时使用--args参数
1gdb --args main.exe [argfile-name]
2#例如使用args.file存储参数
3gdb --args main.exe args.file
  1. gdb启动后使用set args指令设置参数存储文件
1(gdb) set args [argsfile-name]
  1. 在使用gdbrunstart指令时指定参数文件
1(gdb)run [argsfile-name]
2(gdb)start [argsfile-name]


结果输出

1(gdb)run > a.txt #将结果覆盖工作目录下的文件a.txt


常用GDB指令

指令 作用
break ``b 在指定第`` 处添加断点
run``r 运行程序
continue``c 执行到下一个断点或直接执行完毕如果是函数调用,则不会步入
next``n``next n 执行当前位置的下一行代码如果是函数调用,则会步入next n代表往下执行n
print ``p 打印变量``的值
list``l 打印程序源码
quit``q 终止调试
cd 变更gdb的工作目录,gdb工作目录是启动gdb所在的目录,一般要保证gdb的工作目录为源码目录
path gdb内部,append``到PATH变量中
watch 监控变量,只要变量发生变更。就停止运行注意,watch也可以监控一个表达式是否发生变化
info watchpoints 查看监控点数量
info break 查看断点信息

GDB断点

GDB断点类型 对应指令
普通断点 breakorb
观察断点 watch
捕捉断点 catch

Break指令

location参数的选取以及含义

location的值 含义
linenum linenum 是一个整数,表示要打断点处代码的行号。要知道,程序中各行代码都有对应的行号,可通过执行 l(小写的 L)命令看到。
filename:linenum filename 表示源程序文件名;linenum 为整数,表示具体行数。整体的意思是在指令文件 filename中的第 linenum 行打断点。

|
| + offset
- offset | offset 为整数(假设值为 2),+offset 表示以当前程序暂停位置(例如第 4 行)为准,向后数 offset 行处(第 6 行)打断点;-offset 表示以当前程序暂停位置为准,向前数offset 行处(第 2 行)打断点。

|
| function

| function 表示程序中包含的函数的函数名,即 break命令会在该函数内部的开头位置打断点,程序会执行到该函数第一行代码处暂停。

|
| filename:function | filename 表示远程文件名;function 表示程序中函数的函数名。整体的意思是在指定文件 filenamefunction 函数的开头位置打断点。 |

tbreak

t means temp.
Tbreak指令创建的断点在当前这次运行之后就会被删除

rbreak

r means rugular expression.
rbreak会在函数的开头打断点,使用正则表达式匹配函数名,所有匹配的函数都会被打上断点

1(gdb)rbreak <regular-expression>

条件断点

可以使用如下语句在特定条件下打断点
break ... if <condition>
<condition>成立时,进行断点的设置

Watch指令

watch 只有当被监控变量(表达式)的值发生改变,程序才会停止运行。
rwatch 只要程序中出现读取目标变量(表达式)的值的操作,程序就会停止运行;
awatch 只要程序中出现读取目标变量(表达式)的值或者改变值的操作,程序就会停止运行。

注意事项

注意:如果一个变量还没有出现在上下文context中(即程序还没运行到出现变量那一行),那就不能直接watch,一般直接在变量声明处打断点,然后再进行watch,示例如下

 1(gdb) l
 21       #include <iostream>
 32       using namespace std;
 43
 54       int main(){
 65
 76       int a = 0;
 87       while(a<=100){
 98       a++;
109       }
1110
12(gdb) l
1311      return 0;
1412      }
15(gdb) watch a
16No symbol "a" in current context.
17(gdb) b 6
18Breakpoint 1 at 0x1171: file main.cpp, line 6.
19(gdb) run
20Starting program: /root/code/a.out 
21
22Breakpoint 1, main () at main.cpp:6
236       int a = 0;
24(gdb) watch a
25Hardware watchpoint 2: a

条件断点

watch <expression> if <condition>
条件<condition>成立时监控表达式或者变量<expression>的值

Catch指令

catch指令是事件驱动,即指定事件(如异常)发生时,产生预定的动作(打断程序)。
catch指令语法:catch <event>

event取值 含义
throw [exception] 当程序中抛出 exception 指定类型异常时,程序停止执行。如果不指定异常类型(即省略 exception),则表示只要程序发生异常,程序就停止执行。
catch [exception] 当程序中捕获到exception 异常时,程序停止执行。exception 参数也可以省略,表示无论程序中捕获到哪种异常,程序都暂停执行。
load [regexp]``unload [regexp] 其中,regexp 表示使用正则表达式表示的目标动态库的名称,load 命令表示当 regexp 动态库加载时程序停止执行;unload 命令表示当 regexp 动态库被卸载时,程序暂停执行。regexp 参数也可以省略,此时只要程序中某一动态库被加载或卸载,程序就会暂停执行。

示例如下:

 1(gdb) l
 21       #include <iostream>
 32       using namespace std;
 43
 54       int main(){
 65
 76       int a = 0;
 87       while(a<=100){
 98       a++;
109       }
1110      throw 100;
12(gdb) catch throw int
13Catchpoint 1 (throw)
14(gdb) run
15Starting program: /root/code/a.out 
16
17Catchpoint 1 (exception thrown), 0x00007ffff7d82672 in __cxa_throw () from /lib/x86_64-linux-gnu/libstdc++.so.6

Condition指令

Condition指令给特定的断点添加条件表达式
增加condition语法:condition <bnum> <expression>
删除condition语法:condition <bnum>
<bnum>为断点标号,可以使用info break查看
只有当表达式成立时,特定断点才会生效,否则不进行中断

Ignore指令

ignore指定特定断点的失效次数
ignore语法:ignore <bnum> <count>
<bnum>为断点标号,可以使用info break查看
<count>为失效次数
失效次数每次-1,一旦一个断点的失效次数为0,那么断点生效

 1(gdb) l
 21       #include <iostream>
 32       using namespace std;
 43
 54       int main(){
 65
 76       int a = 0;
 87       while(a<=100){
 98       a++;
109       }
1110      throw 100;
12(gdb) b 8
13Breakpoint 1 at 0x11c2: file main.cpp, line 8.
14(gdb) ignore 1 100 #跳过一号断点一百次
15Will ignore next 100 crossings of breakpoint 1.
16(gdb) run
17Starting program: /root/code/a.out 
18
19Breakpoint 1, main () at main.cpp:8
208       a++;
21(gdb) print a
22$1 = 100 #在第一百一次循环的时候生效了,前一百次被跳过
23(gdb)

断点删除

普通断点info break [n]查看断点信息,n为可选参数,标明查看某个断点的信息
观察断点info watchpoint [n]

  1. 删除指定位置所有断点

clear <location>
location 参数为某个函数的函数名时,表示删除位于该函数入口处的所有断点。

  1. 删除单个断点

delete <bnum>
<bnum>为断点编号

断点禁用与激活

禁用断点可以暂时使断点失效。

  1. 禁用断点

disable [num...]
[num...]表示多个断点编号,使用空格分割

  1. 激活断点

enable [num...]

GDB单步调试

单步调试就是指每次指执行一行代码,有三个指令用来进行单步调试

指令名 效果
next``next count 跳过函数内部,直接按行执行不提供count则默认count为1
step``step count 会进入函数内部
until``until location 不带参数的until命令,可以使 GDB 调试器快速运行完当前的循环体,并运行至循环体外停止,如果没在循环体中,那么也是执行下一行。location表示,程序执行到某个位置时,进行停止。
1

标题:GDB——Linux下的调试工具
作者:cyberloafing
地址:https://www.goloaf.top/articles/2022/06/28/1656427040308.html

avatar