将大型核心文件转换为“迷你核心”文件

Posted

技术标签:

【中文标题】将大型核心文件转换为“迷你核心”文件【英文标题】:Convert large core files to "minicore" files 【发布时间】:2012-10-04 22:33:27 【问题描述】:

如何将核心文件缩减为线程堆栈?

我希望能够在 mini core 上运行 gdb thread apply all bt,仅此而已

我正在处理大型 (>4GB) 多线程 Linux ELF 核心文件,这些文件太大而无法返回进行分析。

我看到google-breakpad 是为了在进程崩溃时创建一个“小型转储”。在google-breakpad 中有两个实用程序core2mdminidump-2-core 乍一看应该能够将核心文件转换为小型转储格式,然后从小型转储返回到仅包含堆栈信息的核心文件。问题在于 core2md 需要 /proc/$PID/ 下的进程信息,而这不是我拥有的。

【问题讨论】:

如果您在创建核心文件时可以控制它们,您可以使用setrlimit(RLIMIT_CORE) 来限制核心文件的最大大小(或者使用ulimit shell builtin,如果你是从 Bash 启动的)。 这样做的问题是它会削减核心文件,而不仅仅是转储堆栈信息。 你为什么不要求在它发生的服务器上做thread apply all bt 发生这种情况的服务器是客户的嵌入式 linux 机器,附带剥离的二进制文件。这就是为什么我无法检索大型核心文件并且无法使用符号进行回溯。 【参考方案1】:

您最好的选择可能是将 google breakpad 集成到您的 Linux 进程中,这样当发生崩溃时,它是 google breakpad 记录崩溃而不是操作系统创建核心文件。这将为您提供所需的信息,然后您可以使用 minidump_stackwalk 转储调用堆栈(便于汇总大量崩溃),也可以使用 minidump-2-core 创建核心文件。

不幸的是,Linux 似乎没有一种有效的方法来创建仅使用线程堆栈的内容的最小核心文件。这些文件(Windows 世界中的小型转储)非常有用——它们具有非常高的信息大小比,可以轻松收集数百万个故障转储。

【讨论】:

【参考方案2】:

您可能可以编写一个简单的程序,从核心文件中删除大部分数据。

核心文件由代表不同 VMA 的 PT_LOAD 程序头条目组成:

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  NOTE           0x0000000000004b80 0x0000000000000000 0x0000000000000000
                 0x0000000000009064 0x0000000000000000  R      1
  LOAD           0x000000000000dbe4 0x0000000000400000 0x0000000000000000
                 0x0000000000000000 0x000000000009d000  R E    1
  LOAD           0x000000000000dbe4 0x000000000069c000 0x0000000000000000
                 0x0000000000004000 0x0000000000004000  RW     1
  LOAD           0x0000000000011be4 0x00000000006a0000 0x0000000000000000
                 0x0000000000004000 0x0000000000004000  RW     1
  LOAD           0x0000000000015be4 0x0000000001872000 0x0000000000000000
                 0x0000000000ed4000 0x0000000000ed4000  RW     1
  LOAD           0x0000000000ee9be4 0x00007f248c000000 0x0000000000000000
                 0x0000000000021000 0x0000000000021000  RW     1
  LOAD           0x0000000000f0abe4 0x00007f2490885000 0x0000000000000000
                 0x000000000001c000 0x000000000001c000  R      1
  LOAD           0x0000000000f26be4 0x00007f24908a1000 0x0000000000000000
                 0x000000000001c000 0x000000000001c000  R      1
[...]

PT_NOTE 条目包含(除其他外)有关线程状态的信息:

Displaying notes found at file offset 0x00004b80 with length 0x00009064:
  Owner                 Data size       Description
  CORE                 0x00000088       NT_PRPSINFO (prpsinfo structure)

  [Thread #1]
  CORE                 0x00000150       NT_PRSTATUS (prstatus structure)
  CORE                 0x00000200       NT_FPREGSET (floating point registers)
  LINUX                0x00000440       NT_X86_XSTATE (x86 XSAVE extended state)
  CORE                 0x00000080       NT_SIGINFO (siginfo_t data)

  [other threads ...]

PT_NOTE 处理

您想保留这个PT_NOTE 程序头条目。

此外,您可以从 prstatus 结构中提取堆栈指针:

struct elf_prstatus 
  [...]
  elf_gregset_t pr_reg;   /* GP registers */
  [...]
;

PT_LOAD 处理

从所有线程中提取所有堆栈指针后,您就可以处理PT_LOAD 条目:

如果FileSize == 0,这个程序头在core文件中不消耗任何内存,可以忽略;

如果某个线程的堆栈指针在这个虚拟内存区域,这可能是一个堆栈,你可能需要保留它;

否则,您也许可以将其从核心文件中删除(将其替换为带有FileSize == 0 的程序头条目)。

或者,您可能能够完全删除所有非堆栈区域的程序头条目。

创建您自己的核心转储程序

另一种解决方案是编写一个核心转储程序,直接生成它并在/proc/sys/kernel/core_pattern(man core)中注册。

【讨论】:

以上是关于将大型核心文件转换为“迷你核心”文件的主要内容,如果未能解决你的问题,请参考以下文章

我们有许多 EBCDIC 格式的大型机文件,Python 中有没有办法将大型机文件解析或转换为 csv 文件或文本文件?

使用任何开源代码或工具将大型机二进制文件转换为 Ascii

将大型 CSV 文件转换为 JSON [关闭]

使用 python 和 pandas 将错误创建的大型 csv 文件转换为制表符分隔文件

sh 将大型视频文件转换为优化的480p视频,而不会失去大量的质量

将核心数据文件从二进制转换为 XML