
On the long road of software development, bugs are like “little monsters” hiding in the dark, occasionally jumping out to cause trouble for developers. Once, the European Space Agency (ESA) launched the Ariane 5 rocket for the first time, which was an important moment in the history of space exploration, but a single line of code led to a catastrophic failure, resulting in the rocket, worth nearly 500 million euros, exploding 37 seconds after launch. Upon investigation, it was found that there was a software defect in the guidance system, where a 64-bit floating-point variable was converted to a 16-bit signed integer from dead code originating from Ariane 4, causing an integer overflow that ultimately led to the rocket’s self-destruction. This story tells us that a seemingly insignificant bug can lead to immeasurable consequences.
When we encounter issues such as program crashes or abnormal results during development, do we often feel at a loss? Don’t worry, today I will introduce the GDB debugging tool, which is a powerful weapon for us to defeat these “little monsters”. It helps us delve into the program’s internals, uncover hidden bugs, and make the program obedient.
1. What is GDB?
1.1 Overview of GDB
GDB, short for GNU Debugger, is a powerful program debugging tool released by the GNU open-source organization. Since it was written by Richard Stallman in 1986, it has continuously evolved and improved, becoming the preferred tool for debugging programs on Linux systems, holding a significant position in the entire Linux ecosystem. It acts like an experienced detective, diving into the “crime scene” of the program to help developers find the hidden “criminals”—the bugs.
GDB supports multiple programming languages, including but not limited to C, C++, Fortran, Ada, Objective-C, Go, and D, and can seamlessly integrate with a series of mainstream compilers such as GCC, Clang, and LLVM. This means that no matter which programming language you use for development, GDB can provide efficient debugging support, whether in desktop applications, server-side services, or embedded system development, offering developers an unparalleled debugging experience with its powerful features and flexible interaction methods.
- GDB official website: https://www.gnu.org/software/gdb/
- Supported programming languages: Ada / C / C++ / Objective-C / Pascal, etc.
- GDB operation modes: local debugging and remote debugging.
The latest released version is 8.0, and GDB can run on Linux and Windows operating systems.
1.2 Advantages of GDB
Rich functionality: GDB provides comprehensive debugging features, such as setting breakpoints (including regular breakpoints and conditional breakpoints), single-step execution (step and next), viewing variable values (print), observing memory (x command), and backtracing function call stacks (backtrace). These features help developers analyze the program’s runtime state in depth and quickly locate issues. For example, when debugging a complex C++ program, we can set conditional breakpoints to pause the program when a specific variable meets certain conditions, allowing us to precisely capture the moment the issue occurs; using backtrace, we can clearly understand the order of function calls and the context between each layer of calls, quickly pinpointing where the problem occurs in the function call chain.
Cross-platform support: It supports a wide range of operating systems and platforms, including Linux, Windows (via MinGW or Cygwin), macOS, and various embedded platforms (such as ARM, RISC-V, etc.). Whether you are developing desktop applications, mobile applications, or embedded systems, GDB can play a role. In remote debugging, GDB is very flexible and can connect with systems of different architectures, suitable for cross-platform and multi-architecture debugging. For example, when developing software that runs on both Linux and Windows systems, using GDB allows for unified debugging operations across different systems, improving development efficiency.
Powerful extensibility: GDB supports a plugin mechanism, allowing users to enhance its functionality by installing third-party plugins for memory analysis, performance profiling, remote debugging, etc. Users can also extend GDB’s capabilities through Python scripts for customized debugging operations. This is particularly useful in scenarios where complex calculations or automated analysis are needed during debugging. For instance, when debugging a large-scale data processing program, one can write Python scripts to automate the analysis of the vast amounts of data generated during program execution, quickly identifying potential issues.
Open-source and free: As an open-source software, GDB has a large community support, allowing developers to freely access, use, and modify its source code. This not only reduces development costs but also enables GDB to continuously absorb the wisdom and strength of the community, evolving and improving over time. Additionally, the rich community resources, such as documentation, tutorials, and forums, provide convenience for developers learning and using GDB.
Compared to some debugging tools built into integrated development environments (IDEs), GDB, while lacking a flashy graphical interface, is more lightweight, flexible, and independent, not relying on any complex graphical interfaces or large libraries, making it very suitable for use in resource-constrained environments, such as embedded development. In server or remote development environments, GDB does not require a graphical interface and can directly connect to the target machine via SSH for debugging. Moreover, GDB can provide lower-level control and debugging capabilities than most IDEs, such as directly manipulating memory, registers, and even modifying the program’s execution flow, which is crucial for some advanced debugging needs.
2. Basic Operations of GDB
2.1 Installing and Starting GDB
(1) Installing GDB
- gdb -v to check if the installation was successful; if not, install it (make sure the compiler is already installed, such as gcc).
- Start gdb
- gdb test_file.exe to start gdb debugging, directly specifying the executable file name to debug
- Alternatively, enter gdb to start, and after entering gdb, use the command file test_file.exe to specify the file name
- If the target executable file requires input parameters (such as argv[] receiving parameters), parameters can be specified in three ways:
- When starting gdb, use gdb –args text_file.exe
- After entering gdb, run set args param_1
- After entering gdb debugging, run param_1 or start param_1
(2) Starting GDB
Before using GDB to debug a program, we need to compile the program and generate an executable file that contains debugging information. For example, with a C language program, when using the GCC compiler, we can achieve this by adding the -g parameter to the compile command, such as:
gcc -g -o my_program my_program.c
The generated my_program executable file will contain the symbol information required for debugging, which acts like “map markers” in the program, helping GDB accurately locate key positions in the code, such as variables, functions, and line numbers during debugging.
There are several common methods to start GDB:
①Debugging a new program: The most direct way is to enter gdb followed by the executable file name in the terminal, for example:
gdb my_program
This method is suitable when we need to start debugging from the initial state of the program; GDB will load the program’s debugging information and be ready to accept debugging commands.
②Attaching to a running process: When the program is already running and we want to debug this running instance, we can use the attach command. First, obtain the process ID (PID) of the program using the command ps -ef | grep my_program, then use the following command to attach GDB to that process:
gdb
(gdb) attach <PID>
This method is very useful when the program encounters runtime errors and we need to debug without restarting the program; it allows us to directly view the current running state of the program and analyze the cause of the issue.
③Debugging with core files: If the program crashes during execution and generates a core file (the system may not generate core files by default; it needs to be set to allow core file generation using the command ulimit -c unlimited), we can use GDB to load the core file for debugging. The command is as follows:
gdb my_program core
A core file acts like a “snapshot” of the program at the time of the crash, recording the memory state, register values, and other key information at the time of the crash. By analyzing the core file, we can find the cause of the crash, such as null pointer references or array out-of-bounds issues.
2.2 Using GDB
Running the program
run (r) to run the program; if parameters are needed, use run arg1 arg2 ...
Viewing source code
list (l): view the last ten lines of source code
list fun: view the source code of the fun function
list file:fun: view the source code of the fun function in the file
Setting breakpoints and watchpoints
break line_number/fun to set a breakpoint.
break file:line_number/fun to set a breakpoint.
break if <condition>: pause the program when the condition is met.
info break (abbreviated: i b): view breakpoints.
watch expr: pause the program when the value of expr changes.
delete n: delete the breakpoint.
Single-step debugging
continue (c): run to the next breakpoint.
step (s): single-step into the function, similar to step in in VC.
next (n): single-step without entering the function, similar to step out in VC.
finish: run the program until the current function returns, printing the stack address and return value and parameter values at the time of return.
until: when tired of single-stepping within a loop, this command runs the program until exiting the loop.
Viewing runtime data
print (p): view runtime variables and expressions.
type: view types.
print array: print all elements of the array.
print *array@len: view dynamic memory. len is the number of elements in the array.
print x=5: change runtime data.
2.3 Common Command Details
⑴ Setting breakpoints (break): Breakpoints are one of the most commonly used tools in debugging; they act like “roadblocks” set along the execution path of the program. When the program execution reaches a breakpoint, it will pause, allowing us to check the program’s state. The basic command to set a breakpoint is break, which can be abbreviated as b. For example, to set a breakpoint at the entry of the main function, we can use the following command:
(gdb) b main
We can also set a breakpoint at a specific line number; assuming our code file is my_program.c, to set a breakpoint at line 20, we can do the following:
(gdb) b my_program.c:20
Additionally, we can set conditional breakpoints that only activate when certain conditions are met. For example, to pause the program when the value of variable i equals 10:
(gdb) b my_program.c:30 if i == 10
⑵ Running the program (run): After setting breakpoints, use the run command (abbreviated as r) to start the program. If the program requires command line parameters, they can be added directly after the run command, for example:
(gdb) run arg1 arg2
The run command will cause the program to execute from the starting position until it encounters the first breakpoint or the program ends.
⑶Continuing execution (continue): When the program is paused at a breakpoint, if we want the program to continue executing until the next breakpoint or the program ends, we can use the continue command, abbreviated as c:
(gdb) c
This command is very useful; after we check the program state at the current breakpoint, we can continue the program’s execution to observe subsequent runtime conditions.
⑷Single-step execution (next, step):
next: The next command (abbreviated as n) is used for single-step execution, executing one line of code at a time, but when encountering a function call, it does not enter the function but treats the function call as a single line of code and executes past it. For example:
(gdb) n
Assuming we have a function call result = add_numbers(a, b), using the next command will execute this function call directly and stop at the next line of code without entering the add_numbers function to see its execution process.
step: The step command (abbreviated as s) also performs single-step execution, but when encountering a function call, it enters the function, pausing at the first line of code within the function. For example:
(gdb) s
Using the step command when encountering the add_numbers function call will enter the add_numbers function, allowing us to view the internal execution logic of the function, check the variable changes and calculation results at each step, which is very effective for debugging issues within the function.
⑸ Printing variable values (print): During debugging, we often need to view the values of variables, which can be done using the print command (abbreviated as p). For example, to view the value of variable i, we can use the following command:
(gdb) p i
If the variable is a complex data structure, such as a struct or object, the print command can also display all its member information. Additionally, expressions can be evaluated, for example:
(gdb) p a + b
This command will calculate the value of a + b and display it.
⑹Viewing breakpoint information (info break): Using the info break command (abbreviated as i b) allows us to view information about all currently set breakpoints, including the breakpoint number, location, condition, etc. For example:
(gdb) i b
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000004005c8 in main at my_program.c:10
breakpoint already hit 1 time
2 breakpoint keep y 0x00000000004005e0 in main at my_program.c:20 if i == 10
Through this information, we can clearly understand the status of the breakpoints, facilitating breakpoint management, such as deleting or disabling certain breakpoints.
2.4 Program Errors
- Compilation errors: Errors that occur when writing the program do not conform to language specifications, such as syntax errors.
- Runtime errors: These errors cannot be detected by the compiler but may cause the program to crash during execution, such as illegal memory address access.
- Logical errors: The program compiles and runs smoothly, but does not perform the expected tasks.
2.5 Debugging Segmentation Faults with GDB
What is a segmentation fault? A segmentation fault is an error caused by accessing an illegal address.
- Accessing system data areas, especially writing data to protected memory addresses. For example: accessing address 0.
- Memory out-of-bounds (array out-of-bounds, inconsistent variable types, etc.) accessing memory areas not belonging to the current program.
To debug segmentation faults with GDB, you can run the program directly; when the program crashes, GDB will print the runtime information, such as: received SIGSEGV signal, then you can use the <span>bt</span> command to print the stack trace information, and then modify the program based on the code where the error occurred.
2.6 Debugging Core Files
(1) Core Files
When a program crashes, a file called <span>core</span> is generally generated. The core file records the memory image of the program at the time of the crash and includes debugging information; the process of generating the core file is called <span>core dump</span>. The system does not generate this file by default.
(2) Setting Up Core File Generation
- ulimit -c: check the core dump status.
- ulimit -c xxxx: set the size of the core file.
- ulimit -c unlimited: set the core file size to unlimited.
(3) Debugging Core Files with GDB
After setting <span>ulimit -c xxxx</span>, if the program encounters a segmentation fault again, a <span>core</span> file will be generated. Use <span>gdb core</span> to debug the core file, and use the <span>bt</span> command to print the stack trace information.
3. Using GDB for Program Debugging
Generally speaking, GDB mainly helps you accomplish the following four functions:
1. Start your program and run it according to your custom requirements.2. Allow the program being debugged to stop at the breakpoints you specify (breakpoints can be conditional expressions).3. When the program is paused, you can check what is happening in your program at that moment.4. Dynamically change the execution environment of your program.
From the above, GDB does not differ much from general debugging tools; it essentially accomplishes these functions. However, in the details, you will find the power of GDB as a debugging tool. While many may be accustomed to graphical debugging tools, sometimes command-line debugging tools offer functionalities that graphical tools cannot achieve. Let’s take a look at an example of debugging:
Source program: tst.c
1 #include <stdio.h>
2
3 int func(int n)
4 {
5 int sum=0,i;
6 for(i=0; i<n; i++)
7 {
8 sum+=i;
9 }
10 return sum;
11 }
12
13
14 main()
15 {
16 int i;
17 long result = 0;
18 for(i=1; i<=100; i++)
19 {
20 result += i;
21 }
22
23 printf("result[1-100] = %d /n", result );
24 printf("result[1-250] = %d /n", func(250) );
25 }
Compile to generate the executable file: (on Linux)
hchen/test> cc -g tst.c -o tst
Using GDB for debugging:
hchen/test> gdb tst <---------- Start GDB
GNU gdb 5.1.1
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-SUSE-linux"...
(gdb) l <-------------------- l command is equivalent to list, listing the source code from the first line.
1 #include <stdio.h>
2
3 int func(int n)
4 {
5 int sum=0,i;
6 for(i=0; i<n; i++)
7 {
8 sum+=i;
9 }
10 return sum;
11 }
12
13
14 main()
15 {
16 int i;
17 long result = 0;
18 for(i=1; i<=100; i++)
19 {
20 result += i;
(gdb) <-------------------- Pressing Enter repeats the last command
21 }
(gdb) break 16 <-------------------- Set a breakpoint at line 16 of the source program.
Breakpoint 1 at 0x8048496: file tst.c, line 16.
(gdb) break func <-------------------- Set a breakpoint at the entry of the func() function.
Breakpoint 2 at 0x8048456: file tst.c, line 5.
(gdb) info break <-------------------- View breakpoint information.
Num Type Disp Enb Address What
1 breakpoint keep y 0x08048496 in main at tst.c:16
2 breakpoint keep y 0x08048456 in func at tst.c:5
(gdb) r <--------------------- Run the program, run command abbreviated
Starting program: /home/hchen/test/tst
Breakpoint 1, main () at tst.c:17 <---------- Paused at the breakpoint.
17 long result = 0;
(gdb) n <--------------------- Execute one statement, next command abbreviated.
18 for(i=1; i<=100; i++)
(gdb) n
20 result += i;
(gdb) n
18 for(i=1; i<=100; i++)
(gdb) n
20 result += i;
(gdb) c <--------------------- Continue running the program, continue command abbreviated.
Continuing.
result[1-100] = 5050 <---------- Program output.
Breakpoint 2, func (n=250) at tst.c:5
5 int sum=0,i;
(gdb) n
6 for(i=1; i<=n; i++)
(gdb) p i <--------------------- Print the value of variable i, print command abbreviated.
$1 = 134513808
(gdb) n
8 sum+=i;
(gdb) n
6 for(i=1; i<=n; i++)
(gdb) p sum
$2 = 1
(gdb) n
8 sum+=i;
(gdb) p i
$3 = 2
(gdb) n
6 for(i=1; i<=n; i++)
(gdb) p sum
$4 = 3
(gdb) bt <--------------------- View the function stack.
#0 func (n=250) at tst.c:5
#1 0x080484e4 in main () at tst.c:24
#2 0x400409ed in __libc_start_main () from /lib/libc.so.6
(gdb) finish <--------------------- Exit the function.
Run till exit from #0 func (n=250) at tst.c:5
0x080484e4 in main () at tst.c:24
24 printf("result[1-250] = %d /n", func(250) );
Value returned is $6 = 31375
(gdb) c <--------------------- Continue running.
Continuing.
result[1-250] = 31375 <---------- Program output.
Program exited with code 027. <-------- Program exited, debugging ended.
(gdb) q <--------------------- Exit gdb.
hchen/test>
Now that we have this intuitive understanding, let’s systematically learn about GDB.
Basic GDB commands:
Common GDB Commands Format Meaning Abbreviation
list List [start, end] List the code in the file l
print Print variable name Print variable content p
break Break [line number or function name] Set a breakpoint b
continue Continue [start, end] Continue running c
info Info variable name List information i
next Next Next line n
step Step Enter function (step in) S
display Display variable name Display parameters
file File filename (can be absolute or relative path) Load file
run Run args Run program r
4. Advanced Features of GDB
4.1 Backtrace
During program debugging, understanding the order of function calls and the context between each layer of calls is crucial. Sometimes, when a program encounters an error, we may not know which function call chain the error originated from; this is where the backtrace feature comes in handy. GDB provides the backtrace command, abbreviated as bt, to display the current call stack information.
When the program runs into an exception or pauses at a breakpoint, entering the bt command will list each stack frame from shallow to deep, with each stack frame containing the function name, source file name, line number, and parameter values. For example, if we have a program with multiple function calls:
#include <stdio.h>
void function_c(int num) {
int result = num * 2;
printf("Function C: result = %d\n", result);
}
void function_b(int num) {
function_c(num + 1);
}
void function_a() {
int num = 5;
function_b(num);
}
int main() {
function_a();
return 0;
}
When debugging this program in GDB, if the program pauses inside the function_c function, entering the bt command may yield the following output:
(gdb) bt
#0 function_c (num=6) at test.c:5
#1 0x000000000040056d in function_b (num=5) at test.c:9
#2 0x0000000000400588 in function_a () at test.c:13
#3 0x00000000004005a4 in main () at test.c:17
From the output, we can clearly see the order of function calls: main calls function_a, function_a calls function_b, and function_b calls function_c, and we can also see the parameter values at each function call. This is very helpful for quickly locating where the problem occurred; for example, if a division by zero error occurs in function_c, we can use the backtrace information to trace back how the parameter passed to function_c was calculated, thus finding the root of the problem.
4.2 Dynamic Memory Detection
Memory leaks, illegal accesses, and other memory issues are hidden killers of program robustness; they can lead to performance degradation or even crashes after the program runs for a while. While there are specialized memory analysis tools like Valgrind, GDB itself also has certain memory detection capabilities, especially when combined with the heap plugin, which can perform preliminary checks on the program’s heap memory usage.
First, we need to obtain and load the heap plugin, assuming the plugin file is gdbheap.py, use the following command to load the plugin:
(gdb) source /path/to/gdbheap.py
Then, we can attach GDB to the running process (assuming the process ID is <pid>) and use the commands provided by the plugin to view the heap memory allocation status:
(gdb) attach <pid>
(gdb) monitor heap
After executing the above commands, GDB will display relevant information about the heap memory, such as the number of memory blocks, sizes, allocation status, etc. By observing this information, we can identify potential memory issues. For example, if we find that a large number of small memory blocks are allocated and not released for a long time, there may be a risk of memory leaks; if we see abnormal allocation and release order of memory blocks, there may be illegal memory access issues.
Here is a simple example demonstrating how to use GDB and the heap plugin to detect memory issues:
#include <stdio.h>
#include <stdlib.h>
int main() {
int *ptr1 = (int *)malloc(10 * sizeof(int));
int *ptr2 = (int *)malloc(20 * sizeof(int));
free(ptr1);
// Intentionally not freeing ptr2 to create a memory leak
return 0;
}
After running the program, using GDB and the heap plugin for detection, by analyzing the heap memory information output by the plugin, we may discover that the memory pointed to by ptr2 has not been released, thus locating the memory leak issue.
4.3 Conditional Breakpoints and Watchpoints
Conditional Breakpoints: In some complex programs, we may not want the program to pause at every breakpoint but rather only when specific conditions are met; this is where conditional breakpoints come into play. For example, in a program processing an array, we suspect that an array out-of-bounds issue occurs when the array index i exceeds the array size; we can set a conditional breakpoint as follows:
(gdb) break array_processing_function if i >= array_size
In this way, the program will only pause at array_processing_function when i is greater than or equal to array_size, greatly improving debugging efficiency and avoiding frequent pauses at irrelevant breakpoints, allowing us to capture the moment the issue occurs more precisely.
Watchpoints: Watchpoints are used to monitor changes in variable values. When the observed variable is modified, GDB will automatically pause the program, which is particularly useful for tracking elusive issues that are difficult to reproduce. For example, in a multithreaded program, if a global variable’s value is unexpectedly modified, but we are unsure which thread modified it and under what circumstances, we can set a watchpoint for this global variable:
(gdb) watch global_variable
When the value of global_variable changes, the program will immediately pause, allowing us to check the current thread status, call stack, and other information to determine how the variable was modified, thus finding the root of the problem. Additionally, read watchpoints (rwatch) and read/write watchpoints (awatch) can also be set; rwatch pauses the program when the variable is read, and awatch pauses the program when the variable is read or modified, allowing us to choose the appropriate type of watchpoint based on specific debugging needs.
4.4 Remote Debugging
In actual development, we often encounter situations where we need to debug programs deployed on remote servers or embedded devices. GDB supports remote debugging over the network, greatly simplifying the complexity of cross-device debugging.
The basic principle of remote debugging is to run the GDB server (gdbserver) on the remote device and connect the local GDB client to the server. The specific operation steps are as follows:
⑴ On the remote device: First, ensure that gdbserver is installed on the remote device; you can check if it is installed by using the gdbserver –version command. Then start gdbserver, specifying the program to debug and the listening port, for example:
gdbserver :<port> /path/to/remote_program
Where <port> is an unused port number that can be specified arbitrarily based on the actual situation, and /path/to/remote_program is the path of the program to be debugged. After successful startup, gdbserver will listen on the specified port, waiting for the local GDB client to connect.
⑵On the local GDB client: Start GDB locally and load a local copy of the executable file that matches the remote program (make sure it was compiled with debugging information), then use the target remote command to connect to the remote gdbserver:
gdb ./local_program
(gdb) target remote <remote_host>:<port>
<remote_host> is the IP address or hostname of the remote device, and <port> is the port number specified when starting gdbserver on the remote device. After a successful connection, you can use various debugging commands in the local GDB client as if you were debugging a local program, such as setting breakpoints, single-stepping, viewing variable values, etc. GDB will communicate with the remote gdbserver over the network to achieve remote program debugging.
For example, when developing an embedded system program, we can run gdbserver on the development board (remote device) and use the GDB client on the local PC for debugging. This way, we can conveniently debug programs running on remote embedded devices in the local environment, improving development efficiency.
5. Practical Tips
5.1 Using TUI Mode to Enhance Efficiency
GDB’s TUI (Terminal User Interface) mode provides a compromise between text-based interaction and graphical user interaction, significantly enhancing efficiency during debugging. In TUI mode, GDB divides the terminal screen into a source text window and a console window, allowing us to intuitively see the execution status of the code.
Starting TUI mode is very simple; just add the -tui parameter when starting GDB. For example:
gdb -tui my_program
If you are already in normal GDB mode, you can switch to TUI mode using the shortcut Ctrl + X + A; pressing this shortcut again will return to normal mode.
Once in TUI mode, we can use a series of shortcuts and commands to perform debugging operations. For example, when using the n (next) command to single-step through the code, the source text window will highlight the currently executing line in real-time, while the console window will output the execution results; when setting breakpoints, a special marker will appear next to the line number where the breakpoint is set, making it easier to identify and manage breakpoints.
When debugging a complex C++ project, I needed to switch back and forth between multiple functions to view the code execution logic. TUI mode allowed me to clearly see the contextual relationships of the code directly in the source text window, and combined with single-step execution and breakpoint settings, I quickly located the logical error in the program. Moreover, when the program is paused, pressing the Ctrl + X + S shortcut allows me to directly use GDB commands without having to confirm each time by pressing Enter, further improving debugging efficiency.
5.2 Custom Commands and Script Automation
In daily debugging work, we often repeat the same sequence of commands, such as setting the same breakpoints or viewing specific variable values each time we debug. To improve debugging efficiency, GDB allows us to define these common commands as custom commands or scripts.
The format for defining custom commands is as follows:
define command_name
statement1
statement2
...
end
Where command_name is the name of the custom command, and statement is the specific GDB command. For example, we can define a custom command named my_debug to set multiple breakpoints and start the program:
define my_debug
b main
b function_a
b function_b
r
end
After defining the custom command, simply enter the command name in GDB to execute these commands.
For more complex operations, we can write GDB scripts. A GDB script is a text file containing a series of GDB commands, with the extension .gdb. For example, we create a script file named debug_script.gdb with the following content:
b main
b function_c if i > 10
r
In GDB, use the source command to load the script:
(gdb) source debug_script.gdb
This way, the commands in the script will be executed sequentially. GDB also provides rich flow control commands, such as if…else…end, while…end, etc. By combining these commands, we can write powerful automated debugging scripts to implement complex debugging logic. When debugging a large database application, I wrote a script that loops through the connection objects in the database connection pool, checking the status and properties of each connection, quickly identifying connection leaks and configuration errors, greatly saving debugging time.
5.3 Using with IDEs
Although GDB itself is a powerful command-line debugging tool, it can also be used in conjunction with some integrated development environments (IDEs) to fully leverage the advantages of both. For example, Eclipse CDT provides an intuitive graphical interface, making it easy for us to perform code editing, project management, and debugging operations while integrating GDB’s powerful debugging capabilities.
To use GDB for debugging in Eclipse CDT, first create a C/C++ project and ensure that the project’s compilation settings include debugging information (usually in the project properties under C/C++ Build – Settings, select Debug configuration and check the Generate debug info option). Then, set breakpoints in the project’s source code and click the debug button on the Eclipse toolbar; Eclipse will automatically start GDB and associate it with the project.
During debugging, we can view variable values, call stack information, perform single-step execution, continue execution, and other operations in Eclipse’s debugging view, all of which are completed through Eclipse’s graphical interface, but at the underlying level, they are executed by GDB. This approach retains GDB’s powerful functionality while providing a more convenient and intuitive debugging experience, especially friendly for novice developers, allowing them to quickly get started with debugging work.