Fight the Future

Java言語とJVM、そしてJavaエコシステム全般にまつわること

JavaプロセスがダンプしたコアファイルをjhsdbとGDBで見る

手持ちのコアファイルがない場合は、yasuenagさんのリポジトリからすぐに作れます!!

https://github.com/YaSuenag/garakuta/tree/master/NativeSEGV

Linuxではあらかじめulimit -c unlimitedしてから実行してください。

デバッグ情報付きのOpenJDKビルドを使います。OpenJDKのソースをcloneして:

$ configure --enable-debug --with-native-debug-symbols=internal --disable-warnings-as-errors
$ make images

です。

今回はjdk14 (https://hg.openjdk.java.net/jdk/jdk14/) をビルドしたものを使いました。buildディレクトリ以下にOpenJDKビルドができあがります。OpenJDKのビルドをしたことがない方には、オレ流のOpenJDKの開発環境(JJUG CCC 2019 Fall講演資料)を見ていただくとよいです(これもyasuenagさん…)。

 $ jdk14/build/linux-x86_64-server-fastdebug/jdk/bin/java -version
openjdk version "14-internal" 2020-03-17
OpenJDK Runtime Environment (fastdebug build 14-internal+0-adhoc.jyukutyo.jdk14)
OpenJDK 64-Bit Server VM (fastdebug build 14-internal+0-adhoc.jyukutyo.jdk14, mixed mode)

このJDKにPATHを通しておきましょう。さて、jhsdbを立ち上げるわけですが、LinuxにはCLIしかないことも多いので、今回はjhsdbのリモート・デバッグ・サーバーを起動し、WindowsのjhsdbのGUIから接続して見ます。こんな感じのコマンドでjhsdbのサーバーを起動できます。

Examples: jhsdb debugd --pid 1234 or  jhsdb debugd --core ./core.1234 --exe ./myexe

ではコアファイルとOpenJDKデバッグ版でjhsdbのリモート・デバッグ・サーバーを起動します。

 $ jhsdb debugd --exe jdk14/build/linux-x86_64-server-fastdebug/jdk/bin/java --core ./core
Attaching to core ./core from executable /home/jyukutyo/code/jdk14/build/linux-x86_64-server-fastdebug/jdk/bin/java and starting RMI services, please wait...
Debugger attached and RMI services started.

startedと出力されれば起動しています。

WindowsでもjhsdbのGUIを起動します。jhsdb hsdbを実行します。

$ jhsdb hsdb

File -> Connect to debug serverを選択し、マシン名を入力します。java.rmi.ConnectExceptionが出て接続できない場合は、WindowsのC:\Windows\System32\drivers\etc\hostsやLinuxの/etc/hostsを確認すると解決する可能性が高いです。私はWindowsのHyper-VでテキストモードのUbuntuを起動しており、内部ネットワークで固定のIPアドレスをUbuntuに割り当てていましたが、Windowsのhostsは設定していたもののLinuxのhostsを見落としており、最初接続できませんでした。

このとき、サーバーで指定したJDKのバージョンと、WindowsでGUIを起動したJDKのバージョンが異なると、上記の警告が出ます。また、バージョンの組み合わせによって例外が発生したり、GUIが使えない場合があります。そういう場合は、同じか少なくとも近いバージョンを使いましょう。

WARNING: Hotspot VM version 14-internal+0-adhoc.jyukutyo.jdk14 does not match with SA version 11.0.7+10. You may see unexpected results.

たとえば今回だとデバッグサーバは14、クライアントをAdoptOpenJDKの11で接続すると、次のような例外が出て使用できません。

f:id:jyukutyo:20200627055335p:plain

無事接続できると、このような画面になります。

f:id:jyukutyo:20200627060258p:plain

Tools -> Class Browserを選択します。java.lang.Objectを探してみましょう。

f:id:jyukutyo:20200627060758p:plain

アドレスがわかりました。0x00000008000010c0です。次に、Tools -> Inspectorを選択します。Address欄に0x00000008000010c0を入れてEnterを押します。

f:id:jyukutyo:20200627061022p:plain

HotSpot VMのシンボル名に関わるコード - Fight the Futureで話題にした、Symbolを見ることにします。

f:id:jyukutyo:20200627061238p:plain

java.lang.Objectクラスのシンボルのアドレスがわかりました。0x00007ff2580650f0です。これ以上の詳細を調べるには、GDBを使います。Linuxでデバッグサーバーを終了し、GDBを起動します。

$ gdb /home/jyukutyo/code/jdk14/build/linux-x86_64-server-fastdebug/jdk/bin/java core
(gdb)

あとは、先ほど調べたアドレスを使うだけです。

(gdb) p ((Symbol*)0x00007ff2580650f0) -> _length_and_refcount
$3 = 1114111
(gdb) p ((Symbol*)0x00007ff2580650f0) -> _body
$4 = "ja"
(gdb) p (char[])(((Symbol*)0x00007ff2580650f0) -> _body)[0]@16
$5 = "java/lang/Object"

シンボル名java/lang/Objectが見れました。もちろんbtしてバックトレースを見たりもできます。