GDBでコアダンプ解析
今回はコアダンプを用いたGDBでのデバッグ方法を解説します。
そもそもコアダンプとは
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のリンクを貼っておきます。なぜオススメかは、、、またの機会ということで。