old-www/LDP/LG/issue73/mauerer.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&lt;stdio.h&gt;
int main() {
int count;
int fac;
for (count = 1; count &lt; 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&amp;
<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-&gt;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-&gt;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-&gt;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&lt;stdio.h&gt;
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-&gt;name = names[0];
start-&gt;age = ages[0];
start-&gt;prev = NULL;
start-&gt;next = NULL;
pers = start;
for (count=1; count &lt; 3; count++) {
temp = (person_t*)malloc(sizeof(person_t));
temp-&gt;name = names[count];
temp-&gt;age = ages[count];
pers-&gt;next = temp;
temp-&gt;prev = pers;
pers = temp;
}
temp-&gt;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-&gt;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-&gt;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&lt;stdio.h&gt;
/* 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-&gt;opval.op = times;
node = (tree_t*)malloc(sizeof(tree_t));
node-&gt;right = NULL;
node-&gt;left = NULL;
node-&gt;opval.val = 7;
root-&gt;right = node;
node = (tree_t*)malloc(sizeof(tree_t));
node-&gt;opval.op = plus;
root-&gt;left = node;
node = (tree_t*)malloc(sizeof(tree_t));
node-&gt;left = NULL;
node-&gt;right = NULL;
node-&gt;opval.val = 5;
root-&gt;left-&gt;left = node;
node = (tree_t*)malloc(sizeof(tree_t));
node-&gt;left = NULL;
node-&gt;right = NULL;
node-&gt;opval.val = 3;
root-&gt;left-&gt;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-&gt;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&lt;stdio.h&gt;
#include&lt;math.h&gt;
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 &lt; 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 &lt; points; count++) {
threed[count] = (float*)malloc(points*sizeof(float));
for (count2 = 0; count2 &lt; 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-&gt;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-&gt;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 &copy; 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 ============================================================-->