How to debug C code using GDB
GNU Debugger (also known as GDB) is a debugger that allows the user
to see “what’s happening” inside a program as it executes.
GDB can be used to debug programs written in C
, C++
, Fortran
, and Modula-2.
Sample code
# include <stdio.h>
int main()
{
int i, num, j;
printf ("Type a number: ");
scanf ("%d", &num );
for (i=1; i<num; i++)
j=j*i;
printf("%d factor is: %d!\n",num,j);
}
The code receives a number from the user through the scanf command and
calculates its factorial.
However, this code intentionally contains an error
that when the number 6 is entered, the program returns 0
when it should return 720.
6 factor is: 0!
Why does this happen? That’s what we’ll try to find out using GDB!
Step 1 - Compiling the code
To use GDB in your code, you need to use the -g
argument when compiling,
which allows the compiler to collect information that will be essential for
the debugging process. (See an example below)
$ cc -g factorial.c -o factorial
Step 2 - Initialize GDB
Initialize GDB with the code below:
$ gdb factorial.c
If you don’t have GDB installed on your system, just use the following command:
$ sudo apt install gdb
Step 3 - Setting a breakpoint
A breakpoint is basically a signal that will define where your code should
stop while it is executing, this will prevent your code from skipping over
the part you want to examine.
To set a new breakpoint use the break
command
or his short version b
(gdb) break line_number
In our case, since I want to examine the code loop, I will set the breakpoint for line 9:
(gdb) break 9
Breakpoint 1 at 0x11d3: file factorial.c, line 9.
Step 4 - Running the program
To run the program, use the run [args]
command (arguments can be used
just as you were running the program normally). Since in our case arguments
are not necessary, I will just use run
.
run
Starting program: /home/user/folder/factorial
With the code running it will execute normally until it reaches the first breakpoint defined and display the following message:
Breakpoint 1, main () at factorial.c:7
7 for (i=1; i<num; i++)
And now you will use some commands to debug, as explained in the topics below…
Step 5 - Displaying variable values
To check the value of a variable use the print
command along
with the variable name (which can also be abbreviated as p
),
for example:
(gdb) print i
$1 = 1
(gdb) print j
$2 = 3042592
(gdb) print num
$3 = 6
As you can see, the variable “j” was not initialized correctly. Therefore,
it will have a default garbage value, which will result in an unexpected
value in the factorization.
To fix the problem, simply define the “j” variable as 1, recompile the
program, and run it again. The problem seems to be fixed… but even
after that, something continues to cause the wrong factorial to be returned.
Extra Commands
Although it is an extra topic, the commands that will be mentioned are just
as essential as those addressed above.
There are three types of operations you can perform in GDB after the
program has reached the defined breakpoint. These commands are:
c
or continue
: The code will continue to execute until it reaches another breakpoint.n
or next
: It will execute a single line of instructions, something like skipping to the next command to be executed.s
or step
: Similar to next
, it will execute single instructions but with the difference that functions will not be treated as single instructions, making it execute line by line.l
or list
: This command will display the program source code.help
: Displays a help screen with some other useful commands.
If you want to more commands click here
References
https://linux.die.net/man/1/gdb
https://u.osu.edu/cstutorials/2018/09/28/how-to-debug-c-program-using-gdb-in-6-simple-steps/