GDB
The GNU Debugger, more widely known as the gdb, is one of the most powerful debuggers out there for C/C++. One thing I have noticed when I was learning gdb was that there were no simple and quick tutorials for gdb except a very few which I have lost track of. Because of that, I decided to write one which should get you started debugging with gdb in no time (I too am a student, so if you notice any errors or feel like adding a new tip or a trick, feel free)
To get started with gdb you need a few things. First you need gdb, a compiler such as gcc, a text editor that show line numbers (not needed, but it’s a really good idea), such as vi or emacs and a c/c++ source file you need to debug.
Once you start gdb, you will be prompted with the (gdb) prompt. Now it’s ready to accept commands. I will use the example below of using the gdb as the tutorial since I believe it’s the easiest method, everything in bold is what I commanded gdb, normal font is gdb’s output, and italics starting with // are my comments.
// First compile the program
[janitha@somecomputer somefolder]$ gcc -g -o a4 a4.c
// Then load a4 into gdb and run gdb
[janitha@somecomputer somefolder]$ gdb a4
GNU gdb Red Hat Linux (6.3.0.0-1.21rh)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type “show copying” to see the conditions.
There is absolutely no warranty for GDB. Type “show warranty” for details.
// Once your inside gdb, run your program
// You can specify arguments right after run
(gdb) run
Starting program: /home/j/college/cpsc/a4/linkedlist/a4
Reading symbols from shared object read from target memory…done.
Loaded system supplied DSO at 0xd84000
Program Output
// It run the program, if sucessful it will display the programs output
// or if it segfaults it will tell you where in your code it happened
Program exited normally.
// Now lets add a breakpoint at line 80 in the source
(gdb) break 80
Breakpoint 1 at 0x804872e: file a4.c, line 80.
// and another break point at 114
(gdb) break 114
Breakpoint 2 at 0x80487db: file a4.c, line 114.
// Later you can view what and where your break points are
// using “info breakpoints”. As you can see each breakpoint is
// assigned a unique number starting from 1
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x0804872e in radix at a4.c:80
2 breakpoint keep y 0x080487db in write at a4.c:114
// Lets run the program again
(gdb) run
Starting program: /home/j/college/cpsc/a4/linkedlist/a4
Reading symbols from shared object read from target memory…done.
Loaded system supplied DSO at 0xa40000
Breakpoint 1, radix (master=0x8079008) at a4.c:84
84 for(i=0; i<10; i++) {
// Ok, so the program ran until it hit the first breakpoint
// and your program is paused
// At this time, you can take a look at your variables and values of them
(gdb) print *master
$1 = {front = 0x8079180, back = 0x80792c0}
// Print will accept variable names and pointers and even dereference them
(gdb) print *master->front
$2 = {value = 3458, back = 0x8079190}
// or it can simply show the value of i variable at that given time
(gdb) print i
$3 = 10
// Next will run the program just a single source line in
// the current function
(gdb) next
87 while(!isempty(master)) {
// You can optionally give it how many lines, in this case run 5 lines down
(gdb) next 5
90 enqueue(subqueue[digit(current, i)], current);
// Step will go into a function call, in this case into digit()
(gdb) step
digit (number=35, pos=0) at a4.c:64
64 return (int)(number/power10(pos))%10;
(gdb) next
66 }
// You can run line by line inside that functiony
// and once that function is done, it will come back to original function
(gdb) next
radix (master=0x8079008) at a4.c:87
87 while(!isempty(master)) {
// Print can also call on funtions and show their values
// is empty() is a function I write, and it will dispay the return value
// you can call on any function this way
(gdb) print isempty(master)
$4 = 0
// Display is like print, except it will keep on displaying
(gdb) display *master
1: *master = {front = 0x80791a0, back = 0x80792c0}
// Now after every command it will show the value of the displays
// and you can have as many displays as you want
(gdb) next
89 current = dequeue(master);
1: *master = {front = 0x80791a0, back = 0x80792c0}
(gdb) next
90 enqueue(subqueue[digit(current, i)], current);
1: *master = {front = 0x80791b0, back = 0x80792c0}
// Each display is also given a unique number, and you can
// use undisplay to hide them
(gdb) undisplay 1
(gdb) next
87 while(!isempty(master)) {
// Whatis will show what that variable is a type of
(gdb) whatis master
type = Queue *
// Continue will run the program until it reaches
// another break point or the program stops
(gdb) continue
Continuing.
Breakpoint 2, write (master=0x8079008) at a4.c:115
115 while(!isempty(master)) {
// If you want to delete a breakpoint, use delete
// and give it the breakpoint number. Find the
// breakpoint number by doing “info breakpoints”
(gdb) delete 1
// Or if you want to delete all the break points, simply run delete
(gdb) delete
Delete all breakpoints? (y or n) y
(gdb) continue
Continuing.
Programoutput
Program exited normally.
Those are just the very basic commands. Other useful commands that are somewhat basic but didn’t use above are file which you can use to load another binary file into gdb. info stack will show the current stack and the order in which the functions were called and quit which will stop gdb and get out. Use the help command to explore and figure out what the other commands do. Now you can Google around and find other tutorials which go into the deep end of the gdb pool. Below are some ways to efficiently use gdb.
The first trick is that you don’t have to type the whole command to gdb. For example, instead of typing print blahblahall the type, you can just do p blahblah. Be careful since this works because the only command in gdb starting with a p is print. For example, c won’t run continue, because there is another command called condition, so you can shorten continue by typing cont since there is only one command starting with cont. i b will run info breakpoints and n 5 will go over 5 lines. Almost every command I used in the example above can be shortened this way and saves time and effort. The other most time saving trick is simply hitting enter at the console without any command. This will run the last command. So if you typed next last, hitting enter over and over would just go nexting through.
The next thing I would say is not to use gdb alone, use it with a text editor that supports it such as emacs, gdbtui or ddd which can put a graphical symbol and display where in the source the program is currently at. Emacs has an excellent integration with gdb, so you can create a new buffer (usually by the side) in emacs and run m-x gdb, and in the source use shortcuts like c-spc to make a break point in the source. This is how I personally use gdb.
Of course using this text only command line interface for everything isn’t goig to take you far when debugging very big programs, and this is only efficient for debugging small programs or simply to figure out where a segfault is coming from. But once you know the basic commands of gdb, you can get started with ddd. Think of ddd this way, if you think gdb is the swiss army knife of debugging, then ddd is the swiss army knife complete with a samurai sword and a thermonuclear warhead. Personally, I think by far it is the most powerful debugger combination since it combines the ease of traditional graphical debuggers such as visual studio and eclipse at the same time having a command line interface of gdb. In gdb when you display it would output the variables or pointer values to the console as text, but with ddd you could create graphical objects such as boxes and expand and view the items with point and click ease. For example, you could simply double click on the pointer in the source, and it would create a display object representing the pointer, and clicking on that will dereference and display as a new item, and clicking on that will expand to its value and before you know it you have a graphical representation of a linked list or what ever your making complete with arrows showing where each item is pointing and makes life extremly easy. Other features include displaying one and two dimensional arrays as tables, along with the ability to integrate with gnuplot so you can view things like how a sorting algorithm works graphically.
As a conclusion, gdb is a really powerful debugger. It’s a slightly more challenging to get used to than other graphical debuggers, but once you do it can do insane things. When combined with something like emacs or similar editor that can interface directly with gdb, it becomes even more powerful. And with ddd, it’s unstoppable. So give gdb a try if you are fed up with visual studio style debugging, just maybe you will find gdb useful. Feel free to comment or add more information about gdb.