第 3 章 调试应用程序

调试应用程序是一个非常广泛的主题。这部分为开发人员提供了在多个情况下进行调试的最常见技术。

3.1. 使用调试信息启用调试

要调试应用程序和库,需要调试信息。以下小节介绍了如何获取此信息。

3.1.1. 调试信息

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

  • 源代码文本
  • 源代码文本如何与二进制代码关联

此类信息称为调试信息。

Red Hat Enterprise Linux 将 ELF 格式用于可执行二进制文件、共享库或 debuginfo 文件。在这些 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 选项设置优化。但是,更改优化等级会改变可执行代码,并可能会更改实际行为,包括删除一些错误。
  • 要在调试信息中包含宏定义,请使用 -g3 选项而不是 -g
  • -fcompare-debug GCC 选项测试 GCC 使用调试信息和没有调试信息编译的代码。如果生成的两个二进制文件相同,则测试通过。此测试可确保可执行代码不受任何调试选项的影响,这会进一步确保调试代码中没有隐藏的错误。请注意,使用 -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 目录中。

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

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

先决条件

  • 必须在系统上安装您要调试的应用程序或库。
  • 在系统中必须安装 GDB 和 debuginfo-install 工具。详情请参阅设置调试应用程序
  • 必须在系统上配置和启用提供 debuginfodebugsource 软件包的存储库。详情请参阅 启用调试和源存储库

步骤

  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 软件包,请按照 手动应用程序或库获取 debuginfo 软件包中所述的步骤操作

其他资源

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

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

注意

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

先决条件

  • 必须在系统中安装应用程序或库。
  • 应用程序或库是从软件包安装的。
  • 系统中必须有 debuginfo-install 工具。
  • 必须在系统中配置和启用提供 debuginfo 软件包的频道。

步骤

  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 软件包提供。要安装它并启用其使用:

      # dnf 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 的形式)的详情。

    重要

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

    • 文件从当前配置中包管理工具不知道的包安装。
    • 该文件使用本地下载并手动安装的软件包进行安装。在这种情况下,无法自动决定合适的 debuginfo 软件包。
    • 您的软件包管理工具配置错误。
    • 该文件没有从任何软件包安装。在这种情况下,不存在相关的 debuginfo 软件包。

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

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

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