A debugger plays a vital role in any software development system. Nobody can write a bug-free code all at once. During the course of development, bugs are being raised and needs to be solved for further enhancement. A development system is incomplete without a debugger. Considering the open source developers community, GNU Debugger is their best choice. It is also used for commercial software development on UNIX type platforms.
GNU Debugger, also known as gdb, allows us to sneak through the code while it executes or what a program was trying to do at the moment before it crashed. GDB basically helps us to do four main things to catch flaws in the source code.
- Start the program, specifying arguments that may affect the general behavior.
- Stop the program on specified conditions.
- Examine the crash or when program was stopped.
- Change the code and to experiment with the modified code instantaneously.
We can use gdb to debug programs written in C and C++ without much effort. As of now support for other programming languages like D, Modula-2, Fortran are partial.
Getting started with GNU Debugger or GDB
GDB is invoked using the gdb command. On issuing gdb, it displays some information about platform and drops you into the (gdb) prompt as shown below.
[root@fedora20 ~]# gdb
Sample Output
GNU gdb (GDB) Fedora 7.6.50.20130731-19.fc20 Copyright (C) 2013 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-redhat-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word". (gdb)
Type help list to out the different classes of commands available inside gdb. Type help followed by a class name for a list of commands in that class. Type help all for the list of all commands. Command name abbreviations are allowed if they are unambiguous. For example, you can type n instead of typing next or c for continue and so on.
Most Commonly used GDB Commands
Commonly used gdb commands are listed in the following table. These commands are to be used from the gdb command prompt (gdb).
Command
|
Description
|
run
|
Start a program execution
|
quit
|
Quit gdb
|
print expr
|
Print expression where expr may be a variable name too
|
next
|
Go to next line
|
step
|
Step into next line
|
continue
|
Continue from the current line till the end of program or next break point
|
Note the difference between the two commands step and next. The next command does not go inside function if next line is a function call. Whereas step command can go in inside function and see what happens there.
A sample session with GDB
Consider the following source code.
// sum.c #include <stdio.h> int sum (int a, int b) { int c; c = a + b; return c; } int main() { int x, y, z; printf("\nEnter the first number: "); scanf("%d", &x); printf("Enter the second number: "); scanf("%d", &y); z = sum (x, y); printf("The sum is %d\n\n", z); return 0; }
In order to debug the output file we need to compile the same with -g option to gcc as follows.
$ gcc -g sum.c -o sum
The output file sum can be attached to gdb via either of the following 2 ways:
1. By specifying the output file as an argument to gdb.
$ gdb sum
2. Running output file inside gdb using file command.
$ gdb (gdb) file sum
The list command lists lines in the source code file and moves the pointer. So first list will display the first 10 lines and next list displays the next 10 and so on.
(gdb) list 1 #include <stdio.h> 2 3 int sum (int a, int b) { 4 int c; 5 c = a + b; 6 return c; 7 } 8 9 int main() { 10 int x, y, z;
To start execution, issue the run command. Now the program gets executed normally. But we forgot to put some breakpoints in the source code for debugging, right? These breakpoints can be specified for functions or at specified lines.
(gdb) b main
Note: I have used an abbreviation b for break.
After setting break point at main function, rerunning the program will stop at the line 11. The same thing can be made into effect if the line number is known before.
(gdb) b sum.c:11
Now step through the lines of code using the next or n command. It is important to note that next command does not go inside function code unless a break point is set on the function. Let’s try out the print command now. Set break point on function sum as below.
(gdb) b sum Breakpoint 1 at 0x4005aa: file sum.c, line 5. (gdb) r Starting program: /root/sum Enter the first number: 2 Enter the second number: 3 Breakpoint 1, sum (a=2, b=3) at sum.c:5 5 c = a + b; (gdb) p a $1 = 2 (gdb) p b $2 = 3 (gdb) c Continuing. The sum is 5 [Inferior 1 (process 3444) exited normally]
If the program being run requires command line parameters then provide the same along with the run command as.
(gdb) run . . .
Shared library files associated with the current running program can be listed as.
(gdb) info share From To Syms Read Shared Object Library 0x00000035a6000b10 0x00000035a6019c70 Yes /lib64/ld-linux-x86-64.so.2 0x00000035a641f560 0x00000035a6560bb4 Yes /lib64/libc.so.6
Modifying Variables
GDB is also capable of modifying variables throughout the execution of program. Let’s try this out. As mentioned above set break point at line 16 and run the program.
(gdb) r Starting program: /root/sum Enter the first number: 1 Enter the second number: 2 Breakpoint 1, main ( ) at sum.c:16 16 printf("The sum is %d\n\n", z); (gdb) set z=4 (gdb) c Continuing. The sum is 4
Now a = 1, b = 2 and result should be z = 3. But here we changed the final result to z = 4 in the main function. In this way debugging can be made easier using gdb.
Enable/Disable Breakpoints
To get the list of all breakpoints type info breakpoints.
(gdb) info breakpoints Num Type Disp Enb Address What 1 breakpoint keep y 0x00000000004005c2 in main at sum.c:11
Here there is only one break point and it is To. enabled disable the breakpoints specify the breakpoint number along with the disable command. To enable afterwards use the enable command.
(gdb) disable 1 (gdb) info breakpoints Num Type Disp Enb Address What 1 breakpoint keep n 0x00000000004005c2 in main at sum.c:11
You can also delete the breakpoints with delete command.
Debugging running Processes
Numerous processes are running in background in a GNU/Linux system. To debug a running process first of all we need to find the process id of that particular process. pidof command gives you the pid of a process.
$ pidof <process_name>
Now we need to attach this pid to gdb. There are 2 ways.
1. By specifying pid along with gdb.
$ gdb -p <pid>
2. Using attach command from gdb.
(gdb) attach <pid>
That’s all for now. These are only basics of gdb to get a good start in debugging source code and it is much more than the things explained above. For example, we can debug using the stack information, environment variables and lot more. Try to play around with all these stuffs…
Thank you for such a great tutorial.
Its well explained
I used to use the dbx debugger on AIX, and it had a really nice feature that I wish gdb had. There was a ‘call’ command that allowed you to call any function in the app from a breakpoint. I would add functions to my libraries specifically to allow printing out complex data in variables during debugging – and then use another nice dbx feature, macros, to define simple shortcuts to make it all easy. For example, the system in question used a weird binary date format, but the date library had a DisplayFormattedDate(mydate) function, and I set up a dd(x) alias to it to make this even easier. And of course there was more complex binary stuff similarly displayable. Of course, a nice graphical IDE that wrapped dbx might’ve been even nicer, but this call thing was really powerful. It’d be nice if gdb had something similar – and if IDE’s based on gdb gave you a way to access it (I think kdebug has a command window where you could do that).
Thanks for this great introductory tutorial … just what I needed.