明けましておめでとうございます。今年も宜しくお願いします。

というわけで昨年末に調べていたJNIプログラム デバッグ 方法のまとめ。

これが一番参考になった。Debugging integrated Java and C/C++ code



※JPDAは Java Platform Debugger Architectureの略、 JVM の機能の一つ。jdbは JDK 付属の Java 用デバッガ。 gdb はいつもの GNU Debugger。

senna-javaでの例

JavaプログラムとC/C++プログラムをデバッグビルド。

Javaプログラムではantを使っているのでbuild.xmlにて設定。

<property name="debug" value="true" />

C/C++プログラムはMakefileを設定。

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]

gdbでjavaプロセスにアタッチ。

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完結可能なものに限る)