Red Hat Training

A Red Hat training course is available for RHEL 8

第 3 章 调试应用程序

调试应用程序是一个非常广泛的话题。本节为开发人员提供了在各种情况下进行调试的最通用的技术。

3.1. 启用带有调试信息的调试

要调试应用和库,需要调试信息。以下章节描述了如何获取此信息。

3.1.1. 调试信息

在调试任何可执行代码时,两种类型的信息允许程序员通过工具和扩展来理解二进制代码:

  • 源代码文本
  • 源代码文本如何与二进制代码相关的描述

此类信息称为调试信息。

Red Hat Enterprise Linux 对可执行二进制文件、共享库或 debuginfo 文件使用 ELF 格式。在这些 ELF 文件中,DWARF 格式用于保存调试信息。

要显示存储在 ELF 文件中的 DWARF 信息,请运行 readelf -w file 命令。

重要

STABS 是一种较旧、功能较弱的格式,有时与 UNIX 一起使用。红帽不鼓励使用它。GCC 和 GDB 仅在尽最大努力的基础上提供 STABS 生产和消费。一些其他工具,如 Valgrind 和 elfutils ,不适用于 STABS。

其他资源

3.1.2. 使用 GCC 启用 C 和 C++ 应用程序的调试

由于调试信息较大,因此默认情况下,不会包含在可执行文件中。要用它启用 C 和 C++ 应用程序的调试,您必须明确指示编译器创建它。

要在编译和链接代码时使用 GCC 启用调试信息的创建,请使用 -g 选项:

$ gcc ... -g ...
  • 由编译器和链接器执行的优化可能会产生难以与原始源代码相关的可执行代码:变量可能被优化、循环被展开、操作被合并到周围操作中,等等。这会对调试产生负面影响。为提高调试体验,请考虑使用 -Og 选项设置优化。但是,更改优化级别会更改可执行代码,并可能会改变实际d 行为,包括删除一些 bug。
  • 要在调试信息中也包含宏定义,请使用 -g3 选项,而不是 -g 选项。
  • -fcompare-debug GCC 选项测试使用带有调试信息的 GCC 编译的代码,而无需调试信息。如果生成的两个二进制文件相同,则测试通过。此测试确保可执行代码没有受到任何调试选项的影响,这进一步确保调试代码中没有隐藏的 bug。请注意,使用 -fcompare-debug 选项会显著增加编译时间。有关这个选项的详情,请查看 GCC 手册页。

其他资源

3.1.3. debuginfo 和 debugsource 软件包

debuginfodebugsource 软件包包含程序和库的调试信息和调试源代码。对于安装在 Red Hat Enterprise Linux 存储库的软件包中的应用程序和库,您可以从其它渠道获得单独的debuginfodebugsource 软件包。

调试信息软件包类型

有两种类型的软件包可用于调试:

debuginfo 软件包
debuginfo 软件包提供为二进制代码功能提供的人类可读名称所需的调试信息。这些软件包包含 .debug 文件,其中包含 DWARF 调试信息。这些文件被安装到 /usr/lib/debug 目录中。
Debugsource 软件包
debugsource 软件包包含用于编译二进制代码的源文件。分别安装了 debuginfodebugsource 软件包后,GDB 或 LLDB 等调试程序可以将二进制代码的执行与源代码相关联。源代码文件被安装到 /usr/src/debug 目录中。

与 RHEL 7 的不同

在Red Hat Enterprise Linux 7 中,debuginfo 软件包包含这两种类型的信息。Red Hat Enterprise Linux 8 将调试信息所需的源代码数据从 debuginfo 软件包分割为单独的 debugsource 软件包。

软件包名称

debuginfodebugsource 软件包提只对具有相同名称、版本、发行和架构的二进制软件包供有效的调试信息:

  • 二进制软件包:packagename-version-release.architecture.rpm
  • debuginfo 软件包: packagename-debuginfo-version-release.architecture.rpm
  • Debugsource 软件包: packagename-debugsource-version-release.architecture.rpm

3.1.4. 使用 GDB 获取应用程序或库的 debuginfo 软件包

需要调试信息来调试代码。对于从软件包安装的代码,GNU Debugger(GDB)自动识别缺少的调试信息,解析软件包名称并提供有关如何获取软件包的具体建议。

先决条件

流程

  1. 启动连接到要调试的应用程序或库的 GDB。GDB 自动识别缺少的调试信息,并建议要运行的命令。

    $ gdb -q /bin/ls
    Reading symbols from /bin/ls...Reading symbols from .gnu_debugdata for /usr/bin/ls...(no debugging symbols found)...done.
    (no debugging symbols found)...done.
    Missing separate debuginfos, use: dnf debuginfo-install coreutils-8.30-6.el8.x86_64
    (gdb)
  2. 退出 GDB:输入 q 并使用 Enter 进行确认。

    (gdb) q
  3. 运行 GDB 建议的命令来安装所需的 debuginfo 软件包:

    # dnf debuginfo-install coreutils-8.30-6.el8.x86_64

    dnf 软件包管理工具提供更改摘要、要求确认,并在确认后,下载并安装所有必需的文件。

  4. 如果 GDB 没有推荐 debuginfo 软件包,请按照 第 3.1.5 节 “手动为应用程序或库获取 debuginfo 软件包” 中描述的流程操作。

其他资源

3.1.5. 手动为应用程序或库获取 debuginfo 软件包

您可以通过定位可执行文件,然后查找安装它的软件包来手动确定您需要安装哪些 debuginfo 软件包。

注意

红帽建议您 使用 GDB 来确定安装的软件包。只有在 GDB 无法建议要安装的软件包时,才使用此手动流程。

先决条件

流程

  1. 查找应用程序或库的可执行文件。

    1. 使用 which 查找应用程序文件。

      $ which less
      /usr/bin/less
    2. 使用 locate 命令查找库文件。

      $ locate libz | grep so
      /usr/lib64/libz.so.1
      /usr/lib64/libz.so.1.2.11

      如果调试的最初原因包含错误消息,请选择库的文件名中与错误消息中提及的具有相同的额外数字的结果。若有疑问,请使用文件名不包含其他数字的结果来尝试遵循该流程的其余部分。

      注意

      locate 命令由 mlocate 软件包提供。要安装并启用它:

      # yum install mlocate
      # updatedb
  2. 搜索提供该文件的软件包的名称和版本:

    $ rpm -qf /usr/lib64/libz.so.1.2.7
    zlib-1.2.11-10.el8.x86_64

    输出以 name:epoch-version.release.architecture 格式提供已安装软件包的详细信息。

    重要

    如果此步骤没有生成任何结果,则无法确定哪一个软件包提供了二进制文件。有几个可能的情况:

    • 文件是从 current 配置中包管理工具不知道的包安装的。
    • 文件从本地下载和手动安装的包中安装的。在这种情况下,自动确定合适的 debuginfo 软件包是不可能的。
    • 您的软件包管理工具配置错误。
    • 文件不是从任何软件包安装的。在这种情况下,没有对应的 debuginfo 软件包存在。

    因为后续步骤依赖于此,所以您必须解决这种情况或中止这个过程。描述确切的故障排除步骤不在本流程范围内。

  3. 使用 debuginfo-install 工具安装 debuginfo 软件包。在命令中,使用软件包名称以及您在上一步中确定的其他详情:

    # debuginfo-install zlib-1.2.11-10.el8.x86_64