DBX Tutorial

A graphics based web browser such as the NCSA mosaic or Netscape is recommended for viewing this document.

* Introduction to DBX

* Using DBX

* Examples 
  1. a easy start
  2. using more commands
  3. using core

* A Final Word

* Other References

Back to
Week 1 C Programming Notes

__________________________________________________________________

Introduction to DBX

Debugging is usually considered to be the most difficult, frustrating and longest step in programming. It is in this step that we come to fully understand the true nature of the programs we write. We need a tool to help us with this. That's why we have DBX. DBX is an interactive debugging tool in the UNIX environment that can help you to locate bugs quickly and easily. The current version of dbx that comes with IRIX 4 release 5.3 works with C/C++ (cc/CC), fortran77 (f77), assembler (as) and pascal (pc). DBX is easy to learn and use. (But even if it were difficult to learn, it would be well worth the trouble because of the potential troubles it may prevent.)

DBX is used after you finally got your code to compile, and it isn't doing what you want it to do (including the infamous core dump). At this point, there must be a logical problem or a dumb mistake in the code that the compiler cannot identify. Don't you wish that you could go thru your program with the CPU step by step with the ability to check the variables in your program on the way?? That is exactly what DBX enables you to do!! In this tutorial, we are going to describe release 5.3 of dbx that comes with IRIX 4.

Back to table of contents

__________________________________________________________________

Using DBX

When you compile a object to be used by dbx, type: cc -g source file name -o object_filename. Be sure the -g switch is used. To input the object file into the dbx for debug, make sure the source file and the object file are in the same directory, then type: dbx object_filename

Command Summary

The followings are a few common commands you will be using inside dbx:

run                      runs the program inputted into dbx

stop at line_number      sets a break point at line_number.  A running 
			 program would automatically stop at the 
			 breakpoint and returns control to the debugger.
			 
stop in function_name    sets a breakpoint at first line of function_name

cont                     continues execution after a breakpoint

print expression         prints out the value of the expression which
			 might be a variable

step                     executes the current line of the program.   If the 
			 current line is a function call, then go into the 
			 function and stop at the first line of the function

next                     executes the current line of the program.  If the 
			 current line is a function call, then execute the 
			 function as one single line and stop at the next line.

list                     lists the C source code of the program with line 
			 numbers

where                    prints out where you currently are in the program 
			 by printing out a list of active functions
		
assign exp1 = exp2       assign the value of exp2 to the variable in 
			 exp1

delete event# delete the breakpoint specified by event#

delete all delete all breakpoints

trace variable_name prints out the value of the variable when the value changes

There are other commands that could be useful for you. If you are interested, type help in dbx for further details.

Back to table of contents

__________________________________________________________________

Examples

Example 1 - a easy start

Here's a very simple program that prints out a fahrenheit-to-centigrade table.

%(1) cat example1.c
#include <stdio.h>

main()
{    int fahr, celsius;
     int lower, upper, step;
     lower = 0;
     step = 20;
     fahr = lower;
     while (fahr <= upper)
        {  celsius = 5 * (fahr - 32) /9;
           printf("%d\t%d\n", fahr, celsius);
           fahr = fahr + step;
        }
 }

%(2) cc -g -o example1 example1.c
%(3) example1
0       -17
Somehow it only prints out one line of output. We will try to use dbx to debug it.

%(4) dbx example1
dbx version 3.18 Jan 24 1995 12:01:24
Type 'help' for help.
Process 25121 (example1) started
[2] Process 25121 (example1) stopped at [main:4 ,0x4008a8]
   4  lower = 0;
(dbx) list
     5       step = 20;
     6       fahr = lower;
     7       while (fahr <= upper)
     8          {  celsius = 5 * (fahr - 32) /9;
     9             printf("%d\t%d\n", fahr, celsius);
    10             fahr = fahr + step;
    11          }
    12       return 0;
    13   }
    14  
(dbx) list 7,11
     7       while (fahr <= upper)
     8          {  celsius = 5 * (fahr - 32) /9;
     9             printf("%d\t%d\n", fahr, celsius);
>   10             fahr = fahr + step;
    11          }
(dbx)
The program seems to stop too soon. We'll set a breakpoint at the loop.

(dbx) stop at 7
Process 25121: [3] stop at "/home/ucc/disk003/poonc/work/example1.c":7
(dbx) run
Process 25121 (example1) terminated
Process 26430 (example1) started
[3] Process 26430 (example1) stopped at [main:7 ,0x4008c0]
   7  while (fahr <= upper)
