undump(1)

http://shinh.skr.jp/binary/undump.tgz

undump(1) は、 core の状態に復帰するためのソフトウェアです。

i@u ~/wrk/undump> cat stop.c
#include <stdio.h>
#include <sys/signal.h>

int main() {
    puts("undump test starting!");
    raise(SIGTRAP);
    puts("undump succeeded!");
    return 0;
}
i@u ~/wrk/undump> gcc stop.c -o stop
i@u ~/wrk/undump> ./stop
undump test starting!
zsh: trace trap (core dumped)  ./stop
i@u ~/wrk/undump> ./undump stop core.7501
undump succeeded!

のように、復帰してるのがわかると思います。上記のように普通に落ちた場合の core 、goog-coredumper 、 gdbgcore 、なんかで動作確認してあります。用途は計算を中断して復帰とか。プロセスを増やしたりする目的とかでも使えたりするかもしれません(JavaVMの起動時間短縮ネタなんかに使えると面白げかも。コアの場合はサーバいらないし)。動作はたぶん x86Linux だけです。基本的にあんまりチェックはされてません。

そういえば肝心の perl -u から復帰できてません。 Perl_pop_scope なんていう見るからにブラックマジックな関数名が目に入ったので追う気が失せました。まぁ気が向いたら完成度上げます。

これからの Web アプリは、情報入力フォームを出してコアダンプ→再度呼ばれたら undump して入力確認画面を出してコアダンプ→再度呼ばれたら undump して顧客情報登録して exit 、というような流れになりますので覚えておいて下さい。

忘れないうちに実装説明メモ。

起動して pipe 作っておいて fork 。

子プロセス側では、書き込み方向の pipe を閉じて、 PTRACE_TRACEME して、 LD_PRELOAD に preload.so を忍び込ませて、環境変数を用いて pipe のファイルディスクリプタ後から調べられるようにしてから、 exec 。

親プロセス側は、とりあえず core のヘッダを読んで情報収集。そんで子プロセスの exec を wait 。処理が帰ってきたら、コアを読んで得られたメモリマップの情報を pipe につっこむ。ここで子プロセスを走らせて wait 。

子プロセス側は exec の後に、 preload.so の constructor 指定された関数が動く。このタイミングなら exec 直後と違って mmap が一通り終了してる。ヒープの開始点を sbrk でゲット、んで環境変数から pipe を持ってくる。そんで pipe から mmap の情報をゲット。ヒープを sbrk で広げる。 mmap されてない領域があったら mmap しておく、 mmap のサイズが足りない領域は mremap しておく。これらは、プロセスが起動した直後と、実際にコアを出した時で mmap の状態が違うことが多いのでこういうことをしてます。そんで pipe を close してから raise(SIGTRAP); で自分を止める。

親プロセスに戻る。 ptrace を使って子プロセスのメモリとレジスタの状況を再現。 pipe とかは閉じてやって、子プロセスを走らせて終わり。

なにかあれば下記メールアドレスへ。
shinichiro.hamaji _at_ gmail.com
shinichiro.h