GDB (GNU Debugger) – A Powerful Tool for Database Kernel Developers
Welcome to the world of database kernel development! Today, we will learn about a very important tool that acts like a doctor’s stethoscope or a detective’s magnifying glass, helping us delve into the internal workings of programs and uncover hidden bugs. This tool is GDB, the GNU Debugger.
1. Theory: Basic Concepts of GDB
1.1 What is GDB?
GDB is a powerful command-line debugging tool that allows you to:
- Start a program: Run your program under the control of GDB.
- Pause a program: Pause execution at specific points in the program.
- Check status: View variable values, memory contents, function call stacks, etc.
- Step through execution: Execute the program line by line and observe changes at each step.
- Modify the program: Temporarily change variable values or even modify program instructions during debugging.
In simple terms, GDB allows you to “see through” the internal world of a program, helping you understand its behavior and identify issues.
1.2 Debugging Process
When using GDB to debug a program, the following process is typically followed:
- Compile the program: Use the
<span>-g</span>
option to compile the program, generating a version that includes debugging information. This debugging information contains the mapping between source code and machine code, allowing GDB to correlate machine code addresses with source code line numbers.gcc -g my_program.c -o my_program
- Start GDB: Use the
<span>gdb <program_name></span>
command to start GDB.gdb my_program
- Set breakpoints: Set breakpoints at critical points in the program, causing it to pause when it reaches these points.
- Run the program: Use the
<span>run</span>
command to execute the program. - Check status: After the program pauses, use GDB commands to view variable values, stack information, etc.
- Step through execution: Use the
<span>next</span>
(next step) or<span>step</span>
(enter function) commands to step through the program. - Continue execution: Use the
<span>continue</span>
command to let the program continue running until the next breakpoint or the program ends. - Exit GDB: Use the
<span>quit</span>
command to exit GDB.
1.3 Common Commands
GDB provides a rich set of commands, here are some of the most commonly used:
<span>break <line_number/function_name></span>
(abbreviated as<span>b</span>
): Set a breakpoint.<span>break 10</span>
: Set a breakpoint at line 10.<span>break my_function</span>
: Set a breakpoint at the entry of the<span>my_function</span>
function.<span>break <file>:<line></span>
: Set a breakpoint at line<span><line></span>
in file<span><file></span>
.<span>run</span>
(abbreviated as<span>r</span>
): Run the program.<span>run <arguments></span>
: Run the program with arguments.<span>next</span>
(abbreviated as<span>n</span>
): Execute the next line of code (without entering functions).<span>step</span>
(abbreviated as<span>s</span>
): Execute the next line of code (entering functions).<span>continue</span>
(abbreviated as<span>c</span>
): Continue executing the program until the next breakpoint.<span>print <variable_name></span>
(abbreviated as<span>p</span>
): Print the value of a variable.<span>print my_variable</span>
: Print the value of<span>my_variable</span>
.<span>print *my_pointer</span>
: Print the value of the memory pointed to by<span>my_pointer</span>
.<span>backtrace</span>
(abbreviated as<span>bt</span>
): View the function call stack. It shows which functions called the current function and the parameters used during the calls.<span>info locals</span>
: View local variables in the current function.<span>list</span>
(abbreviated as<span>l</span>
): Display source code.<span>list <line_number></span>
: Display several lines of code centered around<span><line_number></span>
.<span>list <function_name></span>
: Display the code of the<span><function_name></span>
function.<span>quit</span>
(abbreviated as<span>q</span>
): Exit GDB.<span>help <command></span>
: View help information for a command.
2. Practice
Now, let’s master the use of GDB through some practical examples.
2.1 Debugging a Simple C Program with GDB
First, we create a simple C program <span>hello.c</span>
:
#include <stdio.h>
int main() {
int i;
for (i = 0; i < 5; i++) {
printf("Hello, world! %d\n", i);
}
return 0;
}
-
Compile the program:
gcc -g hello.c -o hello
-
Start GDB:
gdb hello
-
Set a breakpoint: Set a breakpoint at the
<span>printf</span>
function call.break 5
-
Run the program:
run
The program will pause at the breakpoint, and you will see output similar to the following:
Breakpoint 1, main () at hello.c:5 5 printf("Hello, world! %d\n", i);
-
View variable: Check the value of variable
<span>i</span>
.print i
Output:
$1 = 0
-
Step through execution: Execute the next line of code.
next
The program will execute the
<span>printf</span>
function and output “Hello, world! 0”. -
Continue execution: Let the program continue running until the next breakpoint.
continue
The program will continue looping and pause each time it reaches the
<span>printf</span>
function. -
Exit GDB:
quit
2.2 Connecting GDB to a PostgreSQL Process for Debugging
PostgreSQL is a multi-process database system. To debug PostgreSQL, you first need to find the PostgreSQL process ID (PID) and then connect GDB to that process.
-
Find the PostgreSQL process ID:
You can use the
<span>ps</span>
command or the<span>pg_ctl status</span>
command to find the PID of the PostgreSQL process. For example:ps aux | grep postgres
Find output similar to the following:
postgres 1234 0.0 0.1 ... /usr/lib/postgresql/14/bin/postgres ...
Where
<span>1234</span>
is the PostgreSQL process ID. -
Start GDB and connect to the PostgreSQL process:
gdb -p 1234
This will connect GDB to the PostgreSQL process with PID 1234.
-
Set a breakpoint:
You need to know the source code path of PostgreSQL to set breakpoints in GDB. Assume you have cloned the PostgreSQL source code to the
<span>/path/to/postgresql</span>
directory.break /path/to/postgresql/src/backend/executor/execMain.c:1000
This sets a breakpoint at line 1000 of the
<span>execMain.c</span>
file, where<span>execMain</span>
is the core function for query execution in PostgreSQL. -
Let PostgreSQL execute a query:
Now, let PostgreSQL execute a query, for example:
SELECT * FROM my_table;
When PostgreSQL reaches the breakpoint you set, GDB will pause the program.
-
Check status:
You can use GDB commands to view variable values, stack information, etc., for example:
print queryDesc->sourceText
This will print the currently executing SQL query.
2.3 Setting Breakpoints, Viewing Variables, and Analyzing Program Execution Flow
Through the above practice, you have learned how to connect GDB to a PostgreSQL process and set breakpoints. Now, let’s delve deeper into how to use GDB to analyze program execution flow.
-
Conditional breakpoints:
Sometimes, we only want to pause the program under specific conditions. Conditional breakpoints can achieve this. For example, we want to pause the program only when the value of variable
<span>i</span>
is 3:break 5 if i == 3
This sets a breakpoint at line 5, which will only pause the program when the value of
<span>i</span>
is 3. -
Watchpoints:
A watchpoint can pause the program when the value of a variable changes. For example, we want to pause the program when the value of variable
<span>i</span>
changes:watch i
When the value of
<span>i</span>
changes, the program will pause and inform you of the new and old values of<span>i</span>
. -
Stack tracing:
When an error occurs in the program, stack tracing can help us find where the error happened. Using the
<span>backtrace</span>
command allows you to view the function call stack. The stack information will tell you which functions called the current function and the parameters used during the calls. -
Analyzing execution flow:
By setting breakpoints, viewing variables, stepping through execution, and using stack tracing, we can gradually analyze the program’s execution flow, understand its behavior, and identify issues.
Conclusion
GDB is a very powerful debugging tool, and mastering its use is crucial for database kernel developers. Through this lesson, you should have grasped the basic concepts, common commands, and usage methods of GDB. In actual development, practice more and flexibly apply GDB, and you will surely become an excellent database kernel developer!
Remember, debugging is like a detective solving a case; it requires patience, attention to detail, and keen observation. I wish you all the best on your journey in database kernel development!
The above content is based on DeepSeek-R1 and Gemini 2.0 Flash generation, with slight manual adjustments. Thanks to Hangzhou DeepSeek Artificial Intelligence Basic Technology Research Co., Ltd. and Google.
Please verify the correctness of AI-generated content, and of course, it also adds some fun in troubleshooting.