我有一个来自可能存在文件描述符泄漏的进程的核心转储文件(它打开文件和套接字,但显然有时忘记关闭其中一些)。有没有办法找出进程在崩溃之前打开了哪些文件和套接字?我无法轻易重现崩溃,因此分析核心文件似乎是获得错误提示的唯一方法。
8 回答
如果您有一个核心文件并且您已经使用调试选项 (-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)。
有了这些信息,您可以轻松找到导致崩溃的原因、打开了哪些文件以及崩溃和文件描述符泄漏是否相关。
您最好的选择是为任何使您的程序崩溃的信号(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
然后你可以从你的信号处理程序返回,你应该像往常一样得到一个核心转储。
我跳转到此信息的方法之一就是strings
在核心文件上运行。例如,当我最近在核心上运行文件时,由于文件夹的长度,我会得到一个截断的参数列表。我知道我的运行会从我的主目录打开文件,所以我只是运行:
strings core.14930|grep jodie
但这是一个我有一根针和一个干草堆的例子。
您可以尝试使用strace
来查看open
,socket
并close
调用程序。
编辑:我认为您无法从核心获取信息;最多它会在某个地方有文件描述符,但这仍然没有给你实际的文件/套接字。(假设您可以区分打开和关闭的文件描述符,我也对此表示怀疑。)
如果程序忘记关闭这些资源,可能是因为发生了以下情况:
fd = open("/tmp/foo",O_CREAT);
//do stuff
fd = open("/tmp/bar",O_CREAT); //Oops, forgot to close(fd)
现在我不会在内存中拥有 foo 的文件描述符。
如果这没有发生,您可能能够找到文件描述符编号,但话又说回来,这不是很有用,因为它们在不断变化,当您开始调试时,您将不知道它实际上意味着哪个文件当时。
我真的认为您应该使用 strace、lsof 和朋友来现场调试。
如果有办法从核心转储中做到这一点,我也很想知道它:-)
最近在我的错误故障排除和分析过程中,我的客户向我提供了一个在他的文件系统中生成的 coredump,他离开站以便快速扫描文件并读取其内容我使用了命令
字符串 core.67545 > coredump.txt,后来我能够在文件编辑器中打开文件。
核心转储是进程在崩溃时可以访问的内存的副本。根据泄漏的发生方式,它可能丢失了对句柄的引用,因此它可能被证明是无用的。
lsof 列出系统中所有当前打开的文件,您可以检查其输出以查找泄漏的套接字或文件。是的,您需要运行该过程。您可以使用特定的用户名运行它,以轻松识别您正在调试的进程中哪些是打开的文件。
我希望其他人有更好的信息:-)
另一种找出进程打开了哪些文件的方法 - 再次,仅在运行时 - 是查看 /proc/PID/fd/ ,其中包含打开文件的符号链接。