我有一个核心转储文件,其中的进程可能存在文件描述符泄漏(它打开了一些文件和套接字,但显然有时忘记关闭其中一些)。有没有办法找出进程在崩溃前打开了哪些文件和套接字?由于难以重现崩溃,因此分析核心文件似乎是获取有关错误提示的唯一方法。
$ 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)。
有了这些信息,您就可以轻松找出导致崩溃的原因,打开了哪些文件以及崩溃和文件描述符泄漏是否有关联。
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
然后你可以从你的信号处理程序中返回,通常情况下应该会获得一个核心转储。
在 IT 技术中,有一种方法可以快速获取信息,就是对核心文件运行 strings
命令。例如,最近我运行 file 命令来分析一个核心文件,但由于文件夹名字过长,参数列表被截断了。我知道我的运行会打开来自我的主目录的文件,因此我只需输入以下命令:
strings core.14930|grep jodie
最近在进行错误排除和分析时,我的客户向我提供了一个核心转储文件,该文件在他的文件系统中生成,他离开了工作地点,为了快速扫描文件并阅读其内容,我使用了以下命令:
strings core.67545 > coredump.txt 稍后,我能够在文件编辑器中打开该文件。
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等工具进行在线调试。
如果有一种方法可以从核心转储中完成它,我也很想知道它:-)
核心转储是进程崩溃时访问的内存的副本。根据泄漏发生的方式,它可能已经丢失了对句柄的引用,因此可能被证明是无用的。
lsof列出系统中当前打开的所有文件,您可以检查其输出以查找泄漏的套接字或文件。是的,您需要让进程运行。您可以使用特定的用户名运行它,以轻松区分正在调试的进程的打开文件。
我希望有人拥有更好的信息 :-)
另一种在运行时找出进程打开了哪些文件的方法是查看 /proc/PID/fd/,其中包含指向打开文件的符号链接。