Remote Debugging with GDB

From Gumstix User Wiki
Revision as of 10:22, 27 July 2010 by Gustavs (Talk | contribs) (New Debugging Tutorial)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Tutorial for Debugging a program with a logical error

This 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 []
  1. Compile the program and execute the program.
root@overo:~# g++ -g broken.cpp -o broken  <enter>
root@overo:~# ./broken  <enter>

hint: Do not type “g++ -o broken broken.cpp”

  1. In this program no matter the input the output always is infinity. The -g option is important because it enables meaningful GDB debugging. Start the debugger
root@overo:~# gdb broken <enter>
  1. This only starts the debugger; it does not start running the program in the debugger. Look at the source :code and set a breakpoint at line 43
(if GDB is not your command line, i.e. (gdb), type) --> gdb

Complete the following steps

(gdb) b 43

Doing that will make this appear below

double seriesValue = ComputeSeriesValue(x, n);

  1. Now, we start to run the program in the debugger.
(gdb) run
  1. Note: If you still need to supply the command-line arguments for the execution of the program, simply include them after the run command, just as normally done on the command line. The program starts running and asks us for the input.
HINT: if you left any commands out before or want to put one in, do it now

Let's 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:

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
Please enter an integer value for n : 3

Breakpoint 1, main () at broken.cpp:43
43  double seriesValue = ComputeSeriesValue(x, n);

  1. Note that the program execution stopped at our first (and only) breakpoint. Step into the ComputeSeriesValue() function

To step into a function call, we use the following command:

(gdb) step
ComputeSeriesValue (x=2, n=3) at broken.cpp:17
17  double seriesValue=0.0;
  1. At this point, the program control is at the first statement of the function ComputeSeriesValue (x=2, n=3) Next let's step through the program until we get into ComputeFactorial.

To stay on track follow these commands carefully.

(gdb) next
18  double xpow=1;
(gdb) n
20  for (int k = 0; k <= n; k++) {
(gdb) <enter> 
21    seriesValue += xpow / ComputeFactorial(k) ;
(gdb) s
ComputeFactorial (number=0) at broken.cpp:7
7  int fact=0;
Note: Step lets you get a closer look at each function and line, while next skips over whole functions to the next one.
Here we use n and s instead of next and step, respectively. If the command is simply a repeat of the previous command, you can just hit return, which will execute the last command. Finally, we step (with s) into ComputeFactorial(). (If we'd used next, it would have stepped over ComputeFactorial.)
  1. Where are we?
If you want to know where you are in the program's execution (and how, to some extent, you got there), you can view the contents of the stack using the backtrace command as follows:
     (gdb) bt
     #0  ComputeFactorial (number=0) at broken.cpp:7
     #1  0x08048907 in ComputeSeriesValue (x=3, n=2) at broken.cpp:21
     #2  0x08048a31 in main () at broken.cpp:43

Note: Backtrace lets you see where you have been and what you have done, in the case you get lost or confused it is very useful.

  1. Watching changes We can step through the program (using the next command) and examine the values using the print command.

Once again, follow these commands carefully in order to stay on track.
     (gdb) next
     9  for (int j = 0; j <= number; j++) {
     (gdb) n
     10    fact = fact * j;
     (gdb) n
     9  for (int j = 0; j <= number; j++) {
     (gdb) print fact
     $2 = 0
     (gdb) n
     13  return fact;
     (gdb) quit

Try to find the error.
HINT: Look inside the “print fact” command

The print command (abbreviated p) reveals that the value of fact never changes. Note that the function is returning a value of 0 for the function call ComputeFactorial(number=0). This is an ERROR! The answer will always equal zero.

By taking a closer look at the values printed above, we realize that we are computing fact=fact * j where fact has been initialized to 0, (0 = 0 * j); fact should have been initialized to 1. We quit GDB with the quit command. Next we need to change the following line:

(gdb) quit
int fact = 1;
HINT: It is near the top of the program’s code.

Recompile the code and run it, you will get the expected output.