読者です 読者をやめる 読者になる 読者になる

gdb + core 解析

C/C++ Debug GDB Linux

core ファイルを解析するメモ。

下準備

まず意図的に SEGV させるコードを書く。

  
$ vi a.cpp  

  
#include   
  
class CPrint  
{  
private:  
    int m_number;  
    char *m_str;  
  
public:  
    CPrint() : m_number(10), m_str(NULL) {}  
    ~CPrint() {}  
  
    void print(){  
        // ここで SEGV る予定  
        printf( "%d, %c\n", m_number, m_str[0] );  
    }  
};  
  
int main()  
{  
    CPrint p;  
    p.print();  
    return 0;  
}  

続けて core を出力させる設定。環境は Linux CentOS 5。

  
$ ulimit -c unlimited  

core dumped

下準備で作成したソースコードをコンパイル。-g を忘れずに。

  
$ g++ a.cpp -g  

実行する。当然 SEGV る。

  
$ ./a.out  
セグメンテーション違反です (core dumped)  

core ファイルが吐かれていることを確認。

  
$ ls  
a.cpp  a.out  core.1613  

core 解析

gdb を立ち上げる。gdb 実行バイナリ coreファイル

  
$ gdb a.out core.1613  
...  
Program terminated with signal 11, Segmentation fault.  
#0  0x08048568 in CPrint::print (this=0xbfe45794) at a.cpp:15  
15              printf( "%d, %c\n", m_number, m_str[0] );  
(gdb)  

呼び出された順番で関数を表示する。

  
(gdb) where  
#0  0x08048568 in CPrint::print (this=0xbfe45794) at a.cpp:15  
#1  0x080484fd in main () at a.cpp:22  
(gdb)  

ソースコードを表示する。

  
(gdb) list  
10          CPrint() : m_number(10), m_str(NULL) {}  
11          ~CPrint() {}  
12  
13          void print(){  
14              // ここで SEGV る予定  
15              printf( "%d, %c\n", m_number, m_str[0] );  
16          }  
17      };  
18  
19      int main()  
(gdb)  

変数の値を確認する。
クラスのメンバ変数もアドレスさえ分かれば確認できる。

  
(gdb) p ((class CPrint *) 0xbfe45794)->m_number  
$2 = 10  
(gdb)  

いちいち ((class CPrint *) 0xbfe45794) とうつのが面倒な場合は、変数に代入する。

  
(gdb) set $c = ((class CPrint *) 0xbfe45794)  
(gdb) p $c->m_number  
$3 = 10  
(gdb) p $c->m_str  
$4 = 0x0