Now, you can invoke DDD (Note: Invocation) on the `sample'
executable:
$ ddd sample
After a few seconds, DDD comes up. The "Source Window" contains the
source of your debugged program; use the "Scroll Bar" to scroll through
the file.
The "Debugger Console" (at the bottom) contains DDD version
information as well as a GDB prompt.(2)
GNU DDD Version 3.3.12, by Dorothea Lütkehaus and Andreas Zeller.
Copyright (C) 1995-1999 Technische Universität Braunschweig, Germany.
Copyright (C) 1999-2001 Universität Passau, Germany.
Copyright (C) 2001-2004 Universität des Saarlandes, Germany.
Reading symbols from sample...done.
(gdb) _
The first thing to do now is to place a "Breakpoint" (Note:
Breakpoints), making `sample' stop at a location you are interested
in. Click on the blank space left to the initialization of `a'. The
"Argument field" `():' now contains the location (`sample.c:31'). Now,
click on `Break' to create a breakpoint at the location in `()'. You
see a little red stop sign appear in line 31.
The next thing to do is to actually "execute" the program, such that
you can examine its behavior (Note: Running). Select `Program =>
Run' to execute the program; the `Run Program' dialog appears.
In `Run with Arguments', you can now enter arguments for the
`sample' program. Enter the arguments resulting in erroneous behavior
here--that is, `8000 7000 5000 1000 4000'. Click on `Run' to start
execution with the arguments you just entered.
GDB now starts `sample'. Execution stops after a few moments as the
breakpoint is reached. This is reported in the debugger console.
(gdb) break sample.c:31
Breakpoint 1 at 0x8048666: file sample.c, line 31.
(gdb) run 8000 7000 5000 1000 4000
Starting program: sample 8000 7000 5000 1000 4000
Breakpoint 1, main (argc=6, argv=0xbffff918) at sample.c:31
(gdb) _
The current execution line is indicated by a green arrow.
=> a = (int *)malloc((argc - 1) * sizeof(int));
You can now examine the variable values. To examine a simple
variable, you can simply move the mouse pointer on its name and leave
it there. After a second, a small window with the variable value pops
up (Note: Value Tips). Try this with `argc' to see its value (`6').
The local variable `a' is not yet initialized; you'll probably see
`0x0' or some other invalid pointer value.
To execute the current line, click on the `Next' button on the
command tool. The arrow advances to the following line. Now, point
again on `a' to see that the value has changed and that `a' has
actually been initialized.
To examine the individual values of the `a' array, enter `a[0]' in
the argument field (you can clear it beforehand by clicking on `():')
and then click on the `Print' button. This prints the current value of
`()' in the debugger console (Note: Printing Values). In our case,
you'll get
(gdb) print a[0]
$1 = 0
(gdb) _
or some other value (note that `a' has only been allocated, but the
contents have not yet been initialized).
To see all members of `a' at once, you must use a special GDB
operator. Since `a' has been allocated dynamically, GDB does not know
its size; you must specify it explicitly using the `@' operator (Note:
Array Slices). Enter `a[0]@(argc - 1)' in the argument field and
click on the `Print' button. You get the first `argc - 1' elements of
`a', or
(gdb) print a[0]@(argc - 1)
$2 = {0, 0, 0, 0, 0}
(gdb) _
Rather than using `Print' at each stop to see the current value of
`a', you can also "display" `a', such that its is automatically
displayed. With `a[0]@(argc - 1)' still being shown in the argument
field, click on `Display'. The contents of `a' are now shown in a new
window, the "Data Window". Click on `Rotate' to rotate the array
horizontally.
Now comes the assignment of `a''s members:
=> for (i = 0; i < argc - 1; i++)
a[i] = atoi(argv[i + 1]);
You can now click on `Next' and `Next' again to see how the
individual members of `a' are being assigned. Changed members are
highlighted.
To resume execution of the loop, use the `Until' button. This makes
GDB execute the program until a line greater than the current is
reached. Click on `Until' until you end at the call of `shell_sort' in
=> shell_sort(a, argc);
At this point, `a''s contents should be `8000 7000 5000 1000 4000'.
Click again on `Next' to step over the call to `shell_sort'. DDD ends
in
=> for (i = 0; i < argc - 1; i++)
printf("%d ", a[i]);
and you see that after `shell_sort' has finished, the contents of `a'
are `1000, 1913, 4000, 5000, 7000'--that is, `shell_sort' has somehow
garbled the contents of `a'.
To find out what has happened, execute the program once again. This
time, you do not skip through the initialization, but jump directly into
the `shell_sort' call. Delete the old breakpoint by selecting it and
clicking on `Clear'. Then, create a new breakpoint in line 35 before
the call to `shell_sort'. To execute the program once again, select
`Program => Run Again'.
Once more, DDD ends up before the call to `shell_sort':
=> shell_sort(a, argc);
This time, you want to examine closer what `shell_sort' is doing.
Click on `Step' to step into the call to `shell_sort'. This leaves
your program in the first executable line, or
=> int h = 1;
while the debugger console tells us the function just entered:
(gdb) step
shell_sort (a=0x8049878, size=6) at sample.c:9
(gdb) _
This output that shows the function where `sample' is now suspended
(and its arguments) is called a "stack frame display". It shows a
summary of the stack. You can use `Status => Backtrace' to see where
you are in the stack as a whole; selecting a line (or clicking on `Up'
and `Down') will let you move through the stack. Note how the `a'
display disappears when its frame is left.
Let us now check whether `shell_sort''s arguments are correct.
After returning to the lowest frame, enter `a[0]@size' in the argument
field and click on `Print':
(gdb) print a[0] @ size
$4 = {8000, 7000, 5000, 1000, 4000, 1913}
(gdb) _
Surprise! Where does this additional value `1913' come from? The
answer is simple: The array size as passed in `size' to `shell_sort' is
_too large by one_--`1913' is a bogus value which happens to reside in
memory after `a'. And this last value is being sorted in as well.
To see whether this is actually the problem cause, you can now assign
the correct value to `size' (Note: Assignment). Select `size' in the
source code and click on `Set'. A dialog pops up where you can edit
the variable value.
Change the value of `size' to `5' and click on `OK'. Then, click on
`Finish' to resume execution of the `shell_sort' function:
(gdb) set variable size = 5
(gdb) finish
Run till exit from #0 shell_sort (a=0x8049878, size=5) at sample.c:9
0x80486ed in main (argc=6, argv=0xbffff918) at sample.c:35
(gdb) _
Success! The `a' display now contains the correct values `1000,
4000, 5000, 7000, 8000'.
You can verify that these values are actually printed to standard
output by further executing the program. Click on `Cont' to continue
execution.
(gdb) cont
1000 4000 5000 7000 8000
Program exited normally.
(gdb) _
The message `Program exited normally.' is from GDB; it indicates
that the `sample' program has finished executing.
Having found the problem cause, you can now fix the source code.
Click on `Edit' to edit `sample.c', and change the line
shell_sort(a, argc);
to the correct invocation
shell_sort(a, argc - 1);
You can now recompile `sample'
$ gcc -g -o sample sample.c
$ _
and verify (via `Program => Run Again') that `sample' works fine now.
(gdb) run
`sample' has changed; re-reading symbols.
Reading in symbols...done.
Starting program: sample 8000 7000 5000 1000 4000
1000 4000 5000 7000 8000
Program exited normally.
(gdb) _
All is done; the program works fine now. You can end this DDD
session with `Program => Exit' or `Ctrl+Q'.
---------- Footnotes ----------
(1) Actual numbers and behavior on your system may vary.
(2) Re-invoke DDD with `--gdb', if you do not see a `(gdb)' prompt
here (Note: Choosing an Inferior Debugger)
automatically generated by info2www version 1.2.2.9