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

coreファイルの取得 - (2010/06/05 (土) 11:56:00) の編集履歴(バックアップ)


coreファイルは、プログラムの異常(セグメンテーションフォルトなど)や、killコマンドなどにより、プログラムが特定のシグナルを受信した際に取得されます。
coreファイルに関してはman coreにいろいろ書いてあるので、そちらを見た方がよいのですが、ここでは単純にcoreとるために必要なことだけ書いて置きます。
※長くなったので、コンテンツをたたんで見出しを見えるようにしています。+をクリックして見てください。


coreが取得されるシグナル

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

取得場所とファイル名

+ ...
 coreが取得される場所は、受信したプログラムが動作しているカレントディレクトリです。
 ファイル名は、通常は 'core' もしくは 'core.<PID>' という名称で取得されます。ファイル名は「/proc/sys/kernel/core_pattern」により変更可能です(詳細はman core参照)。

core取得の制限サイズ

+ ...
 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

coreの取得方法

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

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

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

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

Google coredumper

+ ...
 Google codeにcoredumperというプロジェクトがあります。
 gcoreのように、プロセスを止めずにcoreを取得するためのライブラリです。
 shとは関係ありませんが、core取得ということでここに使いかたを書いておきます。

■インストール
 http://code.google.com/p/google-coredumper/からダウンロードし、適当なところに展開します。試したときは 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ページに以下のように出ています。coredumper.hをincludeして、coreを取得したいところでWriteCoreDump(coreファイル名)とするだけですね。
<google/coredumper.h>
 ...
 WriteCoreDump('core.myprogram');
 /* Keep going, we generated a core file,
  * but we didn't crash.
  */

■サンプル
ソース
<stdio.h>
<stdlib.h>
<string.h>
<errno.h>
<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のこことかここを見ると、APIの説明があります。core取得時に圧縮もできたりするようです。