Home
Research Publications
Teaching Students CV Software Funding Activities

Debugging

A debugger is yet another invaluable tool for a software engineer.  It provides a powerful mechanism for peering into the inner workings of complex programs and often comes paired with a user-friendly graphical user interface that makes it easy to use a debugger's important features.  By this point in your academic progress you likely have a basic familiarity with using a debugger for such tasks as setting breakpoints, examining the values of variables, and viewing a program's call stack.  This lab will cover some of the more advanced debugging capabilities that you may not have been exposed to previously.

Breakpoint Types

While most software developers are familiar with using line breakpoints, many other breakpoint types exist as well:
A list of all currently defined breakpoints is available in Eclipse's "Breakpoints" view.  The "Breakpoints" view is loaded automatically in the "Debug" perspective (usually in the same tab grouping as "Variables"), or can be opened manually in any perspective by selecting "Window -> Show View -> Other... -> Debug -> Breakpoints".  The "Breakpoints" view also provides a convenient way to enable/disable breakpoints and to edit their properties (see section on properties below).

Breakpoint Properties

In addition to the breakpoint types listed above, each breakpoint has a set of properties that can be used to refine the conditions under which a breakpoint will halt program execution.  These properties can be edited by right clicking on the breakpoint (either within the "Breakpoints" view or on the indicator that appears to the left within the editor) and selecting the "Breakpoint Properties..." context menu item.  Here are some of the most commonly used properties:
Exercise
The following program generates arbitrary hashes and prints them to the screen in an infinite loop.  It has been written in such a way that any changes to the program are very likely to change the output - a scenario in which debuggers become a very important tool.  Your task is to use a breakpoint to figure out the 49,791st hash value that will be printed.  (Hint: Don't worry too much about how the values are generated, just find where the value to be printed is computed and use the breakpoint expertise introduced above to find the answer)
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;


/**
* DebugHash provides an executable program to print arbitrary values to
* the screen in an infinite loop. It is written in such a way that code
* changes are very likely to change the output, and thus demonstrates the
* utility of debuggers to instrument code without modifying it.
*
*/
public class DebugHash {

/**
* Using a supplied seed value, compute arbitrary (but repeatable) values
* based upon an underlying hashing algorithm.
*
* @param seed - the seed used to determine the sequence of arbitrary values.
*/
private static void printArbitraryHashes(byte seed) {
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
System.exit(-1);
}

byte[] last_hash = {seed};

while (true) {
md5.update(last_hash);
byte[] new_hash = md5.digest();

String hashString = getHashString(new_hash);
System.out.println(hashString);

last_hash = new_hash;
}
}

/**
* Translate a given byte array into a hexadecimal String represention of
* the given array.
*
* @param hash - the byte array to be translated.
* @return - the hexadecimal String representation.
*/
private static String getHashString(byte[] hash) {
return String.format("%032x", new BigInteger(1, hash));
}

/**
* Entry-point for this executable class.
*
* @param args - the command line parameters (unused by this program).
*/
public static void main(String[] args) {
byte seed = 0;
for (StackTraceElement element: Thread.currentThread().getStackTrace()) {
seed += element.getLineNumber();
}

printArbitraryHashes(seed);
}
}
Another challenge...
Exercise
For this exercise we'll emulate the process of dealing with a bug report from a user.  Download the following codebase:
http://subversion.assembla.com/svn/ee461l-debugginglab/trunk/

A user of this software has provided the following bug report:
The sorting algorithm throws exceptions when traversing through the array and when a null element is present in the array.

Your task is to work through the following steps to put this bug to rest:
  1. Find a way to reliably reproduce the bugs.
  2. Write a jUnit test fixture (containing one or more tests as appropriate) that fails because of these bugs and can be added to the program's test suite.
  3. Use the debugger to track down the source of the bugs.
  4. Fix the code to remove the bugs.

Reference materials:
Developed with guidance from Miryung Kim and Kyle Prete

Copyright (c) 2011 Professor Miryung Kim, a course development TA Evan Grim

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.  A copy of the license can be found on the GNU web site here.