Java - JNI - C/C++ デバッグ入門
明けましておめでとうございます。今年も宜しくお願いします。
というわけで昨年末に調べていたJNIプログラムデバッグ方法のまとめ。
これが一番参考になった。Debugging integrated Java and C/C++ code
まとめ
こんな感じ。
※JPDAはJava Platform Debugger Architectureの略、JVMの機能の一つ。jdbはJDK付属のJava用デバッガ。gdbはいつものGNU Debugger。
senna-javaでの例
Javaプログラムではantを使っているのでbuild.xmlにて設定。
<property name="debug" value="true" />
OPT = -Wall -fPIC -g
リビルド
ant clean test
JPDAを使ってjavaを実行。
LD_LIBRARY_PATH="." \ java -Xdebug -Xnoagent -Djava.compiler=none \ -Xrunjdwp:transport=dt_socket,server=y,suspend=y \ -cp "lib/junit.jar:senna-java-0.01.jar:classes:tests" \ junit.textui.TestRunner senna.SnippetTest
こんな感じで待ちうけポート番号が示される。
Listening for transport dt_socket at address: 34436
jdbを実行。ポート番号を指定する。
tritonn@dev32:/srv/senna-java/trunk$ jdb -sourcepath "src/java" -attach 34436 uncaught java.lang.Throwable を設定しました 保留した uncaught java.lang.Throwable を設定しました jdb の初期化中です... > VM が起動しました: 現行の呼び出しスタックにはフレームがありません main[1]
まだjavaプログラムが開始されていない = System.loadLibrary()が呼ばれていない = C/C++プログラム(共有ライブラリ)もロードされていない状態。
javaプログラム側の良さそうな場所にjdbでブレークポイントを入れる。
main[1] stop in senna.SnippetTest.testSnippet ブレークポイント senna.SnippetTest.testSnippet を保留しています。 クラスがロードされた後に設定されます。 main[1]
そこまで実行。設定したところで停止する。
main[1] cont > 保留した ブレークポイント senna.SnippetTest.testSnippet を設定しました ブレークポイントのヒット: "スレッド=main", senna.SnippetTest.testSnippet(), line=40 bci=0 main[1]
tritonn@dev32:/srv/senna-java/trunk/src/jni$ gdb --pid=`pgrep -x java` GNU gdb Red Hat Linux (6.3.0.0-1.143.el4rh) Copyright 2004 Free Software Foundation, Inc. ..(中略)... Loaded symbols for /lib/libgcc_s.so.1 0x006367a2 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2 (gdb)
System.loadLibrary()が呼ばれた後なら、ここで自由にbreakpointを設定できる。(呼ばれる前にも"予約"は可能ですが)
(gdb) b Java_senna_Snippet_exec Breakpoint 1 at 0xb39b259e: file senna_Snippet.c, line 107. (gdb) c Continuing.
breakpointを設定したらcontinueしておく。
jdb側でもcontinueする。
main[1] cont >
gdb側のbreakpointがヒット。後はお好きに。
(gdb) c Continuing. [Switching to Thread -1208027456 (LWP 648)] Breakpoint 1, Java_senna_Snippet_exec (env=0x8057b0c, obj=0xbfffcec4, jstr=0xbfffcec0) at senna_Snippet.c:107 107 snip = this_sen_snip(env, obj); (gdb) list 102 sen_rc rc; 103 jclass string_class; 104 jobjectArray array; 105 char **results; 106 107 snip = this_sen_snip(env, obj); 108 string = (*env)->GetStringUTFChars(env, jstr, NULL); 109 string_len = (*env)->GetStringUTFLength(env, jstr); 110 SEN_LOG(sen_log_debug, "sen_snip_exec: snip=%p, string=%s, string_len=%d", 111 snip,string,string_len); (gdb)
※もっと手軽な方法を募集中です(CUI完結可能なものに限る)