首页 文章

如何用gdb分析程序的核心转储文件?

提问于
浏览
126

我的程序运行如下:

exe -p param1 -i param2 -o param3

它崩溃并生成了一个核心转储文件 core.pid

我想通过分析核心转储文件

gdb ./exe -p param1 -i param2 -o param3 core.pid

但是gdb将 exe 的参数识别为gdb的输入 .

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

9 回答

  • 8

    您可以通过多种方式将核心与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选项 .

  • 20

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

    gdb <executable_path> <coredump_file_path>
    

    创建“进程”的Coredump文件,作为“core.pid”文件 . 进入gdb-prompt后,(在执行上述命令时),键入;

    ...
    (gdb) where
    

    这将为您提供堆栈信息,您可以在其中分析崩溃/故障的原因 . Other command, 出于同样的目的;

    ...
    (gdb) bt full
    

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

  • 0

    跳过参数,gdb不需要它们:

    gdb ./exe core.pid
    
  • 3

    RMS's gdb Debugger Tutorial

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

    确保您的文件确实是 core 图像 - 使用 file 进行检查 .

  • 24

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

  • 10

    无论可执行文件是否有参数,在任何带有生成的核心文件的二进制文件上运行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
    
  • 0

    objdump + gdb minimal runnable example

    TL; DR:

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

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

    编译并运行以生成核心:

    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)
    

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

    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
    

    这直接指向了越野车7号线 .

    Binutils analysis

    第一:

    file core
    

    告诉我们 core 文件实际上是一个ELF文件:

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

    这就是为什么我们能够使用通常的binutils工具更直接地检查它 .

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

    man 5 core
    

    然后:

    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
    

    并且在备注区域中存在更多元数据 . 值得注意的是,我猜PC必须在那里(TODO确认):

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

    objdump -s core
    

    其中包含:

    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..........
    

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

    在Ubuntu 16.04 amd64,GCC 6.4.0,binutils 2.26.1中测试 .

  • 148

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

    gdb - The GNU Debugger
    
     syntax:
    
     # gdb executable-file core-file
    
     ex: # gdb out.txt core.xxx
    

    谢谢 .

  • 1

    只需键入命令

    $ gdb <Binary> <codeDump>
    

    要么

    $ gdb <binary>
    
    $ gdb) core <coreDump>
    

    无需提供任何命令行争论 . 由于早期练习而生成的代码转储 .

相关问题