Linuxのプログラムをデバッグするとき、一番困ることはあの有名の「Segmentation Fault」ですね。
プログラムが膨大でマルチプロセス等を使っていたら、どこで問題を起こしているのかすらわからないです。
本編はLinuxのCore Dump機能で問題発生行を特定する方法を紹介します。
まず、前提としてはSegmentation Faultは再現できること。(当たり前ですよね)
下記のプログラムを例とします。
#include<stdio.h>
#include<string.h>
#define DATA "TEST"
char mngfile[2][50];
int main()
{
memset( mngfile, '\0', sizeof(mngfile) );
GetMngFile(mngfile);
return 0;
}
int GetMngFile( mngfile )
char mngfile[2][50];
{
int i=0;
char file[128];
for(i=0;i<999;i++)
{
memset( file, '\0', sizeof(file) );
strcpy(file,"abc");
sprintf(mngfile[i],"%s_%s",file,DATA);
printf("%d,%s\n",i,mngfile[i]);
}
return 0;
}
次に、コンパイルオプションに「-g」を付けてコンパイルします。
gcc test2.c -g -o test2
多くのLinuxではデフォルトCoreDump機能を無効にしてあるため、有効にします。
ulimit -c unlimited (生成するCoreのサイズを制限しない)
プログラムを実行してみます。
./test2
セグメンテーション違反です (core dumped)
この時、カレントディレクトリで「core.11504」のようなファイルが生成されます。
このCoreをGDBでデバッグしてみましょう。
gdb ./test2 core.11504
・・・
Core was generated by `./test2'.
(test2がCoreを吐いている)
Program terminated with signal 11, Segmentation fault.
(シグナル11でプログラムが終了され、セグメンテーション違反発生)
Reading symbols from /lib/tls/libc.so.6...done.
Loaded symbols for /lib/tls/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
#0 0x0058668b in _IO_default_xsputn_internal () from /lib/tls/libc.so.6
(最終実行ステップはlibc.so.6ライブラリの_IO_default_xsputn_internal()関数内にある)
(gdb)bt (BackTraceしてみます。)
#0 0x0058668b in _IO_default_xsputn_internal () from /lib/tls/libc.so.6
#1 0x005645fa in vfprintf () from /lib/tls/libc.so.6
#2 0x0057c71b in vsprintf () from /lib/tls/libc.so.6
#3 0x0056995b in sprintf () from /lib/tls/libc.so.6
#4 0x080484ce in GetMngFile (mngfile=0x8049740) at test2.c:27
#5 0x08048441 in main () at test2.c:12
わたしのソースにのみ興味があるので、先頭にあるStack Frame番号の詳細をみます。
(gdb) frame 4
#4 0x080484ce in GetMngFile (mngfile=0x8049740) at test2.c:27
27 sprintf(mngfile[i],"%s_%s",file,DATA);
これでソースの27行目のsprintfで問題があることを判明しました。
このソースをよく見ると、配列mngfileの定義数を超えたメモリー領域のデータ改ざんのあったので、
これで問題判明です。