Linux 上的核心转储文件:如何获取打开文件的信息?

Posted

技术标签:

【中文标题】Linux 上的核心转储文件:如何获取打开文件的信息?【英文标题】:core dump files on Linux: how to get info on opened files? 【发布时间】:2010-09-08 16:24:44 【问题描述】:

我有一个来自可能存在文件描述符泄漏的进程的核心转储文件(它打开文件和套接字,但显然有时忘记关闭其中一些)。有没有办法找出进程在崩溃之前打开了哪些文件和套接字?我无法轻易重现崩溃,因此分析核心文件似乎是获得错误提示的唯一方法。

【问题讨论】:

【参考方案1】:

如果你有一个核心文件并且你已经使用调试选项(-g)编译了程序,你可以看到核心被转储到哪里:

$ gcc -g -o something something.c
$ ./something
Segmentation fault (core dumped)
$ gdb something core

您可以使用它来进行一些事后调试。一些 gdb 命令:bt 打印堆栈,fr 跳转到给定的堆栈帧(参见 bt 的输出)。

现在,如果您想查看在分段错误时打开了哪些文件,只需处理 SIGSEGV 信号,然后在处理程序中,转储 /proc/PID/fd 目录的内容(即使用 system('ls - l /proc/PID/fs') 或 execv)。

有了这些信息,您可以轻松找到导致崩溃的原因、打开了哪些文件以及崩溃和文件描述符泄漏是否相关。

【讨论】:

这并没有真正回答问题,即使用核心文件来发现打开的文件,而不是向现有程序添加调试输出。 Oliver 无论如何都无法重现该问题。【参考方案2】:

最好的办法是为使程序崩溃的任何信号(SIGSEGV 等)安装一个信号处理程序。

然后,在信号处理程序中,检查 /proc/self/fd,并将内容保存到文件中。以下是您可能会看到的示例:

Anderson cxc # ls -l  /proc/8247/fd
total 0
lrwx------ 1 root root 64 Sep 12 06:05 0 -> /dev/pts/0
lrwx------ 1 root root 64 Sep 12 06:05 1 -> /dev/pts/0
lrwx------ 1 root root 64 Sep 12 06:05 10 -> anon_inode:[eventpoll]
lrwx------ 1 root root 64 Sep 12 06:05 11 -> socket:[124061]
lrwx------ 1 root root 64 Sep 12 06:05 12 -> socket:[124063]
lrwx------ 1 root root 64 Sep 12 06:05 13 -> socket:[124064]
lrwx------ 1 root root 64 Sep 12 06:05 14 -> /dev/driver0
lr-x------ 1 root root 64 Sep 12 06:05 16 -> /temp/app/whatever.tar.gz
lr-x------ 1 root root 64 Sep 12 06:05 17 -> /dev/urandom

然后你可以从你的信号处理程序返回,你应该像往常一样得到一个核心转储。

【讨论】:

【参考方案3】:

我跳转到此信息的一种方法是在核心文件上运行strings。例如,当我最近在核心上运行文件时,由于文件夹的长度,我会得到一个截断的参数列表。我知道我的运行会从我的主目录打开文件,所以我只是运行:

strings core.14930|grep jodie

但这是一个我有一根针和一个干草堆的案例。

【讨论】:

【参考方案4】:

您可以尝试使用strace 来查看程序发出的opensocketclose 调用。

编辑:我认为您无法从核心获取信息;最多它会在某个地方有文件描述符,但这仍然没有给你实际的文件/套接字。 (假设您可以区分打开和关闭的文件描述符,我也对此表示怀疑。)

【讨论】:

【参考方案5】:

如果程序忘记关闭这些资源,可能是因为发生了以下情况:

fd = open("/tmp/foo",O_CREAT);
//do stuff
fd = open("/tmp/bar",O_CREAT); //Oops, forgot to close(fd)

现在我不会在内存中拥有 foo 的文件描述符了。

如果这没有发生,您也许可以找到文件描述符编号,但话又说回来,这不是很有用,因为它们在不断变化,当您开始调试时,您将不知道是哪个文件它实际上是当时的意思。

我真的认为您应该使用 strace、lsof 和朋友进行现场调试。

如果有办法从核心转储中做到这一点,我也很想知道:-)

【讨论】:

【参考方案6】:

最近在我的错误排除和分析过程中,我的客户向我提供了一个在他的文件系统中生成的 coredump,他离开站以便快速扫描文件并读取其内容,我使用了该命令

字符串 core.67545 > coredump.txt 后来我能够在文件编辑器中打开文件。

【讨论】:

【参考方案7】:

核心转储是进程崩溃时可以访问的内存的副本。根据泄漏的发生方式,它可能丢失了对句柄的引用,因此它可能被证明是无用的。

lsof 列出系统中所有当前打开的文件,您可以检查其输出以查找泄漏的套接字或文件。是的,您需要运行该过程。您可以使用特定的用户名运行它,以轻松识别您正在调试的进程中哪些是打开的文件。

我希望其他人有更好的信息:-)

【讨论】:

【参考方案8】:

另一种找出进程打开了哪些文件的方法(同样,仅在运行时)是查看 /proc/PID/fd/ ,其中包含用于打开文件的符号链接。

【讨论】:

以上是关于Linux 上的核心转储文件:如何获取打开文件的信息?的主要内容,如果未能解决你的问题,请参考以下文章

打开具有不同可执行文件但源相同的核心转储文件

如何获取 Java.exe/jvm.dll 的符号文件以分析崩溃核心转储文件?

如何使用 VSCode 调试 Linux 核心转储?

JVM崩溃。如何获取错误日志或核心转储

在核心转储文件上使用 gdb 获取变量的值

核心转储已创建,但未写入文件?