当前位置: 首页 > news >正文

gdb调试教程

什么是gdb

GDB(GNU Debugger)是一个功能强大的调试器,用于调试和分析程序的运行。它是自由软件基金会(FSF)的 GNU 项目的一部分,可在多个操作系统上使用,包括 Linux、Unix、Windows 等。

GDB 可以帮助开发人员在程序运行过程中找到和修复错误,以及分析程序的行为和性能。它提供了一系列的命令和功能,用于设置断点、单步执行、查看变量和内存、跟踪函数调用等。通过与编译器和调试信息配合使用,GDB 可以提供丰富的调试信息,帮助开发人员深入了解程序的执行过程。

GDB 支持多种编程语言,包括 C、C++、Objective-C、Fortran、Java 等。它可以与不同的编译器和开发环境集成,例如 GCC、Clang、Visual Studio 等。

使用 GDB,开发人员可以通过在程序执行过程中检查和修改变量的值、跟踪函数调用和返回、查看程序的堆栈和内存状态等来诊断和解决问题。它还支持调试多线程程序和远程调试,使得在复杂的开发场景下进行调试变得更加方便和灵活。

实战

安装gdb

ubuntu安装gdb:sudo apt install gdb
centos安装gdb:sudo yum install gdb

1、准备好调试的代码

创建 main.cpp, 文件内容如下:

#include "iostream"int getAge(){int count=0;count ++;std::cout <<"getAge function" << std::endl;return 1;
}int main() {std::cout << "Hello, World! yeindong" << std::endl;std::cout << "getAge:"<<getAge() << std::endl;return 0;
}
2、编译

输入以下命令进行编译

g++ main.cpp -g -o main_gdb

其中,-g表示编译生成的目标文件中包含了源代码的调试信息,这些信息可以在调试器中使用;
没有报错就表示成功

如果是大项目有多个文件,就得用makefile来编译,以下是一个makefile示例

main=main.o
student=student.o
man_student=main.o student.omain : $(man_student)g++  -g -o main $(man_student)
$(main): main.cppg++ -g -c main.cpp$(student):  student.cpp student.hppg++ -g -c student.cpp student.hppclean :rm main $(man_student)
3、启用gdb调试

输入以下命令即可开启gdb调试,main_gdb 是刚刚编译后生成的可执行文件;

gdb main_gdb
4、break 断点相关指令

那上面的代码例子,添加断点有5种方式,
比如我们想要调试getAge函数,那么就输入以下命令即可

break getAge

其他添加断点的方式

# 在程序的第5行添加断点
b 5
break 5# 在main.cpp的第10行添加断点
b main.cpp:10
break main.cpp:10# 条件断点,当满足条件时自动断点,当i变量等于10的时候断点
break if i == 10
b if i == 10# 在指定地址添加断点
break *0x12345678
b *0x12345678

这样一个断点就打好了,还会告诉你断点在main.cpp的第4行

另外,如果我们打了很多断点,可以通过以下指令来查看所有的断点

infp break
i b

可以看到,目前有一个断点,最左边的1是这个断点的编号,

5、run运行程序

在第4步已经打好断点了,然后就可以运行了,输入以下指令后会自动运行到断点的位置后停住

run

运行后我们发现,自动运行到断点的位置了;

未完待续

6、continue 断点处继续执行

刚刚已经执行了run指令运行到断点位置了,通过以下指令可以让它继续执行到下一个断点,如果没有断点就会执行到结束为止;

continue

当看到[Inferior 1 (process 10693) exited normally]字符串的时候就表示已经程序已经执行完毕了;

7、delete / clear 删除断点

删除断点有2种方式,分别为delete 和 clear

1、清除所有断点

delete # 清除前会提示确认,确认候才会删除所有断点

2、delete 删除通过编号单个断点
delete只能通过编号删除断点

delete 断点编号

先通过 info break 查询断点的编号为6,然后通过delete 6 删除断点

3、clear 删除断点
clear可以通过函数名称删除断点

比如现在要删除 getAge 函数的断点

clear getAge

执行后发现,编号为7的getAge函数断点已经没了

8、next 单步执行

在运行过程,可以通过next进行单步或者多步执行

# 单步执行
next 
n# 一次性执行2步
next 2
n 2

9、step 进入函数内部

在执行断点时可以进入函数内部

step

先在 std::cout << "getAge:"<<getAge() << std::endl; 所在行打上断点,然后输入 step 指令,会发现断点就进入到了getAge函数内部了

10、print 查看变量的值
print 变量名

11、set var xxx = x 设置变量的值

设置变量的值为10

set var count = 10

12、watch 监听变量的值

watch 用于监听变量的值,当变量的值发生改变时会自动暂停,并打印出改动前后的值,注意,必须先run了之后再设置watch指令,也就是说,如果我要监听 count,必须在栈中存在这个变量才能监听,否则是无法监听的

watch xxx

设置后,类型为 hw watchpoint

