系列文章目录
第三章 开发工具的认识与使用
文章目录
- 系列文章目录
- @[TOC](文章目录)
- 前言
- 一、文件的编译
- 1.1 debug 配置
- 1.2 release 配置
- 二、Linux 文件调试
- 三、程序调试器gdb
- 3.1 认识gdb
- 3.2 cgdb的使用
- 3.2.1 基本操作
- 3.2.2 断点和运行操作
- 3.2.2.1 断点信息
- 3.2.2.2 断点操作
- 3.2.2.3 运行操作
- 3.2.2.4 其他操作
- 四、gdb的调试技巧
- 4.1 watch 监视变量变化
- 4.2 set var 修改运行时变量
- 4.3 条件断点
- 4.3.1 新建条件断点
- 4.3.2 断点新增条件
- 4.4 分屏操作
- 总结
文章目录
- 系列文章目录
- @[TOC](文章目录)
- 前言
- 一、文件的编译
- 1.1 debug 配置
- 1.2 release 配置
- 二、Linux 文件调试
- 三、程序调试器gdb
- 3.1 认识gdb
- 3.2 cgdb的使用
- 3.2.1 基本操作
- 3.2.2 断点和运行操作
- 3.2.2.1 断点信息
- 3.2.2.2 断点操作
- 3.2.2.3 运行操作
- 3.2.2.4 其他操作
- 四、gdb的调试技巧
- 4.1 watch 监视变量变化
- 4.2 set var 修改运行时变量
- 4.3 条件断点
- 4.3.1 新建条件断点
- 4.3.2 断点新增条件
- 4.4 分屏操作
- 总结
前言
在Linux当中,我们也会遇到代码中的bug,那此时我们就渴望像vs当中一样可以对代码进行调试,因此本节我们就来学习在Linux当中代码的调试工具的使用——gdb。
一、文件的编译
文件源码编译成可执行文件的过程中,可以分为两种编译模式:debug模式和release模式,因此形成的不同文件也就具有对应的特点。
1.1 debug 配置
debug配置是编译器的一套编译规则,由该配置产出的文件可以进行调试,常用于开发中的测试,它决定了该文件在编译过程中细节的处理:
- 定义:Debug 配置编译的程序,包含完整的符号调试信息,不启用代码优化
- 作用:专门给开发者写代码、找 bug、测试功能用的模式
- 特点:
- 不做代码优化:在该配置下形成的程序在执行时,不会进行优化代码(即对代码的增删改操作,如:省略中间变量)
- 保留完整调试信息:编译时会把变量名、函数名、代码行号、注释关联信息全部打包进 exe(调试符号)
- 内存检查宽松:一些轻微内存错误(比如越界、野指针)Debug 能勉强运行,Release 直接崩溃
1.2 release 配置
该配置为开发后发布客户端所使用的,它有着以下的细节:
- 定义:Release 配置编译的程序,启用完整代码优化,不包含调试符号信息;如需事后调试,可单独生成 .pdb 调试文件
- 作用:代码完全写完、无 bug 后,打包给别人运行、作业提交、软件发布用的模式
- 特点:
- 度代码优化(编译器自动提速):编译器会自动:删除没用的代码、变量合并重复逻辑精简运算步骤调整代码顺序,提升运行速度
- 删除全部调试信息:去掉变量名、行号、断点信息,无法调试,只能直接运行
- 内存检查严格:Debug 能运行的轻微 bug,Release 会直接闪退、崩溃,因为优化会暴露内存问题
二、Linux 文件调试
就如同上述所说的文件只有通过debug配置编译,才能对代码进行调试。而Linux中编译而成的文件默认是release 版本,本质是gcc 和 g++ 编译时默认选择的是该配置。想要配置为debug版本就需要通过选项改变:
gcc mycmd.c -o mycmd
-g通过该选项实现编译成可调试文件
而文件调制的本质无非三点:
- 找到问题:通过断点将代码分块,以块为单位快速排查问题
- 查看代码上下文:在找到问题后,对代码块的代码详细运行查看(分为逐语句和逐过程),当然还可以使用监视窗口查看变量的变化
- 解决问题:根据所学知识,修改和优化问题代码
通过以上调试的过程,成功实现问题的查找和解决。
三、程序调试器gdb
3.1 认识gdb
GDB:是一款用于调试可执行程序的调试器工具
直接使用命令gdb 可执行文件来调试文件,进入调试界面是这样的情况:
我们就可以通过在此处进行对文件的调试,可以实现初步的调试功能:打断点、单行运行、过程运行等,但是这样我们都无法看到现在执行的代码和运行的情况,因此我们推荐使用cgdb这个工具,是gdb的加强升级版,使用方式为:cgdb 可执行文件(不是系统自带,需要安装)
centos:sudo yum install -y cgdb
ubuntu:sudo apt-get install -y cgdb
通过cgdb,我们就能在调试时看到代码和运行到的进程了。
3.2 cgdb的使用
Linux作为命令行操作,它的应用程序也离不开命令行,所以让我们来学习下cgdb的命令使用。
3.2.1 基本操作
基本操作涉及cgdb的进入、退出等不涉及具体使用的操作
| 编号 | 命令 | 作用 |
|---|---|---|
| 1 | cgdb 可执行文件(debug) | 进入cgdb界面 |
| 2 | quit | 退出cgdb |
| 3 | list / l 源代码 | 显示文件的源代码(后加:数字从代码第几行开始显示) |
3.2.2 断点和运行操作
调式的实现离不开断点的使用,以及运行方法。通过合适的断点分块和判断运行过程还是语句,实现问题的查找
3.2.2.1 断点信息
断点就是你让程序停下来的标记,是调试(cgdb/gdb)最核心的功能。
当然系统为了区分不同的断点,给断点设置了不同的信息,我们使用命令info b进行查看:
让我们先来认识以下断点信息都有哪些:
- Num:断点编号,每个断点都有自己的编号,并且编号是逐渐递增的,即使删除1号,新增也是4号(不退出情况)
- Type:断点类型,断点分为五个类型,常用为:breakpoint(普通断点)、watchpoint(观察断点)
- Disp:断点存活方式:keep= 永久有效,不会自动删除,还有tbreak(临时断点)
- Enb:是否启用:
y= 启用,n= 禁用 - Address:内存地址(代码在内存里的位置,不用管)
- What:断点位置:哪个文件、第几行、哪个函数
下面会对某些信息做详细解释。
3.2.2.2 断点操作
| 编号 | 命令 | 作用 |
|---|---|---|
| 1 | b / break 数字 | 在该程序的第几行打断点 |
| b 文件:行号 | 在对应的文件行打断点 | |
| b 文件:函数 | 在对应的文件该函数处打断点 | |
| 2 | info b | 查看断点信息 |
| 3 | d 断点编号 | 删除相应编号的断点 |
| 4 | disable / enable 断点编号 | 禁用 / 启用 对应的断点编号 |
3.2.2.3 运行操作
| 编号 | 命令 | 作用 |
|---|---|---|
| 1 | run / r | 运行程序,直到遇到断点或程序结束 |
| 2 | next / n | 逐过程运行,将函数调用视为一个整体步骤执行(例如:直接执行完整个函数,不进入其内部) |
| 3 | step / s | 逐语句运行,gdb记录最新的一条输入语句 |
| 4 | finsh | 直接执行完当前函数 |
| 5 | c | 直接由上一断点运行到下一断点 |
| 6 | until 行号 | 快速执行到第几行 |
3.2.2.4 其他操作
我们来讲解以下除了以上调试功能外的常用其他操作:
bt:查看代码的调用栈
我们会遇到这样一个情况:在函数调用返回值的时候需要使用两次n才能运行到下一行。这是因为返回值是函数的一个临时变量,需要mov操作将该变量赋值给变量,所以使用函数赋值做了两件事:callq 和 mov。p:查看变量的值
在调试过程中,查看当前的变量存储的数据值。还可以充当临时计算的工具display / undisplay:加入 / 删除 监视变量
通过常显示来显示每一步变量的变化情况,便于查看代码上下文info locals:查看现在执行代码块中的临时变量及变量的值
四、gdb的调试技巧
4.1 watch 监视变量变化
在display的监视功能的基础上,新增了变量的变化信息:当变量存储数据改变时列出新老数据
- 用法:
watch + 变量新增监视变量;d + 变量删除监视变量 - 功能:如果你有⼀些变量不应该修改,但是你怀疑它修改导致了问题,你可以watch它,如果变化了,就会通知你
4.2 set var 修改运行时变量
我们常常会遇到发现变量异常,此时我们需要退出调试并重新设值再次运行,才能继续。而set var这个命令就可以在运行时直接修改变量
- 用法:
set var flag = 1修改运行程序中的变量 - 功能:不用改代码、不用重新编译,直接在命令行改变量的值。
4.3 条件断点
4.3.1 新建条件断点
创建一个带有条件实现的断点,实现如:达到目标循环次数时停止运行
- 用法:
b 行号 条件:满足条件时触发断点。(如:b 6 if i == 8)
4.3.2 断点新增条件
为已有的断点新增运行条件
- 用法:
condition 断点编号 条件:为已存断点新增满足条件。(如:condition 6 if i == 8)
4.4 分屏操作
cgdb还可以通过Esc分屏进入到代码文件当中操作,i从代码屏回到调试窗口。
总结
本章的开发工具到本节就结束了,下一章我们将学习到Linux底层的东西,感谢您的阅读,期待下一次的学习。