为什么我的核心转储缺少 NT_FILE 注释?
Why are my core dumps missing an NT_FILE note?
我在我的 Fedora 系统上设置了 "ulimit -c unlimited",因此段错误会生成核心转储文件。这是有效的。
我在这些 URL 中看到 NT_FILE 注释:
ELF core file format
但我的核心文件只包含这些注释:
$ readelf --notes core.simple.11
Notes at offset 0x000003f8 with length 0x00000558:
Owner Data size Description
CORE 0x00000150 NT_PRSTATUS (prstatus structure)
CORE 0x00000088 NT_PRPSINFO (prpsinfo structure)
CORE 0x00000130 NT_AUXV (auxiliary vector)
CORE 0x00000200 NT_FPREGSET (floating point registers)
为什么没有NT_FILE注释?我如何找出核心文件可能基于的各种目标文件,更重要的是,虚拟地址这些文件在哪里映射到核心映像?
没有 NT_FILE 注释中的地址映射信息,我不知道如何在目标文件的 DWARF 调试信息中执行代码地址查找。
核心文件中的程序头:
$ readelf --segments core.simple.11
Elf file type is CORE (Core file)
Entry point 0x0
There are 17 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
NOTE 0x00000000000003f8 0x0000000000000000 0x0000000000000000
0x0000000000000558 0x0000000000000000 0
LOAD 0x0000000000001000 0x0000000000400000 0x0000000000000000
0x0000000000001000 0x0000000000001000 R E 1000
LOAD 0x0000000000002000 0x0000000000600000 0x0000000000000000
0x0000000000001000 0x0000000000001000 RW 1000
LOAD 0x0000000000003000 0x00000035fe800000 0x0000000000000000
0x0000000000001000 0x000000000001e000 R E 1000
LOAD 0x0000000000004000 0x00000035fea1d000 0x0000000000000000
0x0000000000001000 0x0000000000001000 R 1000
LOAD 0x0000000000005000 0x00000035fea1e000 0x0000000000000000
0x0000000000001000 0x0000000000001000 RW 1000
LOAD 0x0000000000006000 0x00000035fea1f000 0x0000000000000000
0x0000000000001000 0x0000000000001000 RW 1000
LOAD 0x0000000000007000 0x00000035fec00000 0x0000000000000000
0x0000000000001000 0x0000000000173000 R E 1000
LOAD 0x0000000000008000 0x00000035fed73000 0x0000000000000000
0x0000000000000000 0x00000000001ff000 1000
LOAD 0x0000000000008000 0x00000035fef72000 0x0000000000000000
0x0000000000004000 0x0000000000004000 R 1000
LOAD 0x000000000000c000 0x00000035fef76000 0x0000000000000000
0x0000000000001000 0x0000000000001000 RW 1000
LOAD 0x000000000000d000 0x00000035fef77000 0x0000000000000000
0x0000000000005000 0x0000000000005000 RW 1000
LOAD 0x0000000000012000 0x00007fc22db59000 0x0000000000000000
0x0000000000003000 0x0000000000003000 RW 1000
LOAD 0x0000000000015000 0x00007fc22db6c000 0x0000000000000000
0x0000000000001000 0x0000000000001000 RW 1000
LOAD 0x0000000000016000 0x00007fff81c40000 0x0000000000000000
0x0000000000016000 0x0000000000016000 RW 1000
LOAD 0x000000000002c000 0x00007fff81dee000 0x0000000000000000
0x0000000000001000 0x0000000000001000 R E 1000
LOAD 0x000000000002d000 0xffffffffff600000 0x0000000000000000
0x0000000000000000 0x0000000000001000 R E 1000
可执行文件中的程序头:
$ readelf --segments simple
Elf file type is EXEC (Executable file)
Entry point 0x400390
There are 8 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000001c0 0x00000000000001c0 R E 8
INTERP 0x0000000000000200 0x0000000000400200 0x0000000000400200
0x000000000000001c 0x000000000000001c R 1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x0000000000000674 0x0000000000000674 R E 200000
LOAD 0x0000000000000678 0x0000000000600678 0x0000000000600678
0x00000000000001e4 0x00000000000001f8 RW 200000
DYNAMIC 0x00000000000006a0 0x00000000006006a0 0x00000000006006a0
0x0000000000000190 0x0000000000000190 RW 8
NOTE 0x000000000000021c 0x000000000040021c 0x000000000040021c
0x0000000000000044 0x0000000000000044 R 4
GNU_EH_FRAME 0x00000000000005a8 0x00000000004005a8 0x00000000004005a8
0x000000000000002c 0x000000000000002c R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 8
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
03 .ctors .dtors .jcr .dynamic .got .got.plt .data .bss
04 .dynamic
05 .note.ABI-tag .note.gnu.build-id
06 .eh_frame_hdr
07
我的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
Why is there no NT_FILE note?
正如 Mark Plotnick 所指出的,这是一个相当新的内核添加。
GDB 绝对不需要 NT_FILE
注释(事实上,当前的 GDB 似乎根本不使用 NT_FILE
,除非 writing 使用 gcore
命令的核心文件)。
How can I figure out the various object files the core file may be based on, and more importantly, the virtual addresses where those files were mapped into the core image?
GDB 的工作方式是查看 core
中的主要可执行文件 PT_DYNAMIC
,从中提取 DT_DEBUG
,然后为它提供指向 _r_debug
,其中包含 struct link_map
的链表 r_map
,链表中的每个节点都描述了加载的 ELF 文件。
(gdb) info shared
命令将显示上述信息的解码版本,但您需要提供匹配的二进制文件:core
本身不包含足够的信息。
现在,你的问题不是很清楚,可以有几种不同的理解方式。
可能是:"I have a core, which application crashed?"使用file core
希望路径名的前16个字符足够。如果这还不够,运行ning strings core
通常会揭示是哪个应用程序生成的。您还应该考虑将 /proc/sys/kernel/core_pattern
设置为包含 %e
或 %E
的内容,这样以后这个问题就很容易回答了。
可能是:"I have several versions of application foo
, and want to know which version of foo
produced this particular core"。在这种情况下,您应该将 foo
与 -Wl,--build-id
链接器标志链接起来。该标志在 foo
二进制文件中创建 NT_GNU_BUILD_ID
注释。该注释保留 strip
,并且也保存在核心文件中。然后您可以 运行 eu-unstrip -n --core /path/to/core
,这将产生如下输出:
eu-unstrip -n --core core
0x400000+0x208000 c266a51e4b85b16ca17bff8328f3abeafb577b29@0x400284 - - [exe]
0x7ffe3f7d9000+0x1000 7f14688f101a2ace5cad23dfbfbc918616651576@0x7ffe3f7d9340 . - linux-vdso.so.1
0x7fb5b6ec3000+0x2241c8 d0f537904076d73f29e4a37341f8a449e2ef6cd0@0x7fb5b6ec31d8 /lib64/ld-linux-x86-64.so.2 /usr/lib/debug/lib/x86_64-linux-gnu/ld-2.19.so ld-linux-x86-64.so.2
0x7fb5b6afe000+0x3c42c0 cf699a15caae64f50311fc4655b86dc39a479789@0x7fb5b6afe280 /lib/x86_64-linux-gnu/libc.so.6 /usr/lib/debug/lib/x86_64-linux-gnu/libc-2.19.so libc.so.6
从上面的输出中,您可以确切地知道使用了哪些 ELF 二进制文件,和它们在内存中的加载位置。
P.S。我刚刚尝试从使用 -Wl,--build-id=none
构建的 a.out
中转储核心,结果 eu-unstrip
输出仍然非常有用:
eu-unstrip -n --core core
0x400000+0x202000 - - - [exe]
0x7fff5e1a0000+0x1000 7f14688f101a2ace5cad23dfbfbc918616651576@0x7fff5e1a0340 . - linux-vdso.so.1
0x7fbda432d000+0x2241c8 d0f537904076d73f29e4a37341f8a449e2ef6cd0@0x7fbda432d1d8 /lib64/ld-linux-x86-64.so.2 /usr/lib/debug/lib/x86_64-linux-gnu/ld-2.19.so ld-linux-x86-64.so.2
0x7fbda3f68000+0x3c42c0 cf699a15caae64f50311fc4655b86dc39a479789@0x7fbda3f68280 /lib/x86_64-linux-gnu/libc.so.6 /usr/lib/debug/lib/x86_64-linux-gnu/libc-2.19.so libc.so.6
更新:
There is no PT_DYNAMIC program header in my core file itself,
不,但是 PT_DYNAMIC
是一个 可写 段 @0x6006a0
。该段实际上是(由动态加载程序)写入的,因此总是保存在 core
中(作为其他修改后的数据)。
在您的情况下,内容位于 PT_LOAD
段 @0x600000
中(即 core
中文件偏移 0x2000
处的段)。
我在我的 Fedora 系统上设置了 "ulimit -c unlimited",因此段错误会生成核心转储文件。这是有效的。
我在这些 URL 中看到 NT_FILE 注释:
ELF core file format
但我的核心文件只包含这些注释:
$ readelf --notes core.simple.11
Notes at offset 0x000003f8 with length 0x00000558:
Owner Data size Description
CORE 0x00000150 NT_PRSTATUS (prstatus structure)
CORE 0x00000088 NT_PRPSINFO (prpsinfo structure)
CORE 0x00000130 NT_AUXV (auxiliary vector)
CORE 0x00000200 NT_FPREGSET (floating point registers)
为什么没有NT_FILE注释?我如何找出核心文件可能基于的各种目标文件,更重要的是,虚拟地址这些文件在哪里映射到核心映像?
没有 NT_FILE 注释中的地址映射信息,我不知道如何在目标文件的 DWARF 调试信息中执行代码地址查找。
核心文件中的程序头:
$ readelf --segments core.simple.11
Elf file type is CORE (Core file)
Entry point 0x0
There are 17 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
NOTE 0x00000000000003f8 0x0000000000000000 0x0000000000000000
0x0000000000000558 0x0000000000000000 0
LOAD 0x0000000000001000 0x0000000000400000 0x0000000000000000
0x0000000000001000 0x0000000000001000 R E 1000
LOAD 0x0000000000002000 0x0000000000600000 0x0000000000000000
0x0000000000001000 0x0000000000001000 RW 1000
LOAD 0x0000000000003000 0x00000035fe800000 0x0000000000000000
0x0000000000001000 0x000000000001e000 R E 1000
LOAD 0x0000000000004000 0x00000035fea1d000 0x0000000000000000
0x0000000000001000 0x0000000000001000 R 1000
LOAD 0x0000000000005000 0x00000035fea1e000 0x0000000000000000
0x0000000000001000 0x0000000000001000 RW 1000
LOAD 0x0000000000006000 0x00000035fea1f000 0x0000000000000000
0x0000000000001000 0x0000000000001000 RW 1000
LOAD 0x0000000000007000 0x00000035fec00000 0x0000000000000000
0x0000000000001000 0x0000000000173000 R E 1000
LOAD 0x0000000000008000 0x00000035fed73000 0x0000000000000000
0x0000000000000000 0x00000000001ff000 1000
LOAD 0x0000000000008000 0x00000035fef72000 0x0000000000000000
0x0000000000004000 0x0000000000004000 R 1000
LOAD 0x000000000000c000 0x00000035fef76000 0x0000000000000000
0x0000000000001000 0x0000000000001000 RW 1000
LOAD 0x000000000000d000 0x00000035fef77000 0x0000000000000000
0x0000000000005000 0x0000000000005000 RW 1000
LOAD 0x0000000000012000 0x00007fc22db59000 0x0000000000000000
0x0000000000003000 0x0000000000003000 RW 1000
LOAD 0x0000000000015000 0x00007fc22db6c000 0x0000000000000000
0x0000000000001000 0x0000000000001000 RW 1000
LOAD 0x0000000000016000 0x00007fff81c40000 0x0000000000000000
0x0000000000016000 0x0000000000016000 RW 1000
LOAD 0x000000000002c000 0x00007fff81dee000 0x0000000000000000
0x0000000000001000 0x0000000000001000 R E 1000
LOAD 0x000000000002d000 0xffffffffff600000 0x0000000000000000
0x0000000000000000 0x0000000000001000 R E 1000
可执行文件中的程序头:
$ readelf --segments simple
Elf file type is EXEC (Executable file)
Entry point 0x400390
There are 8 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000001c0 0x00000000000001c0 R E 8
INTERP 0x0000000000000200 0x0000000000400200 0x0000000000400200
0x000000000000001c 0x000000000000001c R 1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x0000000000000674 0x0000000000000674 R E 200000
LOAD 0x0000000000000678 0x0000000000600678 0x0000000000600678
0x00000000000001e4 0x00000000000001f8 RW 200000
DYNAMIC 0x00000000000006a0 0x00000000006006a0 0x00000000006006a0
0x0000000000000190 0x0000000000000190 RW 8
NOTE 0x000000000000021c 0x000000000040021c 0x000000000040021c
0x0000000000000044 0x0000000000000044 R 4
GNU_EH_FRAME 0x00000000000005a8 0x00000000004005a8 0x00000000004005a8
0x000000000000002c 0x000000000000002c R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 8
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
03 .ctors .dtors .jcr .dynamic .got .got.plt .data .bss
04 .dynamic
05 .note.ABI-tag .note.gnu.build-id
06 .eh_frame_hdr
07
我的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
Why is there no NT_FILE note?
正如 Mark Plotnick 所指出的,这是一个相当新的内核添加。
GDB 绝对不需要 NT_FILE
注释(事实上,当前的 GDB 似乎根本不使用 NT_FILE
,除非 writing 使用 gcore
命令的核心文件)。
How can I figure out the various object files the core file may be based on, and more importantly, the virtual addresses where those files were mapped into the core image?
GDB 的工作方式是查看 core
中的主要可执行文件 PT_DYNAMIC
,从中提取 DT_DEBUG
,然后为它提供指向 _r_debug
,其中包含 struct link_map
的链表 r_map
,链表中的每个节点都描述了加载的 ELF 文件。
(gdb) info shared
命令将显示上述信息的解码版本,但您需要提供匹配的二进制文件:core
本身不包含足够的信息。
现在,你的问题不是很清楚,可以有几种不同的理解方式。
可能是:"I have a core, which application crashed?"使用file core
希望路径名的前16个字符足够。如果这还不够,运行ning strings core
通常会揭示是哪个应用程序生成的。您还应该考虑将 /proc/sys/kernel/core_pattern
设置为包含 %e
或 %E
的内容,这样以后这个问题就很容易回答了。
可能是:"I have several versions of application foo
, and want to know which version of foo
produced this particular core"。在这种情况下,您应该将 foo
与 -Wl,--build-id
链接器标志链接起来。该标志在 foo
二进制文件中创建 NT_GNU_BUILD_ID
注释。该注释保留 strip
,并且也保存在核心文件中。然后您可以 运行 eu-unstrip -n --core /path/to/core
,这将产生如下输出:
eu-unstrip -n --core core
0x400000+0x208000 c266a51e4b85b16ca17bff8328f3abeafb577b29@0x400284 - - [exe]
0x7ffe3f7d9000+0x1000 7f14688f101a2ace5cad23dfbfbc918616651576@0x7ffe3f7d9340 . - linux-vdso.so.1
0x7fb5b6ec3000+0x2241c8 d0f537904076d73f29e4a37341f8a449e2ef6cd0@0x7fb5b6ec31d8 /lib64/ld-linux-x86-64.so.2 /usr/lib/debug/lib/x86_64-linux-gnu/ld-2.19.so ld-linux-x86-64.so.2
0x7fb5b6afe000+0x3c42c0 cf699a15caae64f50311fc4655b86dc39a479789@0x7fb5b6afe280 /lib/x86_64-linux-gnu/libc.so.6 /usr/lib/debug/lib/x86_64-linux-gnu/libc-2.19.so libc.so.6
从上面的输出中,您可以确切地知道使用了哪些 ELF 二进制文件,和它们在内存中的加载位置。
P.S。我刚刚尝试从使用 -Wl,--build-id=none
构建的 a.out
中转储核心,结果 eu-unstrip
输出仍然非常有用:
eu-unstrip -n --core core
0x400000+0x202000 - - - [exe]
0x7fff5e1a0000+0x1000 7f14688f101a2ace5cad23dfbfbc918616651576@0x7fff5e1a0340 . - linux-vdso.so.1
0x7fbda432d000+0x2241c8 d0f537904076d73f29e4a37341f8a449e2ef6cd0@0x7fbda432d1d8 /lib64/ld-linux-x86-64.so.2 /usr/lib/debug/lib/x86_64-linux-gnu/ld-2.19.so ld-linux-x86-64.so.2
0x7fbda3f68000+0x3c42c0 cf699a15caae64f50311fc4655b86dc39a479789@0x7fbda3f68280 /lib/x86_64-linux-gnu/libc.so.6 /usr/lib/debug/lib/x86_64-linux-gnu/libc-2.19.so libc.so.6
更新:
There is no PT_DYNAMIC program header in my core file itself,
不,但是 PT_DYNAMIC
是一个 可写 段 @0x6006a0
。该段实际上是(由动态加载程序)写入的,因此总是保存在 core
中(作为其他修改后的数据)。
在您的情况下,内容位于 PT_LOAD
段 @0x600000
中(即 core
中文件偏移 0x2000
处的段)。