I'm debugging using core dumps, and note that gdb needs you to supply the executable as well as the core dump. Why is this? If the core dump contains all the memory that the process uses, isn't the executable contained within the core dump? Perhaps there's no guarantee that the whole exe is loaded into memory (individual executables are not usually that big though) or maybe the core dump doesn't contain all relevant memory after all? Is it for the symbols (perhaps they're not loaded into memory normally)?
The core dump is just the dump of your programs memory footprint, if you know where everything was then you could just use that.
You use the executable because it explains where (in terms of logical addresses) things are located in memory, i.e. the core file.
If you use a command
objdump it will dump the meta data about the executable object you are investigating.
Using an executable object named a.out as an example.
objdump -h a.out dumps the header information only, you will see sections named eg. .data or .bss or .text (there are many more). These inform the kernel loader where in the object various sections can be found and where in the process address space the section should be loaded, and for some sections (eg .data .text) what should be loaded. (.bss section doesn't contain any data in the file but it refers to the amount of memory to reserve in the process for uninitialised data, it is filled with zeros ).
The layout of the executable object file conforms to a standard, ELF.
objdump -x a.out - dumps everything
If the executable object still contains its symbol tables (it hasn't been stripped -
man strip and you used
-g to generate debug generation to
assuming a c source compilation), then you can examine the core contents by symbol names, e.g. if you had a variable/buffer named inputLine in your source code, you could use that name in
gdb to look at its content. i.e.
gdb would know the offset from the start of your programs initialised data segment where inputLine starts and the length of that variable.
Update after @mirabilos comment below.
But if using the symbol table as in
$ gdb --batch -s a.out -c core -q -ex "x buf1"
0x601060 <buf1>: 0x72617453
and then not using symbol table and examining address directly in,
$ gdb --batch -c core -q -ex "x 0x601060"
I have examined memory directly without using the symbol table in the 2nd command.
I also see, @user580082 's answer adds further to explanation, and will up-vote.
The core file is a snapshot of the stack image, memory mappings and registers at the time of process termination. The contents of which can be manipulated as given in core man page. By default private mappings, shared mappings and ELF header information is dumped into core file.
Coming to your question, the reason that gdb requires executable is because it doesn't simulate the execution, by reading and interpreting the binary instructions like valgrind does instead it becomes the parent of the process so as to control the behavior of the process during run time. It uses the core file to determine the memory mappings and processor state of process during crash.
In Linux parent processes can get additional information about their children, in particular the ability to ptrace them which allow the debugger to access process's low level information like read/write its memory, registers, change signal mappings, stop its execution etc.
You will understand the requirement of executable inspite of having core file more once you read how any debugger works.
(in addition of other good answers)
On modern Linux (and many Unix-like) systems, the debugging information (including meta-data about symbol's types, source code location, type of variables, etc etc ....) is in DWARF format and sits inside the ELF executable (or ELF shared libraries) when it is compiled with some
-g option. I recommend compiling programs to be debugged with
-g3 -O0 and perhaps
-fno-inline if using a recent GCC; however, with GCC you can even compile with both optimization & debugging info, e.g. with
-O2 -g1, although the debug info might in that case be a bit "fuzzy" (this might slightly help to catch some naughty Heisenbugs).
It is quite sensible to avoid putting that information in core files, because you might have many different core files (imagine a widely used software with many users making bug reports, most of them with a
core dump) for the same executable. Also core(5) files are dumped by the kernel, which should not care about existence of DWARF sections in elf(5) executables (because these sections are not mapped into the virtual address space of the faulting process which dumped core on some signal(7)). There is even the possibility to have the debug information being put in separate files (outside of the executable).
BTW, GDB can be painfully used to debug core dumps for executables without any debug information. But then you practically debug at the machine code level (not at the symbolic level provided by programming languages and their compilers).