[英]How do I analyze a program's core dump file with GDB when it has command-line parameters?
My program operates like this:我的程序是这样运行的:
exe -p param1 -i param2 -o param3
It crashed and generated a core dump file, core.pid
.它崩溃并生成了核心转储文件core.pid
。
I want to analyze the core dump file by我想分析核心转储文件
gdb ./exe -p param1 -i param2 -o param3 core.pid
But GDB recognizes the parameters of the EXE file as GDB's input.但是GDB将EXE文件的参数识别为GDB的输入。
How do I analyze a core dump file in this situation?在这种情况下如何分析核心转储文件?
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.您可以通过多种方式将核心与 GDB 一起使用,但是将要传递给可执行文件的参数传递给 GDB 并不是使用核心文件的方式。 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> <core-file>
或gdb <executable> -c <core-file>
或
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).崩溃场景显示在 GDB 中(在 Ubuntu 上使用 GDB 7.1 版进行检查)。
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
.如果要将参数传递给要在 GDB 中调试的可执行文件,请使用--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.手册页将有助于查看其他 GDB 选项。
Simple usage of GDB, to debug coredump files: GDB的简单用法,调试coredump文件:
gdb <executable_path> <coredump_file_path>
A coredump file for a "process" gets created as a "core.pid" file. “进程”的核心转储文件被创建为“core.pid”文件。
After you get inside the GDB prompt (on execution of the above command), type:进入 GDB 提示符后(在执行上述命令时),键入:
...
(gdb) where
This will get you with the information, of the stack, where you can analayze the cause of the crash/fault.这将为您提供堆栈信息,您可以在其中分析崩溃/故障的原因。 Other command, for the same purposes is:出于相同目的的其他命令是:
...
(gdb) bt full
This is the same as above.这与上述相同。 By convention, it lists the whole stack information (which ultimately leads to the crash location).按照惯例,它会列出整个堆栈信息(最终会导致崩溃位置)。
objdump
+ gdb
minimal runnable example objdump
+ gdb
最小可运行示例
TL;DR:特尔;博士:
objdump -s core
can be used to dump memory in bulk objdump -s core
可用于批量转储内存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);
}
Compile, and run to generate core:编译并运行以生成核心:
gcc -ggdb3 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
ulimit -c unlimited
rm -f core
./main.out
Output:输出:
text addr: 0x4007d4
data addr: 0x7ffec6739220
mmap addr: 0x1612010
Segmentation fault (core dumped)
GDB points us to the exact line where the segmentation fault happened, which is what most users want while debugging: GDB 将我们指向发生分段错误的确切行,这是大多数用户在调试时想要的:
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
which points us directly to the buggy line 7.这将我们直接指向了错误的第 7 行。
CLI arguments are stored in the core file and don't need to be passed again CLI 参数存储在核心文件中,不需要再次传递
To answer the specific CLI argument questions, we see that if we change the cli arguments eg with:为了回答特定的 CLI 参数问题,我们看到如果我们更改 cli 参数,例如:
rm -f core
./main.out 1 2
then this does get reflected in the previous bactrace without any changes in our commands:那么这确实反映在之前的 bactrace 中,而我们的命令没有任何变化:
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
.所以请注意现在如何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.我猜它只是将它存储为main
的参数,就像它存储任何其他函数的参数一样。
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:不太明显的是如何检查环境变量: 如何从核心转储中获取环境变量环境变量也存在于内存中,因此 objdump 确实包含该信息,但我不确定如何方便地一次性列出所有这些信息, 一一如下确实适用于我的测试:
p __environ[0]
Binutils analysis Binutils 分析
By using binutils tools like readelf
and objdump
, we can bulk dump information contained in the core
file such as the memory state.通过使用像readelf
和objdump
这样的 binutils 工具,我们可以批量转储core
文件中包含的信息,例如内存状态。
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.大部分/全部也必须通过 GDB 可见,但那些 binutils 工具提供了更大量的方法,这对于某些用例来说很方便,而 GDB 更方便进行更具交互性的探索。
First:第一的:
file core
tells us that the core
file is actually an ELF file:告诉我们core
文件实际上是一个ELF文件:
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.这就是为什么我们能够使用通常的 binutils 工具更直接地检查它。
A quick look at the ELF standard shows that there is actually an ELF type dedicated to it:快速浏览一下ELF 标准会发现实际上有一个 ELF 类型专用于它:
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 :并且笔记区域中存在更多元数据, 特别是prstatus
包含 PC :
Displaying notes found at file offset 0x00000468 with length 0x00000b9c:
Owner Data size Description
CORE 0x00000150 NT_PRSTATUS (prstatus structure)
CORE 0x00000088 NT_PRPSINFO (prpsinfo structure)
CORE 0x00000080 NT_SIGINFO (siginfo_t data)
CORE 0x00000130 NT_AUXV (auxiliary vector)
CORE 0x00000246 NT_FILE (mapped files)
Page size: 4096
Start End Page Offset
0x0000000000400000 0x0000000000401000 0x0000000000000000
/home/ciro/test/main.out
0x0000000000600000 0x0000000000601000 0x0000000000000000
/home/ciro/test/main.out
0x0000000000601000 0x0000000000602000 0x0000000000000001
/home/ciro/test/main.out
0x00007f8d939ee000 0x00007f8d93bae000 0x0000000000000000
/lib/x86_64-linux-gnu/libc-2.23.so
0x00007f8d93bae000 0x00007f8d93dae000 0x00000000000001c0
/lib/x86_64-linux-gnu/libc-2.23.so
0x00007f8d93dae000 0x00007f8d93db2000 0x00000000000001c0
/lib/x86_64-linux-gnu/libc-2.23.so
0x00007f8d93db2000 0x00007f8d93db4000 0x00000000000001c4
/lib/x86_64-linux-gnu/libc-2.23.so
0x00007f8d93db8000 0x00007f8d93dde000 0x0000000000000000
/lib/x86_64-linux-gnu/ld-2.23.so
0x00007f8d93fdd000 0x00007f8d93fde000 0x0000000000000025
/lib/x86_64-linux-gnu/ld-2.23.so
0x00007f8d93fde000 0x00007f8d93fdf000 0x0000000000000026
/lib/x86_64-linux-gnu/ld-2.23.so
CORE 0x00000200 NT_FPREGSET (floating point registers)
LINUX 0x00000340 NT_X86_XSTATE (x86 XSAVE extended state)
objdump
can easily dump all memory with: objdump
可以轻松地转储所有内存:
objdump -s core
which contains:其中包含:
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.它与我们运行中的 stdout 值完全匹配。
This was tested on Ubuntu 16.04 amd64, GCC 6.4.0, and binutils 2.26.1.这在 Ubuntu 16.04 amd64、GCC 6.4.0 和 binutils 2.26.1 上进行了测试。
Just skip the parameters.直接跳过参数。 GDB doesn't need them: GDB 不需要它们:
gdb ./exe core.pid
A slightly different approach will allow you to skip GDB entirely.稍微不同的方法将允许您完全跳过 GDB。 If all you want is a backtrace, the Linux-specific utility 'catchsegv' will catch SIGSEGV and display a backtrace.如果您只需要回溯,Linux 特定的实用程序“catchsegv”将捕获 SIGSEGV 并显示回溯。
From RMS's GDB debugger tutorial :来自RMS 的 GDB 调试器教程:
prompt > myprogram
Segmentation fault (core dumped)
prompt > gdb myprogram
...
(gdb) core core.pid
...
Make sure your file really is a core
image -- check it using file
.确保您的文件确实是core
映像 - 使用file
检查。
It doesn't matter if the executable has arguments or not.可执行文件是否有参数并不重要。 To run GDB on any binary with a generated core file, the syntax is below.要使用生成的核心文件在任何二进制文件上运行 GDB,语法如下。
Syntax:
gdb <binary name> <generated core file>
Eg:
gdb l3_entity 6290-corefile
Let me take the below example for more understanding.让我以下面的例子来加深理解。
bash-4.1$ **gdb l3_entity 6290-corefile**
**Core was generated** by `/dir1/dir2/dir3/l3_entity **Program terminated with signal SIGABRT, Aborted.**
#0
#1
#2
#3
#4
#5
#6
#7
#8
#9
#10
(gdb)
From the above output, you can guess something about core, whether it is a NULL access, SIGABORT, etc..从上面的输出,你可以猜到一些关于core的东西,是否是NULL访问,SIGABORT等等。
These numbers #0 to #10 are the stack frames of GDB.这些数字#0 到#10 是 GDB 的堆栈帧。 These stack frames are not of your binary.这些堆栈帧不是您的二进制文件。 In the above 0 - 10 frames if you suspect anything wrong select that frame在上面的 0 - 10 帧中,如果您怀疑有任何错误,请选择该帧
(gdb) frame 8
Now to see more details about it:现在查看有关它的更多详细信息:
(gdb) list +
To investigate the issue further, you can print the suspected variable values here at this point in time.要进一步调查该问题,您可以在此时在此处打印可疑的变量值。
(gdb) print thread_name
Simply type the command:只需键入命令:
$ gdb <Binary> <codeDump>
Or或者
$ gdb <binary>
$ gdb) core <coreDump>
There isn't any need to provide any command line argument.不需要提供任何命令行参数。 The code dump generated due to an earlier exercise.由于先前的练习而生成的代码转储。
我只使用coredumpctl debug
(在 Fedora 32 上),它给了我一个 GDB 控制台来调试我最近的核心转储。
You can analyze the core dump file using the "gdb" command.您可以使用“gdb”命令分析核心转储文件。
gdb - The GNU Debugger
syntax:
# gdb executable-file core-file
example: # gdb out.txt core.xxx
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.