| I l @ ve RuBoard |
17.3 Going Through the OutputEnabling debug printout is a nice way of getting information, but many times there is so much data that the information you want can easily get lost. The shell or command-line interpreter allows you to redirect what would normally go to the screen to a file through the use of the >file option. For example: buggy -D9 >tmp.out will run the program buggy with a high level of debug set and send the output to the file tmp.out . The text editor on your system also makes a good file browser. You can use its search capabilities to look through the file containing the debug output for the information you want to find. |
| I l @ ve RuBoard |
| I l @ ve RuBoard |
17.4 Interactive
|
|
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:
Start execution of a program.
Insert a breakpoint at the given line number. When a running program
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.
Continue execution after a breakpoint.
Display the value of an expression.
Execute a single line in the program. If the current statement calls a function, the function is single-stepped.
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 the source program.
Print the list of currently active functions.
Print a list of breakpoints.
Remove a breakpoint.
We have a program that should count the number of threes and sevens in a series of
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
(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
We have reached the point where
seven_count
is
(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
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 |