Difference between revisions of "Remote Debugging with GDB"
(New Debugging Tutorial) |
Searchworks (Talk | contribs) (remove spam) |
||
(31 intermediate revisions by 4 users not shown) | |||
Line 1: | Line 1: | ||
− | + | In this tutorial we will go over how to perform a basic debugging with GDB, the GNU debugger. This environment allows us to debug C, C++ and Java (compiled to machine code, not for running in a Java Virtual Machine) programs. | |
+ | *We will complete these tasks step by step | ||
+ | :*Install the GDB debugger | ||
+ | :*Run the debugger | ||
+ | :*Set Breakpoints | ||
+ | :*Navigate the code in your program | ||
+ | :*Diagnose an error and how to fix it | ||
− | : | + | *Required Items |
− | : | + | :*Overo COM with Expansion Board |
− | : | + | :*Mini B to Standard A Cable |
+ | :*Bootable MicroSD card | ||
+ | :*5V Power Supply | ||
− | + | *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 pertains to debugging and C 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++]]. | ||
+ | If you haven't yet, install a C/C++ SDK with the following command | ||
+ | opkg update | ||
+ | opkg install task-native-sdk | ||
− | + | 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 [http://cs.baylor.edu/~donahoo/tools/gdb/broken.cpp |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! + .... | cout << "(x^0)/0! + (x^1)/1! + (x^2)/2! + (x^3)/3! + (x^4)/4! + .... | ||
.... + (x^n)/n! " << endl | .... + (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 | |
+ | The '-g' switch tells the compiler to include debugging symbols in the executable. Run the program as such: | ||
+ | ./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 | (gdb) b 43 | ||
+ | You could also set a breakpoint to a specific functions call, such as: | ||
+ | (gdb) b ComputeSeriesValue | ||
+ | However, for the purpose of this tutorial, use the line number. If you wish, you can play around with using the function instead, but it will cause you to diverge from this tutorial. | ||
− | + | 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); | 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 | (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 | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | Let's enter the values as x=2 and n=3 | + | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
Breakpoint 1, main () at broken.cpp:43 | Breakpoint 1, main () at broken.cpp:43 | ||
43 double seriesValue = ComputeSeriesValue(x, n); | 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 | |
− | To | + | |
− | + | ||
(gdb) step | (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' <br> | ||
+ | Hint: | ||
+ | The GDB Debugger also has nice 'shortcuts'. For example, 'step' and 's' are the same command. So is 'breakpoint' and 'b'. | ||
+ | ---- | ||
+ | You should see the following outputted: | ||
ComputeSeriesValue (x=2, n=3) at broken.cpp:17 | ComputeSeriesValue (x=2, n=3) at broken.cpp:17 | ||
17 double seriesValue=0.0; | 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: | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | To | + | |
− | + | ||
(gdb) next | (gdb) next | ||
18 double xpow=1; | 18 double xpow=1; | ||
− | (gdb) | + | (gdb) <enter> |
20 for (int k = 0; k <= n; k++) { | 20 for (int k = 0; k <= n; k++) { | ||
(gdb) <enter> | (gdb) <enter> | ||
21 seriesValue += xpow / ComputeFactorial(k) ; | 21 seriesValue += xpow / ComputeFactorial(k) ; | ||
− | (gdb) | + | (gdb) step |
ComputeFactorial (number=0) at broken.cpp:7 | ComputeFactorial (number=0) at broken.cpp:7 | ||
7 int fact=0; | 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 | |
− | + | ||
---- | ---- | ||
+ | Hint: | ||
+ | Backtrace lets you see where you have been and what you have done. In case, you get lost or confused it is very useful. <br> | ||
+ | Hint: | ||
+ | A stack is a data structure in Computer Science which stores data much like a stack of cards. It is a Last On, First Off data structure. For more explanation of how a stack functions, see the wikipedia article. <br> | ||
+ | http://en.wikipedia.org/wiki/Stack_(data_structure) | ||
---- | ---- | ||
− | + | 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. | 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: | 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 you're all set! | ||
− | + | ==More Tutorial== | |
+ | For another tutorial which is more in depth, see: | ||
+ | http://www.cs.cmu.edu/~gilpin/tutorial/ |
Latest revision as of 15:02, 23 November 2010
In this tutorial we will go over how to perform a basic debugging with GDB, the GNU debugger. This environment allows us to debug C, C++ and Java (compiled to machine code, not for running in a Java Virtual Machine) programs.
- We will complete these tasks step by step
- Install the GDB debugger
- Run the debugger
- Set Breakpoints
- Navigate the code in your program
- Diagnose an error and how to fix it
- Required Items
- Overo COM with Expansion Board
- Mini B to Standard A Cable
- Bootable MicroSD card
- 5V Power Supply
- Required Reading (things you should know, or tutorials that explain)
-
- Although the majority of this tutorial pertains to debugging and C programming, it contains useful information which leads to basic understanding of your Overo COM
Contents
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 in Python, C and C++.
If you haven't yet, install a C/C++ SDK with the following command
opkg update opkg install task-native-sdk
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
The '-g' switch tells the compiler to include debugging symbols in the executable. Run the program as such:
./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
You could also set a breakpoint to a specific functions call, such as:
(gdb) b ComputeSeriesValue
However, for the purpose of this tutorial, use the line number. If you wish, you can play around with using the function instead, but it will cause you to diverge from this tutorial.
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'
Hint:
The GDB Debugger also has nice 'shortcuts'. For example, 'step' and 's' are the same command. So is 'breakpoint' and 'b'.
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
Hint:
Backtrace lets you see where you have been and what you have done. In case, you get lost or confused it is very useful.
Hint:
A stack is a data structure in Computer Science which stores data much like a stack of cards. It is a Last On, First Off data structure. For more explanation of how a stack functions, see the wikipedia article.
http://en.wikipedia.org/wiki/Stack_(data_structure)
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 you're all set!
More Tutorial
For another tutorial which is more in depth, see: http://www.cs.cmu.edu/~gilpin/tutorial/