![如果通过管道传输,GDB 可以解码核心吗?](https://linux22.com/image/114366/%E5%A6%82%E6%9E%9C%E9%80%9A%E8%BF%87%E7%AE%A1%E9%81%93%E4%BC%A0%E8%BE%93%EF%BC%8CGDB%20%E5%8F%AF%E4%BB%A5%E8%A7%A3%E7%A0%81%E6%A0%B8%E5%BF%83%E5%90%97%EF%BC%9F.png)
我有巨大的core
文件,因此将其core_pattern
设置gzip
为写入时设置。
稍后如果回溯要获取文件,首先gunzip
必须完成(并且需要很长时间!),然后core
才能将文件提供给gdb
.
我想知道是否有办法管道(core
或正在创建的)gdb
(或任何其他可以获取 的程序backtrace
)。我查了一下gdb
,好像没有这个选项(也没有readelf
);在我能做出这样的东西之前,我想知道是否有 ELF 格式core
(在x86_64
GNU/Linux 上)的东西可以阻止它工作?
- 编辑 -
通过readelf
源代码和其他可以生成回溯的程序,它们似乎正在seek()
通过文件转发和向后!我不确定这是否绝对必要,或者是否可以在一次传递中读取和收集所有需要的信息(因为我想从管道中读取,所以不能选择查找!)
答案1
内核 coredump 处理程序可以从僵尸进程生成回溯,没有首先将核心转储写入磁盘。
我以为 ABRT 可以做到这一点。不过好像有补丁,但是还没有合并:
答案2
生成回溯需要按地址获取内存内容。在核心文件中,其内容包含在核心中的每个虚拟地址位于核心文件中的特定偏移处。当生成回溯的代码执行查找时,该查找的目标是映射到该偏移量的地址的内存内容的偏移量。
将核心文件视为流的障碍在于,没有理由期望与正在获取其内容的地址相对应的偏移量随着每次获取而增加。向后查找简单地意味着当前获取的内容的偏移量小于先前获取的偏移量。
也许从核心文件构造回溯的最简单场景是由始终使用帧指针的代码生成的核心文件。在这种情况下,内存读取来自堆栈,并且帧指针值(每个堆栈帧一个)提供相当于堆栈帧链接列表的内容,其中每个堆栈帧的下一个字是返回地址(在存在适当的符号,可以映射到函数名称和偏移量)。
典型核心文件中增加的地址具有文件内增加的偏移量,并且用帧指针值的链接列表表示的典型回溯对于每个连续帧具有更大的帧指针地址。使用帧指针的代码从核心文件进行简单的回溯可以首先定位堆栈(从堆栈指针寄存器的值),然后遍历帧指针值的链接列表,显示与每个帧关联的返回地址。这种方法将涉及相当数量的缓冲,主要是核心文件开头附近的程序段标头,这些缓冲用于将虚拟地址映射到文件偏移量。这种方法中效率低下的最严重的情况可能是忽略段头(以及用于获取寄存器值的注释)和相关线程的堆栈之间的所有未压缩数据。
从不使用帧指针的代码生成回溯更为复杂,但如果缓冲了足够的数据,这也是可能的。如果正确的符号可用,则更有可能可行,如果调试符号可用,则更可行。与帧指针场景一样,从相关堆栈中获取数据可能是必不可少的。
也许最好的方法是改变大型核心文件节省空间的方式,而不是一开始就希望将核心文件视为流。输出的根本问题gzip
是它不提供随机访问。核心文件的空间高效表示的更好选择是类似于 的格式squashfs
,其中通过压缩恒定大小的块来提供随机访问,并且对这些块进行索引,以便获取指定偏移量的数据首先包括定位和解压缩适当的块,然后在未压缩的数据中查找。
squashfs
使用in 的直接挑战core_pattern
是没有明显的方法来调用mksquashfs
标准输入。也许解决此问题的最简单方法是允许核心文件以其未压缩形式存在足够长的时间以调用mksquashfs
.更节省空间的方法可能涉及编写可以squashfs
从标准输入生成格式的代码;如果mksquashfs
没有理由在图像中包含的文件中向后查找,这可能很简单squashfs
(我不确定这一点,但我对squashfs
格式的理解表明这至少是一种可能性)。
假设您有一个squashfs
包含巨大核心文件的映像,将其提供给生成回溯的工具的一种方法是简化mount
该映像并提供该安装点内的相关路径名,但修改应用程序以squashfs
本地处理格式也是可行的。这种方法的一个优点是,除了简单的回溯之外,对核心文件的任何其他操作也是可用的(核心分析的下一步可能是生成多个回溯,每个线程一个)。