为什么 gdb 抱怨我的核心文件太小然后无法生成有意义的堆栈跟踪?

why does gdb complain that my core files are too small and then fail to produce a meaningful stack trace?

我有一个从段错误生成的核心文件。当我尝试将它加载到 gdb 中时,我如何加载它或是否使用正确的可执行文件似乎并不重要 - 我总是从 gdb 收到关于核心文件被截断的警告:

$ gdb -q /u1/dbg/bin/exdoc_usermaint_pdf_compact /tmp/barry/core.exdoc_usermaint.11
Reading symbols from /u1/dbg/bin/exdoc_usermaint_pdf_compact...done.
BFD: Warning: /tmp/barry/core.exdoc_usermaint.11 is truncated: expected core file size >= 43548672, found: 31399936.

warning: core file may not match specified executable file.
Cannot access memory at address 0x7f0ebc833668
(gdb) q

我担心这个错误: "BFD: Warning: /tmp/barry/core.exdoc_usermaint.11 is truncated: expected core file size >= 43548672, found: 31399936."

为什么gdb认为核心文件被截断了? gdb 对吗? gdb 从哪里获得核心文件的预期大小,我可以仔细检查吗?

背景:

我正在尝试改进我们对生产系统上的段错误的诊断。我的计划是从生产中剥离的可执行文件中获取核心文件,并将它们与我们开发系统上的可执行文件的调试版本一起使用,以快速诊断段错误。在这个问题的早期版本中,我提供了许多与相似但不同的系统相关的细节,但后来我被授予了我们生产系统的一个帐户,并确定大部分细节对问题并不重要。

gdb 版本:

$ gdb
GNU gdb (GDB) Fedora (7.0.1-50.fc12)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.

Linux版本:

$ uname -a
Linux somehost 2.6.32.23-170.fc12.x86_64 #1 SMP Mon Sep 27 17:23:59 UTC 2010 x86_64 x86_64 x86_64 GNU/Linux

我在发帖前阅读了 this question(以及许多其他文章)。提问者的目标与我有些相似,但没有从 gdb 得到任何关于截断的核心文件的错误。因此,与该问题相关的信息对我的问题没有帮助。

核心转储文件格式

在现代 Linux 系统上,核心转储文件使用 ELF object 文件格式进行格式化,并具有特定的配置。 ELF 是一种结构化二进制文件格式,文件偏移量用作文件中数据块之间的参考。

对于核心转储文件,ELF 文件 header 中的 e_type 字段的值为 ET_CORE。

与大多数 ELF 文件不同,核心转储文件通过程序 headers 提供所有数据,并且不存在任何部分 headers。 因此,如果您只需要处理核心文件,您可以选择在计算文件大小时忽略部分 headers。

正在计算核心转储文件大小

计算ELF文件大小:

  1. 考虑文件中的所有块:
    • 区块描述(偏移+大小)
    • ELF 文件 header (0 + e_ehsize)(ELF32 为 52,ELF64 为 64)
    • 程序 header table (e_phoff + e_phentsize * e_phnum)
    • 程序数据块(又名 "segments")(p_offset + p_filesz)
    • headertable部分(e_shoff+e_shentsize*e_shnum)-核心文件不需要
    • 节数据块 - (sh_offset + sh_size) - 核心文件不需要
  2. 删除 header 的 sh_type 为 SHT_NOBITS 的任何部分,因为这些部分仅用于记录已被剥离且不再存在于中的数据的位置文件(不需要核心文件)。
  3. 消除任何大小为 0 的块,因为它们不包含可寻址字节,因此它们的文件偏移量无关紧要。
  4. 文件的末尾将是最后一个块的末尾,这是上面列出的所有剩余块的偏移量 + 大小的最大值。

如果您发现程序 header 或部分 header table 的偏移量超过了文件末尾,那么您将无法计算出预期的文件大小,但您会知道该文件已被截断。

虽然 ELF 文件可能包含未寻址的区域并且比计算的大小更长,但根据我有限的经验,文件的大小与上述方法计算的大小完全相同。

核心文件被截断

gdb 可能会执行与上述类似的计算来计算预期的核心文件大小。

简而言之,如果gdb说你的核心文件被截断了,那很有可能是被截断了

核心转储文件被截断的最可能原因之一是系统 ulimit。这可以在 /etc/security/limits.conf 中以 system-wide 为基础设置,或者使用 ulimit shell 命令以 per-user 为基础设置 [脚注:我对系统一无所知除了我自己的。

尝试命令 "ulimit -c" 检查您的有效核心文件大小限制:

$ ulimit -c
unlimited

此外,值得注意的是,gdb 实际上并没有因为核心文件被截断而拒绝运行。 gdb 仍会尝试生成堆栈回溯,在您的情况下,只有当它尝试访问堆栈上的数据并发现所寻址的特定内存位置不在截断核心文件的末尾时才会失败。

突出显示用于解决类似问题的 Whosebug 的答案 How to get core file greater than 2GB。根据作者的说法,通过更改默认 /etc/systemd/coredump.conf

来解决截断或覆盖问题