This page covers debugging Java code - both natively-compiled and interpreted code - running on or inside libgcj (the "GCJ runtime environment", in other words).
First things first
libgcj does not yet support JDWP, but that is being worked on. In plain English, that means that standard debuggers like the Eclipse Java debugger and JSwat will not work with libgcj. (Other free JVMs might end up supporting JDWP before libgcj does.)
So for now, we will assume the use of gdb, the GNU debugger. Of course you should be able to use one of its third-party frontends if you wish, although frontend support for Java may vary. This page is not a tutorial for gdb - it is just some notes on Java-specific details about debugging.
Preparing for debugging
The following tips will considerably ease your debugging experience:
Avoid using the interpreter for relevant code, if at all possible. Either compile your application to native code in the traditional way, or use the new BC API (see How_to_BC_compile_with_GCJ). If you really need to debug interpreted code, see below.
- Compile with no optimisation (-O0, which is the default if you don't specify any -O flags). Debug optimised code at your own risk. If you do, some variables will undoubtedly be displayed with the wrong values, stack frames might be missing due to inlining, etc.
- Compile with -g, or gdb won't give you very much information. If you are compiling first to bytecode and then bytecode-to-native, you (obviously) need to specify -g in both compilation steps.
The last two tips also apply to other languages that gdb supports, of course.
gdb includes some java language support. Printing values and expressions works, but inferior method calls do not. gdb will print java <code>String</code> objects as strings.
Sometimes gdb seems to get confused and will not print out a java object. Also, sometimes it is handy to print an object more deeply than gdb ordinarily does. For these cases we provide some debugging functions in libgcj that can be used. To call these functions, first <code>set lang c++</code>; when done, use <code>set lang auto</code>.
This prints an object to a depth of 10.
This prints an object and all its instance fields, recursing to the given depth.
This prints an object and all its fields, including static fields, recursing to the given depth.
On Linux systems it is convenient to put these settings in <code>.gdbinit</code>, so that signals used by the thread system will be ignored:
handle SIGPWR nostop noprint pass handle SIGXCPU nostop noprint pass
Here is a gdb macro which will print a <code>_Jv_Utf8Const</code> object, given its address:
define putf p (char *) ($arg0.data) end document putf Print a UTF-8 value end
Here is a gdb macro which will print the class of an object:
define jvclass p (*(_Jv_VTable **) $arg0).clas putf $.name end document jvclass Print name of class of argument object end
One strength of the gdb-based approach is that you can use the same debugger to debug both java and JNI code. However, one thing to note is that gcj inserts a special stub for a java native method. This stub contains the glue code required to find the correct JNI function to call, and then to transform the arguments from the ordinary (CNI) calling convention to the appropriate JNI calling convention.
In order to debug into a JNI method, there are two choices.
Choice 1: just step through the stub. You will end up in a function or two in jni.cc (e.g., <codeJvLookupJNIMethod</code>); you can simply <code>fini</code> to get out of these. I just use <code>step</code> a lot to get through the stub.
Choice 2: When in the stub, type <code>disassemble</code>, and look for the indirect call instruction. (On x86, this will be <code>call</code> with a <code>*</code> before the operand.) Run up to that instruction by typing <code>u *hex_address</code>. Then <code>stepi</code>. You should now be in the native method itself.
Debugging interpreted code
Debugging interpeted code on gdb is painfully clunky, and yields a low ratio of useful information to effort invested, so westronglyrecommend compiling to native any code that you want to debug (see "Preparing for debugging" above).
However, if for some reason you want to:
It is possible to find out the method being executed by an interpreter stack frame. In the current release of gij, the relevant stack frames look like this:
#6 0x039b7bb4 in _Jv_~InterpMethod::run (this=0x64c5d20, retp=0xbfe7b020, args=0xbfe7b040) at ../../../libjava/interpret.cc:1206
First, move <code>up</code> or <code>down</code> onto the frame of interest, if necessary.
To find the class name:
To find the method name:
p (char *) (this->self->name->data)
To find the method signature, in the hard-to-read format used in Java <code>.class</code> files:
p (char *) (this->self->signature->data)
It will likely be difficult to find out what is going on in the interpreter with gdb, beyond just getting method names and signatures, because various voodoo things like gotos and libffi calls happen all the time in the interpreter.
There is not yet any support for sending a signal to the virtual machine to tell it to generate a proper Java stack trace with all the method names (which would be very useful). This is being worked on for gij 4.1. For now, you'll just have to edit your source code and insert something like this at an appropriate point:
<code>new Throwable("DEBUGGING STACK TRACE").printStackTrace();</code>
It is sometimes useful to run [ valgrind || http://valgrind.org/ ] on an executable compiled with gcj. For instance, this can be useful to find memory leaks in JNI code. [ Here || http://vektor.ca/eclipse/gcj.supp ] is a suppression list that is reported to work ok with gij.