Activity  7-3 - Debug your programs


A special program used to find errors (bugs) in programs. A debugger allows a programmer to stop a program at any point and examine and change the values of variables.

Debugging

Debugging is something that can't be avoided. Every programmer will at one point in their programming career have to debug a section of code. There are many ways to go about debugging, from printing out messages to the screen, using a debugger, or just thinking about what the program is doing and making an educated guess as to what the problem is.

Before a bug can be fixed, the source of the bug must be located. For example, with segmentation faults, it is useful to know on which line of code the seg fault is occuring. Once the line of code in question has been found, it is useful to know about the values in that method, who called the method, and why (specifically) the error is occuring. Using a debugger makes finding all of this information very simple.

gdb can only use debugging symbols that are generated by g++. gdb is most effective when it is debugging a program that has debugging symbols linked in to it. With g++, this is accomplished using the -g command line argument. So compile in this way:

g++ -g -Wall file_name.cpp -o executable_name

Loading a program

Consider the following simple program that divides 2 intergers. This program executes as desired (note that I am aware of the fact that the quotient has to be an integer and it is what I desire), but the programcrashes for some input values.

//This program produces the quotient of two integer variables
//Author: Angela Guercio
// Date: March 6, 2010

#include 
using namespace std;

int quote(int x, int v);
//this function produces the integer division of 2 integers


int main()
{int first_number, second_number;
int quotient;
cout << "Enter the first integer number: ";
cin >> first_number;
cout << endl <<  "Enter the second integer number: ";
cin >> second_number;
quotient = quote(first_number, second_number);
          
cout << "The quotient of " << first_number << " divided by " << second_number << " is " << quotient << endl;
cout << "Thank you!" ;
return 0;
}

int quote(int x, int y)
{
return x/y;
}

Compile it and create an executable file called foo.

So you now have an executable file (in this case foo) and you want to debug it. First you must launch the debugger. The debugger is called gdb and you can tell it which file to debug at the shell prompt. So to debug foo we want to type

gdb foo

Here is what it looks like when I run debug:

-bash-3.2$ g++ -g -Wall foo.cpp -o foo
-bash-3.2$ gdb foo
GNU gdb Fedora (6.8-37.el5)
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...
(gdb) 
gdb is now waiting for the user to type a command. We need to run the program so that the debugger can help us see what happens when the program executes. Type run at the (gdb) prompt. Here is what happens when I run this command and insert the value 25 and 0 as input.
This GDB was configured as "i386-redhat-linux-gnu"...
(gdb) run
Starting program: /users/cs/lowlevel/llaguer0/foo 
warning: .dynamic section for "/lib/libc.so.6" is not at the expected address
warning: difference appears to be caused by prelink, adjusting expectations
Enter the first integer number: 25

Enter the second integer number: 0

Program received signal SIGFPE, Arithmetic exception.
0x080486f2 in quote (x=25, y=0) at foo.cpp:28
28      z=x/y;
(gdb) 
 

What happens? The program crashes and returns a Floating Point Exception. The debugger indentifies where the problem occured. The crash occurred at line 28 and the program is also telling me that at that point the variable x has the value 25 and the variable y has the value 0. In this example, it may be clear that the problem is caused by the attempt of dividing a number by 0, since the statement that produces the crash is the division of x by y.

In more complex problem this may not be so clear, so you want to inspect the problem in the area where the bug occurs. One way to do this is to insert a breakpoint and step through, one at a time, every statement of the program until we get to the point of execution where we want to see what is happening. You can stop the execution at any time.

Observe the following dialog in which I insert a breakpoint at line 14 and step through each staments of the program one at a timeby using the full command step or the short s. I also inspect with the command print the content of the variables. Repeat the process on your machine.

-bash-3.2$ gdb foo
GNU gdb Fedora (6.8-37.el5)
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...
(gdb) break 14
Breakpoint 1 at 0x8048783: file foo.cpp, line 14.
(gdb) run
Starting program: /users/cs/lowlevel/llaguer0/foo 

Breakpoint 1, main () at foo.cpp:15
15      cout << "Enter the first integer number: ";
(gdb) step
16      cin >> first_number;
(gdb) step
Enter the first integer number: 25
17      cout << endl <<  "Enter the second integer number: ";
(gdb) s

18      cin >> second_number;
(gdb) s
Enter the second integer number: 0
19      quotient = quote(first_number, second_number);
(gdb) print first_number
$1 = 25
(gdb) print second_number
$2 = 0
(gdb) s
quote (x=25, y=0) at foo.cpp:28
28      z=x/y;
(gdb) print x
$3 = 25
(gdb) print y
$4 = 0
(gdb) print z
$5 = 0
(gdb) s

Program received signal SIGFPE, Arithmetic exception.
0x080486f2 in quote (x=25, y=0) at foo.cpp:28
28      z=x/y;
(gdb) s

Program terminated with signal SIGFPE, Arithmetic exception.
The program no longer exists.
(gdb) 
 

When you use the command step, the debugger proceeds one statement at a time. In some cases, you may prefer to step over function calls (i.e. you do not want step inside the function one statement at a time). In that case, use the comman next or the short one n. This causes the complete execution of the function. The debugger stops at the next current instruction where the command was executed.

To stop the debugger and return to the shell, use the command quit.s

Your just used a Debug! Congrats.