搜索

3.4. 调试崩溃应用程序

download PDF

有时,无法直接调试应用。在这些情况下,您可以在应用程序终止时收集有关应用程序的信息,然后对其进行分析。

3.4.1. 内核转储:它们是什么以及如何使用它们

在应用程序停止工作时,核心转储是部分应用程序内存的副本,以 ELF 格式存储。它包含应用的所有内部变量和堆栈,可以检查应用的最终状态。使用相应的可执行文件和调试信息进行增强时,可以使用调试器以类似于分析正在运行的程序的方式分析核心转储文件。

如果启用了此功能,Linux 操作系统内核会自动记录内核转储。或者,您可以向任何正在运行的应用发送信号,以生成核心转储,而不考虑其实际状态。

警告

某些限制可能会影响生成内核转储的功能。查看当前的限制:

$ ulimit -a

3.4.2. 使用内核转储记录应用程序崩溃

要记录应用程序崩溃,请设置核心转储保存并添加系统信息。

流程

  1. 要启用内核转储,请确保 /etc/systemd/system.conf 文件包含以下行:

    DumpCore=yes
    DefaultLimitCORE=infinity

    您还可以添加注释,描述之前是否存在这些设置以及之前的值。如果需要,这将允许您稍后撤销这些更改。注释是以 # 字符开头的行。

    更改文件需要管理员级别访问权限。

  2. 应用新配置:

    # systemctl daemon-reexec
  3. 删除内核转储大小的限制:

    # ulimit -c unlimited

    若要反转这一更改,可运行值为 0 的 命令,而不运行 无限 值。

  4. 安装 sos 软件包,它提供用于收集系统信息的 sosreport 工具:

    # yum install sos
  5. 当应用程序崩溃时,会生成核心转储并由 systemd-coredump 进行处理。
  6. 创建 SOS 报告以提供有关系统的更多信息:

    # sosreport

    这将创建一个包含您系统信息的 .tar 存档,如配置文件的副本。

  7. 找到并导出内核转储:

    $ coredumpctl list executable-name
    $ coredumpctl dump executable-name > /path/to/file-for-export

    如果应用多次崩溃,第一个命令的输出会列出更多捕获的核心转储。在这种情况下,使用其他信息为第二个命令构建更精确的查询。详情请查看 coredumpctl(1) 手册页。

  8. 将核心转储和 SOS 报告传送到要进行调试的计算机。如果已知,也传输可执行文件。

    重要

    当可执行文件未知时,core 文件的后续分析会识别该文件。

  9. 可选:传输后删除核心转储和 SOS 报告,以释放磁盘空间。

3.4.3. 使用内核转储检查应用程序崩溃状态

先决条件

  • 您必须从发生崩溃的系统中有一个核心转储文件和 sosreport。
  • 在您的系统上必须安装 GDB 和 elfutils。

流程

  1. 要识别发生崩溃的可执行文件,请使用核心转储文件运行 eu-unstrip 命令:

    $ eu-unstrip -n --core=./core.9814
    0x400000+0x207000 2818b2009547f780a5639c904cded443e564973e@0x400284 /usr/bin/sleep /usr/lib/debug/bin/sleep.debug [exe]
    0x7fff26fff000+0x1000 1e2a683b7d877576970e4275d41a6aaec280795e@0x7fff26fff340 . - linux-vdso.so.1
    0x35e7e00000+0x3b6000 374add1ead31ccb449779bc7ee7877de3377e5ad@0x35e7e00280 /usr/lib64/libc-2.14.90.so /usr/lib/debug/lib64/libc-2.14.90.so.debug libc.so.6
    0x35e7a00000+0x224000 3ed9e61c2b7e707ce244816335776afa2ad0307d@0x35e7a001d8 /usr/lib64/ld-2.14.90.so /usr/lib/debug/lib64/ld-2.14.90.so.debug ld-linux-x86-64.so.2

    输出中包含一行中各个模块的详细信息,用空格分隔。此信息按以下顺序列出:

    1. 映射模块的内存地址
    2. 模块的 build-id 及其在内存中的位置
    3. 模块的可执行文件名称,如果未从文件加载为 - 时显示为 - when unknown 或 等
    4. 调试信息源(如果可用时显示为文件名),如 包含在 可执行文件本身中,或 如果根本不存在)
    5. 主模块的共享库名称(soname)或 [exe]

    在本例中,重要的详细信息是文件名 /usr/bin/sleep 和 build-id 2818b2009547f780a5639c904cded443e564973e on the text [exe]。使用此信息,您可以识别分析核心转储所需的可执行文件。

  2. 获取崩溃的可执行文件。

    • 如果可能,请从发生崩溃的系统中复制它。使用从 core 文件提取的文件名。
    • 您也可以在系统上使用相同的可执行文件。在 Red Hat Enterprise Linux 上构建的每个可执行文件都包含带有唯一 build-id 值的备注。确定相关的本地可用可执行文件的 build-id:

      $ eu-readelf -n executable_file

      使用此信息将远程系统上的可执行文件与您的本地副本匹配。内核转储中列出的本地文件和 build-id 的 build-id 必须匹配。

    • 最后,如果应用程序是从 RPM 软件包安装的,您可以从 软件包中获取可执行文件。使用 sosreport 输出来查找所需软件包的确切版本。
  3. 获取由可执行文件使用的共享库。将与 相同的步骤用于 可执行文件。
  4. 如果应用程序以软件包形式分发,请在 GDB 中加载可执行文件,以显示缺少 debuginfo 软件包的提示。如需了解更多详细信息,请参阅 第 3.1.4 节 “使用 GDB 获取应用程序或库的 debuginfo 软件包”
  5. 要详细检查核心文件,使用 GDB 加载可执行文件和核心转储文件:

    $ gdb -e executable_file -c core_file

    有关缺少文件和调试信息的更多消息可帮助您确定调试会话中缺少的内容。如果需要,返回到上一步骤。

    如果应用的调试信息可作为文件而不是软件包提供,请使用 symbolic -file 命令加载这个文件到 GDB 中:

    (gdb) symbol-file program.debug

    使用实际文件名替换 program.debug

    注意

    可能不需要为核心转储中包含的所有可执行文件安装调试信息。这些可执行文件的大部分是应用代码使用的库。这些库可能不会直接导致您要分析的问题,您不需要为它们包含调试信息。

  6. 在应用崩溃时,使用 GDB 命令检查应用的状态。请参阅使用 GDB 检查应用内部状态

    注意

    分析核心文件时,GDB 未附加到正在运行的进程。控制执行的命令无效。

