Menu Close

Red Hat Training

A Red Hat training course is available for RHEL 8

第 10 章 调试 Crashed Application

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

10.1. core dumps:它们的状态以及如何使用它们

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

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

警告

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

$ ulimit -a

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

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

流程

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

    DumpCore=yes
    DefaultLimitCORE=infinity

    您还可以添加注释来描述之前是否有这些设置,以及前面的值。这可让您在以后根据需要撤销这些更改。注释是以 # 字符开头的行。

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

  2. 应用新配置:

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

    # ulimit -c unlimited

    要撤销这个更改,使用值为 0 而不是 unlimited 运行命令。

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

    # 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. 将 core 转储和 SOS 报告传送到进行调试的计算机。传输可执行文件(如果已知)。

    重要

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

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

10.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. 模块的可执行文件名,在未知时以 - 的形式显示,或者在 . 没有从文件中载入该模块时显示
    4. 调试信息源,在可用时以文件名形式显示,当可执行文件本身中包含时作为 . 显示,或者在不存在时显示为 -
    5. 主模块的共享名称(soname)或 [exe]

    在这个示例中,重要详情是文件名 /usr/bin/sleep 和包含文本 [exe] 的行中的 build-id 2818b2009547f780a5639c904cded443e564973e。使用这些信息,您可以识别分析内核转储所需的可执行文件。

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

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

      $ eu-readelf -n executable_file

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

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

    $ gdb -e executable_file -c core_file

    有关缺少文件和调试信息的其他信息可帮助您识别调试会话缺少的内容。如果需要,返回到上一步。

    如果应用程序的调试信息可作为文件提供,而不是软件包,请使用 symbol-file 命令在 GDB 中载入该文件:

    (gdb) symbol-file program.debug

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

    注意

    可能不需要为 core 转储中包含的所有可执行文件安装调试信息。大多数可执行文件都是应用程序代码使用的库。这些库可能不会直接造成您分析的问题,您不需要包括调试信息。

  6. 使用 GDB 命令在应用程序崩溃时检查应用程序的状态。请查看 第 8 章 使用 GDB 检查应用程序 Internal State

    注意

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

其它资源

10.4. 使用 coredumpctl 创建并访问内核转储

systemdcoredumpctl 工具可显著简化在发生崩溃的机器中使用内核转储的过程。该流程概述了如何捕获无响应过程的内核转储。

先决条件

  • 系统必须配置为使用 systemd-coredump 进行内核转储处理。验证它为 true:

    $ sysctl kernel.core_pattern

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

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

流程

  1. 根据可执行文件名称的已知部分查找 hung 进程的 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. 根据需要进一步检查或使用核心文件。

    您可以使用 PID 指定 core 转储和其他值。详情请 查看 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

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

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

      $ coredumpctl dump PID > /path/to/file_for_export

      /path/to/file_for_export 替换为您要放置 core 转储的文件。

10.5. 使用它转储进程内存 gcore

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

流程

  1. 找到进程 id(pid)。使用 pspgreptop 等工具:

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

    $ gcore -o filename pid

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

  3. 在 core 转储完成后,该过程会恢复正常执行。
  4. 创建一个 SOS 报告来提供有关系统的额外信息:

    # sosreport

    这会创建一个包含系统信息的 tar 归档,比如配置文件的副本。

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

10.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。

其它资源