はじめに
ここでの説明は、前提としてダメ元で試して見る程度の内容です。
ちょん切れた完全ではない core ファイルから有効な情報が得られるとは考えない方が良いでしょう。
少し試みてうまくいかなければ、あきらめて次回は正しく core ファイルが取得できるようにお考えいただいた方が時間を無駄にしなくて済みます。
実験
元ネタとして java core: HotSpot コンパイラが SIGSEGV でクラッシュ で使った core ファイルを利用しました。
元の core ファイルは 240M byte 程度のサイズがありますが、以下のようにして 200M byte 程度にちょん切ってみます。
$ dd if=./core.15045 of=./core.x bs=1024k count=200
200+0 レコード入力
200+0 レコード出力
209715200 バイト (210 MB) コピーされました、 4.11797 秒、 50.9 MB/秒
$ ls -l core.15045 core.x
-rw-r--r-- 1 root root 240611328 4月 23 11:51 core.15045
-rw-r--r-- 1 imai imai 209715200 4月 25 18:37 core.x
$
$ objdump -a ./core.x
objdump: 警告: ./core.x は切り詰められています: 予期されるコアファイルサイズ >= 240611328。見つかったサイズ: 209715200。
./core.x: ファイル形式 elf64-x86-64
./core.x
このちょん切れた core ファイルを gdb でみて見ると当然スタック情報なども正しく表示されません。
$ gdb /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/jre-abrt/bin/java ./core.x
... 中略 ...
Core was generated by `java -classpath /usr/share/tomcat/bin/bootstrap.jar:/usr/share/tomcat/bin/tomca'.
Program terminated with signal 6, Aborted.
# 0 0x00007f50747b01f7 in ?? ()
(gdb) bt
# 0 0x00007f50747b01f7 in ?? ()
# 1 0x00007f50747b18e8 in ?? ()
# 2 0x0000000000000020 in ?? ()
# 3 0x0000000000000000 in ?? ()
(gdb)
(gdb) info shared
Cannot access memory at address 0x7f507538f128
Cannot access memory at address 0x7f507538f120
No shared libraries loaded at this time.
(gdb)
add-symbol-file でマップする
gdb で確認ができるように、どのアドレスに、何のライブラリがマッピングされているのかの情報を手動でセットしていきます。
まず、最初に readelf コマンドを使って core ファイルの note セクションから、大まかなマップアドレスを確認します。
次に、そのアドレスに共有ライブラリの .text セクションの開始アドレスを足すことで、マップすべきアドレスが判断できます。
$ readelf -n ./core.x
... 中略 ...
0x00007f507477a000 0x00007f507477b000 0x0000000000000015
/usr/lib64/libz.so.1.2.7
0x00007f507477b000 0x00007f5074933000 0x0000000000000000
/usr/lib64/libc-2.17.so
0x00007f5074933000 0x00007f5074b33000 0x00000000000001b8
/usr/lib64/libc-2.17.so
0x00007f5074b33000 0x00007f5074b37000 0x00000000000001b8
/usr/lib64/libc-2.17.so
...
$ readelf -S /usr/lib64/libc-2.17.so | grep text
[12] .text PROGBITS 000000000001f480 0001f480
$
上記中、最初に表示された /usr/lib/64/libc-2.18.so の開始アドレスと readelf で確認した .text の開始位置を足しアドレスを求めます。
(gdb) p/x 0x00007f507477b000 + 0x000000000001f480
$1 = 0x7f507479a480
(gdb)
このアドレスに、libc-2.17.so をマップします。
(gdb) add-symbol-file /usr/lib64/libc-2.17.so 0x7f507479a480
add symbol table from file "/usr/lib64/libc-2.17.so" at
.text_addr = 0x7f507479a480
(y or n) y
Reading symbols from /usr/lib64/libc-2.17.so...(no debugging symbols found)...done.
Missing separate debuginfos, use: debuginfo-install glibc-2.17-196.el7.x86_64
(gdb)
スタック情報が見えた!
上記のようにして、アドレスを計算しそれぞれの共有ライブラリをマップしていきます。
java core であれば主要なライブラリは libc, libpthread, libjvm ですので、その3つをマップしたのちに、もう一度 gdb でスタック情報を確認してみます。
(gdb) add-symbol-file /usr/lib64/libc-2.17.so 0x7f507479a480
(gdb) add-symbol-file /usr/lib64/libpthread-2.17.so 0x7f5074f55900
(gdb) add-symbol-file /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/jre/lib/amd64/server/libjvm.so 0x7f507390b110
(gdb)
libc, libpthread, libjvm をマップしたのちに、bt でスタックを確認してみます。
(gdb) bt
# 0 0x00007f50747b01f7 in raise ()
# 1 0x00007f50747b18e8 in abort ()
# 2 0x00007f5073f18de9 in os::abort (dump_core=<optimized out>) at /usr/src/debug/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/openjdk/hotspot/src/os/linux/vm/os_linux.cpp:1635
# 3 0x00007f50740a7bcf in VMError::report_and_die (this=this@entry=0x7f5070c49bd0)
at /usr/src/debug/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/openjdk/hotspot/src/share/vm/utilities/vmError.cpp:1074
# 4 0x00007f5073f21ff7 in JVM_handle_linux_signal (sig=11, info=0x7f5070c49e30, ucVoid=0x7f5070c49d00, abort_if_unrecognized=<optimized out>)
at /usr/src/debug/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/openjdk/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp:531
# 5 <signal handler called>
# 6 0x00007f5073f646c0 in Phase::Phase (this=0x0, pnum=Phase::Compiler)
at /usr/src/debug/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/openjdk/hotspot/src/share/vm/opto/phase.cpp:83
# 7 0x00007f5073b78711 in Compile::Compile (this=0x0, ci_env=0x7f5070c4ba40, compiler=0x7f506c072730, target=0x7f503c0ba4f0, osr_bci=-1, subsume_loads=<optimized out>,
do_escape_analysis=true, eliminate_boxing=true) at /usr/src/debug/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/openjdk/hotspot/src/share/vm/opto/compile.cpp:683
# 8 0x00007f5073ae3d30 in C2Compiler::compile_method (this=0x7f506c072730, env=0x7f5070c4ba40, target=0x7f503c0ba4f0, entry_bci=-1)
at /usr/src/debug/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/openjdk/hotspot/src/share/vm/opto/c2compiler.cpp:137
# 9 0x00007f5073b7f788 in CompileBroker::invoke_compiler_on_method (task=task@entry=0x7f506c1595c0)
at /usr/src/debug/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/openjdk/hotspot/src/share/vm/compiler/compileBroker.cpp:1761
# 10 0x00007f5073b80b00 in CompileBroker::compiler_thread_loop ()
at /usr/src/debug/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/openjdk/hotspot/src/share/vm/compiler/compileBroker.cpp:1597
# 11 0x00007f5074059cfa in JavaThread::thread_main_inner (this=this@entry=0x7f506c0a8800)
at /usr/src/debug/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/openjdk/hotspot/src/share/vm/runtime/thread.cpp:1687
# 12 0x00007f507405a07f in JavaThread::run (this=0x7f506c0a8800) at /usr/src/debug/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/openjdk/hotspot/src/share/vm/runtime/thread.cpp:1667
# 13 0x00007f5073f17de2 in java_start (thread=0x7f506c0a8800) at /usr/src/debug/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/openjdk/hotspot/src/os/linux/vm/os_linux.cpp:910
# 14 0x00007f5074f57e25 in start_thread ()
# 15 0x00007f507487334d in clone ()
(gdb)
このように、切り詰められてしまった core ファイルであっても情報が得られる場合があります。