Depurar una mezcla de código Java y C++ no es trivial, sobre todo porque aún no hay disponibles entornos (o plugins) estables que soporten esta posibilidad. Con lo cual hay que recurrir a la siguiente receta, que permite interactuar a la vez con los depuradores nativos de cada lenguaje (sean para consola como gdb, o gráficos como NetBeans)
Primero iniciar el programa en modo de depuración remota:
java -Xdebug -Xnoagent -Djava.compiler=none -Xrunjdwp:transport=dt_socket,server=y,suspend=y -Djava.library.path=$LD_LIBRARY_PATH -cp . -jar PROG.jar Listening for transport dt_socket at address: 37112
Es importante definir java.library.path para que contenga el directorio donde se encuentra la biblioteca .so con el código nativo (en este caso, se le asigna el valor de la variable de entorno LD_LIBRARY_PATH).
Iniciar el depurador de Java y conectarse al puerto indicado por el comando anterior (en el ejemplo, 37112)
jdb -attach 37112
También se puede utilizar un depurador gráfico, por ejemplo el que viene con Eclipse. Para ello basta crear un perfil de depuración de tipo «Remote Java Application». En Connection Properties usar localhost y como puerto el que nos devolvio el anterior comando java (siguiendo con el ejemplo, 37112)
Establecer el punto de parada en el código Java
stop at CLASE:NUM_LINEA run
Una vez alcanzado el punto de parada en el código Java, iniciar el depurador de código nativo y vincularlo con el proceso java mediante su PID
gdb attach PID break JNI_FUNCTION
continue (retoma la ejecución del programa java)
Importante: para que el depurador C++ encuentre la función JNI, el programa Java debe tener ya cargada la biblioteca C++ (archivo .so). Si paramos la ejecución del programa Java demasiado pronto, cuando entremos en el gdb la biblioteca aún no se habrá cargado y por lo tanto al intentar el «break» se quejará de que no encuentra la función.
Estos tres comandos gdb también pueden ejecutarse dentro de ddd, lo cual nos permite depurar el código C++ con la comodidad de un entorno gráfico
Por último, de vuelta en jdb ejecutar run de nuevo (continua la ejecución en el depurador y se detiene en el breakpoint del código nativo definido en gdb)