(dbx) next
Process 26430 (example1) stopped at [main:8 ,0x4008d8]
   8  {  celsius = 5 * (fahr - 32) /9;
(dbx) next
Process 26430 (example1) stopped at [main:9 ,0x4008fc]
   9  printf("%d\t%d\n", fahr, celsius);
(dbx) next
0       -17
Process 26430 (example1) stopped at [main:10 ,0x40091c]
  10  fahr = fahr + step;
(dbx) next
Process 26430 (example1) stopped at [main:12 ,0x400948]
  12  return 0;
That's strange.. the program only ran for one loop then exit. Let's print out the values of the variables and take a look..

(dbx) print fahr
20
(dbx) print upper
0
What? upper = 0! We forgot to set the upper value! We often have bugs that are very simple but are overlooked. DBX gives us an advantage by providing us more clues of the puzzle.

(dbx) quit
%(5)
Back to table of contents


Example 2 - using more commands

The following program right justify an inputted line.

%(1) cat example2.c
#include <stdio.h>
#include <string.h>

int right_justify(char input[], int line);
void generate_blank_string(char blanks[], int linewidth, int word_length);  
main()
{    int index, the_count, line_length = 30;
     char in_string[50];

     for (index = 0, the_count = 0; index < 20; index++)
             {
                (void) fgets(in_string,sizeof(in_string), stdin);
                the_count += right_justify(in_string, line_length);
                
              }
      printf("\n\nThe number of times the article \"the\" occurs is %d\n",
              the_count);
      return 0;
 }


int right_justify(char in_string[], int line_length)
{
      char blank_string[40]; 
      generate_blank_string(blank_string, line_length, strlen(in_string)); 
      printf("%s%s", blank_string, in_string);
      if (strcmp(in_string, "the\n") == 0) return 1;
         else return 0;
}

void generate_blank_string(char blanks[], int linewidth, int word_length)
{ 
      int counter, num_blanks;
      num_blanks = linewidth - word_length;
      for (counter = 1; counter <= num_blanks; counter++)
                        strcat(blanks, " ");
}
%(2) cc -g -o example2 example2.c
%(3) example2
I typed this line
y~`            I typed this line
2nd line is output
y~`           2nd line is output
There are some garbage before the output. Let's use dbx to check it out.

%(4) dbx example2
dbx version 3.18 Jan 24 1995 12:01:24
Type 'help' for help.
Process 21048 (example2) started
[2] Process 21048 (example2) stopped at [main:10 ,0x4009c4]
  10  for (index = 0, the_count = 0; index < 20; index++)
(dbx) list
    11               {
    12                  (void) fgets(in_string,sizeof(in_string), stdin);
    13                  the_count += right_justify(in_string, line_length);
    14
    15                }
    16        printf("\n\nThe number of times the article \"the\" occurs is %d\n
",
    17                the_count);
    18        return 0;
    19   }
    20
(dbx) list
    21
    22  int right_justify(char in_string[], int line_length)
    23  {
    24        char blank_string[40];
    25        generate_blank_string(blank_string, line_length, strlen(in_string)
);
    26        printf("%s%s", blank_string, in_string);
    27        if (strcmp(in_string, "the\n") == 0) return 1;
    28           else return 0;
    29  }
    30
(dbx) list
    31  void generate_blank_string(char blanks[], int linewidth, int word_length
)
    32  {
    33        int counter, num_blanks;
    34        num_blanks = linewidth - word_length;
    35        for (counter = 1; counter <= num_blanks; counter++)
    36                          strcat(blanks, " ");
    37  }
    38
(dbx) stop in generate_blank_string
Process 21048: [3] stop in generate_blank_string
(dbx) run
Process 21048 (example2) terminated
Process 21405 (example2) started
I typed this line
[3] Process 21405 (example2) stopped at [generate_blank_string:34 ,0x400b4c]
  34  num_blanks = linewidth - word_length;
(dbx) where
>  0 generate_blank_string(blanks = 0x7fffae58 = "\177\377\257\250", linewidth =
 30, word_length = 18) ["/home/ucc/disk003/poonc/work/example2.c":34, 0x400b4c]
   1 right_justify(in_string = 0x7fffaea8 = "I typed this line\n", line_length =
 30) ["/home/ucc/disk003/poonc/work/example2.c":25, 0x400aac]
   2 main() ["/home/ucc/disk003/poonc/work/example2.c":13, 0x4009f4]
