Debugging a Java Program with JDB
(only works for programs NOT using System.in for console input)

Video Demonstration

Here is a basic java class we will use for demonstration purposes

public class TestMe {

  private int int_value;
  private String string_value;
  
  public static void main(String[] args)
  {
    TestMe testMe = new TestMe();
        System.out.println("Default Object Created " + testMe.toString());

    testMe.setInt_value(1);
    testMe.setString_value("test");
        System.out.println("Object Changed " + testMe.toString());

    int integer = testMe.getInt_value();
    String string = testMe.getString_value();

    String toString = testMe.toString();
  }

  public TestMe()
  {
  }

  public int getInt_value()
  {
    return int_value;
  }

  public String getString_value()
  {
    return string_value;
  }

  public void setInt_value(int value)
  {
    int_value = value;
  }

  public void setString_value(String value)
  {
    string_value = value;
  }

  public String toString()
  {
    return "StringValue:" + string_value + " intValue:" + int_value;
  }
  
}

Before attempting to debug your code, be sure to use the -g option while compiling your classes. This option tells the compiler to include debugging information in your class file.

C:\debug>javac -g TestMe.java

Start the debugger:

C:\debug>jdb TestMe
Initializing jdb ...
>

At this point, jdb has invoked the Java interpreter, the TestMe class is loaded, and the interpreter stops before enterning main(). If you type "help", you will be given a list of the debugger commands along with a short description of what they do. Note that "stop in", "stop at", "run", "cont", "list", "locals" and "print" and "exit" are especially useful commands. Since you have not yet entered the method called "main", the commands that list the code or print the values of program variables will not work yet.

Let's take a look at how some basic commands work. In order to set breakpoints, we need to know the line numbers or the method names of the places where we would like to break. Most Java text editors, like Editplus, will aloow you to turn on line numbers.

Give the command "stop in TestMe.main" and then "run". The interpreter will continue executing for a very short time until just after it enters main().

> stop in TestMe.main
Deferring breakpoint TestMe.main.
It will be set after the class is loaded.
> run
run TestMe
Set uncaught java.lang.Throwable
Set deferred uncaught java.lang.Throwable
>
VM Started: Set deferred breakpoint TestMe.main

Breakpoint hit: "thread=main", TestMe.main(), line=8 bci=0
8        TestMe testMe = new TestMe();

main[1]

At this point, the debugger halts execution at the first line of the main method. Notice that the cursor has changed to reflect the method that we are currently in. Now you can type "list" to see the source code for the instructions that are about to execute.

main[1] list
4      private String string_value;
5
6      public static void main(String[] args)
7      {
8 =>     TestMe testMe = new TestMe();
9       System.out.println("Default Object Created " + testMe.toString());
10
11        testMe.setInt_value(1);
12        testMe.setString_value("test");
13      System.out.println("Object Changed " + testMe.toString());
main[1] 

jdb also allows us to set multiple breakpoints. To go from one breakpoint directly to the next, jdb provides the "cont" command. Let's set another breakpoint a few lines ahead using the "stop at" command followed by the "cont" command to continue to the next breakpoint and the "list" command to see code around the breakpoint.

main[1] stop at TestMe:11
Set breakpoint TestMe:11
main[1] cont
Default Object Created StringValue:null intValue:0
>
Breakpoint hit: "thread=main", TestMe.main(), line=11 bci=36
11        testMe.setInt_value(1);

main[1] list
7      {
8        TestMe testMe = new TestMe();
9       System.out.println("Default Object Created " + testMe.toString());
10
11 =>     testMe.setInt_value(1);
12        testMe.setString_value("test");
13      System.out.println("Object Changed " + testMe.toString());
14
15        int integer = testMe.getInt_value();
16        String string = testMe.getString_value();
main[1]

you can use the "print" command to view current values for variables (if needed, use the "locals" command first to see what variable are available)

main[1] print testMe
 testMe = "StringValue:null intValue:0"

The final command we will look at si the "step" command which executes the current statement. If that current statement contains a method call, the debugger moves to the first statement in that method call. One tricky point about jdb is that if you use the step command to execute one instruction at a time, you will step into the instructions for calls to methods of predefined Java classes. The source code for predefined Java classes is not available to jdb, so jdb cannot list the lines of code or print the values of any variables in that method.

and repeated use of the "step", "list" and "print" commands to see if variable values are changing as expected. Notice how the first "step" command steps into the setInt_value method

main[1] step
>
Step completed: "thread=main", TestMe.setInt_value(), line=37 bci=0
37        int_value = value;

main[1] list
33      }
34
35      public void setInt_value(int value)
36      {
37 =>     int_value = value;
38      }
39
40      public void setString_value(String value)
41      {
42        string_value = value;
main[1] step
>
Step completed: "thread=main", TestMe.setInt_value(), line=38 bci=5
38      }

main[1] step
>
Step completed: "thread=main", TestMe.main(), line=12 bci=41
12        testMe.setString_value("test");

main[1] print testMe
 testMe = "StringValue:null intValue:1"

You should continue to examine the program's behavior as it executes by setting further breakpoints, or using step to execute one instruction at a time. At each breakpoint, use the print or locals command to examine the values of program variables, until you isolate the error. Use the "exit" command to stop the debugger.

When you think you have found the error, "exit" the debugger and go edit your code, comment out the old statement(s), in case you need them again, correct the error, and recompile and execute it to see if the problem is solved.

Congratulations! You're done with the jdb exercise.

One final point: you may ask, "How do you effectively use jdb?" The effectiveness of use will depend on your comfort level with jdb. When you first use jdb, the most important command is help. The help command lists each command and provides some basic information to help you get started. Once you have the help command mastered, you'll find yourself using the commands that set breakpoints, along with step and list. Any combination of those commands will allow you to get started using jdb. step, list, step, list... should help you quickly locate code that is bombing out on you.

Copyright CS, Illinois Institute of Technology, Fall 2006