May 17th, 2012


Java debugging old-school with JDB.

I've been spending a lot of time at work lately debugging Java. The details are not particularly important, other than to note that the popular description of JavaEE as "the new COBOL" is deadly accurate.

Most of you whipper-snappers probably use Eclipse to do your debugging these days. And that works quite well as long as you happened to compile the code you're debugging. But what happens when you didn't compile the code you're debugging? With Eclipse, you're pretty much screwed. Even if you create a fake project and link in the source, it still never really works quite right. Breakpoints often don't break. Eclipse often can't figure out which line you're actually executing. Etc.

So let's talk about going old-school - enter jdb. Never really intended to be more that a proof of concept for the JPDA, it actually turns out to be surprisingly useful when you need to debug something you don't have source code for and/or didn't compile yourself.

One nice thing about jdb is that if you have a JDK, then you have a copy of it. It's been a standard tool since Java 1.2. If you're on Windows, Unix, a Mac and have installed a JDK, then jdb(.exe) will be waiting in $JDK_HOME/bin/.

Another thing you may be surprised to hear about jdb is that it can do remote socket debug just like Eclipse can. This isn't well documented, so I'll give you the magic invocation here:

First you start the remote program you want to debug on with something like:

java -agentlib:jdwp=transport=dt_socket,server=y,address=8787 myClass

Then on your local machine, run:

jdb -connect,port=8787

Here's a quick cheat-sheet to get you started with the obvious stuff:

stop in com.mydomain.mypackage.myclass.mymethod         # Set breakpoint on method entry
clear   # List (no args) or clear (with args) breakpoints
use /home/mydir/sourcecodedir/     # Set source code path
list    # List source code lines
next    # steps OVER method calls
step    # steps INTO method calls
step up # run until current method returns
cont    # continue exection after breakpoint
print (somevar)   # Show current value of somevar

All pretty standard, I know. But it should be noted that all of the above work whether you have source code or not, which beats the hell out of Eclipse. Now, how about some stuff that's a little more fun?
classpath     # Print JVM's classpath
disablegc (expr)   # prevent garbage collection of an object
classes                   # list all currently loaded classes
class org.package.class   # show details of named class
methods com.this.class    # list a class's methods
fields com.that.class     # list a class's fields
eval (java expression)  # Run arbitrary java code, alter program state at will
redefine com.some.class newcode.class  # Load new .class file to redefine an existing class

Some interesting possibilities there, eh? eval is particularly fun. Need to delete an item out of a HashMap? Just eval myHashMap.remove("thiskey") and you're done. (And yes, Eclipse's debug perspective can do this too if you know how... but how many people do?)

The possibilities for redefine are especially amusing to contemplate...
  • Current Music
    Pearl Jam - Bugs