bamboo’s blog

Bambooの気まぐれブログ

GDBでコアダンプ解析

今回はコアダンプを用いたGDBでのデバッグ方法を解説します。

そもそもコアダンプとは

Wikipediaでは以下のように説明されています。

コアダンプは、ある時点の使用中のメモリの内容をそのまま記録したものであり、一般に異常終了したプログラムのデバッグに使われる。

wikipedia:コアダンプ

記載されてある通り、プログラムが異常終了した際の原因解明に役立ちます。実際どのように使うのか見ていきましょう。

コアダンプの有効化

デフォルトでは大抵コアダンプ機能が無効であるため、以下のコマンドで有効化しておきます。

$ ulimit -c unlimited

(起動時に有効化する場合は~/.bashrcにでも書いておきましょう。)

テストコード

コアダンプが発生する原因には様々なものがありますが、そのうちの1つにセグメンテーション違反(不正なメモリアクセスによる違反)があります。以下のコードを実行すると、Nullポインタアクセスによるセグメンテーション違反が発生します。

#include <iostream>

int entity(int *p) {
    return *p;
}

int main() {
    int *p = nullptr;
    std::cout << entity(p) << std::endl;
    return 0;
}

原因は分かる人には一目瞭然ですが、今回は例としてこのコードをデバッグしてみます。後にデバッグ情報が使用できるように、-gオプションをつけてビルドしてみましょう。

$ g++ -g main.cpp
$ ./a.out
Segmentation fault (core dumped)

セグメンテーション違反が起き、coreファイルが生成されます。

デバッグ

いよいよデバッグです。coreファイル付きでGDBを起動してみましょう。

$ gdb ./a.out core

~(中略)~

Core was generated by `./a.out'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00005605081471b9 in entity (p=0x0) at main.cpp:4
4           return *p;

引数にNullポインタが渡されており、4行目の参照外しが原因となっていることが分かりますね。

バックトレースも見てみましょう。

>>> bt
#0  0x00005605081471b9 in entity (p=0x0) at main.cpp:4
#1  0x00005605081471dd in main () at main.cpp:9

9行目でentity関数を呼び出したのが原因であることが分かります。こうやって異常終了の原因を探るわけです。

最後に

単純なコードならまだしも、複雑なコードだとバグの原因がすぐに分からないことって意外とあります。そんな時はぜひコアダンプを活用してみてください。
おっと、デバッグ関連で思い出しましたが、最後に筆者オススメのGDB dashboardのリンクを貼っておきます。なぜオススメかは、、、またの機会ということで。

github.com