The Data Display Debugger (DDD)
A Quick Start Guide

Back to my home page

CSC231, Microprocessors and Assembly Language
Smith College, Fall 2002

Index

  1. Getting ready to debug
  2. Starting the debugger
  3. Configuring DDD
  4. Setting breakpoints
  5. Debugging
  6. Useful links

1. Getting ready to debug

In order to be debugged, a program needs to contain some special debugging information that is generated by the assembler and included in the output object file. NASM generates this information when used with the "-F" option. The example below shows how we would assemble hello.asm with debugging information.

$ nasm -f elf -F stabs hello.asm

The -f elf option specifies the format of the binary file to be generated - Linux uses ELF, the Executable Linking Format. The second option, -F stabs, tells the assembler to include debugging information in the output file. DDD and GDB use the STABS debugging format.

Below we show a complete example:

$ nasm -f elf -F stabs hello.asm
$ ld -o hello hello.o

As you can see, the linker (ld) does not require any special option.

2. Starting the debugger

To start debugging a program just type ddd and the name of the program. For example:

$ ddd hello &

The DDD window should pop up as shown in Figure 2.1.

The DDD Debugger

Figure 2.1 - The DDD debugging environment

The debugging environment consists of a source frame (top), a GDB shell frame (bottom), and a command toolbox (right).

3. Configuring the debugger

Before we can start using DDD, we need to change some of its default settings.

Select "Edit->Preferences" from the main menu. On the window that will appear, open the "Source" tab (top of the window). Then, check the "Display Source Line Numbers" option (Figure 3.1). Click OK to close the window.

Configure

Figure 3.1 - Display lines in source code

Next, select "Edit->GDB Settings" from the main menu. In the window that pops up, scroll approximately half way down through the list of options, until you find the option "Disassembly flavor". Change its value to "Intel" (Figure 3.2) and click on CLOSE.

Configure

Figure 3.2 - Disassembly Flavor

Finally, click on the "Edit->Save Options" menu to save these changes.

4. Setting breakpoints

The job of a debugger is to let us analyze a program's state at a certain point during its execution. The state of a program is given by the program's registers (EAX, EBX, etc), its stack and memory images.

We can check the state of a program at any point during its execution by setting breakpoints into its source code. A breakpoint identifies an instruction at which execution of the program will be suspended. This temporary suspension allows us to look into the program's registers and examine its memory image. Notice that the debugger will stop before executing the breakpoint instruction.

To set a breakpoint in DDD, right-click on the instruction where you want to set the breakpoint, in the source window. Then, select "Set Breakpoint" from the popup menu, as shown below.

Breakpoints

Figure 4.1 - Setting a breakpoint with DDD

The breakpoint will appear as a "stop" sign on the left of the instruction (Figure 4.2).

Breakpoints

Figure 4.2 - A breakpoint

The breakpoint show in Figure 4.2 will interrupt the program at line 40, before executing the "mov ebx, STDOUT_FILENO" instruction.

What would happen if you set a breakpoint at line 39?

Your program is now ready to be debugged.

5. Debugging

First, open an execution window by selecting the "View->Execution Window" menu or by pressing ALT+F9. This window will show any message that your program writes to standard output.

Then click on the "Run" button in the command toolbox on the right of the screen. As expected, execution stops at line 40, where we set the breakpoint. This is indicated by the green arrow next to the stop signal (Figure 5.1).

Debugging

Figure 5.1 - Execution is suspended at the breakpoint

At this point we can examine the state of the program by first looking into its registers. This is done by selecting the Status->Registers menu. A window will pop up showing the value of all of the program's registers (Figure 5.2). Notice that you can keep this window open as you continue your debug process later on.

Registers

Figure 5.2 - Registers of a program at a breakpoint

As expected, the EAX register contains the value 4, which corresponds to the SYS_WRITE symbol. All of the other registers contain irrelevant values.

If instead of a register we are interested in examining a particular memory location (such as msg), we can use the "Data->Memory" menu (Figure 5.3). A window will pop up asking for the number of bytes to examine, and the start memory address. In the example below we choose to examine 5 bytes starting from the address of msg. Because msg contains a string of characters, we choose char as the format to print these 5 bytes. When you click on "Display", a new frame inside the DDD window will appear, showing the contents of memory (Figure 5.4). Notice that in Figure 5.3 we used &msg to indicate the address of msg.

Data

Figure 5.3 - Show the contents of memory at the address of msg

Data

Figure 5.4 - The contents of memory at msg

It is often helpful, once reached a breakpoint, to continue execution of your program one instruction at the time to observe how the status of the program changes. The Next and Step commands in the toolbox serve at this purpose. Open the registers window as explained earlier, and observe how the values of the registers change as we step through the instructions of the program using Step.

The difference between Next and Step is that Next treats function calls (such as "call myFunction") as a whole instruction, while Step jumps into the code of the function.

Useful Links


Valid XHTML 1.0!