简体   繁体   English

当程序具有命令行参数时,如何使用 GDB 分析程序的核心转储文件?

[英]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:特尔;博士:

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.通过使用像readelfobjdump这样的 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.

相关问题 崩溃时如何将程序的核心转储保存到文件中? - How do I have my program's core dump saved to a file upon a crash? 如何在 Fedora 中分析核心转储文件 - How to analyze a core dump file in fedora 如何使用GDB生成核心转储文件时限制核心转储文件的大小 - How to limit the size of core dump file when generating it using GDB 命令行参数中“-”(破折号)的神奇之处是什么? - What's the magic of "-" (a dash) in command-line parameters? 在Linux上的gdb中加载核心文件时,如何在库路径前添加目录 - How do I prepend a directory the library path when loading a core file in gdb on Linux 如何分析核心转储中的内存使用情况? - How to analyze memory usage from a core dump? 调用gdb时是否可以从命令行参数“关闭打印线程事件”? - Is it possible to 'set print thread-events off' from the command-line arguments when invoking gdb? SSH进入系统时,是否可以像我执行VIM那样从命令行启动Netbeans? - When SSHing into system, is there a way to launch netbeans from command-line like I do VIM? PySpark:如何在工人上安装linux命令行工具? - PySpark: How do I install a linux command-line tool on workers? 如何使用编译器的命令行选项禁用易失性存储类? - How do I disable the volatile storage class using command-line options to the compiler?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM