Debugging is an invigorating process that requires a great deal of attention to detail and analytical thinking. It is comparable to an intricate puzzle, where one must gather evidence, analyze every lead and finally get to the root of the problem.
In this journey, one of the most valuable tools is the GNU Debugger, known as GDB. It helps to navigate through the program’s code, identify errors, and ultimately troubleshoot them. Join me today on a journey through the world of GDB commands and their outputs. As we embark on this journey, I’ll also share with you some of the things I love and dislike about the process.
Debugging with GDB commands
1. Setting the stage with GDB
Before we dive into the ocean of commands, it’s essential to understand the basics. You would typically use GDB for programs written in C and C++. So, let’s get started, shall we?
Starting GDB
The simplest way to invoke GDB is:
$ gdb [your-program]
For instance:
$ gdb hello-world
Output
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2 ... Reading symbols from hello-world... (No debugging symbols found in hello-world) (gdb)
2. The essentials: Running and stopping your program
Running your program
To run your program inside GDB:
(gdb) run
Or if you want to pass arguments:
(gdb) run arg1 arg2
Honestly, I find this command to be among the most straightforward and my personal favorite.
Stopping your program
If you ever wish to stop your program while it’s running, just type:
(gdb) quit
3. The beauty of breakpoints
Ah, breakpoints, the bread and butter of debugging. These commands have saved me hours, if not days. But sometimes, I get a bit carried away and set too many of them (oops!).
Setting a breakpoint
To set a breakpoint at a particular function:
(gdb)>break function_name
Output
Breakpoint 1 at 0x804843f: file hello-world.c, line 6.
To remove a breakpoint:
(gdb) delete breakpoint_number
4. Examining variables and memory
When I’m deep into the debugging process, I often find myself wanting to scrutinize the variables. GDB offers a plethora of commands for this, and I’m grateful for each one of them, though sometimes I do wish there were fewer to remember.
Printing variable values
To print the value of a variable:
(gdb)>print variable_name
Output
$1 = 42
Examining memory
To check memory content:
(gdb) x/nfu address
Where:
- n: number of units to display
- f: format
- u: unit size
Output
0x8049a1c <main+8>: 0x0000002a
5. Diving deeper with backtrace and frame commands
Understanding the flow of a program is paramount. GDB provides some excellent commands that let me do just that. Though, sometimes, I wish they were a tad more intuitive.
Backtrace
When I need to check the call stack:
(gdb) backtrace
Output
#0 0x00007ffff7e1a2a2 in __GI___libc_free (mem=0x555555756260) at malloc.c:3093 #1 0x00005555555546e9 in main () Frame
To select and inspect a particular frame:
(gdb) frame frame_number
6. Stepping through the code
Oh, how I love to tread slowly and steadily through my code. GDB makes it an experience to cherish.
Step over
To execute the current line of code:
(gdb) next
Step into
If you wish to dive deep into a function:
(gdb) step
I must confess, sometimes, I do get a bit impatient with stepping and just let the code run.
7. Modifying variables on-the-fly
Imagine being able to change reality. With GDB, you can—at least for your program.
Setting a variable
To change a variable’s value:
(gdb)>set variable variable_name=value
I find this feature especially handy, but caution is the name of the game here.
8. Continuing after a breakpoint
There have been countless times when I set a breakpoint and after examining the situation, I just want to continue the normal flow. That’s where the continue
command becomes my best friend.
Resume execution
To continue running the program after hitting a breakpoint:
(gdb) continue
The program will then resume and run until the next breakpoint or until it completes.
9. Getting help inside GDB
We all need a little help sometimes. And while I do pride myself on my memory, there are moments when I forget the specifics of a command. That’s when GDB’s inbuilt help feature becomes a lifesaver.
Getting command-specific help
To understand the usage of a specific command:
(gdb) help command_name
Output (for help continue
)
Continue program being debugged, after signal or breakpoint. If proceeding from a place where the normal way to proceed is to step, then you should use the `step' or `next' command.
This command reminds me that no matter how well-acquainted we are with a tool, there’s always something new to learn, or in my case, occasionally remember!
10. Displaying source code with GDB
Amidst all the command outputs and memory addresses, I sometimes lose track of where I am in the source code. It’s a bit embarrassing to admit, but I’m only human! That’s when the list
command becomes my guiding star, illuminating the path in the maze of source code.
Listing source code
To display the source code around your current execution point:
(gdb) list
If you wish to list around a specific function or line number:
(gdb) list function_name
Or:
(gdb) list line_number
Output
5 #include <stdio.h> 6 7 int main() { 8 int x = 5; 9 int y = 10; 10 printf("The sum is: %d\n", x + y); 11 return 0; 12 }
I particularly adore this command because it saves me from context-switching between the debugger and my source code editor. It’s like having a built-in GPS for your program!
Concluding thoughts
Debugging is an essential part of any software development process, yet it can be both challenging and time-consuming. However, with the right tools at your disposal, the journey can become less daunting and more of a joyride. Among the plethora of debugging tools available, GDB stands out as a reliable and powerful tool that can make the process of debugging much simpler and efficient.
In this article, you have discovered some of the most frequently used GDB commands that can help you debug your code with ease. Along with these commands, I also shared some personal anecdotes and preferences that I have developed over the years. It’s important to keep in mind that practice is crucial to mastering any skill, and debugging is no exception. So, keep practicing and refining your skills, and never stop learning. Happy debugging, and may you always be able to find your bugs swiftly and effortlessly!