Java Debugging with gdb

It is possible to debug Java programs compiled with GCJ using GDB. To do this, you need a recent version of GDB. A CVS snapshot version of GDB is recommended: GDB 5.0 and earlier are not able to demangle the symbol names generated by GCC 3.x's new C++/Java ABI. Alternatively, it should also be possible to rebuild GDB 5.0 with an updated libiberty directory. GDB 5.1 will include support for the new ABI.

When debugging GCJ-compiled Java programs, you may need to tell GDB to ignore the SIGPWR and SIGXCPU signals (which are used by the garbage collector). This can be done with the GDB commands:

handle SIGPWR nostop noprint
handle SIGXCPU nostop noprint

Alternately you can place these two lines in the file .gdbinit in $HOME or the directory where you're running GDB.

Remember that some optimizations performed by the compiler can make debugging results unpredictable. When debugging libgcj itself, it is often useful to build a non-optimized library by using `make GCJFLAGS="-g"'.

Here is an example of debugging a simple test program (which uses multiple Java threads) in GDB:

$ javac
$ gcj -g --main=TestT -o TestT TestT.class
$ gdb TestT
GNU gdb 4.18
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux"...
(gdb) handle SIGPWR nostop noprint
Signal        Stop      Print   Pass to program Description
SIGPWR        No        No      Yes             Power fail/restart
(gdb) handle SIGXCPU nostop noprint
Signal        Stop      Print   Pass to program Description
SIGXCPU       No        No      Yes             CPU time limit exceeded
(gdb) break TestT.main
Breakpoint 1 at 0x8049fa2: file, line 64.
(gdb) run
Starting program: /disks/now/grad/mdw/src/ninja/test/mdw/TestT 
[New Thread 16843 (manager thread)]
[New Thread 16835 (initial thread)]
[New Thread 16844]
[Switching to Thread 16844]

Breakpoint 1, TestT.main (args=@806cff0) at
64          TestT a1 = new TestT(1,false);
(gdb) where
(gdb) where 
#0  TestT.main (args=@806cff0) at
#1  0x4011033a in java::lang::FirstThread::run (this=@8064f90)
    at /home/cs/mdw/disks/enclave1/libgcj-991104/libjava/java/lang/
#2  0x400ccdfa in java.lang.Thread.run_ (this=@8064f90)
    at /home/cs/mdw/disks/enclave1/libgcj-991104/libjava/java/lang/
#3  0x4011554a in java::lang::Thread::run__ (obj=@8064f90)
    at /home/cs/mdw/disks/enclave1/libgcj-991104/libjava/java/lang/
#4  0x4012524a in really_start (x=@805fef0)
    at /home/cs/mdw/disks/enclave1/libgcj-991104/libjava/
#5  0x401d7ba6 in GC_start_routine (arg=@807ffe0)
    at /home/cs/mdw/disks/enclave1/libgcj-991104/boehm-gc/linux_threads.c:533
#6  0x401eece9 in pthread_start_thread (arg=@bf7ffe7c) at manager.c:204

Note that the stack trace includes both Java code and the native methods in the libgcj runtime library!

You can examine threads using the info threads and thread commands:

(gdb) info threads
* 3 Thread 16844  TestT.main (args=@806cff0) at
  2 Thread 16835 (initial thread)  0x4022a1bb in __sigsuspend (set=0xbffff4f4)
    at ../sysdeps/unix/sysv/linux/sigsuspend.c:48
  1 Thread 16843 (manager thread)  0x402b37d0 in __poll (fds=0x808fef0, 
    nfds=1, timeout=2000) at ../sysdeps/unix/sysv/linux/poll.c:45
(gdb) thread 2
[Switching to thread 2 (Thread 16835 (initial thread))]
#0  0x4022a1bb in __sigsuspend (set=0xbffff4f4)
    at ../sysdeps/unix/sysv/linux/sigsuspend.c:48
48      ../sysdeps/unix/sysv/linux/sigsuspend.c: No such file or directory.
Current language:  auto; currently c

Page written by Matt Welsh