其他资源

3.4.4. 使用 coredumpctl 创建和访问内核转储

systemdcoredumpctl 工具可显著简化崩溃机器中使用内核转储的工作。此流程概述了如何捕获未响应进程的内核转储。

先决条件

  • 系统必须配置为使用 systemd-coredump 进行 内核转储处理。验证这是正确的:

    $ sysctl kernel.core_pattern

    如果输出以以下内容开始,则配置是正确的:

    kernel.core_pattern = |/usr/lib/systemd/systemd-coredump

流程

  1. 根据可执行文件名称的已知部分,查找挂起进程的 PID:

    $ pgrep -a executable-name-fragment

    此命令将以以下形式输出一行:

    PID command-line

    使用 命令行 值验证 PID 是否属于预期进程。

    例如:

    $ pgrep -a bc
    5459 bc
  2. 向进程发送中止信号:

    # kill -ABRT PID
  3. 验证内核是否已由 coredumpctl 捕获:

    $ coredumpctl list PID

    例如:

    $ coredumpctl list 5459
    TIME                            PID   UID   GID SIG COREFILE  EXE
    Thu 2019-11-07 15:14:46 CET    5459  1000  1000   6 present   /usr/bin/bc
  4. 根据需要进一步检查或使用 core 文件。

    您可以根据 PID 和其他值指定内核转储。详情请查看 coredumpctl(1) 手册页。

    • 显示核心文件的详细信息:

      $ coredumpctl info PID
    • 加载 GDB 调试器中的核心文件:

      $ coredumpctl debug PID

      根据调试信息的可用性,GDB 将建议运行的命令,例如:

      Missing separate debuginfos, use: dnf debuginfo-install bc-1.07.1-5.el8.x86_64

      有关此过程的详情,请参考 第 3.1.4 节 “使用 GDB 获取应用程序或库的 debuginfo 软件包”

    • 导出核心文件以便在其他位置进行进一步处理:

      $ coredumpctl dump PID > /path/to/file_for_export

      使用您要放置内核转储的文件替换 /path/to/file_for_export

3.4.5. 使用 gcore转储进程内存

内核转储调试的工作流允许分析程序的状态离线。在某些情况下,您可以将此工作流用于仍在运行的程序,例如难以通过 进程访问环境。您可以使用 gcore 命令转储仍在运行的任何进程的内存。

流程

  1. 查找进程 id(pid)。使用 pspgrep 和 top 等工具

    $ ps -C some-program
  2. 转储这个过程的内存:

    $ gcore -o filename pid

    这会创建 文件名,并转储其中的进程内存。在内存被转储时,进程的执行将被停止。

  3. 内核转储完成后,进程会恢复正常执行。
  4. 创建 SOS 报告以提供有关系统的更多信息:

    # sosreport

    这将创建一个 tar 存档,其中包含系统的相关信息,如配置文件副本。

  5. 将程序的可执行文件、核心转储和 SOS 报告传送到要进行调试的计算机。
  6. 可选:传输后删除核心转储和 SOS 报告,以释放磁盘空间。

3.4.6. 使用 GDB 转储受保护的进程内存

您可以将进程内存标记为不转储。这样可以节省资源并在进程内存包含敏感数据时确保额外的安全性:例如,银行或记帐应用程序或整个虚拟机上。内核内核转储(kdump)和手动内核转储(gcore,GDB)都不会转储以这种方式标记的内存。

在某些情况下,您必须转储进程内存的所有内容,无论这些保护如何。此流程演示了如何使用 GDB 调试器执行此操作。

流程

  1. 将 GDB 设置为忽略 /proc/PID/coredump_filter 文件中的设置:

    (gdb) set use-coredump-filter off
  2. 将 GDB 设置为忽略内存页面标记 VM_DONTDUMP

    (gdb) set dump-excluded-mappings on
  3. 转储内存:

    (gdb) gcore core-file

    使用您要转储内存的文件名称替换 core-file

其他资源

Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

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

让开源更具包容性

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

關於紅帽

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

© 2024 Red Hat, Inc.