1. GDB 调试概述及原理
GDB(GNU Debugger)是 GNU 项目开发的一款强大的调试工具,支持 C、C++、Fortran 等多种编程语言。它允许开发者控制程序的执行,查看变量的值,调试崩溃的程序,并提供多种用于定位和分析程序问题的功能。
GDB 的基本工作原理:
GDB 主要通过以下几种方式与程序交互:
- 断点:在指定位置暂停程序的执行,便于开发者检查程序的状态。
- 步进执行:逐步执行程序,检查代码的每一步执行情况。
- 堆栈跟踪:查看程序的调用栈信息,帮助定位函数调用链的问题。
- 动态库调试:调试时可以加载和调试共享库,查看程序依赖的动态库的状态。
GDB 由 GNU 项目开发,开源并可以从 GDB 官网 或 GitHub 下载源代码。
GDB 原版英文文档:
GDB 的官方文档提供了详细的指导,可以从 GDB Manual 查阅。
2. GDB 环境配置及核心转储文件调试
2.1 启用核心转储文件(Core Dump)
核心转储文件是程序崩溃时生成的文件,包含了程序运行的内存信息,能帮助开发者调试和定位崩溃原因。
-
查看核心文件大小限制:
ulimit -c
如果返回
0
,表示核心文件生成被禁用。 -
启用核心转储:
ulimit -c unlimited
-
配置核心文件存储路径及命名: 在
/etc/sysctl.conf
中配置core_pattern
,改变核心文件的存储路径和命名规则:kernel.core_pattern = /path/to/core/%e.%p.core
%e
表示程序名,%p
表示进程号,使用该配置会将核心文件存储到指定路径。
-
使配置生效:
sysctl -p
2.2 调试核心转储文件:
假设已启用核心转储,生成了核心文件 core
,可以通过以下命令进行调试:
gdb ./your_program core
-
查看堆栈信息:
(gdb) backtrace
-
查看变量信息:
(gdb) print x
2.3 核心转储文件调试快捷方式:
- 查看堆栈:直接使用
bt
命令查看堆栈:(gdb) bt
3. GDB 断点管理
3.1 设置断点:
-
在函数入口设置断点:
(gdb) break main
这将在
main
函数入口设置一个断点。 -
在指定代码行设置断点:
(gdb) break 20
在源代码第 20 行设置断点。
-
设置条件断点: 只有在满足特定条件时才触发断点:
(gdb) break 20 if x == 5
-
删除断点:
(gdb) delete 1
-
列出断点:
(gdb) info breakpoints
4. GDB 查看运行时信息
在调试过程中,查看程序的运行时信息至关重要。GDB 提供了多种命令来查看变量的值、内存内容、寄存器状态等信息。
4.1 查看变量:
-
查看变量值:
(gdb) print x
-
查看复杂表达式值:
(gdb) print x + y
-
查看数组内容:
(gdb) print array[0]@10
4.2 查看内存和寄存器:
-
查看内存内容:
(gdb) x/10x 0x7fffffff
该命令显示从地址
0x7fffffff
开始的 10 个内存单元,每个单元以十六进制格式显示。 -
查看寄存器值:
(gdb) info registers
4.3 堆栈信息:
- 查看调用堆栈:
(gdb) backtrace
5. GDB 调试控制流
控制流调试功能可以让开发者精确控制程序的执行,逐步分析程序的行为。
5.1 常见控制流命令:
-
继续执行程序:
(gdb) continue
-
单步执行(进入函数):
(gdb) step
-
单步执行(跳过函数):
(gdb) next
-
跳出当前函数:
(gdb) finish
-
跳转到指定代码位置:
(gdb) jump 50
-
设置函数返回值:
(gdb) return 42
6. GDB 多线程调试
在调试多线程程序时,GDB 提供了强大的多线程调试功能,允许开发者分别调试每个线程。
6.1 查看线程信息:
-
查看所有线程:
(gdb) info threads
-
切换到指定线程:
(gdb) thread 2
-
查看当前线程堆栈:
(gdb) backtrace
-
查看当前线程的局部变量:
(gdb) print x
7. GDB 调试共享库
在调试程序时,可能需要加载并调试动态链接库(共享库)。GDB 提供了命令来管理动态库。
7.1 设置共享库搜索路径:
如果程序依赖于某些共享库,GDB 允许开发者设置共享库的搜索路径。通过 set solib-search-path
命令指定共享库路径:
(gdb) set solib-search-path /path/to/your/libs
7.2 查看已加载的共享库:
使用 info sharedlibrary
命令查看当前程序加载的共享库:
(gdb) info sharedlibrary
7.3 加载自定义共享库:
如果需要调试自定义的共享库,可以使用 sharedlibrary
命令手动加载:
(gdb) sharedlibrary libmylibrary.so
8. GDB 调试 C、C++ 程序的 Makefile 和 CMake 配置
为了在 GDB 中进行调试,程序必须包含调试信息。我们可以通过修改编译选项来启用调试信息。
8.1 在 Makefile 中启用调试信息:
在 Makefile 中添加 -g
编译选项,编译器会生成调试信息:
CFLAGS += -g
8.2 在 CMake 中启用调试信息:
在 CMakeLists.txt
文件中设置调试模式:
set(CMAKE_BUILD_TYPE Debug)
这将生成包含调试信息的程序。
9. GDB 常用操作命令
GDB 提供了一些常见的操作命令,帮助开发者更高效地进行调试。
9.1 常用命令:
-
退出 GDB:
(gdb) exit
-
查看帮助:
(gdb) help
-
查看指定命令的帮助:
(gdb) help break
-
显示程序源代码:
(gdb) list 20
-
显示当前执行行:
(gdb) info line
-
打印表达式的值:
(gdb) print expression
-
修改变量的值:
(gdb) set var x = 10
10. GDB 调试示例
假设有以下简单的 C 代码:
#include <stdio.h>
int add(int a, int b) {
return a + b;
}
int main() {
int x = 5;
int y = 10;
int result = add(x, y);
printf("Result: %d\n", result);
return 0;
}
10.1 编译代码:
使用 -g
选项生成调试信息:
gcc -g -o test_program test_program.c
10.2 启动 GDB 调试:
启动 GDB,并设置断点:
gdb ./test_program
(gdb) break add
(gdb) run
10.3 调试过程:
-
程序在
add
函数处停下来。 -
使用
print
命令查看变量:(gdb) print a (gdb) print b
-
使用
continue
继续执行:(gdb) continue