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

  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

其它资源

8.3. 使用 GDB 通过程序代码步骤

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

先决条件

逐步实现代码的 GDB 命令

r (运行)
开始程序的执行。如果 run 使用了任何参数来执行,则这些参数会像程序正常启动一样传递给可执行文件。用户通常在设置了 breakpoint 后发布这个命令。
start
开始执行程序,但在程序主功能开始时停止。如果 start 使用了任何参数来执行,则这些参数会像程序正常启动一样传递给可执行文件。
c (持续)

从当前状态继续执行程序。这个程序的执行将继续执行,直到以下条件之一被满足:

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

从当前状态继续执行程序,直到达到当前源文件中的下行代码。这个程序的执行将继续执行,直到以下条件之一被满足:

  • 已达到断开点。
  • 满足指定条件。
  • 这个程序收到信号。
  • 发生错误。
  • 程序终止。
s (步骤)
step 命令还停止在当前源文件中的每个连续代码行中执行。但是,如果执行当前在包含 函数调用的源行中停止, GDB 在输入功能调用(而不是执行它)后会停止执行。
until 位置
继续执行操作,直到达到由 location 选项指定的代码位置。
fini (finish)

恢复程序的执行,并在从功能返回时停止执行。这个程序的执行将继续执行,直到以下条件之一被满足:

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

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

显示程序内部变量的值对于了解程序正在做什么非常重要。GDB 提供了多个可以用来检查内部变量的命令。本节描述了这些命令中最有用的:

p (print)

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

您可以使用 print 命令使用 pretty-printer Python 或 Guile 脚本扩展 GDB,以自定义显示数据结构(比如类、破坏)。

bt (backtrace)

显示用于访问当前执行点的功能调用链,或者显示在执行被终止前使用的函数链。这对调查带有故障原因的严重错误(比如分段错误)非常有用。

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

您可以使用 btinfo frame 命令自定义显示数据时,使用 帧过滤器 Python 脚本扩展 GDB。术语 框架是 指与单一功能调用关联的数据。

info

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

  • info args 命令显示目前选择的框架功能调用的选项。
  • info locals 命令显示当前选择的帧中的本地变量。

对于可能的项目列表,请在 GDB 会话中运行 help info 命令:

(gdb) help info
l (list)
显示程序停止的源代码中的行。这个命令仅在程序执行停止时才可用。虽然这个命令并不严格显示内部状态, list 可帮助用户了解在程序执行的下一步中将会对内部状态进行哪些更改。

其它资源

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

其它资源

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 选项。

其它资源

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

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

info threads
使用 idgid 号显示线程列表,显示当前的线程。
thread id
使用指定的 id 将线程设置为当前的线程。
thread apply ids command
command 命令应用到 ids 列出的所有线程。ids 选项是一个以空格分开的线程 ID 列表。特殊值 all 会将命令应用到所有线程。
break location thread id if condition
在特定 locationcondition 中设置一个 breakpoint,它只针对线程数 id
watch expression thread id
仅为线程数 id 设置 expression 定义的监视点。
command&
执行命令 command 并立即返回到 gdb 提示符 (gdb),在后台继续任何代码执行。
interrupt
在后台停止执行。

其它资源