3.4. 调试 Crashed 应用程序
有时,无法直接调试应用程序。在这些情况下,您可以在其终止时收集有关应用程序的信息,并在其终止时对其进行分析。
3.4.1. 核心转储:它们是什么以及如何使用它们 复制链接链接已复制到粘贴板!
内核转储(core dump)是应用程序在应用程序停止工作时的一部分的副本,它以 ELF 格式存储。它包含所有应用的内部变量和堆栈,可启用检查应用程序的最终状态。当增强对应的可执行文件和调试信息时,可以使用 debugger 分析核心转储文件,类似于分析正在运行的程序。
如果启用了此功能,Linux 操作系统内核可以自动记录核心转储。或者,您可以向任何正在运行的应用程序发送信号来生成内核转储,而不考虑其实际状态。
有些限制可能会影响生成内核转储的功能。查看当前的限制:
$ ulimit -a
3.4.2. 使用内核转储记录应用程序崩溃 复制链接链接已复制到粘贴板!
要记录应用程序崩溃,请设置内核转储保存并添加系统的信息。
流程
要启用内核转储,请确保
/etc/systemd/system.conf文件包含以下行:DumpCore=yes DefaultLimitCORE=infinity您还可以添加注释,描述之前是否存在这些设置以及之前的值。如果需要,这将使您稍后撤销这些更改。注释是以
#字符开头的行。更改该文件需要管理员级别访问权限。
应用新配置:
# systemctl daemon-reexec删除内核转储大小的限制:
# ulimit -c unlimited要反向更改,请使用值
0而不是unlimited来运行 命令。安装提供
sosreport工具来收集系统信息的sos软件包:# dnf install sos-
当应用程序崩溃时,会生成核心转储,并由
systemd-coredump处理。 创建 SOS 报告以提供有关系统的更多信息:
# sosreport这将创建一个包含您系统信息的
.tar存档,如配置文件的副本。找到内核转储:
$ coredumpctl list executable-name导出内核转储:
$ coredumpctl dump executable-name > /path/to/file-for-export如果应用程序多次崩溃,则第一个命令的输出列出了更多捕获的内核转储。在这种情况下,使用其他信息为第二个命令构建更精确的查询。详情请查看 coredumpctl(1) 手册页。
将内核转储和 SOS 报告传送到进行调试的计算机。另外,也传输可执行文件(如果该文件已知)。
重要当可执行文件未知时,core 文件的后续分析会识别该文件。
- 可选:在传输后将内核转储和 SOS 报告删除,以释放磁盘空间。
3.4.3. 使用内核转储检查应用程序崩溃状态 复制链接链接已复制到粘贴板!
先决条件
- 您必须有一个内核转储文件,以及发生崩溃的系统的 sosreport。
- 在您的系统中必须安装 GDB 和 elfutils。
流程
要识别发生崩溃的可执行文件,请运行带内核转储文件的
eu-unstrip命令:$ eu-unstrip -n --core=./core.98140x400000+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输出中包含一行中每个模块的详细信息,用空格分开。该信息按以下顺序列出:
- 模块映射的内存地址
- 模块的 build-id 以及它在找到的内存中的位置
-
模块的可执行文件名称,如果未知显示为
-,如果模块没有从文件中加载则显示为.。 -
调试信息的来源,在可用时显示为一个文件名,当包括在可执行文件本身中时显示为
.,或在不存在时显示- -
主模块的共享库名称(soname)或
[exe]
在本例中,重要的细节是文件名
/usr/bin/sleep以及在包括文本[exe]的行中的 build-id2818b2009547f780a5639c904cded443e564973e。使用这些信息,您可以识别分析内核转储所需的可执行文件。获取崩溃的可执行文件。
- 如果可能,在发生崩溃的系统中复制它。使用从核心文件中提取的文件名。
您还可以在系统中使用相同的可执行文件。Red Hat Enterprise Linux 上构建的每个可执行文件都包含带有唯一 build-id 值的备注。确定相关本地可用可执行文件的构建 ID:
$ eu-readelf -n executable_file使用此信息将远程系统中的可执行文件与您的本地副本匹配。内核转储中列出的本地文件和 build-id 的 build-id 必须匹配。
-
最后,如果应用程序从 RPM 软件包安装,您可以从软件包中获取可执行文件。使用
sosreport输出来查找所需软件包的确切版本。
- 获取可执行文件使用的共享库。对可执行文件使用的步骤相同。
- 如果应用程序以软件包的形式发布,在 GDB 中加载可执行文件,以显示缺少 debuginfo 软件包的提示。如需了解更多详细信息,请参阅使用 GDB 获取应用程序或库的 debuginfo 软件包。
要详细检查核心文件,使用 GDB 加载可执行文件和内核转储文件:
$ gdb -e executable_file -c core_file有关缺失的文件和调试信息的进一步消息可帮助您识别调试会话中缺少什么。如果需要,返回到上一步。
如果应用程序的调试信息可作为文件而不是软件包提供,使用
symbol-file命令在 GDB 中载入该文件:(gdb) symbol-file program.debug使用实际文件名替换 program.debug。
注意对于核心转储中包含的所有可执行文件,可能不需要安装调试信息。这些可执行文件的大部分是应用代码使用的库。这些库可能不会直接为问题贡献,您不需要为它们包含调试信息。
使用 GDB 命令在应用程序崩溃时检查应用程序状态。请参阅使用 GDB 检查应用程序内部状态。
注意在分析内核文件时,GDB 不会附加到正在运行的进程。用于控制执行的命令无效。
要在应用程序终止时只查看应用程序的堆栈,请使用
eu-stack工具打开核心文件:$ *eu-stack --core __core-file__*这将显示应用的堆栈的列表。
其他资源
3.4.4. 使用 coredumpctl 创建和访问内核转储 复制链接链接已复制到粘贴板!
systemd 的 coredumpctl 工具可显著简化崩溃发生的机器中的核心转储。此流程概述了如何捕获未响应进程的内核转储。
先决条件
该系统必须配置为使用
systemd-coredump进行内核转储处理。验证这一点是否正确:$ sysctl kernel.core_pattern如果输出以以下内容开头,则配置是正确的:
kernel.core_pattern = |/usr/lib/systemd/systemd-coredump
流程
根据可执行文件名称的已知部分,查找挂起进程的 PID:
$ pgrep -a executable-name-fragment这个命令会以以下形式输出一行
PID command-line使用 命令行 值来验证 PID 属于预期进程。
例如:
$ pgrep -a bc5459 bc向进程发送中止信号:
# kill -ABRT PID验证
coredumpctl是否捕获了内核:$ coredumpctl list PID例如:
$ coredumpctl list 5459TIME PID UID GID SIG COREFILE EXE Thu 2019-11-07 15:14:46 CET 5459 1000 1000 6 present /usr/bin/bc根据需要进一步检查或使用 core 文件。
您可以根据 PID 和其他值指定内核转储。详情请查看 coredumpctl(1) 手册页。
后续步骤
要显示核心文件的详情,请运行:
$ coredumpctl info PID要在 GDB 调试器中载入核心文件,请运行:
$ coredumpctl debug PID根据调试信息的可用性,GDB 可能会建议运行命令,例如:
Missing separate debuginfos, use: dnf debuginfo-install bc-1.07.1-23.el10.x86_64有关此过程的详情,请参阅使用 GDB 获取应用程序或库的 debuginfo 软件包。
要导出核心文件以便进一步处理其他位置,请运行:
$ coredumpctl dump PID > /path/to/file_for_export使用您要放置内核转储的文件替换 /path/to/file_for_export。
$ coredumpctl dump PID > /path/to/file_for_export
3.4.5. 使用 gcore转储进程内存 复制链接链接已复制到粘贴板!
核心转储调试的工作流可以离线分析程序的状态。在某些情况下,您可以将此工作流与仍然运行的程序搭配使用,比如很难通过进程访问环境。您可以使用 gcore 命令在仍在运行时转储任何进程的内存。
流程
查找进程 ID(pid)。使用
ps、pgrep和top等工具:$ ps -C some-program转储这个进程的内存:
$ gcore -o filename pid这会创建一个文件 filename 并转储进程内存。转储内存时,进程的执行将停止。
- 在内核转储完成后,进程会恢复正常执行。
创建 SOS 报告以提供有关系统的更多信息:
# sosreport这会创建一个 tar 存档,其中包含您的系统信息,如配置文件的副本。
- 将程序的可执行文件、内核转储和 SOS 报告传送到进行调试的计算机。
- 可选:在传输后将内核转储和 SOS 报告删除,以释放磁盘空间。
3.4.6. 使用 GDB 转储受保护的进程内存 复制链接链接已复制到粘贴板!
您可以将进程内存标记为不转储。这可节省资源并确保进程内存包含敏感数据时的其他安全:例如,在银行或核算应用程序或整个虚拟机上。内核内核转储(kdump)和手动内核转储(gcore、GDB)都不会转储标记为这种方式的内存。
在某些情况下,无论这些保护是什么,您必须转储进程内存的整个内容。此流程演示了如何使用 GDB 调试器进行此操作。
流程
将 GDB 设置为忽略
/proc/PID/coredump_filter文件中的设置:(gdb) set use-coredump-filter off将 GDB 设置为忽略内存页标记
VM_DONTDUMP:(gdb) set dump-excluded-mappings on转储内存:
(gdb) gcore core-file使用您要转储内存的文件名替换 core-file。