3.2. 使用 GDB 检查应用程序内部状态
要找出应用不能正常工作的原因,请控制其执行并使用调试器检查其内部状态。本节描述了如何对此任务使用 GNU Debugger(GDB)。
3.2.1. GNU 调试器(GDB) 复制链接链接已复制到粘贴板!
Red Hat Enterprise Linux 包含 GNU 调试器(GDB),允许您通过命令行用户界面调查程序内部发生了什么情况。
对于 GDB 的图形前端,请安装 Eclipse 集成开发环境。请参阅使用 Eclipse。
- GDB 功能
单个 GDB 会话可以调试以下类型的程序:
- 多线程和分叉程序
- 同时有多个程序
-
远程机器上或带有
gdbserver
工具的容器中的程序通过 TCP/IP 网络连接
- 调试要求
要调试任何可执行代码,GDB 需要该特定代码的调试信息:
- 对于由您开发的程序,您可以在构建代码时创建调试信息。
- 对于从软件包安装的系统程序,您必须安装它们的 debuginfo 软件包。
3.2.2. 将 GDB 附加到进程 复制链接链接已复制到粘贴板!
为了检查进程,必须将 GDB 附加到 进程。
先决条件
流程
使用 GDB 启动程序。
使用 GDB 启动程序:
gdb program
$ gdb program
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 使用程序的文件名或路径替换 program。
设置 GDB 以开始程序的执行。您可以使用
run
命令在开始执行进程前设置断点和gdb
环境。- 将 GDB 附加到已运行的进程。
使用
ps
命令找到进程 ID(pid):ps -C program -o pid h
$ ps -C program -o pid h pid
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 使用程序的文件名或路径替换 program。
将 GDB 附加到此进程:
gdb -p pid
$ gdb -p pid
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 使用
ps
输出中的实际进程 ID 号替换 pid 。
将活跃的 GDB 会话附加到运行的程序:
使用
shell
GDB 命令运行ps
命令,并找到程序的进程 ID(pid):(gdb) shell ps -C program -o pid h pid
(gdb) shell ps -C program -o pid h pid
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 使用程序的文件名或路径替换 program。
使用
attach
命令将 GDB 附加到程序:(gdb) attach pid
(gdb) attach pid
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 使用
ps
输出中的实际进程 ID 号替换 pid。注意在某些情况下,GDB 可能无法找到对应的可执行文件。使用
file
命令指定路径:(gdb) file path/to/program
(gdb) file path/to/program
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
3.2.3. 使用 GDB 逐步浏览程序代码 复制链接链接已复制到粘贴板!
GDB 调试器附加到程序后,您可以使用一些命令来控制程序的执行。这些命令允许您在调试会话过程中逐步调试代码、设置断点和控制程序流。
要有效地使用这些 GDB 命令,您必须通过这些方法提供调试信息:* 程序使用调试信息编译并构建。 已安装相关的 debuginfo 软件包
GDB 提供了一组命令,用于逐步执行和控制程序执行:
r
(run):开始执行程序。如果使用任何参数执行 run
,则这些参数将被传给可执行文件,如同程序已正常启动了一样。用户通常在设置断点后发出此命令。
启动
:开始程序的执行,但会在程序的主功能的开头停止。如果使用任何参数执行 start
,则这些参数将被传给可执行文件,就像程序已正常启动了一样。
c
(continue):从当前状态继续程序的执行。程序的执行将继续,直到达到以下之一变为 true :代表达到一个断点。* 满足指定的条件。* 程序会收到信号。* 发生错误。* 程序终止。
n
(next):继续从当前状态执行程序,直到当前源文件中的下一行代码为止。程序的执行将继续,直到达到以下之一变为 true :代表达到一个断点。* 满足指定的条件。* 程序会收到信号。* 发生错误。* 程序终止。
s
( step
): step 命令还会在当前源文件中的每一行代码处停止执行。但是,如果执行当前在包含 function call 的源行处停止,则 GDB 会在输入 function call (而不是执行它)后停止执行。
until
location: 继续执行,直到达到 location 选项指定的代码位置。
fini
(finish):恢复程序的执行,并在执行从函数返回时停止。程序的执行将继续,直到达到以下之一变为 true :代表达到一个断点。* 满足指定的条件。* 程序会收到信号。* 发生错误。* 程序终止。
q
(quit):终止执行并退出 GDB。
3.2.4. 使用 GDB 显示程序内部值 复制链接链接已复制到粘贴板!
显示程序内部变量的值对于了解程序正在做什么非常重要。GDB 提供了多个您可用来检查内部变量的命令。以下是这些命令中最有用的命令:
p
(print)显示给定的参数的值。通常,参数是任何复杂程度的变量的名称,从简单的单个值到结构。参数也可以是在当前语言中一个有效的表达式,包括程序变量和库函数的使用,或者在测试的程序中定义的函数。
可以使用 pretty-printer Python 或 Guile 脚本来扩展 GDB, 以便使用
print
命令来自定义对数据结构(如类、结构)的显示。bt
(backtrace)显示用于到达当前执行点的函数调用链,或者显示在执行终止之前所使用的函数链。这对于调查原因不明的严重 bug(如分段错误)非常有用。
向
backtrace
命令中添加full
选项也会显示本地变量。可以使用 frame filter Python 脚本来扩展 GDB,以便使用
bt
和info frame
命令自定义显示的数据。术语 frame 指的是与单个函数调用关联的数据。info
info
命令是提供关于各种条目的信息一个通用命令。它使用指定要描述的条目的一个选项。-
info args
命令显示当前所选帧的函数调用的选项。 -
info locals
命令显示当前选定的帧中的局部变量。
如需可能的条目列表,请在 GDB 会话中运行命令
help info
:(gdb) help info
(gdb) help info
Copy to Clipboard Copied! Toggle word wrap Toggle overflow -
l
(list)- 显示程序源代码。当程序已启动,但当前已停止时,这个命令会列出当前停止的程序的源代码,以及几行上下文。在程序启动前,这将列出 main 函数。虽然严格来说命令不是用来显示内部状态,但 list 帮助用户了解在程序执行的下一步中将会对内部状态发生哪些更改。
3.2.5. 使用 GDB 断点在定义的代码位置停止执行 复制链接链接已复制到粘贴板!
通常,仅调查代码的一小部分。断点是标记,告知 GDB 在代码的特定位置停止程序的执行。断点通常与源代码行关联。在这种情况下,放置断点需要指定源文件和行号。
流程
要放置断点。
指定源代码 file 的名称以及在该文件中的 line :
(gdb) br file:line
(gdb) br file:line
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 如果 file 不存在,则使用当前执行点的源文件的名称:
(gdb) br line
(gdb) br line
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 或者,使用函数名称将断点放在其开始上:
(gdb) br function_name
(gdb) br function_name
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 在任务进行一定迭代后,程序可能会遇到错误。要指定额外的 condition 停止执行:
(gdb) br file:line if condition
(gdb) br file:line if condition
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 使用 C 或 C++ 语言条件替换 condition。file 和 line 如以上是相同的。
要 检查 所有断点和监控点的状态:
(gdb) info br
(gdb) info br
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 要使用
info br
的输出中显示的 number 删除 断点:(gdb) delete number
(gdb) delete number
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 要在给定位置 删除 断点:
(gdb) clear file:line
(gdb) clear file:line
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
3.2.6. 使用 GDB 观察点停止对数据访问和更改执行 复制链接链接已复制到粘贴板!
在很多情况下,让程序执行直到某些数据改变了或被访问是有好处的。Watchpoints 是标记,告诉 GDB 在满足特定数据条件时停止程序的执行。
流程
为数据更改放置一个观察点(写入):
(gdb) watch expression
(gdb) watch expression
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 使用描述您要监视的表达式替换 expression。对于变量,expression 等于变量的名称。
为数据访问(读取)放置一个观察点:
(gdb) rwatch expression
(gdb) rwatch expression
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 要针对任何数据访问(读取和写入)放置一个观察点:
(gdb) awatch expression
(gdb) awatch expression
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 检查所有观察点和断点的状态:
(gdb) info br
(gdb) info br
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 删除一个监视点:
(gdb) delete num
(gdb) delete num
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 将 num 选项替换为
info br
命令报告的编号。
3.2.7. 使用 GDB 调试 fork 或线程程序 复制链接链接已复制到粘贴板!
有些程序使用分叉或线程来实现并行代码执行。调试多个同时执行路径需要特殊考虑。
您必须了解进程分叉和线程的概念。
- 使用 GDB 调试 fork 程序
分叉是一种程序(父)创建自身(子)的一个独立副本的情况。使用以下设置和命令影响 GDB 在进行分叉时的作用:
follow-fork-mode
设置控制 GDB 在分叉后是否遵循父项或子项。设置 follow-fork-mode 父项
- 在分叉后,调试父进程。这是默认值。
设置 follow-fork-mode 子项
- 在分叉后,调试子进程。
显示后续模式
-
显示
follow-fork-mode
的当前设置。
set detach-on-fork
设置控制 GDB 是否控制其他进程(未跟随)进程,还是保留它继续运行。设置 detach-on-fork on
-
未遵循的进程(取决于
follow-fork-mode
值 )将独立分离并运行。这是默认值。 set detach-on-fork off
-
GDB 控制这两个进程。其后的进程(取决于
follow-fork-mode
的值)会正常进行调试,而另一个被暂停。 显示 detach-on-fork
-
显示
detach-on-fork
的当前设置。
- 使用 GDB 调试线程程序
-
GDB 能够调试各个线程,并且能够独立地操作和检查它们。要使 GDB 只停止检查的线程,请使用命令
set non-stop on
和set target-async on
您可以将这些命令添加到.gdbinit
文件中。在打开该功能后,GDB 已准备好进行线程调试。
GDB 使用 当前线程 的概念。默认情况下,命令仅应用到当前的线程。
info 线程
-
显示带有相应
id
和gid
的线程列表,代表当前的线程。 线程 ID
-
将指定
id
的线程设置为当前的线程。 线程应用 ids command
-
将
command
命令应用到ids
列出的所有线程。ids
选项是以空格分隔的线程 ID 列表。一个特殊值all
将命令应用到所有线程。 break location thread id if condition
-
只对线程号
id
在带有特定条件
的特定位置
设置一个断点。 watch expression thread id
-
仅为线程编号 ID
id
设置由expression
定义的观察点。 command&
-
执行
command
命令并立即返回到 gdb 提示符(gdb)
,然后在后台继续执行任何代码。 interrupt
- 在后台停止执行。
其他资源