「coreファイルの取得」の編集履歴(バックアップ)一覧に戻る

coreファイルの取得 - (2010/05/01 (土) 23:44:25) のソース

coreファイルは、プログラムの異常(セグメンテーションフォルトなど)や、killコマンドなどにより、プログラムが特定のシグナルを受信した際に取得されます。
coreファイルに関しては[[man core>http://www.linux.or.jp/JM/html/LDP_man-pages/man5/core.5.html]]にいろいろ書いてあるので、そちらを見た方がよいのですが、ここでは単純にcoreとるために必要なことだけ書いて置きます。
&color(red){※長くなったので、コンテンツをたたんで見出しを見えるようにしています。+をクリックして見てください。}

**coreが取得されるシグナル
#region
 以下はPOSIX.1-1990に定められたシグナルで、動作にCoreとあるシグナルを受信するとcoreが取得されます。
|CENTER:BGCOLOR(#EEE8AA):No|CENTER:BGCOLOR(#EEE8AA):シグナル名|CENTER:BGCOLOR(#EEE8AA):シグナル番号|CENTER:BGCOLOR(#EEE8AA):動作|CENTER:BGCOLOR(#EEE8AA):コメント|			
|CENTER:1 |CENTER:SIGINT   |CENTER:2   |CENTER:Term  |CENTER:キーボードからの割り込み (Interrupt)          |
|CENTER:2 |CENTER:SIGQUIT  |CENTER:3   |CENTER:Core  |CENTER:キーボードによる中止 (Quit)                   |
|CENTER:3 |CENTER:SIGILL   |CENTER:4   |CENTER:Core  |CENTER:不正な命令                                    |
|CENTER:4 |CENTER:SIGABRT  |CENTER:6   |CENTER:Core  |CENTER:abort(3) からの中断 (Abort) シグナル          |
|CENTER:5 |CENTER:SIGFPE   |CENTER:8   |CENTER:Core  |CENTER:浮動小数点例外                                |
|CENTER:6 |CENTER:SIGKILL  |CENTER:9   |CENTER:Term  |CENTER:Kill シグナル                                 |
|CENTER:7 |CENTER:SIGSEGV  |CENTER:11  |CENTER:Core  |CENTER:不正なメモリ参照                              |
|CENTER:8 |CENTER:SIGPIPE  |CENTER:13  |CENTER:Term  |CENTER:パイプ破壊: 読み手の無いパイプへの書き出し    |
|CENTER:9 |CENTER:SIGALRM  |CENTER:14  |CENTER:Term  |CENTER:alarm(2) からのタイマーシグナル               |
|CENTER:10|CENTER:SIGTERM  |CENTER:15  |CENTER:Term  |CENTER:終了 (termination) シグナル                   |
|CENTER:11|CENTER:SIGUSR1  |CENTER:10  |CENTER:Term  |CENTER:ユーザ定義シグナル 1                          |
|CENTER:12|CENTER:SIGUSR2  |CENTER:12  |CENTER:Term  |CENTER:ユーザ定義シグナル 2                          |
|CENTER:13|CENTER:SIGCHLD  |CENTER:17  |CENTER:Ign   |CENTER:子プロセスの一時停止 (stop) または終了        |
|CENTER:14|CENTER:SIGCONT  |CENTER:18  |CENTER:Cont  |CENTER:一時停止 (stop) からの再開                    |
|CENTER:15|CENTER:SIGSTOP  |CENTER:19  |CENTER:Stop  |CENTER:プロセスの一時停止 (stop)                     |
|CENTER:16|CENTER:SIGTSTP  |CENTER:20  |CENTER:Stop  |CENTER:端末 (tty) より入力された一時停止 (stop)      |
|CENTER:17|CENTER:SIGTTIN  |CENTER:21  |CENTER:Stop  |CENTER:バックグランドプロセスの tty 入力             |
|CENTER:18|CENTER:SIGTTOU  |CENTER:22  |CENTER:Stop  |CENTER:バックグランドプロセスの tty 出力             |
#endregion

**取得場所とファイル名
#region
 coreが取得される場所は、受信したプログラムが動作しているカレントディレクトリです。
 ファイル名は、通常は '&bold(){core}' もしくは '&bold(){core.<PID>}' という名称で取得されます。ファイル名は「&bold(){/proc/sys/kernel/core_pattern}」により変更可能です(詳細は[[man core>http://www.linux.or.jp/JM/html/LDP_man-pages/man5/core.5.html]]参照)。
#endregion

**core取得の制限サイズ
#region
 coreファイルには取得サイズの制限値があり、ulimitコマンドで見ることができます。
>$ ulimit -a <ーーcoreサイズ以外も表示。coreのみ見たいときは ulimit -c
>core file size          (blocks, -c) 0  <ーー1Kbyte単位。この例だと0Kbyte
> ・・・以下省略

 上記の例だと0Kbyteのためcoreは取得されません。サイズ変更は、一時的に変更するなら以下のコマンドを実行します(実行したシェルとその子プロセスでのみ有効)。
>$ ulimit -c <サイズ>  or  $ ulimit -c unlimited    ・・・後者は無限大とする

 永続的に変更するには以下のファイルを修正します。
>/etc/security/limits.conf
#endregion

**coreの取得方法
#region
 killコマンドを使う場合は、以下のようにします。
>$ kill -<動作がcoreのシグナル番号> <対象プロセスのPID>

 ただし、このkillを使うと対象プロセスも終了してしまいます。終了させたくない場合は、gdbのgcoreコマンドを使います。
>$ gdb
>(gdb) attach <対象プロセスのPID>
>(gdb) gcore <ファイル名>
>(gdb) detach

 これだと、人がコマンドをインタラクティブに入力しないといけないため、自動的にcoreを取得させるなどには使えません。
 そのためRHELやCentOSでは、gdbのgcoreコマンドをshスクリプトで実装した&bold(){gcore}コマンドがあります。
>$ gcore
>usage:  gcore [-o filename] pid

 ディストリビューションによってgcoreコマンドがない場合があるので、[[gcoreコマンド]]にCentOS5.4のgcoreコマンドの内容を書いておきます。gdbがないことはないと思うので、どのディストリビューションでも使えると思います。
#endregion

** Google coredumper
#region
 Google codeに[[coredumper>http://code.google.com/p/google-coredumper/]]というプロジェクトがあります。
 gcoreのように、プロセスを止めずにcoreを取得するためのライブラリです。
 shとは関係ありませんが、core取得ということでここに使いかたを書いておきます。

■インストール
 [[http://code.google.com/p/google-coredumper/]]からダウンロードし、適当なところに展開します。試したときは &bold(){coredumper-1.2.1.tar.gz} が最新でした。
 展開した中のINSTALLファイルにインストール方法がかかれていますが、Linuxの標準的なconfigure、make、make installのパターンでインストール可能です。
 なお、以下のようにするとdebパッケージやrpmパッケージも作れるということで、make installはせずに、make rpm をして、rpmを作成してインストールしました。
>`make deb`     - builds Debian packages
>`make rpm`     - build RedHat RPM packages

 rpmの作成先はmake rpmした際に表示されます。
>$ make rpm
>  ・・・
>The rpm package file(s) are located in /home/test/Soft/develop/coredumper-1.2.1/packages/rpm-unknown
>$ ls /home/tomonari/Soft/develop/coredumper-1.2.1/packages/rpm-unknown
>coredumper-1.2.1-1.x86_64.rpm            coredumper-devel-1.2.1-1.x86_64.rpm
>coredumper-debuginfo-1.2.1-1.x86_64.rpm
 
 coredumperはライブラリであり、プログラムから呼び出すためにはヘッダファイルも必要なため、以下の2つをインストールしました。
>$ sudo rpm -ivh coredumper-1.2.1-1.x86_64.rpm
>$ ls /usr/lib/libcoredumper*
>/usr/lib/libcoredumper.a   /usr/lib/libcoredumper.so.1
>/usr/lib/libcoredumper.la  /usr/lib/libcoredumper.so.1.0.0
>/usr/lib/libcoredumper.so
>$ sudo rpm -ivh coredumper-devel-1.2.1-1.x86_64.rpm
>$ ls /usr/include/google
>coredumper.h

■使いかた
 Webページに以下のように出ています。&bold(){coredumper.h}をincludeして、coreを取得したいところで&bold(){WriteCoreDump(coreファイル名)}とするだけですね。
>#include <google/coredumper.h>
> ...
> WriteCoreDump('core.myprogram');
> /* Keep going, we generated a core file,
>  * but we didn't crash.
>  */

■サンプル
ソース
>#include <stdio.h>
>#include <stdlib.h>
>#include <string.h>
>#include <errno.h>
>#include <google/coredumper.h>
>
>int main(){
>      char *str;
>      short svar;
>      int ret,err;
> 
>      str = "Hello World";
>      svar = 0x1234;
>
>      ret = WriteCoreDump("core.test");
>      err = errno;
>      if ( ret == -1 ){
>              strerror( err );
>              exit(1);
>      }
>
>      printf("WriteCoreDump Success!! ret: %d\n",ret);
>      exit(0);
>}

コンパイル・リンク
>$ gcc -o main main.c -lcoredumper -g   <-- libcoredumperのリンクが必要、-gはgdbで変数の値をみるため

実行
>$ ./main
>WriteCoreDump Success!! ret: 0
>$ ls core.test
>core.test
>$ gdb -c core.test main    <--本当にcore見られるか実験
> ・・・
>(gdb) bt
>#0  0x00002b9b483a5825 in WriteCoreDump () from /usr/lib/libcoredumper.so.1
>#1  0x0000000000400628 in main () at main.c:16
>(gdb) up
>#1  0x0000000000400628 in main () at main.c:16
>16              ret = WriteCoreDump("core.test");
>(gdb) p str
>$1 = 0x400768 "Hello World"
>(gdb) p /x svar
>$2 = 0x1234

なお、coredumperの[[ここ>http://code.google.com/p/google-coredumper/wiki/GetCoreDump]]とか[[ここ>http://code.google.com/p/google-coredumper/wiki/WriteCoreDump]]を見ると、APIの説明があります。core取得時に圧縮もできたりするようです。
#endregion

----