我正在使用核心转储进行调试,请注意,gdb需要您提供可执行文件以及核心转储。为什么是这样?如果核心转储包含该进程使用的所有内存,那么核心转储中是否包含可执行文件?也许不能保证整个exe文件都已加载到内存中(尽管单个可执行文件通常不会那么大),或者核心转储毕竟不包含所有相关内存?是否用于符号(也许它们没有正常加载到内存中)?
我正在使用核心转储进行调试,请注意,gdb需要您提供可执行文件以及核心转储。为什么是这样?如果核心转储包含该进程使用的所有内存,那么核心转储中是否包含可执行文件?也许不能保证整个exe文件都已加载到内存中(尽管单个可执行文件通常不会那么大),或者核心转储毕竟不包含所有相关内存?是否用于符号(也许它们没有正常加载到内存中)?
Answers:
核心转储只是程序内存占用的转储,如果您知道所有内容都在哪里,则可以使用它。
您使用可执行文件是因为它解释了事物(在逻辑地址方面)在内存中的位置,即核心文件。
如果使用命令objdump
,它将转储有关正在调查的可执行对象的元数据。以名为a.out的可执行对象为例。
objdump -h a.out
仅转储标题信息,您将看到名为eg的部分。.data或.bss或.text(还有更多)。这些通知内核加载程序在对象中的哪个地方可以找到各个节,应该在进程地址空间中的哪个地方加载该节,以及对于某些节(例如.data .text)应该加载什么。(.bss节在文件中不包含任何数据,但它指的是在进程中为未初始化的数据保留的内存量,它用零填充)。
可执行目标文件的布局符合标准ELF。
objdump -x a.out
-倾倒一切
如果可执行对象仍然包含其符号表(尚未剥离,man strip
并且您曾经-g
生成调试生成以gcc
假定使用ac源编译),则可以按符号名称检查核心内容,例如,是否有变量/缓冲区在源代码中名为inputLine的情况下,您可以使用该名称gdb
查看其内容。即gdb
会知道从程序初始化的数据段(其中inputLine开始)的起点的偏移量以及该变量的长度。
进一步阅读第1 条, 第2条,以及更具体的可执行和链接格式(ELF)规范。
在@mirabilos评论后更新。
但是如果像这样使用符号表
$ gdb --batch -s a.out -c core -q -ex "x buf1"
产生
0x601060 <buf1>: 0x72617453
然后不使用符号表并直接检查地址,
$ gdb --batch -c core -q -ex "x 0x601060"
产生
0x601060: 0x72617453
我直接检查了内存,没有使用第二个命令中的符号表。
我也看到,@ user580082的答案进一步说明了这一点,并将投票赞成。
核心文件是进程终止时堆栈映像,内存映射和寄存器的快照。其内容可以按照核心手册页中的说明进行操作。默认情况下,私有映射,共享映射和ELF标头信息被转储到核心文件中。
谈到您的问题,gdb需要可执行文件的原因是因为它不像valgrind那样通过读取和解释二进制指令来模拟执行,相反它成为了进程的父级,从而在运行期间控制了进程的行为时间。它使用核心文件来确定崩溃期间的内存映射和进程的处理器状态。
在Linux中,父进程可以获得有关其子进程的其他信息,特别是ptrace的能力,这使调试器可以访问进程的底层信息,例如读/写其内存,寄存器,更改信号映射,停止其执行等。
阅读任何调试器的工作原理后,尽管拥有更多核心文件,您将了解可执行文件的要求。
(除了其他好的答案)
在现代Linux(以及许多类似Unix的系统)上,调试信息(包括有关符号类型,源代码位置,变量类型等的元数据)是DWARF格式,位于ELF可执行文件(或ELF共享库)时使用某些-g
选项进行编译。我建议编译要调试的程序,如果使用最新的GCC,-g3 -O0
也可能要调试;但是,使用GCC,您甚至可以同时编译优化和调试信息,例如使用,尽管在这种情况下调试信息可能有点“模糊”(这可能会有助于捕获一些顽皮的Heisenbugs)。-fno-inline
-O2 -g1
避免将这些信息放在核心文件中是非常明智的,因为core
对于同一个可执行文件,您可能会有许多不同的核心文件(想象一个使用广泛的软件,有许多用户在进行错误报告,其中大多数用户使用转储)。此外核心(5)文件由内核,这不应该关心矮部分存在倾销精灵(5)可执行文件(因为这些部分不映射到虚拟地址空间的断层的过程,其倾倒在一些核心信号( 7))。甚至有可能将调试信息放在单独的文件中(在可执行文件之外)。
顺便说一句,GDB可以很痛苦地用于调试没有任何调试信息的可执行文件的核心转储。但是实际上您是在机器代码级别(而不是编程语言及其编译器提供的符号级别)进行调试的。