GDB(GNU Debugger)是Linux环境下一款强大的命令行调试工具,由GNU项目提供,用于帮助开发者诊断和修复程序中的错误。它支持多种编程语言,包括C、C++、Fortran、Pascal以及其他使用GNU编译器集合(GCC)编译的语言。GDB提供了丰富的功能,如设置断点、单步执行代码、查看和修改变量值、查看调用堆栈、分析内存、执行程序直到特定条件满足等,这些都是软件开发和调试过程中不可或缺的工具。

如何使用GDB进行调试程序:准备程序编译程序时加入调试信息:使用gcc或g++编译时,需要添加-g选项,以便在可执行文件中包含调试信息。例如:

代码语言:javascript复制gcc -g my_program.c -o my_program启动GDB启动GDB:在命令行中输入gdb后跟你的程序名来启动GDB并加载程序。

代码语言:javascript复制gdb my_program基本命令运行程序:在GDB提示符下,输入run或r来运行程序。

代码语言:javascript复制(gdb) run设置断点:可以使用break命令(简写为b)在特定的函数名或代码行设置断点。

代码语言:javascript复制(gdb) break main # 在main函数开始处设置断点

(gdb) break 42 # 在第42行设置断点单步执行:使用step(简写为s)命令逐行执行代码,进入函数内部;使用next(简写为n)命令跳过函数内部,直接执行到下一行。

代码语言:javascript复制(gdb) step

(gdb) next查看变量值:使用print(简写为p)命令查看变量或表达式的值。

代码语言:javascript复制(gdb) print variable_name继续执行至下一个断点:当程序在某个断点暂停时,使用continue(简写为c)命令继续执行,直到遇到下一个断点。

代码语言:javascript复制(gdb) continue查看调用堆栈:使用backtrace(简写为bt)查看当前的函数调用堆栈。

代码语言:javascript复制(gdb) backtrace退出GDB:输入quit(简写为q)退出GDB。

代码语言:javascript复制(gdb) quit进阶使用条件断点:可以在设置断点时指定条件,例如,break if condition会在condition为真的时候才触发断点。查看内存和寄存器:使用x命令查看内存内容,info registers查看CPU寄存器状态。修改变量值:使用set variable variable_name = value命令修改变量值。脚本和自动化:GDB支持编写脚本来自动化调试任务,可以使用source命令执行脚本文件。GDB是一个功能丰富且高度可配置的工具,熟练掌握它对于提高程序调试效率至关重要。由于它是一个命令行工具,初学者可能需要一段时间来熟悉各种命令,但一旦掌握,会发现它在复杂调试场景中的强大和灵活性。

编译Debug版本程序若要调试程序,编译程序的时候必须带上-g调试选项,让程序附带debug信息

代码语言:javascript复制$gcc -g xxx.c -o a.out

$g++ -g xxx.cpp -o a.out启动调试程序GDB启动参数

简写

解释

-quiet

-q

不打印GDB的介绍信息和版权信息

-symbols=

-s

指定被调试程序的符号表文件

-exec=

-e

指定被调试程序的名称

-se=

读取符号表的文件和可执行文件

-core=

-c

使用文件作为一个coredump文件来测试

-directory=

-d

指定被调试程序的源文件搜索路径。默认搜索路径是环境变量PATH

-cd=

指定工作目录,默认为当前目录

–args

若被调试程序后面携带参数,需要加上–args

这里以调试a.out程序为例子(a.out 为附带debug信息的可执行程序)

启动调试程序

代码语言:javascript复制$gdb a.out当不需要查看gdb版本信息时,可以使用-q参数取消打印gdb版本信息

代码语言:javascript复制$gdb -q a.out当要调试的程序带有参数时,需要使用–args选项启动可执行程序,并且在可执行程序后边加上参数

代码语言:javascript复制$gdb --args a.out 100 200常用调试命令调试过程控制命令

简写

解释

(gdb) run

r

运行程序,会自动在第一个断点处暂停执行

(gdb) start

运行程序,单步执行,停在第一执行语句

(gdb) next

n

单步调试,直接执行不会进入函数,类似于Step Over

(gdb) step

s

单步调试,若遇到函数会进入内部,类似于Step Into

(gdb) finish

fi

单步调试,执行完函数并跳出函数,类似于Step Out

(gdb) until

u

使程序运行至第line_number行处暂停,类似于Run To Cursor

(gdb) continue

c

继续运行,直至遇到断点或者程序结束

(gdb) quit

q

终止调试

调试断点设置调试断点命令

简写

解释

(gdb) info break [n]

info b [n]

显示当前程序的断点,其中n为可选的断点编号

(gdb) break

b

添加断点,line_number为源代码的行号

(gdb) clear

删除断点,line_number为源代码的行号

(gdb) delete

删除断点,n为断点的编号

(gdb) delete breakpoints

删除所有断点

(gdb) enable

启用断点,n为断点的编号

(gdb) disable

暂停断点,n为断点的编号

调试源码查看查看源码命令

简写

解释

(gdb) list

l

列出程序源码,默认每次显示10行

(gdb) list

列出程序源码,以line_number行为中心显示前后10行代码

(gdb) list

将显示“func_name”函数的源代码

运行时信息查看打印信息

简写

解释

(gdb) print <表达式>

p

输出表达式的值,“表达式”可以是任何数字、变量、函数调用等

(gdb) display <表达式>

显示表达式的值,单步调试时每次执行都会输出显示

(gdb) watch <表达式>

设置监视点,当表达式的值发生变化会强行终止正在被调试的程序

(gdb) whatis <表达式>

查看表达式的类型定义

(gdb) backtrace

bt

显示当前调用堆栈

多线程调试方法命令

解释

(gdb) info threads

查看当前进程的所有线程运行情况

(gdb) thread

切换到具体id编号的线程上去

(gdb) thread apply

让一个或者多个线程执行GDB命令CMD

(gdb) thread apply all

让所有被调试线程执行GDB命令CMD

以下是多线程中断点的设置方法

(gdb) break thread

在某个文件的line_number行添加断点,只作用于ID指定的线程

(gdb) break thread all

在某个文件的line_number行添加断点,作用于所有的线程

分割窗口设置分割窗口

解释

(gdb) layout src

显示源代码窗口

(gdb) layout asm

显示反汇编窗口

(gdb) layout regs

显示源代码/反汇编和CPU寄存器窗口

(gdb) layout split

显示源代码和反汇编窗口

Ctrl + L

刷新窗口显示

Linux下常用的调试场景在Linux下执行可执行程序时经常会打印Segmentation fault(段错误),当遇到这种情况时,我们可以通过查看程序执行时的堆栈信息定位程序出错的大体位置信息,以方便我们查找问题。

例如执行a.out 时,出现这种情况

代码语言:javascript复制$a.out 100 200

Segmentation fault使用如下命令启动调试程序

代码语言:javascript复制$gdb -q --args a.out 100 200 #启动调试程序

(gdb)r #run 运行程序

... #这里会打印程序执行异常

(gdb)bt #backtrace 打印程序堆栈信息

··· #此时会打印程序的调用堆栈,通过查看堆栈可以得知在调用那个函数时发生崩溃你

(gdb)q #退出调试程序