运行后监听到了count变量的变化,会打印出新值和旧值

12、backtrace查看函数调用栈

在 GDB 中,您可以使用 backtrace 或 bt 命令来查看当前的函数调用堆栈。

以下是使用

backtrace
bt
  1. 在 GDB 中启动程序并运行到断点处。
  2. 在 GDB 的命令行中输入 backtrace 或 bt 命令。
  3. GDB 将显示当前的函数调用堆栈,包括函数名、源文件和行号。

15、frame 查看某个栈的信息

学过数据结构都知道,栈是遵循先入后出的规则;也就是说,用bt指令查看到最顶部的栈信息就是当前断点所在的地方;

# 查看栈顶信息
frame
f
frame 0
f 0# 查看第二层栈的信息
frame 1
f 1

接下来我们先用bt查看所有栈信息,然后在用f 0f 1 查看栈顶和第二层栈信息

通过以下指令可以查看更详细的信息

# 查看栈顶的详细信息
info frame
info frame 0
i f
i f 0# 查看第二层的栈详细信息
info frame 1
i f 1

14、x命令 查看内存值内容

可以使用examine命令(简写是x)来查看内存地址中的值。x命令的语法如下所示:

x/<n/f/u> <addr>

其中 n、f、u都是是可选的参数。 addr 是需要查看的内存起始地址

参数 n:查看的内存长度

参数 n 是一个正整数,表示显示内存的长度,也就是说从当前地址向后显示几个地址的内容。

参数 f:显示格式

格式如下

格式说明
x按十六进制格式显示变量。
d按十进制格式显示变量。
u以无符号十进制格式显示数据。
o按八进制格式显示变量。
t按二进制格式显示变量。
a按地址格式显示变量。
c按字符格式显示变量。
s按字符串格式显示变量。
f按浮点数格式显示变量。

参数 u:显示的字节数量

u 表示从当前地址往后请求的字节数,如果不指定的话,GDB默认是4个bytes,当我们指定了字节长度后,GDB会从指内存定的内存地址开始,读写指定字节,并把其当作一个值取出来。

参数可以用下面的字符来代替

格式说明
b表示单字节,
h表示双字节,
w表示四字节(默认值)
g表示八字节。

举个栗子

默认什么参数都不带的情况下,展示长度为1,以10进制的方式展示

(gdb) x 0x602008  # 等价于 x/1db 0x602008
0x602008:	33

以16进制的方式查看 2个8字节长度的值,总共查看了2*8=16个字节的值

(gdb) x/2xg 0x602000
0x602000:	0x0000000000000000	0x0000000000000021

以16进制查看地址后面10长度的值,

(gdb) x/10xb 0x602000
0x602000:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0x602008:	0x21	0x00

以10进制查看地址后面10长度的值,

(gdb) x/10db 0x602000
0x602000:	0	0	0	0	0	0	0	0
0x602008:	33	0
15、quit 退出gdb

输入以下内容即可退出gdb调试

q
quit

http://www.dtcms.com/a/303337.html

相关文章:

  • 图像轮廓与凸包
  • 网络编程接口htonl学习
  • 如何进行DAP-seq的数据挖掘,筛选验证位点
  • Baumer工业相机堡盟工业相机如何通过YoloV8深度学习模型实现面部口罩的检测识别(C#代码,UI界面版)
  • C++-关于协程的一些思考
  • json取值,如果字段不存在,匹配下一个字段
  • 自定义View学习记录 plinko游戏View
  • 恒坤新材IPO被暂缓审议:收入确认法遭质疑,募资缩水约2亿元
  • 元宇宙经济与数字经济的异同:虚实交织下的经济范式对比
  • 基于Springboot的宠物救助管理系统的设计与实现
  • 【VUE3】搭建项目准备工作
  • 艾格文服装软件怎么用?
  • Windows中查看GPU和Cuda信息的DOS命令总结
  • AI产品经理手册(Ch1-2)AI Product Manager‘s Handbook学习笔记
  • uvm sequence Arbitration
  • AI 驱动、设施扩展、验证器强化、上线 EVM 测试网,Injective 近期动态全更新!
  • git stash apply 冲突合并方法解决
  • 希尔排序(缩小增量排序)面试专题解析
  • unisS5800XP-G交换机配置命令之登录篇
  • 洛谷 P10448 组合型枚举-普及-
  • Visual Studio Code使用
  • 25世界职业院校技能大赛国内赛区承办名单确定,各赛区需全力筹备
  • 【Spring Boot 快速入门】二、请求与响应
  • CGA围手术期:全周期保障老年手术安全
  • 基于深度学习的医学图像分析:使用YOLOv5实现细胞检测
  • TI 2025全国电赛猜题
  • 刘润探展科大讯飞WAIC,讯飞医疗AI该咋看?
  • 【重学数据结构】二叉搜索树 Binary Search Tree
  • LINUX 728 SHELL:grep;sort;diff
  • MOE 速览