You can use the core with GDB in many ways, but passing parameters which is to be passed to the executable to GDB is not the way to use the core file. This could also be the reason you got that error. You can use the core file in the following ways: gdb <executable> <core-file> or gdb <executable> -c <core-file> or
gdb <executable>
...
(gdb) core <core-file>
When using the core file you don't have to pass arguments. The crash scenario is shown in GDB (checked with GDB version 7.1 on Ubuntu). For example:
$ ./crash -p param1 -o param2
Segmentation fault (core dumped)
$ gdb ./crash core
GNU gdb (GDB) 7.1-ubuntu
...
Core was generated by `./crash -p param1 -o param2'. <<<<< See this line shows crash scenario
Program terminated with signal 11, Segmentation fault.
#0 __strlen_ia32 () at ../sysdeps/i386/i686/multiarch/../../i586/strlen.S:99
99 ../sysdeps/i386/i686/multiarch/../../i586/strlen.S: No such file or directory.
in ../sysdeps/i386/i686/multiarch/../../i586/strlen.S
(gdb)
If you want to pass parameters to the executable to be debugged in GDB, use --args . For example:
$ gdb --args ./crash -p param1 -o param2
GNU gdb (GDB) 7.1-ubuntu
...
(gdb) r
Starting program: /home/@@@@/crash -p param1 -o param2
Program received signal SIGSEGV, Segmentation fault.
__strlen_ia32 () at ../sysdeps/i386/i686/multiarch/../../i586/strlen.S:99
99 ../sysdeps/i386/i686/multiarch/../../i586/strlen.S: No such file or directory.
in ../sysdeps/i386/i686/multiarch/../../i586/strlen.S
(gdb)
Man pages will be helpful to see other GDB options. Most useful commands are:
bt (backtrace)
info locals (show values of local variables)
info registers (show values of CPU registers)
frame X (change to stack frame X)
up and down (navigate in the stack frame (call chain))
GDB can be used to find failing line, previously mentioned at: How do I analyze a program's core dump file with GDB when it has command-line parameters?
the core file contains the CLI arguments, no need to pass them again
objdump -s core can be used to dump memory in bulk
Now for the full educational test setup: main.c
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int myfunc(int i) {
*(int*)(NULL) = i; /* line 7 */
return i - 1;
}
int main(int argc, char **argv) {
/* Setup some memory. */
char data_ptr[] = "string in data segment";
char *mmap_ptr;
char *text_ptr = "string in text segment";
(void)argv;
mmap_ptr = (char *)malloc(sizeof(data_ptr) + 1);
strcpy(mmap_ptr, data_ptr);
mmap_ptr[10] = 'm';
mmap_ptr[11] = 'm';
mmap_ptr[12] = 'a';
mmap_ptr[13] = 'p';
printf("text addr: %p\n", text_ptr);
printf("data addr: %p\n", data_ptr);
printf("mmap addr: %p\n", mmap_ptr);
/* Call a function to prepare a stack trace. */
return myfunc(argc);
}
On Ubuntu 22.04, you also need to fight against apport to get your core file: https://askubuntu.com/questions/1349047/where-do-i-find-core-dump-files-and-how-do-i-view-and-analyze-the-backtrace-st/1442665#1442665 e.g. with:
echo 'core' | sudo tee /proc/sys/kernel/core_pattern
and your core is now named as:
core.<pid>
Program output:
text addr: 0x4007d4
data addr: 0x7ffec6739220
mmap addr: 0x1612010
Segmentation fault (core dumped)
GDB points us to the exact line where the segfault happened, which is what most users want while debugging:
gdb -q -nh main.out core
then:
Reading symbols from main.out...done.
[New LWP 27479]
Core was generated by `./main.out'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x0000000000400635 in myfunc (i=1) at main.c:7
7 *(int*)(NULL) = i;
(gdb) bt
#0 0x0000000000400635 in myfunc (i=1) at main.c:7
#1 0x000000000040072b in main (argc=1, argv=0x7ffec6739328) at main.c:28
(gdb) f 1
#1 0x000000000040072b in main (argc=1, argv=0x7ffec6739328) at main.c:28
28 return myfunc(argc);
(gdb) p argc
$1 = 1
which points us directly to the buggy line 7. As you can see from the example, you are now able to inspect program memory at the time of crash to try and determine the cause of failure, the process virtual memory is entirely contained in the core file.
CLI arguments are stored in the core file and don't need to be passed again
To answer the specific CLI argument questions, we see that if we change the cli arguments e.g. with:
rm -f core
./main.out 1 2
then this does get reflected in the previous bactrace without any changes in our commands:
Reading symbols from main.out...done.
[New LWP 21838]
Core was generated by `./main.out 1 2'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x0000564583cf2759 in myfunc (i=3) at main.c:7
7 *(int*)(NULL) = i; /* line 7 */
(gdb) bt
#0 0x0000564583cf2759 in myfunc (i=3) at main.c:7
#1 0x0000564583cf2858 in main (argc=3, argv=0x7ffcca4effa8) at main.c:2
So note how now argc=3 . Therefore this must mean that the core file stores that information. I'm guessing it just stores it as the arguments of main , just like it stores the arguments of any other functions. This makes sense if you consider that the core dump must be storing the entire memory and register state of the program, and so it has all the information needed to determine the value of function arguments on the current stack. Less obvious is how to inspect the environment variables: How to get environment variable from a core dump Environment variables are also present in memory so the objdump does contain that information, but I'm not sure how to list all of them in one go conveniently, one by one as follows did work on my tests though:
p __environ[0]
Binutils analysis
By using binutils tools like readelf and objdump , we can bulk dump information contained in the core file such as the memory state. Most/all of it must also be visible through GDB, but those binutils tools offer a more bulk approach which is convenient for certain use cases, while GDB is more convenient for a more interactive exploration. First:
file core
tells us that the core file is actually an ELF file:
core: ELF 64-bit LSB core file x86-64, version 1 (SYSV), SVR4-style, from './main.out'
which is why we are able to inspect it more directly with usual binutils tools. A quick look at the ELF standard shows that there is actually an ELF type dedicated to it:
Elf32_Ehd.e_type == ET_CORE
Further format information can be found at:
man 5 core
Then:
readelf -Wa core
gives some hints about the file structure. Memory appears to be contained in regular program headers:
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
NOTE 0x000468 0x0000000000000000 0x0000000000000000 0x000b9c 0x000000 0
LOAD 0x002000 0x0000000000400000 0x0000000000000000 0x001000 0x001000 R E 0x1000
LOAD 0x003000 0x0000000000600000 0x0000000000000000 0x001000 0x001000 R 0x1000
LOAD 0x004000 0x0000000000601000 0x0000000000000000 0x001000 0x001000 RW 0x1000
and there is some more metadata present in a notes area, notably prstatus contains the PC:
Contents of section load1:
4007d0 01000200 73747269 6e672069 6e207465 ....string in te
4007e0 78742073 65676d65 6e740074 65787420 xt segment.text
Contents of section load15:
7ffec6739220 73747269 6e672069 6e206461 74612073 string in data s
7ffec6739230 65676d65 6e740000 00a8677b 9c6778cd egment....g{.gx.
Contents of section load4:
1612010 73747269 6e672069 6e206d6d 61702073 string in mmap s
1612020 65676d65 6e740000 11040000 00000000 egment..........
which matches exactly with the stdout value in our run. This was tested on Ubuntu 16.04 amd64, GCC 6.4.0, and binutils 2.26.1.
Mozilla rr reverse debugging as the ultimate "core file"
Core files allow you to inspect the stack at break. But in general what you really need to do is to go back in time to further decide the root failure cause. The amazing Mozilla rr allows you to do that, at the cost of a larger trace file, and a slight performance hit. Example at: How does reverse debugging work?
9条答案
按热度按时间jecbmhm31#
You can use the core with GDB in many ways, but passing parameters which is to be passed to the executable to GDB is not the way to use the core file. This could also be the reason you got that error. You can use the core file in the following ways:
gdb <executable> <core-file>
orgdb <executable> -c <core-file>
orWhen using the core file you don't have to pass arguments. The crash scenario is shown in GDB (checked with GDB version 7.1 on Ubuntu).
For example:
If you want to pass parameters to the executable to be debugged in GDB, use
--args
.For example:
Man pages will be helpful to see other GDB options.
Most useful commands are:
bt
(backtrace)info locals
(show values of local variables)info registers
(show values of CPU registers)frame X
(change to stack frame X)up
anddown
(navigate in the stack frame (call chain))bakd9h0s2#
GDB的简单用法,调试核心转储文件:
A coredump file for a "process" gets created as a "core.pid" file.
进入GDB提示符后(在执行上述命令时),键入:
这将为您提供堆栈的信息,您可以在其中分析崩溃/故障的原因。**其他命令,**用于相同的目的是:
这和上面一样,按照惯例,它列出了整个堆栈信息(最终导致崩溃的位置)。
km0tfn4u3#
objdump
+gdb
minimal runnable exampleTL;DR:
objdump -s core
can be used to dump memory in bulkNow for the full educational test setup:
main.c
Compile, and run to generate core:
On Ubuntu 22.04, you also need to fight against apport to get your core file: https://askubuntu.com/questions/1349047/where-do-i-find-core-dump-files-and-how-do-i-view-and-analyze-the-backtrace-st/1442665#1442665 e.g. with:
and your core is now named as:
Program output:
GDB points us to the exact line where the segfault happened, which is what most users want while debugging:
then:
which points us directly to the buggy line 7.
As you can see from the example, you are now able to inspect program memory at the time of crash to try and determine the cause of failure, the process virtual memory is entirely contained in the core file.
CLI arguments are stored in the core file and don't need to be passed again
To answer the specific CLI argument questions, we see that if we change the cli arguments e.g. with:
then this does get reflected in the previous bactrace without any changes in our commands:
So note how now
argc=3
. Therefore this must mean that the core file stores that information. I'm guessing it just stores it as the arguments ofmain
, just like it stores the arguments of any other functions.This makes sense if you consider that the core dump must be storing the entire memory and register state of the program, and so it has all the information needed to determine the value of function arguments on the current stack.
Less obvious is how to inspect the environment variables: How to get environment variable from a core dump Environment variables are also present in memory so the objdump does contain that information, but I'm not sure how to list all of them in one go conveniently, one by one as follows did work on my tests though:
Binutils analysis
By using binutils tools like
readelf
andobjdump
, we can bulk dump information contained in thecore
file such as the memory state.Most/all of it must also be visible through GDB, but those binutils tools offer a more bulk approach which is convenient for certain use cases, while GDB is more convenient for a more interactive exploration.
First:
tells us that the
core
file is actually an ELF file:which is why we are able to inspect it more directly with usual binutils tools.
A quick look at the ELF standard shows that there is actually an ELF type dedicated to it:
Further format information can be found at:
Then:
gives some hints about the file structure. Memory appears to be contained in regular program headers:
and there is some more metadata present in a notes area, notably
prstatus
contains the PC:objdump
can easily dump all memory with:which contains:
which matches exactly with the stdout value in our run.
This was tested on Ubuntu 16.04 amd64, GCC 6.4.0, and binutils 2.26.1.
Mozilla
rr
reverse debugging as the ultimate "core file"Core files allow you to inspect the stack at break.
But in general what you really need to do is to go back in time to further decide the root failure cause.
The amazing Mozilla rr allows you to do that, at the cost of a larger trace file, and a slight performance hit.
Example at: How does reverse debugging work?
vybvopom4#
跳过参数即可。GDB不需要这些参数:
dced5bon5#
来自RMS的GDB调试器教程:
确保您的文件确实是
core
图像--使用file
检查它。gupuwyp26#
一种稍微不同的方法可以让你完全跳过GDB。如果你只需要一个回溯,Linux专用的实用程序'catchsegv'将捕获SIGSEGV并显示一个回溯。
rjee0c157#
可执行文件是否有参数并不重要。要在任何带有生成的核心文件的二进制文件上运行GDB,语法如下。
让我举下面的例子来更好地理解。
从上面的输出中,你可以猜出一些关于核心的东西,不管它是NULL访问、SIGABORT等等。
这些数字#0到#10是GDB的堆栈帧。这些堆栈帧不是你的二进制。在上面的0 - 10帧中,如果你怀疑有什么不对的地方,选择那个帧
现在来看看更多的细节:
要进一步调查此问题,您可以及时在此处打印可疑的变量值。
tf7tbtn28#
我只是使用
coredumpctl debug
(在Fedora 32上),它给了我一个GDB控制台来调试我最近的核心转储。raogr8fs9#
Simply type the command:
Or
There isn't any need to provide any command line argument. The code dump generated due to an earlier exercise.