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 附加到已作为进程运行的程序:

  1. 使用 ps 命令查找进程 id(pid):

    $ ps -C program -o pid h
     pid

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

  2. 将 GDB 附加到此过程:

    $ gdb program -p pid

    使用到 程序的 文件名或路径替换 program,将 pid 替换为 ps 输出中的实际进程 ID 号。

将 Already Running GDB 附加到 Already Running Process

将已在运行的 GDB 附加到已在运行的程序:

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

    (gdb) shell ps -C program -o pid h
     pid

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

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

    (gdb) attach pid

    pid 替换为 ps 输出中的实际进程 ID 号。

注意

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

(gdb) file path/to/program
其它资源

20.2.3. 使用 GDB 逐步处理程序代码

GDB 调试器附加到程序后,您可以使用多个命令来控制程序的执行。

先决条件
通过代码逐步进行 GDB 命令
r (run)
开始执行 程序。如果通过参数执行了 运行,这些参数将作为程序正常启动,传递到可执行文件。用户通常在设置断点后发出此命令。
开始
启动程序的执行过程,并在主要功能开始时停止。如果以参数 开头,则这些参数将被传递到可执行文件,就像程序正常启动一样。
c (续)

继续从当前状态执行 程序。程序的执行将继续,直到以下条件之一变为 true:

  • 到达断点
  • 满足指定条件
  • 程序收到信号
  • 发生错误
  • 程序终止
n (next)

此命令的另一个常见名称为 步骤。继续从当前状态执行程序,直到达到当前源文件中的下一行代码。程序的执行将继续,直到以下条件之一变为 true:

  • 到达断点
  • 满足指定条件
  • 程序收到信号
  • 发生错误
  • 程序终止
s (步骤)
这个命令的另一个常见名称为 步骤step 命令在当前源文件中每个连续代码行停止执行。但是,如果当前在包含 函数调用 的源行停止执行,GDB 会在输入函数调用后停止执行(而不是执行它)。
直到 位置
继续执行,直到达到位置选项指定的代码 位置
Fini (芬兰)

恢复执行程序,并在执行从函数返回时停止执行。程序的执行将继续,直到以下条件之一变为 true:

  • 到达断点
  • 满足指定条件
  • 程序收到信号
  • 发生错误
  • 程序终止
q (quit)
终止执行并退出 GDB。
其它资源

20.2.4. 使用 GDB 显示程序内部值

显示程序内部变量的值对于了解程序正在执行的操作非常重要。GDB 提供了多个命令,可用于检查内部变量。这部分论述了这些命令的最有用的信息。

先决条件
  • 了解 GDB 调试器
显示程序的内部状态的 GDB 命令
P (打印)

显示给定参数的值。通常,参数是任何复杂性的变量的名称,从简单的单个值到结构。参数也可以是在当前语言中有效的表达式,包括使用程序变量和库函数,或者正在测试的程序中定义的函数。

可以使用 print 命令对数据结构(如类、结构)进行自定义显示,使用设计器 Python 或 Guile 脚本来扩展 GDB。

BT (回溯)

显示用于到达当前执行点的函数调用链,或在执行被信号前使用的功能链。这对于调查带有困难原因的严重错误(如分段错误)非常有用。

backtrace 命令中添加 完整 选项也会显示本地变量。

可以使用 框架过滤 Python 脚本来扩展 GDB,以自定义使用 btinfo 帧 命令显示的数据。术语 指的是与单个函数调用关联的数据。

info

info 命令是一种通用命令,用于提供关于各种项目的信息。它取指定项目的选项。

  • info args 命令显示目前为所选帧的函数调用的参数。
  • info locals 命令在当前选定的帧中显示本地变量。

如需可能的项目列表,请在 GDB 会话中运行命令 帮助信息

(gdb) help info
l (列表)
显示程序停止的源代码中的 行。此命令仅在程序执行停止时才可用。虽然不能严格显示内部状态的命令,但 list 有助于用户了解程序的执行下一步中对内部状态的更改。
其它资源

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 线程
显示具有 idgid 号的线程列表,表示当前的线程。
线程 ID
将指定 id 设为当前线程的线程。
线程应用 ids 命令
将命令 应用到按 ID 列出的所有线程。 ids 选项是空格分隔的线程 ID 列表。特殊值 all 会将命令应用到所有线程。
如果 条件中断 位置 线程 id
特定位置 设置一个断点,且仅限于线程号 id特定条件
watch 表达式 线程 ID
设定仅由 表达式 定义的监视点,用于线程编号 ID
命令&
执行 命令,并立即返回到 GDB 提示符 (gdb),并在后台继续执行代码。
中断
在后台停止执行。
其它资源
Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

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

让开源更具包容性

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

關於紅帽

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

© 2024 Red Hat, Inc.