Debugging a Java Program with JDB

JDB is an interactive debugger that comes bundled with the Java Development Kit. It runs from the command line, which means you have to type to use it, which a lot of people think makes it unusable. In fact, even its own documentation says that it’s not really intended for heavy-duty use, but just as a starting point towards writing a better, more user-friendly debugger. That’s kind of like your mom telling your prom date that your brother is smarter and handsomer than you. Even if it’s true, it’s just not called for.

I don’t know. JDB seems fine to me. Then again, I like typing.

1. Follow the steps in the previous tutorial to set up the environment.

2. In any convenient location, create a new directory named “DebuggingTest”.

3. Copy the file “JavaPathAndProgramNameSet.bat”, created in the previous tutorial, to the newly created DebuggingTest directory.

4. Still in the DebuggingTest directory, create a new text file named “DebuggingTest.java”, containing the following text.

public class DebuggingTest
{
    public static void main(String[] args)
    {
        int one = 1;
        int two = 2;

        int sum = add(one, two);

        System.out.println(one + " + " + two + " = " + sum);
    }

    private static int add(int addend0, int addend1)
    {
        int returnValue = addend0 + addend1;

        return returnValue;
    }
}

5. In the DebuggingTest directory, create a new text file named ProgramBuildForDebugging.bat", containing the following text.  Note that this batch file is nearly identical to the one from the prevous tutorial, except that the option "-g" has been added to the command line for javac.exe.

call JavaPathAndProgramNameSet.bat

%javaPath%\javac.exe -g %programName%.java

pause

6. In the DebuggingTest directory, double-click the icon for ProgramBuildForDebugging.bat to run it.  A console window will appear, and DebuggingTest.java will be compiled.

7. After the compilation completes, close the console window by presssing any key.  The file DebuggingTest.class should now be present in the DebuggingTest directory.  Note that class files compiled with the -g option are larger than those compiled without, because extra information must be stored to allow for debugging.

8. In the DebuggingTest directory, create a new text file named "ProgramDebug.bat", containing the following text.

call JavaPathAndProgramNameSet.bat

%javaPath%\jdb.exe %programName%

pause

9. In the DebuggingTest directory, double-click the icon for ProgramDebug.bat to run it.  A console window will appear, and the prompt for JDB will appear in it, as shown below.

Initializing jdb...
>

10. At the JDB prompt, type "help" and press the enter key.  A list of JDB commands will appear.  Review this list, making special note of the commands "run", "where", "print", "stop in", "stop at", "clear", "step", "step up", "next" "cont", "list", and "use".

11. At the JDB prompt, type "use ." and press the enter key.  This will set the sourcepath to the current directory.  The sourcepath is a list of directories where the jdb will look to find the source code files associated with the program.  If a sourcepath is not specified, it will not be possible to view the code listing as the debugger steps through it.

12. At the JDB prompt, type "stop in DebugggingTest.add" and press the enter key.  This will set a breakpoint at the beginning of the add() method.

13. At the JDB prompt, type "run" and press the enter key.  This will cause the program to start running.  The program will run until it either finishes or encounters a breakpoint.  In this example, the debugger will stop at the breakpoint that was set in the previous step, and a notification will appear as shown below.

Breakpoint hit: "thread=main", DebuggingTest.add(), line=15 bci=0
15              int returnValue = addend0 + addend1;

14. At the JDB prompt, type "where" and press enter.  The debugger will display a list of the current execution stack.  In this example, the stack contains only two items, the add() method and the main() method which called it.

[1] DebuggingTest.add (DebuggingTest.java:15)
[2] DebuggingTest.main (DebuggingTest.java:8)

15. At the JDB prompt, type "list" and press enter.  A listing of the code surrounding the current breakpoint will appear.  For this example, it will look something like the text shown below.

11      }
12
13      private static int add(int addend0, int addend1)
14      {
15 =>           int returnValue = addend0 + addend1;
16
17              return returnValue;
18      }
19    }

16. At the JDB prompt, type "next" and press enter.  The debugger will execute the current line and stop at the next, displaying the notification shown below.

Step completed: "thread=main", DebuggingTest.add(), line=17 bci=4
17              return returnValue;

17. At the JDB prompt, type "print returnValue" and press enter.  The value of the returnValue variable will be displayed.

main[1] print returnValue
returnValue = 3

18. At the JDB prompt, type "step up" and press enter.  The debugger will finish executing the current method and return to the calling method.  In this example, the calling method is the main() method.

main[1] step up
Step completed: "thread=main", DebuggingTest.main(), line=8, bci=9
8                int sum = add(one, two);

19. At the JDB prompt, type "cont" and press enter.  The debugger will resume normal execution of the program, stopping at the next breakpoint.  Since there are no further breakpoints in this example, entering "cont" will allow the program to display its message and exit.

main[1] cont
> 1 + 2 = 3

The application exited

Additional Notes

  • The "next" command "steps over" any method calls on the current line, while the "step" command "steps into" any such method calls.
  • The "stop at" command can be used to set a breakpoint at a specific line number.
  • The "reenter" command can be used to re-start execution of the current method.
  • If the source code is contained in multiple directories, the names of these directories should be separated by semicolons when they are passed to the "use" command.
  • If the source code is not in the default package, it may be necessary to prepend the name of the relevant package, plus a dot, to the class and method name.
  • To set a breakpoint in an "inner" class (that is, a class declared within another class), the names of the "outer" and "inner" classes must be delimited by a dollar sign ($) rather than with a dot.
About these ads
This entry was posted in Uncategorized and tagged , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s