Remote Debugging with GDB

From Gumstix User Wiki
Revision as of 15:46, 28 July 2010 by JustinC474 (Talk | contribs)

Jump to: navigation, search

In this tutorial we will go over how to perform a basic debugging with GDB, the GNU debugger. This environment allows us to debug machine code. You will not be able to debug java programs with this unless you find a way to compile you java file into an executable that does not require a Java Virtual Machine.

  • We will complete these tasks step by step
  • Installing the GDB debugger
  • Running the debugger
  • Learn how to set Breakpoints
  • Learn how to navigate the code in your program
  • Learn how to diagnose and error and how to fix it
  • Required Items
  • Overo COM with Expansion Board
  • Mini B to Standard A Cable
  • Bootable MicroSD card
  • Required Reading (things you should know, or tutorials that explain)
  • [HelloWorld | HelloWorld in Python, C and C++]
  • [Eclipse on Gumstix for new users | Eclipse Tutorial]
  • Although the majority of this tutorial regards Eclipse and Java programming, it contains useful information which leads to basic understanding of your Overo COM

Installing the GDB Debugger

Before starting this, you should have Console access to your Overo COM and should know how to program and run a basic C++ program. If you do not know how to do this, see [HelloWorld | HelloWorld in Python, C and C++].

To install the GDB debugger, run the following command in your command line:

opkg update
opkg install gdb

Once this has completed, you will have the GNU GDB debugger installed on your Overo COM

Creating the Test File

Now that we have the debugging environment

Run the following in your command line:

nano broken.cpp

Then copy and paste the code from |Broken.cpp into your shell. When you copy and paste there will be two syntax errors that you must fix at the lines:

cout << "This program is used to compute the value of the following
series : " << endl;

and

cout << "(x^0)/0! + (x^1)/1! + (x^2)/2! + (x^3)/3! + (x^4)/4! + ....
.... + (x^n)/n! " << endl

Copying and pasting added an extra line break to these two lines, and we want to undo this by deleting one space at the beginning of each second line so it looks like this:

cout << "This program is used to compute the value of the following series : " << endl;

and

cout << "(x^0)/0! + (x^1)/1! + (x^2)/2! + (x^3)/3! + (x^4)/4! + ........ + (x^n)/n! " << endl

Now save and exit by pressing the following:

  • Ctrl + O
  • <Enter>
  • Ctrl + X

Compile and Run broken.cpp

Now that we have our test file (broken.cpp) ready to go, it is time to run it.

Compile the program to create an executable file (broken) by entering the following command:

g++ -g broken.cpp -o broken

Then run it:

./broken

Note: Use 'g++ -g broken.cpp -o broken' to compile. If you use g++ -o, g++ --ggdb -Wall, or any other method of compilation the debugging will not follow this tutorial exactly.


Enter any numbers into the program for x and n. Run it a couple times, you should notice that the answer is always the same: infinity. This is obviously wrong.

Consider: x=1, n=1 (1^0)/0! + (1^1)/1! 1/1 + 1/1 2

NOT infinity

Debugging the Program

Now, it is time that we debugged our program.

First, you need to start the GDB environment by issuing the following command:

gdb

You should see the following command line appear:

(gdb)

Then, you need to 'tell' the debugger which file it is that we are debugging, do this by issuing the command:

(gdb) exec-file broken

Now, it is time to run our program by issuing the command:

(gdb) run

Notice that the program runs normally and again, gives us the answer inf. This is because the error we have is a computation error, and does not cause our program to crash. So, its time to set a Breakpoint in our program.

Setting a Breakpoint


Hint: A breakpoint is a point in the program at which the debugger will stop the code from executing. Then, you can choose to 'step' through the program line by line to 'see' exactly what the CPU is doing. This way, you can effectively watch the program execute and discover where the problem is!


Lets set a breakpoint within the program so that we can see what is going on. Lets start by setting a breakpoint at line 43. Do this with the following command:

(gdb) b 43

Hint: If the program outputs: No symbol table is loaded. Use the "file" command. Then use the following command:

(gdb) file broken

This will set the file so that you can add a breakpoint without error


Line 43 is the following:

double seriesValue = ComputeSeriesValue(x, n);

So the program will stop executing immediately before it executes the function ComputeSeriesValue(x, n).

Now, lets run the program with our command:

(gdb) run

Let's enter the values as x=2 and n=3, with an expected output value is 5. Here is a snapshot of what the program should output at this point:

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

The program has stopped at our breakpoint, line 43.

Stepping into a function

Next, we are going to step into the function ComputeSeriesValue(x, n)


Hint: 'Stepping' through a function allows us to go line by line, and see exactly what lines of code are being executed. This way we can manually diagnose the computation problem.


To start stepping, issue the following command

(gdb) step

Hint: A nice thing about the GDB Debugger is that it will save the last command you issued so that you don't need to type it over and over. This way you can keep stepping through the function by pressing <enter>. You do not need to retype 'step'


You should see the following outputted:

ComputeSeriesValue (x=2, n=3) at broken.cpp:17
17  double seriesValue=0.0;

At this point, the program has gone to line 17, and is at the first line of the function ComputeSeriesValue, which sets the double seriesValue to 0.0.

Now, we wish to use the 'next' function until we reach the function CompueFraction(). To do this, use the following commands:

(gdb) next
18  double xpow=1;
(gdb) <enter>
20  for (int k = 0; k <= n; k++) {
(gdb) <enter> 
21    seriesValue += xpow / ComputeFactorial(k) ;
(gdb) step
ComputeFactorial (number=0) at broken.cpp:7
7  int fact=0;

Using Backtrace

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


See the error?

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:

change the line

int fact = 0;

to

int fact =1;

and your all set!

For another tutorial see: http://www.cs.cmu.edu/~gilpin/tutorial/