20.2. 使用 GDB 检查应用程序的内部状态
若要找出应用无法正常工作的原因,请控制其执行并使用调试器检查其内部状态。本节论述了如何将 GNU Debugger(GDB)用于此任务。
20.2.1. GNU Debugger(GDB)
debugger 是一个可以控制代码执行和检查代码状态的工具。这个功能用于调查程序中出现的情况以及原因。
Red Hat Enterprise Linux 包含 GNU debugger(GDB),它通过命令行用户界面提供此功能。
对于到 GDB 的图形 frontend,请安装 Eclipse 集成开发环境。请参阅使用 Eclipse。
GDB 能力
单个 GDB 会话可以调试:
- 多线程和分叉程序
- 一次多个程序
-
远程机器或带有
gdbserver
实用工具通过 TCP/IP 网络连接连接的容器中的程序
调试要求
要调试任何可执行代码,GDB 需要相应的调试信息:
- 对于由您开发的程序,您可以在构建代码时创建调试信息。
- 对于从软件包安装的系统程序,必须安装对应的 debuginfo 软件包。
20.2.2. 将 GDB 附加到进程
为了检查进程,必须将 GDB 附加到 进程。
先决条件
使用 GDB 启动程序
当该程序没有作为进程运行时,使用 GDB 启动它:
$ gdb program
使用文件名或程序路径替换 程序。
GDB 开始执行程序。您可以使用 run
命令开始执行进程,然后设置断点和 gdb
环境。
将 GDB 附加到 Already Running Process
将 GDB 附加到已作为进程运行的程序:
使用
ps
命令查找进程 id(pid):$ ps -C program -o pid h pid
使用文件名或程序路径替换 程序。
将 GDB 附加到此过程:
$ gdb program -p pid
使用到 程序的 文件名或路径替换 program,将 pid 替换为
ps
输出中的实际进程 ID 号。
将 Already Running GDB 附加到 Already Running Process
将已在运行的 GDB 附加到已在运行的程序:
使用
shell
GDB 命令运行ps
命令并查找程序的进程 id(pid):(gdb) shell ps -C program -o pid h pid
使用文件名或程序路径替换 程序。
使用
attach
命令将 GDB 附加到程序:(gdb) attach pid
将 pid 替换为
ps
输出中的实际进程 ID 号。
在某些情况下,GDB 可能无法找到对应的可执行文件。使用 file
命令指定路径:
(gdb) file path/to/program
其它资源
- 使用 GDB 进行调试 - 2.1 调用 GDB
- 使用 GDB 进行调试 - 4.7 调试 Already-running 进程
20.2.3. 使用 GDB 逐步处理程序代码
GDB 调试器附加到程序后,您可以使用多个命令来控制程序的执行。
先决条件
- 在系统中必须安装 GDB
您必须有所需的调试信息可用:
- 程序使用调试信息编译和构建,或者
- 已安装相关的 debuginfo 软件包
- GDB 已附加到要调试的程序
通过代码逐步进行 GDB 命令
r
(run)-
开始执行 程序。如果通过参数执行了
运行
,这些参数将作为程序正常启动,传递到可执行文件。用户通常在设置断点后发出此命令。 开始
-
启动程序的执行过程,并在主要功能开始时停止。如果以参数
开头
,则这些参数将被传递到可执行文件,就像程序正常启动一样。
c
(续)继续从当前状态执行 程序。程序的执行将继续,直到以下条件之一变为 true:
- 到达断点
- 满足指定条件
- 程序收到信号
- 发生错误
- 程序终止
n
(next)此命令的另一个常见名称为
步骤
。继续从当前状态执行程序,直到达到当前源文件中的下一行代码。程序的执行将继续,直到以下条件之一变为 true:- 到达断点
- 满足指定条件
- 程序收到信号
- 发生错误
- 程序终止
s
(步骤)-
这个命令的另一个常见名称为
步骤
。step
命令在当前源文件中每个连续代码行停止执行。但是,如果当前在包含 函数调用 的源行停止执行,GDB 会在输入函数调用后停止执行(而不是执行它)。 直到
位置- 继续执行,直到达到位置选项指定的代码 位置。
Fini
(芬兰)恢复执行程序,并在执行从函数返回时停止执行。程序的执行将继续,直到以下条件之一变为 true:
- 到达断点
- 满足指定条件
- 程序收到信号
- 发生错误
- 程序终止
q
(quit)- 终止执行并退出 GDB。
其它资源
- 第 20.2.5 节 “使用 GDB Breakpoints 在定义的代码位置停止执行”
- 使用 GDB 进行调试 - 4.2 启动您的程序
- 使用 GDB 进行调试 - 5.2 Continuing and Stepping
20.2.4. 使用 GDB 显示程序内部值
显示程序内部变量的值对于了解程序正在执行的操作非常重要。GDB 提供了多个命令,可用于检查内部变量。这部分论述了这些命令的最有用的信息。
先决条件
- 了解 GDB 调试器
显示程序的内部状态的 GDB 命令
P
(打印)显示给定参数的值。通常,参数是任何复杂性的变量的名称,从简单的单个值到结构。参数也可以是在当前语言中有效的表达式,包括使用程序变量和库函数,或者正在测试的程序中定义的函数。
可以使用
print
命令对数据结构(如类、结构)进行自定义显示,使用设计器 Python 或 Guile 脚本来扩展 GDB。BT
(回溯)显示用于到达当前执行点的函数调用链,或在执行被信号前使用的功能链。这对于调查带有困难原因的严重错误(如分段错误)非常有用。
在
backtrace
命令中添加完整
选项也会显示本地变量。可以使用 框架过滤 Python 脚本来扩展 GDB,以自定义使用
bt
和info 帧
命令显示的数据。术语 帧 指的是与单个函数调用关联的数据。info
info
命令是一种通用命令,用于提供关于各种项目的信息。它取指定项目的选项。-
info args
命令显示目前为所选帧的函数调用的参数。 -
info locals
命令在当前选定的帧中显示本地变量。
如需可能的项目列表,请在 GDB 会话中运行命令
帮助信息
:(gdb) help info
-
l
(列表)-
显示程序停止的源代码中的 行。此命令仅在程序执行停止时才可用。虽然不能严格显示内部状态的命令,但
list
有助于用户了解程序的执行下一步中对内部状态的更改。
其它资源
- Red Hat Developer 博客条目 - GDB Python API
- 使用 GDB 进行调试 - 10.9 Pretty Printing
20.2.5. 使用 GDB Breakpoints 在定义的代码位置停止执行
在很多情况下,让程序在达到某一行代码之前会执行非常有优势。
先决条件
- 了解 GDB
在 GDB 中使用 Breakpoints
breakpoints 是告知 GDB 停止执行程序的标记。断点最常与源代码行关联:放置断点需要指定源文件和行号。
放置断点 :
指定源代码 文件的名称以及该文件中 的行 :
(gdb) br file:line
如果文件不存在,则使用当前执行点的源文件的名称:
(gdb) br line
或者,使用函数名称来放置 breakpoint:
(gdb) br function_name
在任务发生多次迭代后,程序可能会遇到错误。指定暂停执行的额外 条件 :
(gdb) br file:line if condition
使用 C 或 C++ 语言中的条件替换 条件。文件 和 行 的含义与上方相同。
检查 所有断点和监控点的状态:
(gdb) info br
使用
info br
的输出中显示的 数量 来删除 断点:(gdb) delete number
在给定位置 删除 断点:
(gdb) clear file:line
20.2.6. 使用 GDB Watchpoints 在数据访问和更改时停止执行
在很多情况下,让程序执行直到访问某些数据或被访问为止。本节列出了最常见的监视点。
先决条件
- 了解 GDB
在 GDB 中使用 Watchpoints
Watchpoints 是指示 GDB 停止执行程序的标记。Watchpoints 与数据关联:放置监视点需要指定描述变量、多个变量或内存地址的表达式。
为数据 更改 放置 监视点(写入):
(gdb) watch expression
将 expression 替换为描述您要监视内容的表达式。对于变量,表达式 等于变量的名称。
为 数据访问 放置 监视点(读取):
(gdb) rwatch expression
为 任何 数据访问 放置 监视点(读写):
(gdb) awatch expression
检查 所有监视点和断点的状态:
(gdb) info br
删除 观察点:
(gdb) delete num
将 num 选项替换为
info br
命令报告的编号。
20.2.7. 使用 GDB 调试验证或线程程序
些程序使用分叉或线程来实现并行代码执行。调试多个同步执行路径需要特殊考虑。
先决条件
- 了解 GDB 调试器
- 了解进程分叉和线程的概念
使用 GDB 调试已验证程序
Forking 是程序(父级)创建自身(子级)的独立副本的情况。使用以下设置和命令将 GDB 的反应影响到发生 fork 的修改:
following
-fork-mode 设置控制 GDB 是否紧跟
父项还是分叉后面的子级。设置 follow-fork-mode parent
- 在分叉后,调试父进程。这是默认值。
设置 follow-fork-mode child
- 在分叉后,调试子进程。
显示 follow-fork-mode
-
显示以下
fork-mode
的当前设置。
set detach-on-fork
设置控制 GDB 是否保持对其他(未跟随)进程的控制,或使其保持运行。设置 detach-on-fork on
-
不后的进程(取决于后续模式的值)将分离并运行。
这是默认值。
设置 detach-on-fork off
-
GDB 保持对这两个进程的控制。随后的进程(取决于
follow-fork-mode
的值)像往常一样被调试,而另一个则暂停。 显示 detach-on-fork
-
显示
detach-on-fork
的当前设置。
使用 GDB 调试线程程序
GDB 能够调试各个线程,并且能够独立操作和检查它们。要使 GDB 仅停止检查的线程,请使用命令 设置不停止并在其
上设置 target-async。
您可以将这些命令添加到 .gdbinit
文件。启用该功能后,GDB 已准备好执行线程调试。
GDB 使用 当前线程 的概念。默认情况下,命令仅应用于当前线程。
info 线程
-
显示具有
id
和gid
号的线程列表,表示当前的线程。 线程 ID
-
将指定
id
设为当前线程的线程。 线程应用 ids 命令
-
将命令 应用到按
ID
列出的所有线程。ids
选项是空格分隔的线程 ID 列表。特殊值all
会将命令应用到所有线程。 如果 条件中断 位置 线程 id
-
在
特定位置
设置一个断点,且仅限于线程号id
的特定条件
。 watch 表达式 线程 ID
-
设定仅由
表达式
定义的监视点,用于线程编号ID
。 命令&
-
执行
命令
,并立即返回到 GDB 提示符(gdb)
,并在后台继续执行代码。 中断
- 在后台停止执行。
其它资源
- 使用 GDB 进行 调试 - 使用多个线程调试程序 4.10
- 使用 GDB 进行调试 - 4.11 Debugging Forks