17.4 Interactive Debuggers

I l @ ve RuBoard

17.4 Interactive Debuggers

Most compiler manufacturers provide an interactive debugger. They give you the ability to stop the program at any point, examine and change variables , and "single-step" through the program. Because each debugger is different, a detailed discussion of each tool is not possible.

Most compilers require that you enable debugging with a command-line option. If this option is not present, debugging information is not included in the program. If you used the compilations flags suggested in Chapter 2, your programs have been compiled with debugging enabled.

17.4.1 Basic Debugging Commands

However, we are going to discuss one debugger: GDB. This program is available for many Unix machines from the Free Software Foundation. Borland-C++ and Visual C++ have their own built-in debuggers. Although the exact syntax used by your debugger may be different, the principles shown here will work for all debuggers.

Basic GDB commands are the following:

run

Start execution of a program.

break line-number

Insert a breakpoint at the given line number. When a running program reaches a breakpoint, execution stops and control returns to the debugger.

break function- name

Insert a breakpoint at the first line of the named function. Commonly, the command break int main is used to stop execution at the beginning of the program.

cont

Continue execution after a breakpoint.

print expression

Display the value of an expression.

step

Execute a single line in the program. If the current statement calls a function, the function is single-stepped.

next

Execute a single line in the program, but treat function calls as a single line. This command is used to skip over function calls.

list

List the source program.

where

Print the list of currently active functions.

status

Print a list of breakpoints.

delete

Remove a breakpoint.

17.4.2 Debugging a Simple Program

We have a program that should count the number of threes and sevens in a series of numbers . The problem is that it keeps getting the wrong answer for the number of sevens. Our program is shown in Example 17-1.

Example 17-1. seven/count.cpp
 1: #include <iostream>  2:   3: int seven_count;    /* number of seven's in the data */  4: int data[5];        /* the data to count 3 and 7 in */  5: int three_count;    /* the number of threes in the data */  6:   7: int main(  ) {  8:     int index;  /* index into the data */  9:     void get_data(int data[]); 10:  11:     seven_count = 0; 12:     three_count = 0; 13:     get_data(data); 14:  15:     for (index = 1; index <= 5; ++index) { 16:         if (data[index] == 3) 17:             ++three_count; 18:         if (data[index] == 7) 19:             ++seven_count; 20:     } 21:     std::cout << "Three's " << three_count <<  22:             " Seven's " << seven_count << '\n'; 23:     return (0); 24: } 25: /******************************************************** 26:  * get_data -- get 5 numbers from the command line      * 27:  ********************************************************/ 28: void get_data(int data[]) 29: { 30:     std::cout << "Enter 5 numbers\n"; 31:     std::cin >> data[1] >> data[2] >> data[3] >> data[4] >> data[5]; 32: } 

When we run this program with the data 3 7 3 0 2, the results are:

 Threes 3 Sevens 3 

We start by invoking the debugger (GDB) with the name of the program we are going to debug ( count ). The debugger initializes, outputs the prompt (gdb) , and waits for a command.

 %  gdb count  GDB is free software and you are welcome to distribute copies of it under certain conditions; type "show copying" to see the conditions. There is absolutely no warranty for GDB; type "show warranty" for details. GDB 4.12 (m68k-sun-sunos4.0.3),  Copyright 1994 Free Software Foundation, Inc... (gdb) 

We don't know where the variable is getting changed, so we'll start at the beginning and work our way through until we get an error. At every step, we'll display the variable seven_count just to make sure it's okay.

We need to stop the program at the beginning so we can single-step through it. The command break main tells GDB to set a breakpoint at the first instruction of the function main :

 (gdb)  break main  Breakpoint 1 at 0x22c2: file count.cpp, line 12. (gdb) 

The number 1 is used by GDB to identify the breakpoint. Now we need to start the program. The command run tells GDB to start the program, which will run until it hits the first breakpoint:

 (gdb)  run  Starting program: /usr/sdo/count/count  Breakpoint 1, main (  ) at count.cpp:12 11          seven_count = 0; (gdb) 

The message Breakpoint 1, main... indicates that the program encountered a breakpoint and has now turned control over to debug.

We have reached the point where seven_count is initialized . The command next will execute a single statement, treating function calls as one statement. (The name of the command for your debugger may be different.) We go past the initialization and check to see whether it worked:

 (gdb)  next  12          three_count = 0; (gdb)  print seven_count  = 0 (gdb) 

Initialization worked. We try the next few lines, checking all the time:

 (gdb)  next  13          get_data(data); (gdb)  print seven_count  = 0 (gdb)  next  Enter 5 numbers 3 7 3 0 2 15          for (index = 1; index <= 5; ++index) { (gdb)  print seven_count  = 2 (gdb) 

seven_count somehow changed the value to 2. The last statement we executed was get_data(data); so something is going on in that function. We add a breakpoint at the beginning of get_data , get rid of the one at main , and start the program over with the run command:

 (gdb)  break   get_data  Breakpoint 2 at 0x23b2: file count.cpp, line 30. (gdb)  info breakpoints  Num Type           Disp Enb Address    What 1   breakpoint   keep y   0x000022c2 in main at count.cpp:11 2   breakpoint   keep y   0x000023b2 in get_data(int *) at count.cpp:30 (gdb)  delete 1  (gdb)  run  The program being debugged has been started already. Start it from the beginning? (y or n)  Y  Starting program: /usr/sdo/count/count  Breakpoint 2, get_data (data=0x208f8) at count.cpp:30 (gdb) 

We now start single-stepping again until we find the error:

 Breakpoint 2, get_data (data=0x208f8) at count.cpp:30 30          std::cout << "Enter 5 numbers\n"; (gdb)  print seven_count  = 0 (gdb)  next  31     std::cin >> data[1] >> data[2] >> data[3] >> data[4] >> data[5]; (gdb)  print seven_count  = 0 (gdb)  next  Enter 5 numbers 3 7 3 0 2 32      } (gdb)  print seven_count  = 2 (gdb)  list 23  23          return (0); 24      } 25      /******************************************************** 26       * get_data -- get 5 numbers from the command line      * 27       ********************************************************/ 28      void get_data(int data[]) 29      { 30          std::cout << "Enter 5 numbers\n"; 31     std::cin >> data[1] >> data[2] >> data[3] >> data[4] >> data[5]; 32      } 

At line 32 the data was good, but when we reached line 33, the data was bad, so the error is located at line 33 of the program, the std::cin . We've narrowed the problem down to one statement. By inspection, we can see that we are using data[5], an illegal member of the array data .

But why does seven_count go bad? Since data is only five elements long, there is no data[5] . However, the std::cin >> data[5] has to put the data someplace, so it decided to put it in a random memory location, in this case seven_count .

I l @ ve RuBoard


Practical C++ Programming
Practical C Programming, 3rd Edition
ISBN: 1565923065
EAN: 2147483647
Year: 2003
Pages: 364

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net