如何在GDB具有命令行参数的情况下分析程序的核心转储文件?

时间:2011-11-29 04:29:02

标签: linux debugging gdb coredump

我的程序运行如下:

exe -p param1 -i param2 -o param3

崩溃并生成核心转储文件core.pid

我想通过

分析核心转储文件
gdb ./exe -p param1 -i param2 -o param3 core.pid

但是GDB将EXE文件的参数识别为GDB的输入。

在这种情况下如何分析核心转储文件?

10 个答案:

答案 0 :(得分:155)

您可以通过多种方式将核心与gdb一起使用,但将要传递给可执行文件的参数传递给gdb不是使用核心文件的方法。这也可能是你遇到这个错误的原因。您可以通过以下方式使用核心文件:
gdb <executable> <core-file>gdb <executable> -c <core-file>

gdb <executable>
...
(gdb) core <core-file>

使用核心文件时,您不必传递参数。崩溃场景显示在gdb中(使用Ubuntu上的gdb版本7.1进行检查)。 例如:

$ ./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) 

如果要将参数传递给要在gdb中调试的可执行文件,请使用--args 例如:

$ 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) 

手册页有助于查看其他gdb选项。

答案 1 :(得分:26)

简单使用GDB,调试coredump文件:

gdb <executable_path> <coredump_file_path>

&#34;进程&#34;的Coredump文件得到了创造,作为&#34; core.pid&#34;文件。 进入gdb-prompt后,(在执行上述命令时),键入;

...
(gdb) where

这将为您提供堆栈信息,您可以在其中分析崩溃/故障的原因。 其他命令,用于相同目的;

...
(gdb) bt full

这与上述相同。按照惯例,它列出了整个堆栈信息(最终导致崩溃位置)。

答案 2 :(得分:20)

跳过params,gdb不需要它们:

gdb ./exe core.pid

答案 3 :(得分:10)

来自RMS's gdb Debugger Tutorial

prompt > myprogram
Segmentation fault (core dumped)
prompt > gdb myprogram
...
(gdb) core core.pid
...

确保您的文件确实是core图片 - 请使用file进行检查。

答案 4 :(得分:9)

稍微不同的方法将允许您完全跳过GDB。如果你想要的只是一个回溯,那么linux特定的实用程序'catchsegv'将捕获SIGSEGV并显示一个回溯。

答案 5 :(得分:3)

可执行文件是否具有参数并不重要,要在任何具有生成的核心文件的二进制文件上运行GDB语法如下所示。

Syntax: 
gdb <binary name> <generated core file>    
Eg: 
gdb l3_entity 6290-corefile    

让我以下面的例子来加深理解。

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)

从上面的输出中,你可以猜出核心是关于它是NULL访问还是SIGABORT等。

这些数字#0到#10是GDB的堆栈帧。这些堆栈帧不是您的二进制文件。如果您怀疑有任何错误,请在上述0-10帧中选择该帧

(gdb) frame 8 

现在查看有关它的更多详细信息:

(gdb) list + 

要进一步调查问题,您可以在此时打印可疑变量值。

(gdb) print thread_name 

答案 6 :(得分:3)

http://localhost + <span class="dt-time">{{ entity.created_at | utcTimeConversion: utcOffset : "MMM DD YYYY"}}</span> 最小的可运行示例

TL; DR:

现在进行完整的教育测试设置:

main.c

gdb

编译并运行以生成内核:

objdump -s core

输出:

#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);
}

GDB将我们指向发生段错误的确切行,这是大多数用户在调试时想要的行:

gcc -ggdb3 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
ulimit -c unlimited
rm -f core
./main.out

然后:

text addr: 0x4007d4
data addr: 0x7ffec6739220
mmap addr: 0x1612010
Segmentation fault (core dumped)

直接将我们指向越野车第7行。

Binutils分析

第一:

gdb -q -nh main.out core

告诉我们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 文件实际上是ELF文件:

file core

这就是为什么我们能够使用常规的binutils工具直接对其进行检查。

快速浏览ELF standard会发现实际上有一种专用于它的ELF类型:

core

更多格式信息可以在以下位置找到:

core: ELF 64-bit LSB core file x86-64, version 1 (SYSV), SVR4-style, from './main.out'

然后:

Elf32_Ehd.e_type == ET_CORE

给出有关文件结构的一些提示。内存似乎包含在常规程序头中:

man 5 core

,并且在注释区域中还有一些元数据。值得注意的是,我猜PC必须在那里(TODO确认):

readelf -Wa core

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 可以轻松地通过以下方式转储所有内存:

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

与我们运行中的stdout值完全匹配。

在Ubuntu 16.04 amd64,GCC 6.4.0,binutils 2.26.1中进行了测试。

答案 7 :(得分:0)

您可以使用“gdb”命令分析核心转储文件。

 gdb - The GNU Debugger

 syntax:

 # gdb executable-file core-file

 ex: # gdb out.txt core.xxx 

感谢。

答案 8 :(得分:0)

只需输入命令

即可
$ gdb <Binary> <codeDump>

$ gdb <binary>

$ gdb) core <coreDump>

无需提供任何命令行争论。由于之前的练习而生成的代码转储。

答案 9 :(得分:0)

我只使用 coredumpctl debug(在 Fedora 32 上),它为我提供了一个 GDB 控制台来调试我最近的核心转储。