コマンドラインパラメータがあるプログラムのコアダンプファイルをGDBでどのように分析しますか?


156

私のプログラムは次のように動作します:

exe -p param1 -i param2 -o param3

クラッシュしてコアダンプファイルが生成されましたcore.pid

コアダンプファイルを分析したい

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

しかし、GDBはEXEファイルのパラメーターをGDBの入力として認識します。

この状況でコアダンプファイルを分析するにはどうすればよいですか?


1
あなたexefirefoxLinuxのようなシェルスクリプト(いくつかの変数を設定するなど)ではないことを確信していますか?
Basile Starynkevitch、

回答:


182

コアは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)

manページは、他のGDBオプションを確認するのに役立ちます。


38

コアダンプファイルをデバッグするためのGDBの簡単な使用法:

gdb <executable_path> <coredump_file_path>

「プロセス」のコアダンプファイルは、「core.pid」ファイルとして作成されます。

(上記のコマンドの実行時に)GDBプロンプト内に入ったら、次のように入力します。

...
(gdb) where

これにより、クラッシュ/障害の原因を分析できるスタックの情報が得られます。 同じ目的の他のコマンドは次のとおりです。

...
(gdb) bt full

これは上記と同じです。慣例により、スタック情報全体がリストされます(最終的にはクラッシュの場所につながります)。


22

パラメータをスキップするだけです。GDBはそれらを必要としません。

gdb ./exe core.pid

しかし、これは機能しません。gdb出力警告:コアファイルは指定された実行可能ファイルと一致しない可能性があります。メモリからの有効なオブジェクトファイルイメージの読み取りに失敗しました。
トレパー

6
「コアファイルは指定された実行可能ファイルと一致しない可能性があります」コアが生成された後、exeを変更しましたか?おそらく別のコマンドラインオプションで再構築しましたか?コアを生成したのとまったく同じバイナリをGDBに与えることが非常に重要です。そうしないと、ゴミが出ます。
11:29にロシア語を採用

2
また、gdbに渡されるバイナリが削除されていないことを確認してください。'file <binary name>'を実行して、ストリップされているかどうかを確認できます。
Diwakar Sharma 14年

12

objdump+ gdb最小限の実行可能な例

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は、セグメンテーション違反が発生した正確な行を示します。これは、ほとんどのユーザーがデバッグ中に必要なものです。

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を直接示します。

CLI引数はコアファイルに保存され、再度渡す必要はありません

特定のCLI引数の質問に答えるために、例えばcli引数を次のように変更すると、

rm -f core
./main.out 1 2

その後、これはコマンドに変更を加えずに前のバクトレースに反映されます。

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

だから今どのように注意してくださいargc=3。したがって、これは、コアファイルがその情報を格納することを意味する必要があります。main他の関数の引数を保存するのと同じように、それをの引数として保存するだけだと思います。

これは、コアダンプがプログラム全体のメモリとレジスタの状態を格納する必要があると考える場合に意味があり、現在のスタックの関数引数の値を決定するために必要なすべての情報が含まれています。

環境変数を検査する方法はそれほど明白ではありませんコアダンプから環境変数を取得する方法環境変数もメモリに存在するので、objdumpにはその情報が含まれますが、すべてを一度に一覧表示する方法がわかりません、しかし次のように一つずつ私のテストでうまくいきました:

p __environ[0]

Binutils分析

readelfおよびのようなbinutilsツールを使用することにより、メモリの状態などobjdumpcoreファイルに含まれる情報を一括ダンプできます。

ほとんど/すべてがGDBからも見える必要がありますが、これらのbinutilsツールは、特定のユースケースに便利な、よりバルクなアプローチを提供します。一方、GDBは、よりインタラクティブな探索に便利です。

最初:

file core

coreファイルが実際にはELFファイルであることを伝えます。

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

これが、通常のbinutilsツールを使用して、より直接的に検査できる理由です。

ELF標準ざっと見てみると、実際にはELF専用のタイプがあることがわかります。

Elf32_Ehd.e_type == ET_CORE

詳細なフォーマット情報は、次の場所にあります。

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

さらに、ノート領域にいくつかのメタデータがあり、特にprstatusPCが含まれています

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でテストされています。



9

少し異なるアプローチでは、GDBを完全にスキップできます。必要なのがバックトレースだけである場合、Linux固有のユーティリティ'catchsegv'はSIGSEGVをキャッチしてバックトレースを表示します。


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

0

コマンドを入力するだけです:

$ gdb <Binary> <codeDump>

または

$ gdb <binary>

$ gdb) core <coreDump>

コマンドライン引数を提供する必要はありません。以前の演習のために生成されたコードダンプ。


-1

「gdb」コマンドを使用してコアダンプファイルを分析できます。

 gdb - The GNU Debugger

 syntax:

 # gdb executable-file core-file

 example: # gdb out.txt core.xxx 

1
out.txtは実行可能ファイルですか?それは誤解を招くファイル拡張子のようです。
アラン、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.