🐛 GNU Debugger (GDB)
🎯 Introduction to GDB
The GNU Debugger (GDB) is the most powerful and widely-used debugger for programs written in C, C++, and many other programming languages. It allows you to see what's happening inside a program while it executes or what it was doing at the moment it crashed.
💡 What GDB Can Do:
🔄 GDB Debugging Workflow
🛠️ Setting Up for Debugging
Compilation with Debug Information
To debug effectively, compile your program with the -g flag:
$ gcc -g -o myprogram myprogram.c
$ gcc -g -Wall -Wextra -o advanced_program advanced_program.c
⚠️ Important: The -g flag includes debugging symbols in the executable. Without it, GDB won't be able to show source code or variable names.
📚 Essential GDB Commands
💻 Concrete Example: Debugging a Buggy Program
Sample C Program with Bugs
// File: buggy_program.c
#include <stdio.h>
#include <stdlib.h>
int factorial(int n) {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1); // Bug: no bounds checking
}
int divide_numbers(int a, int b) {
return a / b; // Bug: division by zero not handled
}
int main() {
int numbers[] = {5, 0, -3, 10};
int size = sizeof(numbers) / sizeof(numbers[0]);
printf("Testing factorial and division:\n");
for (int i = 0; i < size; i++) {
int num = numbers[i];
printf("Number: %d\n", num);
// Calculate factorial
int fact = factorial(num);
printf("Factorial of %d: %d\n", num, fact);
// Divide by the number
int result = divide_numbers(100, num);
printf("100 / %d = %d\n", num, result);
printf("---\n");
}
return 0;
}
Step-by-Step Debugging Session
🚀 Complete Debugging Session:
$ gcc -g -o buggy_program buggy_program.c
$ gdb ./buggy_program
(gdb) list
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int factorial(int n) {
5 if (n <= 1) {
6 return 1;
7 }
8 return n * factorial(n - 1);
9 }
10
(gdb) break main
Breakpoint 1 at 0x1149: file buggy_program.c, line 14.
(gdb) break divide_numbers
Breakpoint 2 at 0x1129: file buggy_program.c, line 11.
(gdb) run
Starting program: /path/to/buggy_program
Breakpoint 1, main () at buggy_program.c:14
14 int numbers[] = {5, 0, -3, 10};
(gdb) print numbers
$1 = {5, 0, -3, 10}
(gdb) continue
Continuing.
Testing factorial and division:
Number: 5
Factorial of 5: 120
Breakpoint 2, divide_numbers (a=100, b=5) at buggy_program.c:11
11 return a / b;
(gdb) print a
$2 = 100
(gdb) print b
$3 = 5
(gdb) continue
Continuing.
100 / 5 = 20
---
Number: 0
Factorial of 0: 1
Breakpoint 2, divide_numbers (a=100, b=0) at buggy_program.c:11
11 return a / b;
(gdb) print b
$4 = 0
(gdb) print a/b
Floating point exception
🐛 Bug Found! Division by zero detected! The program will crash when trying to divide 100 by 0.
🧠 Memory and Stack Visualization
Program Memory Layout During Debugging
🔍 Advanced GDB Features
Watchpoints
Monitor when a variable changes:
(gdb) watch variable_name
(gdb) rwatch variable_name // Read watchpoint
(gdb) awatch variable_name // Access watchpoint
Recommended by LinkedIn
Conditional Breakpoints
Break only when certain conditions are met:
(gdb) break 20 if x > 10
(gdb) break function_name if parameter == NULL
(gdb) condition 1 x != 0 // Add condition to existing breakpoint
Examining Memory
(gdb) x/10x $sp // Examine 10 hex words at stack pointer
(gdb) x/s 0x12345678 // Examine as string
(gdb) x/i $pc // Examine as instruction
(gdb) x/20b &array[0] // Examine 20 bytes
Call Stack Navigation
(gdb) backtrace // Show full call stack
(gdb) frame 2 // Switch to frame 2
(gdb) up // Move up one frame
(gdb) down // Move down one frame
(gdb) info frame // Show current frame info
🛡️ Debugging Core Dumps
When a program crashes, it may create a core dump. Here's how to analyze it:
$ ulimit -c unlimited # Enable core dumps
$ ./buggy_program
Floating point exception (core dumped)
$ gdb ./buggy_program core
(gdb) backtrace
#0 0x0000000000001129 in divide_numbers (a=100, b=0) at buggy_program.c:11
#1 0x00000000000011a3 in main () at buggy_program.c:25
(gdb) frame 0
(gdb) print a
$1 = 100
(gdb) print b
$2 = 0
💡 Core Dump Analysis Tips:
🎭 GDB Debugging Strategies
Problem-Solving Approach
Common Debugging Scenarios
⚡ Pro Tips and Best Practices
🎯 Efficient Debugging Tips:
Sample .gdbinit Configuration
# .gdbinit file
set print pretty on
set print array on
set print array-indexes on
set history save on
set history size 10000
set history filename ~/.gdb_history
# Custom commands
define hook-quit
set confirm off
end
# Show more context when listing
set listsize 20
⚠️ Security Note: GDB will only read .gdbinit files in your home directory by default. To use project-specific .gdbinit files, you need to add set auto-load safe-path / to your home directory's .gdbinit.
🎓 Conclusion
GDB is an incredibly powerful tool that can save you hours of debugging time once you master its features. Remember that debugging is both an art and a science – use GDB's systematic approach combined with your understanding of the code to efficiently track down bugs.
🚀 Next Steps:
Hi Friends, Any other topics or concepts you are curious about, please write them down here, I will pick some to explain. 👏
Gdb dashboard!!
gdb is really a powerful tool. I found a memory corruption using gdb on one of the programs I wrote for sockets. Tweaked the pointer and the program worked like magic.
Nice post