搜索

3.2. 使用 GDB 检查应用程序内部状态

download PDF

要找出应用不能正常工作的原因,请控制其执行并使用调试器检查其内部状态。本节描述了如何对此任务使用 GNU Debugger(GDB)。

3.2.1. GNU 调试器(GDB)

Red Hat Enterprise Linux 包含 GNU 调试器(GDB),允许您通过命令行用户界面调查程序内部发生了什么情况。

GDB 功能

单个 GDB 会话可以调试以下类型的程序:

  • 多线程和分叉程序
  • 同时有多个程序
  • 远程机器上或带有 gdbserver 工具的容器中的程序通过 TCP/IP 网络连接

调试要求

要调试任何可执行代码,GDB 需要该特定代码的调试信息:

  • 对于由您开发的程序,您可以在构建代码时创建调试信息。
  • 对于从软件包安装的系统程序,您必须安装它们的 debuginfo 软件包。

3.2.2. 将 GDB 附加到进程

为了检查进程,必须将 GDB 附加到 进程。

使用 GDB 启动程序

当该程序没有作为进程运行时,使用 GDB 启动它:

$ gdb program

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

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

将 GDB 附加到已在运行的进程

要将 GDB 附加到已作为进程运行的程序:

  1. 使用 ps 命令找到进程 ID(pid):

    $ ps -C program -o pid h
     pid

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

  2. 将 GDB 附加到此进程:

    $ gdb -p pid

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

将已在运行的 GDB 附加到已在运行的进程

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

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

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

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

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

    (gdb) attach pid

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

注意

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

(gdb) file path/to/program

其他资源

3.2.3. 使用 GDB 逐步浏览程序代码

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

先决条件

单步调试代码的 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
l (list)
显示源代码中程序停止的行。此命令仅在程序执行停止时才可用。虽然严格来说不是用来显示内部状态的命令,但 list 帮助用户了解在程序执行的下一步中内部状态将发生哪些变化。

其他资源

3.2.5. 使用 GDB 断点在定义的代码位置停止执行

通常,仅调查代码的一小部分。断点是标记,告知 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 的输出中显示的 number 删除 断点:

    (gdb) delete number
  • 要在给定位置 删除 断点:

    (gdb) clear file:line

其他资源

3.2.6. 使用 GDB 监视点停止在数据访问和更改时执行

在很多情况下,让程序执行直到某些数据改变了或被访问是有好处的。以下示例是最常见的用例。

先决条件

  • 了解 GDB

在 GDB 中使用观察点

Watchpoints 是指示 GDB 停止执行程序的标记。Watchpoints 与数据相关联:放置观察点需要指定描述变量、多个变量或内存地址的表达式。

  • 为数据 更改 放置 监视点(写入):

    (gdb) watch expression

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

  • 数据访问 放置 监视点(读取):

    (gdb) rwatch expression
  • 任何 数据访问 放置 监视点(读写):

    (gdb) awatch expression
  • 检查 所有监视点和断点的状态:

    (gdb) info br
  • 删除 观察点:

    (gdb) delete num

    num 选项替换为 info br 命令报告的编号。

其他资源

3.2.7. 使用 GDB 调试或线程程序

些程序使用分叉或线程来实现并行代码执行。调试多个同步执行路径需要特殊考虑。

先决条件

  • 您必须了解进程分叉和线程的概念。

使用 GDB 调试程序

分叉是一种程序()创建自身()的一个独立副本的情况。使用以下设置和命令来影响 GDB 在发生分叉时执行的操作:

  • following -fork-mode 设置控制 GDB 是否紧跟 父项还是分叉后面的子级。

    设置 follow-fork-mode parent
    分叉后,调试父进程。这是默认值。
    设置 follow-fork-mode child
    分叉后,调试子进程。
    显示 follow-fork-mode
    显示 follow-fork-mode 的当前设置。
  • set detach-on-fork 设置控制 GDB 是否保持对其他(未跟随)进程的控制,或使其保持运行。

    设置 detach-on-fork on
    不遵循的进程(取决于 follow-fork-mode 的值)将被分离并独立运行。这是默认值。
    设置 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 命令
命令 应用到 ids 列出的所有线程。ids 选项是空格分隔的线程 ID 列表。一个特殊值 all 将命令应用到所有线程。
如果 条件中断 位置 线程 id
在特定位置设置断点,并且仅针对线程编号 ID 具有 特定条件
watch 表达式 线程 ID
设置仅用于线程编号 ID表达式 定义的观察点。
命令&
执行命令 并立即返回到 gdb 提示符 (gdb),在后台继续执行任何代码。
中断
在后台暂停执行。

其他资源

Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

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

让开源更具包容性

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

關於紅帽

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

© 2024 Red Hat, Inc.