分类: C/C++
2009-03-07 02:58:35
We are going to be using two programs to illustrate how GDB can be used to debug code.
Debugging a program having a
logical error:
The first sample program has some logical errors. The program is supposed to output the summation of (X^0) /0! + (X^1) /1! + (X^2) /2! + (X^3) /3! + (X^4) /4! + ... + (X^n) /n!, given x and n as inputs. However the program outputs a value of infinity, regardless of the inputs. We will take you step by step through the debugging process and trace the errors
1. Download the sample program from2. Compile the program and execute the program.
g++
broken.c –o broken.
Whatever the input, the output will be inf.
3. Compile the program on a Solaris/Linux machine using the following command.
g++
broken.c –g –o broken
Remember to compile the program using –g option, this option enables GDB to debug the executable broken.
4. Start the debugger.
gdb broken
This only starts the debugger; it does not start running the program in the debugger.
5. Look at the source file broken.c and set a breakpoint in the program in the main function at line 55.
b broken.c : 55
or break broken.c : 55
Line 55 is:
SeriesValue =
ComputeSeriesValue(x, n);
6. Let us set an additional breakpoint in the function ComputeSeriesValue() itself at line 26
b broken.c : 26
Line 23 inside the function ComputeSeriesValue(double x, int n) is:
factorial =
ComputeFactorial( k );
7. Let us set one a breakpoint inside the function ComputeFactorial( int number )at line 11
b
broken.c : 11
Line 11 is:
fact
= fact * j;
8. Now, we start to run the program in the debugger.
(gdb) run
Note: If we have to supply the command-line arguments for the execution of the program then, we run the program in the debugger as follows:
run
arg1 arg2
arg3 ….
9. The program starts running and asks us for the input.
Let us enter the values as x=2 and n=3. The expected output value is 5. The following is a snapshot of the program running in the debugger:
(gdb)
run
Starting
program: /home/csi/d/dave/broken
This
program is used to compute the value of the following series:
(X^0)/0!
+ (X^1)/1! + (X^2)/2! + (X^3)/3! + (X^4)/4! + ... + (X^n)/n!
Please
enter the value of x: 2
55 series Value = ComputeSeriesValue (x, n);
Note that the program execution stopped at line number 55 (which is where it encounters the first breakpoint).
10. Now, let us Step Into the function call to ComputeSeriesValue (x=2, n=3). To step into a function call, we use the following command:
s or step
At this point, the program control is at the first statement of the function ComputeSeriesValue (x=2, n = 3) i.e. at:
Double
series Value = 0.0;
11. Now, let us run the program in normal speed until it encounters the next breakpoint (or end of main or exit). To do this, we use following command:
continue or c
Note: That to execute a statement or a function call in a single step, we can use the command next or n. On doing so, the program control will go to the following line.
Now, the program control will be at:
(gdb)
c
Continuing.
Breakpoint
2, ComputeSeriesValue (x=2, n=3) at broken.c: 26
26
factorial = ComputeFactorial(k);
To display the value of k, we use the following command:
print k or p k
The resulting output is:
(gdb)
p k
$1
= 0
12. Everything has happened as expected up to this point. Now, let’s step intothe function call to ComputeFactorial (k=0) using the step command. To view the contents of the stack, we can use the following command:
bt or backtrace.
The result of the above command is as follows:
(gdb) backtrace
#0
ComputeFactorial (number=0) at broken.c:8
#1
0x80487a9 in ComputeSeriesValue (x=2, n=3) at broken.c:26
#2
0x80488bf in main () at broken.c:55
13. Now, let us run the program statement by statement printing the values of important variables as we do so.
8
int fact=0 , j=0;
(gdb)
n
10
for ( j = 0 ; j <= number ; j++ )
(gdb)
n
Breakpoint
3, ComputeFactorial (number=0) at broken.c:11
11
fact = fact * j;
(gdb)
p fact
$2
= 0
(gdb)
p j
$3
= 0
(gdb)
n
13
return fact;
(gdb)
p fact
$4
= 0
Note that the function is returning a value of 0 for the function call ComputeFactorial(number=0). This is an ERROR!
By taking a closer look at the values printed above, you will realize that we are computing “fact=fact * j” where both fact and j have been initialized to 0. We need to initialize fact=1 and j=1. We need to change the following lines:
Line 8 : int fact = 1, j =1;
Line 10 : for( j=1; j <=
number ; j++ )
14. Then, recompile the code and run it, you will get the expected output.
This program causes a core dump due to a segmentation fault. We will try to trace the reason for this core dump.
Download the program, from
1. Compile the program using the following command.
g++
testit.c –g –o testit
2. Run it normally, you should get the following result:
Segmentation
fault (core dumped)
3. The core dump generates a file called corewhich can be used for debugging. Since, this program is really short, we will not need to set any breakpoints. Use the following command to start running the debugger to debug the core file produced by testit.
gdb
testit core
The output of the above command should look like this:
bash$
gdb testit core
GNU
gdb 19991004
Copyright
1998 Free Software ……….…
Core
was generated by `testit'.
Program
terminated with signal 11, Segmentation fault.
Reading
symbols from /usr/lib/libstdc++-libc6.1-1.so.2...done.
Reading
symbols from /lib/libm.so.6...done.
Reading
symbols from /lib/libc.so.6...done.
Reading
symbols from /lib/ld-linux.so.2...done.
#0
0x804851a in main () at testit.c:10
10
temp[3]='F';
4. As we can see from the output above, the core dump was produced
as a result of execution of the statement on line 10: temp[3] =’F’;
Take a closer look at the declaration of temp on line 5 :
Line 5
char *temp = "Paras";
We find that temp is a char* which has been assigned a string literal, and so we cannot modify the contents of the literal as on line 10. This is what is causing a core dump
|