========================================================================== サーバーが強制終了する場合のcoredumpによる詳細なバグ報告方法 -------------------------------------------------------------------------- < このファイルは何? > Athena使用中にmap-server.exeなどが突然落ちた場合に、落ちたときのスタックの バックトレースをを開発者に伝える方法を解説する。 バグ報告の時に併用すると開発者が喜ぶかもしれない。 ここでの「落ちる」はあくまでサーバーであり、クライアントではない。 またプロセスがcore(またはstackdump)を吐く現象のことであり、 無限ループなどのプロセスは生きているがサーバーの機能は提供されない状態の ことではない。 -------------------------------------------------------------------------- < 目次 > * Cygwinでのstackdumpとcore Cygwin上でcoreファイルを吐く方法を紹介する。 * coreファイルからスタックのバックトレースを得る プログラムが吐いたcoreからバックトレースを得る方法を紹介する。 * 例 実際にとったログの例を示す。 -------------------------------------------------------------------------- < Cygwinでのstackdumpとcore > Cygwinでプログラムが強制終了する(アクセス違反などによるもの)場合、標準では coreではなくstackdumpを吐く。これは全くといって良いほど役に立たないため、 stackdumpをコピペされても開発者はおそらく見ないだろう。 よって次の方法で、stackdumpではなくcoreを吐くようにする。 ** 環境変数に「error_start=dumper.exe」を追加する ** よくわからない場合、次のように作業するといい。(Win2000でのみ確認) * デスクトップの「マイコンピュータ」を右クリックして「プロパティ」を出す。 * [詳細]タブを開き、[環境変数]ボタンをクリックする。 * ユーザー環境変数、システム環境変数のどちらか「CYGWIN」という変数がないか探す * ある場合は、選択して[編集]ボタンを押し、[変数値]に「error_start=dumper.exe」 を追加する。既に何かの単語がある場合は、単語を区切るため、 追加する部分の最初に半角スペースを入れることを忘れないこと。 * ない場合は、システム環境変数に(Administrator権限がないならユーザー環境変数) の[新規]ボタンを押して、[変数名]に「CYGWIN」、辺数値に 「error_start=dumper.exe」を入力する。 * OKを押してウィンドウを閉じ、Cygwinを起動しなおせばよい こうしておくと、stackdumpの変わりにcoreを吐くようになる。 サイズが大きい場合、coreを吐くのには多少時間がかかる。 またcoreを吐いている間、dumper.exeというプログラムのウィンドウが表示される。 -------------------------------------------------------------------------- < coreファイルからスタックのバックトレースを得る > coreを吐く場合、まず開発者はスタックのバックトレースを欲しがる。エラー個所を 判断しやすいからだ。よって、gdbでバックトレースを取り出そう。 まず、次のようにしてgdbを起動する。ここではmap-server.exeを例に出す。 UNIX系OSではコアファイル名を修正する必要があるだろう。(「core」など) $ gdb -c map-server.exe.core なにやら色々英文が表示され、最後に (gdb) というプロンプトが出たはずだ。 この直前にエラーの起こった関数やファイル名などと、その内容が表示されている はずなので、これはコピペすべきだ。 また、ここで「bt」と入力すると、スタックのバックトレースが表示される。 これもコピペするとよい。ただし、あまりにも長い場合は最初の十数行程度で 十分だろう。 ちなみに、「p 変数名」のように入力すると変数を見たりも出来る。 関連しそうな変数の値を色々表示して一緒にコピペすると開発者が喜ぶかもしれない。 gdbを終了する場合は、「q」と打ち込む。 -------------------------------------------------------------------------- < 例 > 以下はmob.cのmob_warp()関数でわざとアクセス違反を起こしてとったログである。 エラーの場所、どういう順で呼び出されたかがわかるだろう。 もちろん、Athenaのパッチ番号の報告を忘れないこと。 パッチが違うと、ソースファイルが変わるので、行番号が役に立たなくなるためだ。 なお以下の例では、バックトレース以外に、 pコマンドを使って該当のMOBの名前(英語)と、マップの名前を表示している。 (FAKE_ANGEL, gef_dun03.gat) #0 mob_warp (md=0x10119c88, x=-1, y=-1, type=-1) at mob.c:1845 1845 memset(NULL,0,1); (gdb) bt #0 mob_warp (md=0x10119c88, x=-1, y=-1, type=-1) at mob.c:1845 #1 0x0042609d in mob_ai_sub_lazy (key=0x68e77f5, data=0x10119c88, app=0x22fe88 "、\"") at mob.c:1412 #2 0x00455b54 in db_foreach (table=0x22fe88, func=0x610691f2 ) at db.c:414 #3 0x10119c88 in ?? () #4 0x0022fe88 in ?? () #5 0x610691f2 in select () (gdb) p mob_db[md->class].name $1 = "FAKE_ANGEL\000\203t\203F\203C\203N\203G\203\223\203" (gdb) p map[md->bl.m].name $2 = "gef_dun03.gat\000\000r"