Remote Debugging with GDB

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

Jump to: navigation, search

Tutorial for Debugging a program with a logical error

In this tutorial we will go over how to perform a basic debugging with GDB.

We will complete these tasks step by step
  • Installing the GDB debugger
  • Running the debugger
  • Learning how to set Breakpoints
  • Learning how to navigate the code in your program
  • Learning how to diagnose and error and how to fix it

NOTE: Before you continue make sure you have GDB installed. To install GDB complete the tasks below

root@overo:~# opkg update	 	<enter>
root@overo:~# opkg install gdb 	<enter>

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 Broken.cpp

WARNING
If you copy and paste this code you will get an error!
To fix this error please follow these directions.
NOTE: The code below is the area that the Error occurs in! (around line #30)
 int main() {
 cout << "This program is used to compute the value of the following series : " << endl;
 cout << "(x^0)/0! + (x^1)/1! + (x^2)/2! + (x^3)/3! + (x^4)/4! + ........ + (x^n)/n! " << endl;
 cout << "Please enter the value of x : " ;
The 3rd line in this section of code will drop down one line in your terminal, and look something like this...
cout << "(x^0)/0! + (x^1)/1! + (x^2)/2! + (x^3)/3! + (x^4)/4! + ....
.... + (x^n)/n! " << endl
To fix this you have to bring all of the code back onto a single line. It should end up looking like this.
cout << "(x^0)/0! + (x^1)/1! + (x^2)/2! + (x^3)/3! + (x^4)/4! + ........ + (x^n)/n! " << endl;


2. Compile the program and execute the program.

root@overo:~# g++ -g broken.cpp -o broken  <enter>
root@overo:~# ./broken  <enter>


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




3. 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>




4. 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 do as follows)

root@overo:~# gdb


Complete the following steps:


(gdb) b 43
This puts a breakpoint at line 43 in the program's code.


Doing that will make this appear below

double seriesValue = ComputeSeriesValue(x, n);




5. Now, we start to run the program in the debugger.


(gdb) run




6. 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: Now is the time to put in any commands you left out before.


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);




7. 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;




8. 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.)




9. 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.




10. Watching changes We can go 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.