The where command entered above shows us we are in a function call "generate_blank_string()", which is called by "right_justify()", which is in turned called by main().

(dbx) step
Process 21405 (example2) stopped at [generate_blank_string:35 ,0x400b60]
  35  for (counter = 1; counter <= num_blanks; counter++)
(dbx) print num_blanks
12
(dbx) print blanks
0x7fffae58 = "\177\377\257\250"
There seems to be something in blanks.

(dbx) stop at 37
Process 21405: [4] stop at "/home/ucc/disk003/poonc/work/example2.c":37
(dbx) cont
[4] Process 21405 (example2) stopped at [generate_blank_string:37 ,0x400ba4]
  37  }
(dbx) print blanks
0x7fffae58 = "\177\377\257\250            "
There are often some garbages in an uninitialized string. The spaces are being appended to the garbages. I bet we can solve the problem by initializing the string. Let's test out the theory.

(dbx) delete 4
The second breakpoint is removed here. Note the 4 in square brankets when we set the breakpoint earlier. That's the event #, and is used as an argument here for the delete command.

(dbx) run
Process 21405 (example2) terminated
Process 22123 (example2) started
I typed this line
[3] Process 22123 (example2) stopped at [generate_blank_string:34 ,0x400b4c]
  34  num_blanks = linewidth - word_length;
(dbx) assign blanks[0]='\0'
'\000'
(dbx) cont
            I typed this line

Interrupt
(dbx) quit
Process 22123 (example2) terminated
It seems to work great. Our problem is solved.

Back to table of contents

_________________________________________________________________

Example 3 - using core dumps

Core dumping is one of the most annoying thing in C programming in a UNIX environment. They give you little hints to the origin of the error. But what is core? It's a copy of the memory when your program crash. DBX can read this information and locate the error.

%(1) cat example3.c
#include <stdio.h>
#include <string.h>

int my_func(char in[]);
main()
{   char line[] = {'h', 'e', 'l', 'l', 'o', 'a', 'c', 'i', 'x' , 'u','\0'};
    int num, count;

    printf("num of vowels are %d\n", my_func(line));    
    return 0;
 }

int my_func(char in[])
{   char in1[50];
    int i;

    for (i = 0; i < strlen(in); i++) 
        in1[i] = in[i+1];
    switch (in[0])
        { case 'a' : return (1 + my_func(in1));
          case 'e' : return (1 + my_func(in1));
          case 'i' : return (1 + my_func(in1));
          case 'o' : return (1 + my_func(in1));
          case 'u' : return (1 + my_func(in1));
          default  : return my_func(in1);
        }
}
%(2) cc -g -o example3 example3.c
%(3) example3
Segmentation fault (core dumped)
%(4) dbx example3
dbx version 3.18 Jan 24 1995 12:01:24
Type 'help' for help.
Process died at pc 0x400984 of signal : Segmentation fault
[using memory image in core]
(dbx)
DBX read the information provided by the core file and go back to the location where the segmentation fault occur. Watch:

(dbx) where
>  0 my_func(in = (nil)) [0x400980]
   1 my_func(in = 0x7c00009c = "") ["/tmp/bruce/example3.c":25, 0x400ad4]
   2 my_func(in = 0x7c0000f4 = "") ["/tmp/bruce/example3.c":25, 0x400ad4]
   3 my_func(in = 0x7c00014c = "") ["/tmp/bruce/example3.c":25, 0x400ad4]
   4 my_func(in = 0x7c0001a4 = "") ["/tmp/bruce/example3.c":25, 0x400ad4]
   5 my_func(in = 0x7c0001fc = "") ["/tmp/bruce/example3.c":25, 0x400ad4]
   6 my_func(in = 0x7c000254 = "") ["/tmp/bruce/example3.c":25, 0x400ad4]
   7 my_func(in = 0x7c0002ac = "") ["/tmp/bruce/example3.c":25, 0x400ad4]
   8 my_func(in = 0x7c000304 = "") ["/tmp/bruce/example3.c":25, 0x400ad4]
   9 my_func(in = 0x7c00035c = "") ["/tmp/bruce/example3.c":25, 0x400ad4]
  10 my_func(in = 0x7c0003b4 = "") ["/tmp/bruce/example3.c":25, 0x400ad4]
  11 my_func(in = 0x7c00040c = "") ["/tmp/bruce/example3.c":25, 0x400ad4]
  12 my_func(in = 0x7c000464 = "") ["/tmp/bruce/example3.c":25, 0x400ad4]
  13 my_func(in = 0x7c0004bc = "") ["/tmp/bruce/example3.c":25, 0x400ad4]
  14 my_func(in = 0x7c000514 = "") ["/tmp/bruce/example3.c":25, 0x400ad4]
  15 my_func(in = 0x7c00056c = "") ["/tmp/bruce/example3.c":25, 0x400ad4]
  16 my_func(in = 0x7c0005c4 = "") ["/tmp/bruce/example3.c":25, 0x400ad4]
  17 my_func(in = 0x7c00061c = "") ["/tmp/bruce/example3.c":25, 0x400ad4]
  18 my_func(in = 0x7c000674 = "") ["/tmp/bruce/example3.c":25, 0x400ad4]
  19 my_func(in = 0x7c0006cc = "") ["/tmp/bruce/example3.c":25, 0x400ad4]
  20 my_func(in = 0x7c000724 = "") ["/tmp/bruce/example3.c":25, 0x400ad4]
  21 my_func(in = 0x7c00077c = "") ["/tmp/bruce/example3.c":25, 0x400ad4]
  22 my_func(in = 0x7c0007d4 = "") ["/tmp/bruce/example3.c":25, 0x400ad4]
  23 my_func(in = 0x7c00082c = "") ["/tmp/bruce/example3.c":25, 0x400ad4]
