917 lines
37 KiB
HTML
917 lines
37 KiB
HTML
<!--startcut ==============================================-->
|
|
<!-- *** BEGIN HTML header *** -->
|
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
|
<HTML><HEAD>
|
|
<title>Visual Debugging with ddd LG #73</title>
|
|
</HEAD>
|
|
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#0000AF"
|
|
ALINK="#FF0000">
|
|
<!-- *** END HTML header *** -->
|
|
|
|
<CENTER>
|
|
<A HREF="http://www.linuxgazette.com/">
|
|
<IMG ALT="LINUX GAZETTE" SRC="../gx/lglogo.png"
|
|
WIDTH="600" HEIGHT="124" border="0"></A>
|
|
<BR>
|
|
|
|
<!-- *** BEGIN navbar *** -->
|
|
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="field.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="index.html"><IMG ALT="[ Table of Contents ]" SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../index.html"><IMG ALT="[ Front Page ]" SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue73/mauerer.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../faq/index.html"><IMG ALT="[ FAQ ]" SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="mwaikambo.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
|
|
<!-- *** END navbar *** -->
|
|
<P>
|
|
</CENTER>
|
|
|
|
<!--endcut ============================================================-->
|
|
|
|
<H4 ALIGN="center">
|
|
"Linux Gazette...<I>making Linux just a little more fun!</I>"
|
|
</H4>
|
|
|
|
<P> <HR> <P>
|
|
<!--===================================================================-->
|
|
|
|
<center>
|
|
<H1><font color="maroon">Visual Debugging with ddd</font></H1>
|
|
<H4>By <a href="mailto:wolfgang@mynetix.de">Wolfgang Mauerer</a></H4>
|
|
</center>
|
|
<P> <HR> <P>
|
|
|
|
<!-- END header -->
|
|
|
|
|
|
|
|
|
|
<H1>
|
|
Overview
|
|
</H1>
|
|
To err is human. Programmers are humans. Therefore programmers err.
|
|
The overwhelming complexity and unsurpassable logic inherent in those
|
|
little words may well be the cause for several years of discussion in the
|
|
philosophers' department, but holds without further doubt one timeless
|
|
truth, when it's brought down to earth again: <EM>All programs written by
|
|
human programmers are full of errors.</EM> Although the belief
|
|
is still alive in some places that
|
|
programming is just a more or less mechanical and stupid exercise
|
|
that can be fulfilled without making any mistakes if only enough care
|
|
is taken and planning is applied, a more sensible way of thinking seems
|
|
to be devastating for programmers at first: Nothing works, all
|
|
programs are full or error, the specs are wrong, and the implementation
|
|
does the opposite as expected. But this is noting against programmers,
|
|
in fact the fully opposite is the case: Programming is a very complicated
|
|
and challenging task, and errors are therefore unavoidable, even for the
|
|
best programmers - only easy things can be done without fault.
|
|
The importance of errors or better: the way how to <I>find</I> and <I>fix</I>
|
|
those errors
|
|
in the lifecycle of a software product is a task whose importance cannot be
|
|
stressed enough over and over. Finding errors is not
|
|
just an unavoidable part in the development cycle, but a vital part of every
|
|
software system's lifespan.
|
|
|
|
<P>
|
|
It seems clear that bugs in software systems must be found, and
|
|
that good tools are needed to assist the programmer in this complicated
|
|
task. As most of you might know, there is
|
|
a very capable debugger available as free software from (who else?)
|
|
the GNU project. Since the GNU people are responsible for the
|
|
most important compiler under linux, the gnu c compiler, both
|
|
programs form a bodacious and capital team when it comes to kill
|
|
nasty bugs in your programs. Those of you who have already used the debugger
|
|
know its spartan interface: It's not bad, but not
|
|
too good either. Even if one is a friend of the command line and text-based
|
|
utilities (as the author certainly is),
|
|
using this form of debugger interaction is not always
|
|
hilarious and can be a quite poignant exercise, especially when
|
|
larger systems with complex data structures are debugged.
|
|
The text interface may be well suited for single-stepping through
|
|
programs, checking simple values or testing certain conditions, but
|
|
it is certainly not the optimal choice for modern, effective and
|
|
easy-to-do debugging of structures deeply connected with each other.
|
|
Other interfaces (like the emacs gud-mode or the new tui interface
|
|
for gdb) offer slightly more comfort, but are not ideal as well.
|
|
|
|
<P>
|
|
We need a graphical interface therefore, and again the GNU project
|
|
offers a very good possibility: DDD, the data display debugger.
|
|
DDD is a graphical interface written by Andreas Zeller
|
|
and Dorothea Luetkenhaus (and the help of many other programmers
|
|
from the free software community) and made into a GNU program
|
|
some time ago (although it was GPLed already before that). If debugging
|
|
weren't such a sometimes very hard job, we would nearly
|
|
be tempted to say that debugging with ddd is mere fun.
|
|
|
|
<P>
|
|
What does ddd offer compared to the pure gdb interface or to other
|
|
debugger front ends like the emacs gud-mode? The main point is not
|
|
just DDD's normal debugging functions (e.g., stepping through your
|
|
source file line by line, setting breakpoints and watchpoints, changing
|
|
the values of program variables), which are supported by ddd (in a
|
|
very convenient and much simpler way compared to the traditional
|
|
gdb interface), but that DDD can also display
|
|
data structures graphically. What does this mean? Consider a linked
|
|
list in C, as we will use it in one of our later examples. The data
|
|
structure basically consists of several data fields together
|
|
with one or more pointer fields to other structures of the same type,
|
|
that together form an interconnected network. The network is made up of the values
|
|
of the pointer variables. It could in principal by reconstructed
|
|
by their hexadecimal contents, giving the memory location of the previous
|
|
or following elements, but this is neither a very convenient
|
|
nor comfortable task. It is very difficult to produce a concise overview
|
|
about the situation this way, and even if the programmer succeeds in
|
|
that laborious task, there is a major drawback: Since memory
|
|
locations change in the next program run (or when a different
|
|
input dataset etc. is used), the work is quickly rendered useless.
|
|
DDD overcomes this limitation by automatically creating diagrams
|
|
from the memory contents, allowing a simple and appealing visual
|
|
view to complex structures.
|
|
|
|
<P>
|
|
But the ability to draw program structures graphically is not the
|
|
only enhancement offered by ddd compared to classical dialog-based
|
|
debugging methods:
|
|
|
|
<P>
|
|
|
|
<UL>
|
|
<LI>The ability to switch between multiple source files automatically.
|
|
</LI>
|
|
<LI>A convenient view of the whole program text (and not just some few
|
|
lines surrounding the actual statement).
|
|
</LI>
|
|
<LI>Different back-end debuggers are supported. This means that
|
|
ddd can not only
|
|
run with gdb as back-end debugger process, but can use debuggers
|
|
for the Python and Perl scripting languages, sun's java debugger
|
|
or dbx and ladebug (on systems other than GNU/Linux) as well.
|
|
</LI>
|
|
<LI>Multiple languages are supported. This is not just a result of
|
|
the multi-debugger ability, but also a benefit of the gdb support
|
|
for different source languages (C, C++, Objective C, Fortran, Java, ...)
|
|
</LI>
|
|
<LI>The same interface is used for all languages supported by the
|
|
underlying debuggers.
|
|
</LI>
|
|
</UL>
|
|
|
|
<P>
|
|
Let's see how all these things look in practice by debugging a simple
|
|
example program.
|
|
|
|
<H1>
|
|
Generating debugging information
|
|
</H1>
|
|
Binary programs normally don't contain any information about the source
|
|
file; they solely perform the codes intended task in terms
|
|
of machine instructions. It is therefore necessary to include so-called
|
|
<I>debugging symbols</I> in the object code before advanced
|
|
features of a debugger can be used (without this, it would be possible
|
|
to step through the program in single machine instruction steps, but
|
|
since there is no direct connection with the source code any more, this
|
|
is not very helpful). There are several different debugging formats
|
|
floating around in the Unix world, but we do not want to dive deeper into this
|
|
subject, since it is mostly important for compiler programmers. Instead,
|
|
we will concentrate on the GNU/Linux platform using the GNU C compiler using
|
|
standard settings.
|
|
|
|
<P>
|
|
The standard option to include debugging information in a program is
|
|
to use the switch <TT>-g</TT> when calling <TT>gcc</TT>:
|
|
|
|
<P>
|
|
|
|
<DIV ALIGN="LEFT">
|
|
<TT>
|
|
[wolfgang<code>@</code>jupiter wolfgang]$ gcc -g fac.c -o fac
|
|
<BR></TT>
|
|
</DIV>
|
|
|
|
<P>
|
|
This will create a binary file <TT>fac</TT> which is bigger in size
|
|
than the normal executable.
|
|
Obviously, this is not a big surprise: Since additional data (like assignments
|
|
between blocks of machine instructions and line numbers in the source code
|
|
etc.) are stored in the code now, the size must increase.
|
|
|
|
<P>
|
|
It is important to note that gcc offers a feature quite rare
|
|
among competing compilers: Debugging information can be generated even
|
|
if optimizations are turned on, e.g. <TT>gcc -g -O2 fac.c fac</TT>
|
|
will work, producing a binary file that is optimized <I>and</I> contains
|
|
debugging information. Although this can be quite handy in some cases,
|
|
there are some well hidden trap doors behind this approach (like
|
|
optimizing away several lines of code), so we won't cover these combinations
|
|
here.
|
|
|
|
<P>
|
|
The source file for <TT>fac.c</TT> has the following contents:
|
|
|
|
<P>
|
|
<PRE>
|
|
#include<stdio.h>
|
|
|
|
int main() {
|
|
int count;
|
|
int fac;
|
|
|
|
for (count = 1; count < 10; count++) {
|
|
fac = faculty(count);
|
|
printf("count: %u, fac: %u\n", count, fac);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int faculty(int num) {
|
|
if (num = 0) {
|
|
return 1;
|
|
}
|
|
else {
|
|
return num * faculty(num - 1);
|
|
}
|
|
}
|
|
</PRE>
|
|
|
|
<P>
|
|
As you can see, the program just performs some really simple calculations:
|
|
We loop over a range of integer values from 1 to 9 and call a function
|
|
to calculate the number's faculty in every loop step. It's
|
|
perfectly clear that this could be done in a much more efficient way,
|
|
but it serves as a good example for general debugging techniques.
|
|
By the way: It will not run correctly, since it contains an error.
|
|
You can check this by executing it in a normal shell, without an attached
|
|
debugger (binaries with included debugging symbols run like
|
|
normal programs, they are just a little bit slower): The only thing
|
|
you get is a core dump that happens due to a segmentation fault.
|
|
So let's put the program into the debugger and find out what's wrong!
|
|
|
|
<H1>
|
|
Stepping through programs
|
|
</H1>
|
|
|
|
<H2>
|
|
Opening a program to debug
|
|
</H2>
|
|
ddd is started by typing
|
|
|
|
<P>
|
|
|
|
<DIV ALIGN="LEFT">
|
|
<TT>
|
|
[wolfgang<code>@</code>jupiter wolfgang]$ ddd&
|
|
<BR></TT>
|
|
</DIV>
|
|
|
|
<P>
|
|
at your prompt; the file name of the program that shall be debugged can
|
|
be supplied as an optional argument. If ddd is not installed on your
|
|
system, this can almost certainly be done using your favorite
|
|
package management system (like apt-get, rpm etc.), since ddd binaries are
|
|
supplied with all major distributions. In case there is no binary package
|
|
for your system (or if you want to compile ddd from scratch for some
|
|
reasons), get the source distribution from <TT>ftp.gnu.org</TT> (or
|
|
preferably one of it's mirrors) and follow the instructions in the
|
|
<TT>INSTALL</TT> file accompanying it.
|
|
|
|
<P>
|
|
If you did not supply the file name on the command line, you can select
|
|
it via the <code>File->Open</code> Program menu entry via a dialog box. ddd then
|
|
loads this program, parses the debugging symbols (or, to be precise:
|
|
lets the back-end debugger parse the symbols)
|
|
and loads the main source file afterwards. Your display should show
|
|
a window similar to figure 1</A>.
|
|
|
|
<P>
|
|
|
|
<P></P>
|
|
<DIV ALIGN="CENTER"><A NAME="sshot1"></A><A NAME="40"></A>
|
|
<TABLE>
|
|
<CAPTION ALIGN="BOTTOM"><STRONG>Figure 1:</STRONG>
|
|
The ddd main window</CAPTION>
|
|
<TR><TD><IMG
|
|
WIDTH="603" HEIGHT="619" BORDER="0"
|
|
SRC="misc/mauerer/img1.png"
|
|
ALT="\begin{figure}\begin{center}
|
|
\epsfig{file=sshot1.eps, scale=0.3} \end{center}\end{figure}"></TD></TR>
|
|
</TABLE>
|
|
</DIV><P></P>
|
|
|
|
<P>
|
|
The ``Command Tool''-Subwindow is very important for our later work. By
|
|
default, it is shown in the main window's right area, offering
|
|
several buttons to perform diverse actions with our
|
|
code (in case you should close the window incidentally, you can reopen
|
|
it either via <TT>F8</TT> or the <code>View->Command Window</code> menu item).
|
|
|
|
<P>
|
|
|
|
<H2>
|
|
Step and Next
|
|
</H2>
|
|
Let's step through the program line by line, watching precisely
|
|
what happens during its execution. To do this, we need to start the program,
|
|
but we also need to set a so-called breakpoint in order to prevent the whole
|
|
program from finishing before we have a chance to interrupt it.
|
|
A breakpoint suspends the program execution on a certain source line,
|
|
giving the opportunity to interact with the debugger and perform debugging
|
|
actions. Point your mouse on the left side of the source window on
|
|
the line <TT>int count;</TT>, press the right mouse button and select
|
|
``Set Breakpoint'' from the popup menu. This creates a red stop sign
|
|
on the corresponding line, meaning that the program execution will stop
|
|
once it reaches this point.
|
|
|
|
<P>
|
|
Now we can get the ball rolling: Select ``run'' from the command tool,
|
|
which will instruct the debugger to start the code. The program
|
|
doesn't run very long, since our breakpoint is located at the very beginning
|
|
of the file; we are now in a debugger interaction mode. The green
|
|
arrow to the left of the source lines shows us the line that will be
|
|
executed <I>next</I> in the source file.
|
|
|
|
<P>
|
|
There a two possibilities to step through a source code: While ``next''
|
|
takes you line by line, but omits procedure calls (and just presents you the
|
|
result of the call), ``step'' will dig through the subroutine's code when
|
|
it is called. As we want to see what's wrong in our program (since the
|
|
error is a very common one, experienced programmers will have seen it
|
|
already certainly), we decide to ``step'' through the program.
|
|
Press the button, and you will find the green source line pointer right
|
|
in the beginning of the faculty subroutine. This is what we intended,
|
|
so you can press ``step'' another time, leading the green arrow directly
|
|
into the else-branch of our conditional decision. This is all right again.
|
|
What would we expect now? Since <TT>num</TT> had the value 1 when we entered
|
|
the subroutine, it should be 0 when we enter the subroutine again recursively,
|
|
resulting in an immediate return of the value 1, which should again result
|
|
in returning 1*1=1 from our first call of faculty, leading us back to the
|
|
main program. Let's check whether this is what actually happens by pressing
|
|
``step'' for another time: The green pointer moves again to the beginning
|
|
of the function, but enters the else-branch again in the next step!
|
|
Obviously, something went wrong: We need to check <TT>num</TT>'s value.
|
|
|
|
<P>
|
|
There are several possibilities to show the value of simple variables
|
|
(e.g. variables of simple types like int, long, float etc.). The most
|
|
common one is to keep the mouse pointer over the variable in the source
|
|
window, waiting until a tooltip with its contents appears on the screen.
|
|
Alternative ways are to press the right mouse button right over the identifier
|
|
and select <TT>Print num</TT> from the popup menu or to mark the identifier
|
|
and select the <code>Data->Print()</code> menu entry. With the last two methods,
|
|
the value is displayed in the gdb output window in the lower region
|
|
of the main window.
|
|
|
|
<P>
|
|
Regardless of the method used, we receive 0 as <TT>num</TT>'s value.
|
|
Why has the second branch been taken, although
|
|
num is 0? Using step for another time confirms your possible assumption
|
|
about the error case:
|
|
If we look at the value of <TT>num</TT> right at the beginning of the function,
|
|
we see that it is -1, but in the next step (again the second branch of
|
|
the if-conditional), it is 0 again: The error is a forgotten <TT>=</TT>
|
|
in the if-clause, resulting in an assignment rather than a comparison!
|
|
Although this is a very common error in C programs, it can cause considerable
|
|
delay to the program's development if it is only well enough hidden.
|
|
Since we won't receive any meaningful result from this incorrect
|
|
program, we can kill it with the ``kill''-Button in the execution window.
|
|
|
|
<P>
|
|
Correct the error by exchanging the "=" with a "==", recompile the
|
|
program (don't forget to include debugging symbols again!) and reload
|
|
it into ddd via the "File"-menu. As you can see, out breakpoint
|
|
is conserved, so we can start the program again from the very beginning.
|
|
If we step through the faculty call now, everything works alright.
|
|
The faculty function is completed, and the green source line pointer
|
|
is now in the <TT>printf(...)</TT>-line. We need to be careful: If we
|
|
select ``step'' for another time, ddd will try to step through the
|
|
print call, which is not possible, since the function is taken from
|
|
the standard C library which is normally not compiled with
|
|
debugging symbols (although it's possible to). We therefore prefer
|
|
``next'' in this case. ``Step'' would
|
|
give us an error message about several missing source files; it would take
|
|
a bunch of ``next''-clicks to get the green pointer back to our source
|
|
code again.
|
|
|
|
<P>
|
|
|
|
<H1>
|
|
Visualizing data structures
|
|
</H1>
|
|
|
|
<H2>
|
|
Simple structures</A>
|
|
</H2>
|
|
In our first, simple example, ddd is similar
|
|
to other interfaces like the emacs gud-mode
|
|
(except for the increased comfort). But here's a unique and marvellous
|
|
feature of ddd: The ability so display
|
|
nested structures graphically. In order to demonstrate
|
|
the corresponding features, we need a new example program,
|
|
<TT>list.c</TT>:
|
|
|
|
<P>
|
|
<PRE>
|
|
#include<stdio.h>
|
|
|
|
int main() {
|
|
typedef struct person_struct {
|
|
/* Data elements */
|
|
char* name;
|
|
int age;
|
|
|
|
/* Link elements */
|
|
struct person_struct *next;
|
|
struct person_struct *prev;
|
|
} person_t;
|
|
|
|
person_t *start;
|
|
person_t *pers;
|
|
person_t *temp;
|
|
|
|
char *names[] = {"Linus Torvalds", "Alan Cox", "Rik van Riel"};
|
|
int ages[] = {30, 31, 32};
|
|
int count; /* Temporary counter */
|
|
|
|
start = (person_t*)malloc(sizeof(person_t));
|
|
start->name = names[0];
|
|
start->age = ages[0];
|
|
start->prev = NULL;
|
|
start->next = NULL;
|
|
pers = start;
|
|
|
|
for (count=1; count < 3; count++) {
|
|
temp = (person_t*)malloc(sizeof(person_t));
|
|
temp->name = names[count];
|
|
temp->age = ages[count];
|
|
pers->next = temp;
|
|
temp->prev = pers;
|
|
pers = temp;
|
|
}
|
|
temp->next = NULL;
|
|
|
|
printf("Data structure created\n");
|
|
return 0;
|
|
}
|
|
</PRE>
|
|
|
|
<P>
|
|
Although you might know the names used in the example, they are not
|
|
important. The ages are chosen at random!
|
|
|
|
<P>
|
|
The code defines a double linked list of person-elements that stores two
|
|
personal properties (name and age) together with two pointers (to
|
|
the next and previous person in the list). Since this is one of the
|
|
most important structures in C, every programmer should have seen
|
|
something like this already several times before, normally in a
|
|
more complete fashion. As before, our program does not perform a too
|
|
important job: It just builds a data structure in memory
|
|
and then exits, but this is sufficient for our purposes. As usual,
|
|
the program must be compiled with debugging symbols included and then
|
|
loaded into ddd.
|
|
|
|
<P>
|
|
For this time, we set our first breakpoint in line 28 (the beginning
|
|
of the <TT>for</TT>-loop) and start our program afterwards. Place the
|
|
mouse pointer over the <TT>start</TT>-identifier: ddd will show you
|
|
in the value tooltip appearing after a small amount of time that it is
|
|
a pointer to an instance of <TT>struct person_t</TT> at a certain
|
|
memory location given in hexadecimal notation. A perfect candidate
|
|
for graphical visualisation!
|
|
|
|
<P>
|
|
Pop up the context menu by pressing the right mouse button over the
|
|
start identifier and select "Display *start" - the star is needed so
|
|
that ddd automatically dereferences the pointer and shows the structure's
|
|
contents. A new section in the
|
|
upper part of the ddd window will show up, containing a figure
|
|
visualising <TT>start</TT>'s contents: <TT>name</TT> and <TT>age</TT>
|
|
are set to the values assigned a few lines before, and <TT>next</TT>,
|
|
<TT>prev</TT> contain <TT>NULL</TT> pointers as expected. Figure 2
|
|
shows the box that you should see on your display (the char pointer's
|
|
hexadecimal value may vary on your system, though).
|
|
|
|
<P>
|
|
|
|
<P></P>
|
|
<DIV ALIGN="CENTER"><A NAME="sshot2"></A><A NAME="73"></A>
|
|
<TABLE>
|
|
<CAPTION ALIGN="BOTTOM"><STRONG>Figure 2:</STRONG>
|
|
Visualisation of a data structure</CAPTION>
|
|
<TR><TD><IMG
|
|
WIDTH="603" HEIGHT="619" BORDER="0"
|
|
SRC="misc/mauerer/img2.png"
|
|
ALT="\begin{figure}\begin{center}
|
|
\epsfig{file=sshot2.eps, scale=0.3} \end{center}\end{figure}"></TD></TR>
|
|
</TABLE>
|
|
</DIV><P></P>
|
|
|
|
<P>
|
|
This is already a pretty amazing feature, isn't it? But let's execute
|
|
our program a little further, seeing how our data structure is built up
|
|
in memory. Use the ``next''-button to step through the for loop's body
|
|
until line 34 (<code>pers->next = temp</code>) is reached: The second person's data
|
|
structure is built and connected with the first person by then.
|
|
When you watch the graph display afterwards, you can see that the
|
|
<TT>next</TT>-field of our first person has a value different than
|
|
0 now, meaning that it points to another structure: The clou: If you
|
|
double-click
|
|
on this value, a new box with the second person's structure opens, and
|
|
the pointer from person 1 to person 2 is automatically displayed as an
|
|
arrow between the boxes.
|
|
|
|
<P>
|
|
We take a different way to create the third person's data structure,
|
|
because it is inconvenient to step through all single lines of a code
|
|
just to see the result. Let's apply another breakpoint in line 39 which
|
|
contains the <TT>printf(...)</TT>-statement. Pressing ``cont'' continues
|
|
the program flow until another breakpoint (our fresh set one) is reached.
|
|
|
|
<P>
|
|
We can display the third person's data structure in the usual way.
|
|
But now, we do not just want to see the pointers from person <tt>n</tt>
|
|
person <tt>n+1</tt>, but also the backward pointers! Double click, for example,
|
|
on the <TT>prev</TT>-field in the second graph: Another box pops up,
|
|
duplicating the first person's box in the display! The same thing happens
|
|
for the <TT>prev</TT>-pointer of the third person. This is obviously not what
|
|
we want, because the same structure should not be displayed twice. We
|
|
have to tell ddd to take care about this.
|
|
|
|
<P>
|
|
Ddd uses a feature called <I>alias detection</I> in order to achieve this,
|
|
which can be activated by activating the <code>Data->Detect</code> Aliases menu
|
|
entry. The display should look like figure 3 now.
|
|
|
|
<P>
|
|
|
|
<P></P>
|
|
<DIV ALIGN="CENTER"><A NAME="llist"></A><A NAME="87"></A>
|
|
<TABLE>
|
|
<CAPTION ALIGN="BOTTOM"><STRONG>Figure 3:</STRONG>
|
|
A linked list of persons</CAPTION>
|
|
<TR><TD><IMG
|
|
WIDTH="571" HEIGHT="57" BORDER="0"
|
|
SRC="misc/mauerer/img5.png"
|
|
ALT="\begin{figure}\begin{center}
|
|
\epsfig{file=list.ps, scale=0.7} \end{center} \end{figure}"></TD></TR>
|
|
</TABLE>
|
|
</DIV><P></P>
|
|
|
|
<P>
|
|
All pointers are shown in the correct manner, giving us a quite good
|
|
impression of the data structure in memory. Sadly, alias detection
|
|
especially with tight connected structures has
|
|
the drawback of slowing down ddd, since several memory locations
|
|
must be compared after every program step in order to see which structures
|
|
in the display represent the same memory location, compacting the graph
|
|
respectively. Additionally, alias detection is
|
|
only available with source languages that allow the back-end debugger to
|
|
provide addresses of arbitrary objects, limiting the possible choices to
|
|
C, C++ and Java at the moment.
|
|
|
|
<P>
|
|
|
|
<H2>
|
|
A more complicated example
|
|
</H2>
|
|
Let us take a look at a slightly more complicated example (at least
|
|
in relation to the created data structure) in order to demonstrate
|
|
ddd's graph layout capabilities. The source code used from now on is
|
|
the following (<TT>arith.c</TT>):
|
|
|
|
<P>
|
|
<PRE>
|
|
#include<stdio.h>
|
|
/* Create a binary tree structure representing an arithmetic expression */
|
|
|
|
enum operator { plus, minus, times, div };
|
|
|
|
typedef struct tree_struct {
|
|
struct tree_struct *left;
|
|
struct tree_struct *right;
|
|
union {
|
|
int op:2;
|
|
int val;
|
|
} opval;
|
|
} tree_t;
|
|
|
|
int main() {
|
|
tree_t *node;
|
|
tree_t *root = (tree_t*)malloc(sizeof(tree_t));
|
|
root->opval.op = times;
|
|
|
|
node = (tree_t*)malloc(sizeof(tree_t));
|
|
node->right = NULL;
|
|
node->left = NULL;
|
|
node->opval.val = 7;
|
|
root->right = node;
|
|
|
|
node = (tree_t*)malloc(sizeof(tree_t));
|
|
node->opval.op = plus;
|
|
root->left = node;
|
|
|
|
node = (tree_t*)malloc(sizeof(tree_t));
|
|
node->left = NULL;
|
|
node->right = NULL;
|
|
node->opval.val = 5;
|
|
root->left->left = node;
|
|
|
|
node = (tree_t*)malloc(sizeof(tree_t));
|
|
node->left = NULL;
|
|
node->right = NULL;
|
|
node->opval.val = 3;
|
|
root->left->right = node;
|
|
|
|
printf("Tree created\n");
|
|
return 0;
|
|
}
|
|
</PRE>
|
|
|
|
<P>
|
|
The program creates a tree representing a arithmetic expression in
|
|
the way compilers see them after the completion of the parsing process:
|
|
Parentheses are superfluous in this form, since the graph structure
|
|
contains this information intrinsically. Each node contains either
|
|
an arithmetic operator (plus, minus, times or div, as defined by the
|
|
enumeration <TT>operators</TT>) or a certain (integer) value. In explicit
|
|
notation, the expression represented by the data structure is
|
|
<tt>(5+3)*7</tt>
|
|
|
|
<P>
|
|
Run the program (after setting a breakpoint before the end, but after
|
|
building the data structure),
|
|
display the root element and open all subsequent members via double-clicking
|
|
on the <TT>left</TT>/<TT>right</TT>-members of the structure. You
|
|
can get all information about the memory structure, but it does not
|
|
look very nice. We want to achieve a look like in figure 4:
|
|
|
|
<DIV ALIGN="CENTER"><A NAME="tree1"></A><A NAME="102"></A>
|
|
<TABLE>
|
|
<CAPTION ALIGN="BOTTOM"><STRONG>Figure 4:</STRONG>
|
|
Simple arithmetic expression represented by a tree</CAPTION>
|
|
<TR><TD><IMG
|
|
WIDTH="524" HEIGHT="325" BORDER="0"
|
|
SRC="misc/mauerer/img7.png"
|
|
ALT="\begin{figure}\begin{center}
|
|
\epsfig{file=tree.ps, scale=0.7} \end{center} \end{figure}"></TD></TR>
|
|
</TABLE>
|
|
</DIV><P></P>
|
|
|
|
<P>
|
|
One change compared to the picture produced by simply unfolding the
|
|
tree is obvious: All elements are layed out in a ordered manner. This can
|
|
certainly be achieved by using the mouse to drag the elements to their
|
|
respective locations, but is not very convenient: A much simpler method
|
|
(at least for the user) is the automatic layout capability provided by
|
|
ddd. To use it, we simply need to select the menu entry
|
|
<code>Data->Layout Graph</code> (or use the shortcut <TT>ALT+Y</TT>). ddd
|
|
layouts the graph in the manner shown afterwards.
|
|
|
|
<P>
|
|
Note that another manual change was applied to the graph. Since we
|
|
use a union structure to represent either a value or an operator
|
|
in every node, ddd displays both possibilities at a time. This may
|
|
be somewhat confusing and should be avoided. The rules are
|
|
clear: If both <TT>left</TT> and <TT>right</TT> pointer are set to
|
|
<TT>NULL</TT>, the node represents a number, otherwise an operator.
|
|
Select ``Undisplay'' from the context menu
|
|
accessible with the right mouse button to delete the unwanted entry. Ddd will
|
|
ask if the action should be applied to all fitting structures or just
|
|
the present one; since we want to delete different values from different
|
|
boxes, the second alternative must be selected.
|
|
|
|
<P>
|
|
Ddd offers some additional features dealing with graph layout
|
|
in the data menu. The reader will surely figure
|
|
out how to use them very quickly since they are quite intuitive
|
|
and self-explaining.
|
|
|
|
<P>
|
|
|
|
<H2>
|
|
Multi-linked structures
|
|
</H2>
|
|
As a last example (and to demonstrate the great possibilities ddd offers
|
|
once again), take a look at figure 5: It shows a graph produced
|
|
by the program <a href="misc/mauerer/poly.c.txt"><tt>poly.c</TT></a> which implements a
|
|
representation for a
|
|
certain polynomial (3*x^2+zy-3xz^3) using a data
|
|
structure presented in the all-time classic work on computer science,
|
|
<I>Fundamental Algorithms</I> (from the Series
|
|
<I>The Art of Computer Programming</I>) by Donald Knuth. You are not
|
|
assumed to understand the graph's meaning instantaneously...Just let
|
|
you impress by the possibility to visualise quite complicated structures
|
|
that would merely be <EM>un</EM>-understandable from the program source alone.
|
|
Note that automatic layout wasn't used for this graph, since it produces
|
|
a correct, but not very informative visualisation: Too much
|
|
information about the idea behind the structure has to go into the layout.
|
|
|
|
<P>
|
|
|
|
<P></P>
|
|
<DIV ALIGN="CENTER"><A NAME="poly"></A><A NAME="121"></A>
|
|
<TABLE>
|
|
<CAPTION ALIGN="BOTTOM"><STRONG>Figure 5:</STRONG>
|
|
A polynomial expression represented in memory</CAPTION>
|
|
<TR><TD><IMG
|
|
WIDTH="408" HEIGHT="888" BORDER="0"
|
|
SRC="misc/mauerer/img9.png"
|
|
ALT="\begin{figure}\begin{center}
|
|
\epsfig{file=poly.ps, scale=0.7} \end{center} \end{figure}"></TD></TR>
|
|
</TABLE>
|
|
</DIV><P></P>
|
|
|
|
<P>
|
|
|
|
<H2>
|
|
Plotting datasets</A>
|
|
</H2>
|
|
Data structures are not the only things ddd is capable of drawing: Additional,
|
|
datasets stored in arrays can be visualised using the well known Gnuplot
|
|
program as helper. Since the generation of such datasets occurs quite
|
|
frequently in scientific programs, we will take a look at this convenient
|
|
feature.
|
|
|
|
<P>
|
|
Program <TT>valtab.c</TT> shows a program that
|
|
creates a value table for a certain function (in this case, a two dimensional
|
|
sine function). Note that you must compile this program
|
|
using the <TT>-lm</TT> switch in gcc in order to include the mathematical
|
|
library!
|
|
|
|
<P>
|
|
<PRE>
|
|
#include<stdio.h>
|
|
#include<math.h>
|
|
|
|
int main() {
|
|
float *val;
|
|
float sval[100];
|
|
float **threed;
|
|
int points = 100;
|
|
float period = 2*M_PI;
|
|
int count, count2;
|
|
|
|
val = (float*) malloc(points*sizeof(float));
|
|
for (count = 0; count < points; count++) {
|
|
val[count] = sin(count * period/(float)points);
|
|
sval[count] = val[count];
|
|
}
|
|
|
|
threed = (float**)malloc(points*sizeof(float));
|
|
float x,y;
|
|
for (count = 0; count < points; count++) {
|
|
threed[count] = (float*)malloc(points*sizeof(float));
|
|
for (count2 = 0; count2 < points; count2++) {
|
|
x = count*period/(float)points;
|
|
y = count2*period/(float)points;
|
|
threed[count][count2] = 1.0f/(x+y)*sin(x+y);
|
|
}
|
|
}
|
|
|
|
/* Normally, we would write the generated data into a file or so. */
|
|
printf("Value tables created\n");
|
|
return 0;
|
|
}
|
|
</PRE>
|
|
|
|
<P>
|
|
Normally, most programs will deal with more complicated functions (or
|
|
acquire their data sets in a different way), but the basic principle
|
|
(filling some values into an array) remains unchanged in all cases.
|
|
|
|
<P>
|
|
We use three kinds of arrays in our sample program to demonstrate the
|
|
different methods for plotting data. The simplest possibility is
|
|
a static, one-dimensional array, as is <TT>sval</TT>. In this case,
|
|
we only need to highlight the identifier by clicking on it with the
|
|
right mouse button and pressing on the ``plot'' icon found in the upper zone
|
|
of the window - voila, a new gnuplot-window with the desired graph opens.
|
|
The graph's appearance can be customised with several menu entries;
|
|
figure 6 shows the output with the plot style changed to
|
|
``lines'' from the default value ``points'' by selecting <code>Plot->Lines</code>
|
|
in the menu.
|
|
|
|
<P>
|
|
|
|
<P></P>
|
|
<DIV ALIGN="CENTER"><A NAME="plot"></A><A NAME="135"></A>
|
|
<TABLE>
|
|
<CAPTION ALIGN="BOTTOM"><STRONG>Figure 6:</STRONG>
|
|
The plot window</CAPTION>
|
|
<TR><TD><IMG
|
|
WIDTH="600" HEIGHT="454" BORDER="0"
|
|
SRC="misc/mauerer/img10.png"
|
|
ALT="\begin{figure}\begin{center}
|
|
\epsfig{file=plot.eps, scale=0.3} \end{center} \end{figure}"></TD></TR>
|
|
</TABLE>
|
|
</DIV><P></P>
|
|
|
|
<P>
|
|
The situation is somewhat more complicated with dynamical created arrays, since
|
|
ddd cannot determine their lengths automatically. A workaround for this
|
|
is the use of so-called <I>array slices</I> that must be defined manually
|
|
in the debugger interaction part in the lower part of the ddd window.
|
|
|
|
<P>
|
|
The expression <code>graph display val[0]@points</code> creates such an array
|
|
slice, where the index-expression <TT>[0]</TT> denotes the lower and
|
|
<code>@points</code> denotes the upper bound for the used values (instead
|
|
of the memory value <TT>points</TT>, a simple integer number can
|
|
be used likewise). Plotting this graph is achieved in the same way as before
|
|
(by pressing the ``plot''-button) and gives (surprise, surprise) the same
|
|
result, since identical datasets are used.
|
|
|
|
<P>
|
|
Plotting three-dimensional graphs works pretty much the same way: The
|
|
identifier of static array needs just to be highlighted with the mouse
|
|
in order to apply the ``plot''-button afterwards, while an array slice has
|
|
to be created when dynamic allocated structures are used. The syntax for this
|
|
is <code>graph display threed[0][0]@points@points</code>, as the reader
|
|
will have expected.
|
|
|
|
<P>
|
|
Since the customisation features available
|
|
with gnuplot for three-dimensional graphs are not very well supported in
|
|
the ddd-interface, such plotting attempts will normally tend to give not
|
|
very good and meaningful results as with two-dimensional
|
|
plots.
|
|
|
|
<P>
|
|
|
|
<H2>
|
|
Printing graphs and plots
|
|
</H2>
|
|
In order to document programs, it can sometimes be convenient to have
|
|
graphical representations for their data structures handy, like the ones
|
|
produces by ddd. Ddd's printer interface offers
|
|
the possibility to create a Postscript version of graphs and plots therefor.
|
|
To print a graph, just select <code>File->Print Graph</code>. A menu pops up
|
|
offering some choices, and hitting the print button produces
|
|
either a file or sends the output directly to the printer.
|
|
|
|
<P>
|
|
The same approach may be applied for plots; the only difference
|
|
is that fewer options are available in the print dialog. While
|
|
graphs can be exported to Postscript as like as well as to the fig-format format
|
|
(as used by the classical Unix drawing tool <TT>xfig</TT>), plot printing
|
|
can be exported only to Postscript.
|
|
|
|
<P>
|
|
Ddd offers many more
|
|
features such as watchpoints, multiple language support etc. These are
|
|
beyond the topic of this article, since we do not intend to repeat the
|
|
excellent documentation coming with ddd.
|
|
(The documentation is available from <a href="http://www.gnu.org/software/ddd">
|
|
http://www.gnu.org/software/ddd</a>.)
|
|
Instead, we encourage readers to explore ddd's rich set of features themselves,
|
|
debugging their own programs.
|
|
|
|
<P>
|
|
As a last remark, let's consider a quotation that ddd uses as one of
|
|
its "tips of the day", because it expresses the importance (and
|
|
limits) of debugging very well:
|
|
|
|
<P>
|
|
<BLOCKQUOTE>
|
|
The debugger isn't a substitute for good thinking. But, in some
|
|
cases, thinking isn't a substitute for a good debugger either. The
|
|
most effective combination is good thinking and good debugger.
|
|
<CITE>--Steve McConnell, Code Complete</CITE>
|
|
</BLOCKQUOTE>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- *** BEGIN bio *** -->
|
|
<SPACER TYPE="vertical" SIZE="30">
|
|
<P>
|
|
<H4><IMG ALIGN=BOTTOM ALT="" SRC="../gx/note.gif">Wolfgang Mauerer</H4>
|
|
<EM><A HREF="mailto:wolfgang@mynetix.de">Wolfgang</A>
|
|
has written several articles for both German and international
|
|
publications, is the author of a German book about text processing and
|
|
works as system administrator and programmer. His main interests
|
|
include programming language theory, operating system kernels (explicitly
|
|
not limited to Linux..), and (sometimes) physics. Besides, he is on a holy war
|
|
against monopolistic, proprietary software. He lives in London
|
|
at the moment.</EM>
|
|
|
|
|
|
<!-- *** END bio *** -->
|
|
|
|
<!-- *** BEGIN copyright *** -->
|
|
<P> <hr> <!-- P -->
|
|
<H5 ALIGN=center>
|
|
|
|
Copyright © 2001, Wolfgang Mauerer.<BR>
|
|
Copying license <A HREF="../copying.html">http://www.linuxgazette.com/copying.html</A><BR>
|
|
Published in Issue 73 of <i>Linux Gazette</i>, December 2001</H5>
|
|
<!-- *** END copyright *** -->
|
|
|
|
<!--startcut ==========================================================-->
|
|
<HR><P>
|
|
<CENTER>
|
|
<!-- *** BEGIN navbar *** -->
|
|
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="field.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="index.html"><IMG ALT="[ Table of Contents ]" SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../index.html"><IMG ALT="[ Front Page ]" SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue73/mauerer.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../faq/index.html"><IMG ALT="[ FAQ ]" SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="mwaikambo.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
|
|
<!-- *** END navbar *** -->
|
|
</CENTER>
|
|
</BODY></HTML>
|
|
<!--endcut ============================================================-->
|
|
|