目录
[二、开始使用 gdb](#二、开始使用 gdb)
在Linux系统的软件开发领域,调试程序是确保软件质量和功能正确性的关键环节。 gdb (GNU Debugger)作为一款功能强大且广泛使用的调试工具,为开发者提供了深入剖析程序运行过程、定位问题根源的有效手段。今天,就让我们深入探究 gdb 的使用方法。
一、背景知识
在程序开发中,程序的发布模式主要有两种: debug 模式和 release 模式。 debug 模式下,程序保留了丰富的调试信息,包括变量名、函数名、行号等,这使得开发者能够在调试过程中清晰地了解程序的内部状态,方便查找问题。(内存更大)
而 release 模式则侧重于程序的运行效率,会对代码进行优化处理,并去除大部分调试信息。
readelf -S 文件名 可以以二进制形式访问文件


readelf -S test.o | grep -i debug这条命令的作用是在ELF文件 test.o 中查找与调试信息相关的节区。
具体解释
readelf -S test.o :使用 readelf 命令的 -S 选项,用于显示 test.o 文件的节区信息,包括节区的名称、类型、大小、地址等详细内容。
| grep -i debug :通过管道符 | 将 readelf -S test.o 的输出结果作为 grep -i debug 的输入, grep 命令用于在输入中搜索包含 debug 字符串的行, -i 选项表示不区分大小写。
执行结果
该命令执行后,会输出 test.o 文件中所有与调试信息相关的节区信息,这些节区通常包含了调试符号、源代码行号等信息,有助于在调试程序时将程序的运行状态与源代码关联起来。
在Linux系统中,使用 gcc/g++ 编译生成的二进制程序,默认采用 release 模式。若要使用 gdb 对程序进行调试,必须在使用 gcc/g++ 编译源代码生成二进制程序时,加上 -g 选项。该选项会使编译器在生成的二进制文件中嵌入调试信息,从而让 gdb 能够识别和利用这些信息进行调试。


二、开始使用 gdb

当我们准备好带有调试信息的二进制程序后,即可启动 gdb 开启调试之旅。启动 gdb 的命令格式为 gdb binFile ,其中 binFile 是待调试的二进制文件名。
若调试完毕想要退出 gdb ,可使用 ctrl + d 组合键,或者直接输入 quit**(q)** 命令。

(一)查看源代码相关指令
**- list / l :**此指令用于显示 binFile 的源代码。它会从上次显示的位置继续往下,每次展示10行代码。通过反复使用该指令,我们能够逐段查看程序的代码逻辑,为后续调试操作奠定基础。
**- list / l 函数名 :**当我们聚焦于特定函数的代码逻辑时,该指令可派上用场。输入函数名后, gdb 会迅速定位并列出该函数的全部源代码内容,方便我们深入分析函数内部实现。
(二)程序执行控制指令
**- r或run :**这是启动程序运行的指令。在完成断点设置等前期调试准备工作后,使用该指令可让程序开始执行,使我们能够观察程序在实际运行过程中的行为表现。
()逐语句执行
**- n或next :单条执行指令。**每执行一次该指令,程序就会执行一条语句,但不会深入函数内部。此指令适用于我们不关心函数内部执行细节,仅需快速推进程序执行流程的场景。
()逐过程执行(理解为跳过一个函数过程)
**- s或step :**与 next 指令不同, step 指令会深入函数调用内部。当我们需要详细了解函数内部的执行逻辑、变量变化以及函数调用关系时,使用该指令可深入到函数内部逐行调试。
(三)断点相关指令
- break(b) 行号 :用于在指定行号处设置断点。当程序执行到设置断点的这一行时,会自动暂停运行,此时我们可以检查程序当前的状态,如变量取值、寄存器状态等信息,以便排查问题。
**- break 函数名 :**在指定函数的开头位置设置断点。这样,当程序运行过程中调用到该函数时,就会立即暂停,方便我们针对该函数进行专项调试,分析函数的输入输出以及内部逻辑是否正确。
**- info break :**用于查看断点信息。当我们在程序中设置了多个断点后,可能难以清晰记住每个断点的具体情况。使用该指令可清晰列出所有已设置断点的详细信息,包括断点编号、所在位置、是否启用等内容,便于我们对断点进行管理。
(四)变量操作相关指令
**- print(p) 表达式 (监视):**该指令用于打印表达式的值。**说白了就是查看变量变化过程,**通过它,我们不仅能够查看变量的当前取值,还能通过表达式变量进行计算、修改变量的值或者调用函数等操作,在调试过程中灵活地探究程序状态。
**- set var :**直接修改变量的值。在调试过程中,当我们想要模拟特定的变量取值情况,以观察程序在不同输入条件下的运行结果时,使用该指令可方便快捷地修改变量值。
(五)其他常用指令
**- finish (跳出函数内部):**执行到当前函数返回,然后暂停下来等待后续命令。当我们进入一个函数内部进行调试,在查看完函数内部相关信息后,若想快速回到函数调用的上层继续调试,使用该指令可直接执行到函数返回,无需逐行单步执行。
**- continue(或c) :**从当前位置开始连续而非单步执行程序。当我们已经仔细检查完程序某个区域的代码,确认该部分代码逻辑无误,想要让程序继续执行下去,以观察后续代码的执行情况时,使用该指令可让程序快速运行,直到遇到下一个断点或程序结束。
**- delete breakpoints :**删除所有断点,当我们调试过程中需要清空已设置的所有断点时可使用。
**- delete breakpoints n :**删除序号为 n 的断点,可针对特定断点进行精准删除操作。
**- disable breakpoints :**禁用断点,使已设置的断点暂时失效,而不删除断点信息,后续可重新启用。
**- enable breakpoints :**启用断点,用于恢复被禁用的断点。
**- display(常显示) 变量名 :**跟踪查看一个变量,每次程序停下来时都会显示它的值,便于持续观察变量在程序运行过程中的变化情况。
**- undisplay :**取消对先前设置跟踪的那些变量的跟踪,当我们不再需要关注某些变量时可使用。
**- until X行号 :**使程序执行到指定的 X 行,可快速跳过不需要逐行调试的代码区域。可调制指定行
**- breakrace(或bt) :**查看各级函数调用及参数,帮助我们梳理程序的函数调用栈,了解函数之间的调用关系和传递的参数情况。
**- info (i) locals :**查看当前栈帧局部变量的值,在调试函数内部逻辑时,可用于检查局部变量的状态。
gdb 功能丰富,指令众多,上述介绍的只是其常用指令集。熟练掌握这些指令,能够极大地提升我们在Linux环境下调试程序的效率,帮助我们更加从容地排查和解决程序中出现的各种问题。希望这篇博客能为大家在 gdb 的使用之路上提供有力的指引,让调试工作变得更加得心应手!