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 启动程序。

    1. 使用 GDB 启动程序:

      $ gdb program
      Copy to Clipboard Toggle word wrap

      使用程序的文件名或路径替换 program

      设置 GDB 以开始程序的执行。您可以使用 run 命令在开始执行进程前设置断点和 gdb 环境。

    2. 将 GDB 附加到已运行的进程。
    3. 使用 ps 命令找到进程 ID(pid):

      $ ps -C program -o pid h
       pid
      Copy to Clipboard Toggle word wrap

      使用程序的文件名或路径替换 program

    4. 将 GDB 附加到此进程:

      $ gdb -p pid
      Copy to Clipboard Toggle word wrap

      使用 ps 输出中的实际进程 ID 号替换 pid

  • 将活跃的 GDB 会话附加到运行的程序:

    1. 使用 shell GDB 命令运行 ps 命令,并找到程序的进程 ID(pid):

      (gdb) shell ps -C program -o pid h
       pid
      Copy to Clipboard Toggle word wrap

      使用程序的文件名或路径替换 program

    2. 使用 attach 命令将 GDB 附加到程序:

      (gdb) attach pid
      Copy to Clipboard Toggle word wrap

      使用 ps 输出中的实际进程 ID 号替换 pid

      注意

      在某些情况下,GDB 可能无法找到对应的可执行文件。使用 file 命令指定路径:

      (gdb) file path/to/program
      Copy to Clipboard Toggle word wrap

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,以便使用 btinfo frame 命令自定义显示的数据。术语 frame 指的是与单个函数调用关联的数据。

info

info 命令是提供关于各种条目的信息一个通用命令。它使用指定要描述的条目的一个选项。

  • info args 命令显示当前所选帧的函数调用的选项。
  • info locals 命令显示当前选定的帧中的局部变量。

如需可能的条目列表,请在 GDB 会话中运行命令 help info

(gdb) help info
Copy to Clipboard Toggle word wrap
l (list)
显示程序源代码。当程序已启动,但当前已停止时,这个命令会列出当前停止的程序的源代码,以及几行上下文。在程序启动前,这将列出 main 函数。虽然严格来说命令不是用来显示内部状态,但 list 帮助用户了解在程序执行的下一步中将会对内部状态发生哪些更改。

通常,仅调查代码的一小部分。断点是标记,告知 GDB 在代码的特定位置停止程序的执行。断点通常与源代码行关联。在这种情况下,放置断点需要指定源文件和行号。

流程

  • 要放置断点

    1. 指定源代码 file 的名称以及在该文件中的 line

      (gdb) br file:line
      Copy to Clipboard Toggle word wrap
    2. 如果 file 不存在,则使用当前执行点的源文件的名称:

      (gdb) br line
      Copy to Clipboard Toggle word wrap
    3. 或者,使用函数名称将断点放在其开始上:

      (gdb) br function_name
      Copy to Clipboard Toggle word wrap
    4. 在任务进行一定迭代后,程序可能会遇到错误。要指定额外的 condition 停止执行:

      (gdb) br file:line if condition
      Copy to Clipboard Toggle word wrap

      使用 C 或 C++ 语言条件替换 conditionfileline 如以上是相同的。

  • 检查 所有断点和监控点的状态:

    (gdb) info br
    Copy to Clipboard Toggle word wrap
  • 要使用 info br 的输出中显示的 number 删除 断点:

    (gdb) delete number
    Copy to Clipboard Toggle word wrap
  • 要在给定位置 删除 断点:

    (gdb) clear file:line
    Copy to Clipboard Toggle word wrap

在很多情况下,让程序执行直到某些数据改变了或被访问是有好处的。Watchpoints 是标记,告诉 GDB 在满足特定数据条件时停止程序的执行。

流程

  • 为数据更改放置一个观察点(写入):

    (gdb) watch expression
    Copy to Clipboard Toggle word wrap

    使用描述您要监视的表达式替换 expression。对于变量,expression 等于变量的名称。

  • 为数据访问(读取)放置一个观察点:

    (gdb) rwatch expression
    Copy to Clipboard Toggle word wrap
  • 要针对任何数据访问(读取和写入)放置一个观察点:

    (gdb) awatch expression
    Copy to Clipboard Toggle word wrap
  • 检查所有观察点和断点的状态:

    (gdb) info br
    Copy to Clipboard Toggle word wrap
  • 删除一个监视点:

    (gdb) delete num
    Copy to Clipboard Toggle word wrap

    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 onset target-async on您可以将这些命令添加到 .gdbinit 文件中。在打开该功能后,GDB 已准备好进行线程调试。

GDB 使用 当前线程 的概念。默认情况下,命令仅应用到当前的线程。

info 线程
显示带有相应 idgid 的线程列表,代表当前的线程。
线程 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
在后台停止执行。
返回顶部
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。 了解我们当前的更新.

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

Theme

© 2025 Red Hat