Chapter 1. A Sample Debug Session

You can use this manual at your leisure to read all about the debugger. However, a handful of commands are enough to get started using the debugger. This chapter illustrates those commands.

The benchmark program Whetstone is frequently used to measure the performance of floating-point operations. We run Whetstone on the target to compare its performance with other computers. The workings of Whetstone are a bit of a mystery, but by using the debugger we can get an insight.

The first step is to compile the Whetstone source with the debug option switched on. There is no need to compile with minimal optimization since the debugger is able to cope with most optimizations.


$ prefix-gcc -g whetstone.adb -o whetstone

Note that prefix should be replaced with the prefix for your product.

The code we wish to look at starts on line 306, just after the array e1 has been set up. Here is part of the Ada source file showing line 306 and some of the surrounding lines.


300      
301           -- Module 2: computations with array elements
302           e1 (1) := 1.0;
303           e1 (2) := -1.0;
304           e1 (3) := -1.0;
305           e1 (4) := -1.0;
306           for i in 1 .. n2 loop
307              e1 (1) := (e1 (1) + e1 (2) + e1 (3) - e1 (4)) * t;
308              e1 (2) := (e1 (1) + e1 (2) - e1 (3) + e1 (4)) * t;

We start the debugger using the following command. You may use the -q option to suppress the banner:

$ prefix-gdb whetstone
XGC target-ada Version 1.5 (debugger)
Copyright (c) 1996, 2001, XGC Software.
Based on gdb version 4.17.gnat.3.11
Copyright (c) 1998 Free Software Foundation...
(gdb)

The easiest way to get to line 306 is to set a breakpoint on that line, then use the run command. Breakpoints are set using the break command. We can check what breakpoints are set using the info command.

(gdb) break whetstone.adb:306
Breakpoint 1 at 0xee2: file whetstone.adb, line 306.
(gdb) info breakpoints
Num Type           Disp Enb Address    What
1   breakpoint     keep y   0x00000ee2 in whetstone at whetstone.adb:306
(gdb)

So far we have been working with the exec target. This is the executable file whetstone cited on the comand line that invoked the debugger. Using just this file, and no target at all, we can look at the values of symbols, inspect the source code, and the generated code, and check the values of static variables.

In order to run the program we must switch to a real or simulated target. The debugger supports both. The simulator target is called sim and a real target is called remote. The debugger will automatically switch to the simulator and load the program into the simulator if we enter the run command at this point.

(gdb) run
Starting program: .../examples/whetstone 
Connected to the simulator.
Loading sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .init         00000408  00000000  00000000  00001000  2**1
                  CONTENTS, ALLOC, LOAD, CODE
  1 .text         00001890  00000408  00000408  00001408  2**1
                  CONTENTS, ALLOC, LOAD, CODE
  2 .rdata        000003ce  00001c98  00001c98  00002c98  2**1
                  CONTENTS, ALLOC, LOAD, READONLY
  3 .data         0000038a  00010000  00002066  00004000  2**1
                  CONTENTS, ALLOC, LOAD, DATA
Start address 0x0
Transfer rate: 73600 bits in <1 sec.
Whetstone: Floating point benchmark

Breakpoint 1, whetstone () at whetstone.adb:306
306           for i in 1 .. n2 loop
(gdb)

What we want to do now is see how the value of e1 changes as we go round the loop. We can print the initial value using the print command. Note that arrays (and structures) may be printed with a single command.

(gdb) print e1(1)
$1 = 1
(gdb) print e1(2)
$2 = -1
(gdb) print e1
$2 = (1 => 1, 2 => -1, 3 => -1, 4 => -1)
(gdb)

We can then step through the program one line at a time using the next command. Like many other commands, the next command repeats when we press Enter. Therefore, after the first next command, we just hit Enter.

(gdb) next
307              e1 (1) := (e1 (1) + e1 (2) + e1 (3) - e1 (4)) * t;
(gdb) enter
308              e1 (2) := (e1 (1) + e1 (2) - e1 (3) + e1 (4)) * t;
(gdb) enter
309              e1 (3) := (e1 (1) - e1 (2) + e1 (3) + e1 (4)) * t;
(gdb) enter
310              e1 (4) := (-e1 (1) + e1 (2) + e1 (3) + e1 (4)) * t;
(gdb)

Let's check the value of e1. This time we'll use the abbreviation.

(gdb) p e1
$3 = (1 => 0, 2 => -0.499975026, 3 => -0.749975085, 4 => -1)

If we need to check the value of e1 each time round the loop, it is tedious to have to step through each line then type the print command at the end of the loop. Instead we can place a breakpoint at the end of the loop and use the continue command to execute to the end of the loop. Furthermore, we can use the display command to print the value of e1 each time the program stops.

(gdb) br
Breakpoint 2 at 0xf2e: file whetstone.adb, line 310.
(gdb) display e1
1: e1 = (1 => 0, 2 => -0.499975026, 3 => -0.749975085, 4 => -1)

Use the continue command to run the program to the next breakpoint. Then press Enter to repeat the continue command. Note that continue may be abbreviated to c.

(gdb) c
Continuing.

Breakpoint 2, whetstone () at whetstone.adb:310
310              e1 (4) := (-e1 (1) + e1 (2) + e1 (3) + e1 (4)) * t;
1: e1 = (1 => -0.0625123829, 2 => -0.468692422, 3 => -0.734320521, 4 => -1.12491918)
(gdb) Enter
Continuing.

Breakpoint 2, whetstone () at whetstone.adb:310
310              e1 (4) := (-e1 (1) + e1 (2) + e1 (3) + e1 (4)) * t;
1: e1 = (1 => -0.0664326251, 2 => -0.466705739, 3 => -0.733313918, 4 => -1.13265347)
(gdb) Enter

To finish the debugging session use the quit command. You may abbreviate quit to q.

(gdb) q
The program is running. Quit anyway (and kill it)? (y or n) y
$