Menu Close
Red Hat Training
A Red Hat training course is available for RHEL 8
第 8 章 使用 GDB 检查应用程序 Internal State
要查找为什么应用程序无法正常工作,控制其执行,并使用 debugger 检查其内部状态。这部分论述了如何在这个任务中使用 GNU Debugger(GDB)。
8.1. GNU debugger(GDB)
Red Hat Enterprise Linux 包含 GNU debugger(GDB),它可让您通过命令行用户界面调查程序内发生的情况。
对于 GDB 的图形前端,安装 Eclipse 集成开发环境。请参阅 使用 Eclipse。
GDB 功能
单个 GDB 会话可以调试以下类型的程序:
- 多线程和请求程序
- 同时多个程序
-
通过 TCP/IP 网络连接在远程机器或带有
gdbserver
工具的容器上的程序
调试要求
要调试任何可执行代码,GDB 需要该特定代码的调试信息:
- 对于您开发的程序,您可以在构建代码时创建调试信息。
- 对于从软件包安装的系统程序,必须安装其 debuginfo 软件包。
8.2. 将 GDB 附加到进程
要检查进程,GDB 必须 附加 到该进程。
先决条件
使用 GDB 启动程序
当程序没有作为进程运行时,使用 GDB 启动它:
$ gdb program
使用到程序的文件名或路径替换 program。
GDB 设置至开始执行程序。在使用 run
命令开始执行进程前,您可以设置 breakpoints 和 gdb
环境。
将 GDB 附加到已在运行的进程中
将 GDB 附加到已作为一个进程运行的程序中:
使用
ps
命令查找进程 ID(pid):$ ps -C program -o pid h pid
使用到程序的文件名或路径替换 program。
将 GDB 附加到此过程中:
$ gdb -p pid
使用
ps
输出中的实际进程 ID 号替换 pid。
将已在运行的 GDB 附加到已在运行的进程中
将已在运行的 GDB 附加到已在运行的程序:
使用
shell
GDB 命令运行ps
命令并查找程序的进程 ID(pid):(gdb) shell ps -C program -o pid h pid
使用到程序的文件名或路径替换 program。
使用
attach
命令将 GDB 附加到程序:(gdb) attach pid
使用
ps
输出中的实际进程 ID 号替换 pid。
在某些情况下,GDB 可能无法找到对应的可执行文件。使用 file
命令指定路径:
(gdb) file path/to/program
其它资源
- 使用 GDB 进行调试 - 2.1 Invoking GDB
- 使用 GDB 进行调试 - 4.7 调试 Already-running 过程
8.3. 使用 GDB 通过程序代码步骤
当 GDB 调试程序 被附加到某个程序后,您可以使用一些命令来控制该程序的执行。
先决条件
您必须有可用的调试信息:
- 使用调试信息编译并构建该程序,或者
- 已安装相关的 debuginfo 软件包
- 必须将 GDB 附加到程序才能调试
逐步实现代码的 GDB 命令
r
(运行)-
开始程序的执行。如果
run
使用了任何参数来执行,则这些参数会像程序正常启动一样传递给可执行文件。用户通常在设置了 breakpoint 后发布这个命令。 start
-
开始执行程序,但在程序主功能开始时停止。如果
start
使用了任何参数来执行,则这些参数会像程序正常启动一样传递给可执行文件。
c
(持续)从当前状态继续执行程序。这个程序的执行将继续执行,直到以下条件之一被满足:
- 已达到断开点。
- 满足指定条件。
- 这个程序收到信号。
- 发生错误。
- 程序终止。
n
(next)从当前状态继续执行程序,直到达到当前源文件中的下行代码。这个程序的执行将继续执行,直到以下条件之一被满足:
- 已达到断开点。
- 满足指定条件。
- 这个程序收到信号。
- 发生错误。
- 程序终止。
s
(步骤)-
step
命令还停止在当前源文件中的每个连续代码行中执行。但是,如果执行当前在包含 函数调用的源行中停止, GDB 在输入功能调用(而不是执行它)后会停止执行。 until
位置- 继续执行操作,直到达到由 location 选项指定的代码位置。
fini
(finish)恢复程序的执行,并在从功能返回时停止执行。这个程序的执行将继续执行,直到以下条件之一被满足:
- 已达到断开点。
- 满足指定条件。
- 这个程序收到信号。
- 发生错误。
- 程序终止。
q
(quit)- 终止执行并退出 GDB。
其它资源
- 第 8.5 节 “使用 GDB 中断点停止在定义的代码位置执行”
- 使用 GDB 进行调试 - 4.2 启动您的程序
- 使用 GDB 进行调试 - 5.2 Continuing and Stepping
8.4. 使用 GDB 显示程序内部值
显示程序内部变量的值对于了解程序正在做什么非常重要。GDB 提供了多个可以用来检查内部变量的命令。本节描述了这些命令中最有用的:
p
(print)显示给定参数的值。通常,参数是任何复杂性的变量名称,从简单单值到结构。参数也可以是当前语言中有效的表达式,包括使用程序变量和库功能,或者正在测试的程序中定义的功能。
您可以使用
print
命令使用 pretty-printer Python 或 Guile 脚本扩展 GDB,以自定义显示数据结构(比如类、破坏)。bt
(backtrace)显示用于访问当前执行点的功能调用链,或者显示在执行被终止前使用的函数链。这对调查带有故障原因的严重错误(比如分段错误)非常有用。
在
backtrace
命令中添加full
选项也会显示本地变量。您可以使用
bt
和info frame
命令自定义显示数据时,使用 帧过滤器 Python 脚本扩展 GDB。术语 框架是 指与单一功能调用关联的数据。info
info
命令是一个通用命令,用于提供有关各种项目的信息。它使用一个选项来指定要描述的项目。-
info args
命令显示目前选择的框架功能调用的选项。 -
info locals
命令显示当前选择的帧中的本地变量。
对于可能的项目列表,请在 GDB 会话中运行
help info
命令:(gdb) help info
-
l
(list)-
显示程序停止的源代码中的行。这个命令仅在程序执行停止时才可用。虽然这个命令并不严格显示内部状态,
list
可帮助用户了解在程序执行的下一步中将会对内部状态进行哪些更改。
其它资源
- GDB Python API - Red Hat Developers Blog 条目
- 使用 GDB 进行调试 - 10.9 Pretty Printing
8.5. 使用 GDB 中断点停止在定义的代码位置执行
通常只调查少量代码。Breakpoints 是告诉 GDB 在代码的特定位置停止执行某个程序的一个标记。Breakpoints 与源代码行最常见关联。在这种情况下,放置一个 breakpoint 需要指定源文件和行号。
要 设置断开点,请执行以下操作:
指定源代码 文件 的名称以及该文件中的 行:
(gdb) br file:line
当 文件 不存在时,会使用当前执行点的源文件名称:
(gdb) br line
或者,使用函数名称将 breakpoint 放在它的启动中:
(gdb) br function_name
在某个任务的某些迭代后,某个程序可能会遇到错误。指定要停止 执行的额外条件:
(gdb) br file:line if condition
使用 C 或 C++ 语言的条件替换 condition。文件 和 行 的含义与以上相同。
检查 所有 breakpoints 和 watchpoint 的状态:
(gdb) info br
使用
info br
输出中显示的 数字 来 删除 中断点:(gdb) delete number
删除 给定位置的 breakpoint:
(gdb) clear file:line
其它资源
- 使用 GDB 调试 — 5.1 Breakpoints, Watchpoints, and Catchpoints
8.6. 使用 GDB 监视点在数据访问和更改时停止执行
在很多情况下,让程序执行直到某些数据更改或被访问为止。本节列出了最常见的用例。
先决条件
- 了解 GDB
在 GDB 中使用监视点
Watchpoints 是告诉 GDB 停止执行某个程序的标记。Watchpoints 与 data 关联:放置一个监视点需要指定描述变量、多个变量或内存地址的表达式。
要 放置 用于数据 更改的监视点 (写):
(gdb) watch expression
使用描述要监视的 表达式 替换 expression。对于变量, 表达式 等于变量名称。
为 数据 访问设置监视点 (读取):
(gdb) rwatch expression
为 任何 数据访问(读写) 放置 一个监视点:
(gdb) awatch expression
检查 所有监视点和 breakpoint 的状态:
(gdb) info br
删除监视 点:
(gdb) delete num
使用
info br
命令报告的数量替换 num 选项。
其它资源
- 使用 GDB 进行调试 - 5.1.2 Setting Watchpoints
8.7. 使用 GDB 调试或线程程序
有些程序使用 forking 或线程来实现并行代码执行。调试多个同步执行路径需要特殊考虑。
先决条件
- 您必须了解调用和线程的概念。
使用 GDB 调试已分叉的程序
当某个程序(父)生成其自身(子)的独立副本时, Forking 是一种情况。使用以下设置和命令来影响 GDB 在 fork 发生时的作用:
follow-fork-mode
设置控制 GDB 是否跟随分叉后的父对象或子级。set follow-fork-mode parent
- 在 fork 后,调试父进程。这是默认值。
set follow-fork-mode child
- 在 fork 后,调试子进程。
show follow-fork-mode
-
显示
follow-fork-mode
的当前设置。
set detach-on-fork
设置控制 GDB 是否对另一个进程(未遵循)进行控制或将其保留运行。set detach-on-fork on
-
未遵循的进程(取决于
follow-fork-mode
的值)会被分离并独立运行。这是默认值。 set detach-on-fork off
-
GDB 保持对两个进程的控制。接下来的进程(取决于
follow-fork-mode
的值)像通常一样调试,另一个会被挂起。 show detach-on-fork
-
显示
detach-on-fork
的当前设置。
使用 GDB 调试 Threaded Programs
GDB 能够调试独立的线程,并可以独立操作和检查它们。要使 GDB 只停止检查的线程,请使用命令 set non-stop on
和 set target-async on
。您可以将这些命令添加到 .gdbinit
文件中。启用该功能后,GDB 就可以进行线程调试。
GDB 使用 当前线程的概念。默认情况下,命令只应用到当前的线程。
info threads
-
使用
id
和gid
号显示线程列表,显示当前的线程。 thread id
-
使用指定的
id
将线程设置为当前的线程。 thread apply ids command
-
将
command
命令应用到ids
列出的所有线程。ids
选项是一个以空格分开的线程 ID 列表。特殊值all
会将命令应用到所有线程。 break location thread id if condition
-
在特定
location
的condition
中设置一个 breakpoint,它只针对线程数id
。 watch expression thread id
-
仅为线程数
id
设置expression
定义的监视点。 command&
-
执行命令
command
并立即返回到 gdb 提示符(gdb)
,在后台继续任何代码执行。 interrupt
- 在后台停止执行。
其它资源
- 使用 GDB 进行调试 - 4.10 Debugging Programs 使用多 Threads
- 使用 GDB 进行调试 - 4.11 调试 Fork