More (n if no)?n
(dbx)
Well.. it seems like we got a infinite recursion on our hands. It should not recurse that many times.

(dbx) list
(dbx) stop in my_func
Process     0: [2] stop in my_func
(dbx) list 13
    13  int my_func(char in[])
    14  {   char in1[50];
    15      int i;
    16  
>   17      for (i = 0; i < strlen(in); i++) 
    18          in1[i] = in[i+1];
    19      switch (in[0])
    20          { case 'a' : return (1 + my_func(in1));
    21            case 'e' : return (1 + my_func(in1));
    22            case 'i' : return (1 + my_func(in1));
    23            case 'o' : return (1 + my_func(in1));
(dbx) run
Process 25752 (example3) started
[2] Process 25752 (example3) stopped at [my_func:17 ,0x400990]
  17  for (i = 0; i < strlen(in); i++) 
(dbx) print in1
"e"
(dbx) print (in)
Note that we put 'in' in a () because it's a dbx keyword.

0x7fffaeec = "helloacixu" 
(dbx) stop at 17 if (in)[0]='u'
Process 25752: [3] stop if in + 0 * 1 = 'u' at "/tmp/bruce/example3.c":17
Note above it is possible to add a conditional break point in dbx. In the example above, the program returns control to the debugger when in[0]=='u'.

(dbx) delete 3
(dbx) cont
[2] Process 25752 (example3) stopped at [my_func:17 ,0x400990]
  17  for (i = 0; i < strlen(in); i++) 
(dbx) print (in)
0x7fffabcc = "u" 
(dbx) step
Process 25752 (example3) stopped at [my_func:18 ,0x4009b4]
  18  in1[i] = in[i+1];
(dbx) step
Process 25752 (example3) stopped at [my_func:17 +0x40,0x4009d0]
  17  for (i = 0; i < strlen(in); i++) 
(dbx) print in1
"" 
(dbx) 
We forgot to tell it to stop recursing when we finish processing the string! All we need to do is add the following to solve the problem:

if (in[0] == '\0') return 0;

* One very important note - depending on the amount of memory your program consume at the time of error, the core is often huge in size. The one created in the above example is about 67 megabyte. The home directories of undergrads on the AUXPEX (one of the main storage system on the campus managed by computing servies) has a quota limit of 1 megabyte. If you write your programs in your home directory and it is on AUXPEX, the chance is that the core file can only be able to written partially.

Back to table of contents

__________________________________________________________________

A Final Word

Debuggers are the best thing since sliced bread. They are easy to use and help you find problems quickly. It is absolutely an indispensible tool for programmers in UNIX. C compiler packages such as turbo C and Borland C++, as well as other compiler packages for other languages, even have integrated debuggers in their editors. Most debuggers' functionalities are very similar. Some debuggers might have more fancies than the others, but the basic functions are identical.

Back to table of contents

__________________________________________________________________

Other References

The Online help in dbx is good source of information. To use it, type help at the (dbx) prompt. You can also read the man page of dbx. To do this, type 'man dbx' at the unix prompt. (Man pages are also a very useful source of reference for C commands and other UNIX commands. Most C commands have their associated man pages. Try typing man printf at the unix prompt.)

Back to table of contents


Last Modified: June 16, 1995