The GNU debugger (Gdb)
This guide will introduce you about how to debug your c programs with gdb.
Lets start with its invocation, if your program is just an executable without arguments you just have to run:
$ gdb ./program
Or if your program needs arguments to run add the option --args
to gdb use:
$ gdb --args ./program arg1 arg2 ...
Now you are on the gdb terminal, maybe you feel lost and you don’t know which commands are available in this new terminal, so let me show you the important ones (or at least the ones that I use most).
Displaying the code of the program
To check the code use:
(gdb) list
(gdb) l
Or if you wish to avoid having to run these commands constantly to see the code use the command:
(gdb) layout src
It will convert your boring terminal into a window showing the code you need to check and a terminal behind to put more gdb commands, one of the trade-offs of this mode is that your arrow keys will be used to navigate into the code blocking the ability on your terminal to move the cursor, backward and forward, to return to the previous mode execute:
tui disable
Telling Gdb where to pause the program
Before running the code we need to specify where the program should stop, after all we are debugging code. The command to do that is break and you can use it in multiple ways:
(gdb) break LINENUMBER
(gdb) break FUNCTION_NAME
(gdb) break FILE.c:LINENUMBER
(gdb) break FILE.c:FILE_FUNCTION_NAME
(gdb) b LINENUMBER
(gdb) b FUNCTION_NAME
(gdb) b FILE.c:LINENUMBER
(gdb) b FILE.c:FILE_FUNCTION_NAME
Suspicious readers have noted that list and break command have a shortened versions which begin by just its first character so to avoid redundancy the next commands that have their shortened versions will be written in the following way:
c[ommand]
Here is one example with break
and list
:
(gdb) b[reak] LINENUMBER
(gdb) l[ist]
Running the code
Now we know how to stop the program, lets start it, to run the program for the first time use the command:
(gdb) r[un]
If a breakpoint was set before, the program will stop there. Once the program
stops you can use list
to check where you are. If you need to advance one line
at a time in the program put:
(gdb) n[ext]
Also there is a similar command that will get into subroutines when possible, for example if you stop on a function and you want to dive in the function to check if everything is fine is better to use:
(gdb) s[tep]
If Instead of advancing one line at time you need to go until a specific line the command:
(gdb) u[ntil] LINENUMBER
will be helpful, another command useful to execute the program until the next breakpoint is:
(gdb) c[ontinue]
And if for whatever reason you need to restart the program use again the command:
(gdb) r[un]
Looking variables
Now you stopped where you wanted, its time to check if the variables at that state of the program have its expected values. The first we will is:
(gdb) p[rint] VAR_NAME
with print, you can check not only single variables, it you want you can see arrays or structs variables, it is even possible to the value of pointers using the following syntax:
(gdb) p[rint] *PTR@NUMBER_OF_FIELDS
The other one I use often is:
(gdb) printf "FMT_STR", VAR1, ...
it works in the same way as a C printf function and is usefull to show multiple variables at one call, where is one example showing a string and an integer
(gdb) printf "%d: %s", INTEGER_VAR, CHAR_PTR_VAR
Closing GDB
Now you finally found the bug, and you know how to fix it, but to your surprise you don’t know how to exit gdb, well the command is easy:
(gdb) q[uit]
And Finally getting help
With the commands explained above you have a basic understanding of how to debug with gdb but this is just a taste, sometimes you need more information, to get it you can use:
(gdb) h[elp]
(gdb) h[elp] COMMAND
(gdb] h[elp] TOPIC
help command will show you the available commands on gdb and how to use them, the rest is up to you.