4.6.3. 使用 GDB 调试应用
4.6.3.1. GDB 概述
GDB(GNU Debugger)是
GDB 主要
1986年:GDB 的
第一个 版本 发布。它 是 由 Stallman 在 其 工作 的 早期 阶段 开发 的,主要 是 为了 调试 GNU 项目 的 软件,尤其 是 GCC(GNU 编译器)编译 的 程序。 1990年代:随着
开源 软件 和 GNU 项目 的 发展,GDB 被 广泛应用 到 各种 开发 项目 中。它 支持 多种 编程语言(如 C、C++、Fortran 等),并 逐步 支持 更 多 的 操作系统 和 平台。 2000年代:GDB 增加
了 更 多功能,如 多线程 调试、远程 调试、与 硬件 相关 的 调试(例如 使用 JTAG 接口)等。 2010年代
至今:GDB 继续 得到 活跃 维护,增加 了 对 现代 硬件 架构 的 支持(如 ARM、RISC-V 等),并 进一步 扩展 了 远程 调试 和 嵌入式 系统 调试 的 功能。GDB 的 功能 仍 在 不断 扩展,逐步 成为 世界 上 最 强大 的 调试 工具 之一。
4.6.3.2. GDB 的主要功能
GDB 的
程序执行
控制 可以
启动 程序 并 控制 其 执行(单步 执行、跳过、暂停 等)。 支持
在 程序 的 不同 位置(例如:行号 或 函数)设置 断点。
变量
检查 可以
在 程序运行 时 检查和 修改 变量 的 值,帮助 开发者 追踪 程序 状态。
堆栈
跟踪 当
程序 崩溃 或 发生 异常 时,GDB 可以 显示 程序 的 调用 堆栈(backtrace),帮助 开发者 定位问题 源。
动态
调试 支持
动态 加载 库 和 函数,可以 在 程序运行 时 对 其 进行 调试。
源代码
级 调试 可以
通过 源代码(如 C 或 C++ 的 源代码)进行 调试,显示 变量、函数调用 和 执行 位置。
多
平台 支持 支持
多种 架构(如 x86、ARM 等),以及 跨平台 调试。
4.6.3.3. 常用的 GDB 调试命令
常用
| 命令 | 说明 |
|---|---|
l (list) |
显示 |
r (run) |
运行 |
b (breakpoint) <行号> |
在 |
b <源文件>:<函数名> |
在 |
b <源文件>:<行号> |
在 |
info b |
查看 |
d (delete) <断点编号> |
删除 |
d breakpoints |
删除 |
disable b (breakpoints) |
禁用 |
enable b (breakpoints) |
启用 |
disable b (breakpoint) <编号> |
禁用 |
enable b (breakpoint) <编号> |
启用 |
enable breakpoint |
启用 |
n (next) |
逐 |
s (step) |
逐 |
bt (backtrace) |
显示 |
set var |
修改 |
p (print) <变量名> |
打印 |
display <变量名> |
跟踪 |
undisplay <变量名> |
取消 |
until <行号> |
跳转 |
finish |
执行 |
c (continue) |
从 |
注: 括号
GDB 详细
4.6.3.4. GDB 调试的具体方法介绍
编写测试程序
在 PC 端-g 选项
示例 demo.c:
#include <stdio.h>
int main()
{
int a = 0;
char i = 0;
for(i =0; i <10; i++)
{
a = i + 1;
int b = 10/a;
printf("b = %d\n",b);
}
return 0;
}
编译
注意,编译opt/arm-gnu-toolchain-11.3.rel1-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-gcc,为了.bashrc 中
alias arm_gcc='/opt/arm-gnu-toolchain-11.3.rel1-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-gcc'
alias arm_gdb='/opt/arm-gnu-toolchain-11.3.rel1-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-gdb'
具体
$ arm_gcc -g demo.c -o gdb_demo
$ ls
demo.c gdb_demo
$ file gdb_demo
gdb_demo: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1,
for GNU/Linux 3.7.0, with debug_info, not stripped
最终gdb_demo。
GDB 调试过程
将 gdb_demo 、demo.c 传到/userdata 目录),然后
root@buildroot:/userdata# chmod +x gdb_demo
root@buildroot:/userdata# gdb gdb_demo
GNU gdb (GDB) 13.2
Copyright (C) 2023 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "aarch64-buildroot-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from gdb_demo...
# 从 line 1 开始显示 demo.c 的 10 行代码
(gdb) l 1
warning: Source file is more recent than executable.
1 #include <stdio.h>
2
3 int main()
4 {
5 int a = 0;
6 char i = 0;
7 for(i =0; i <10; i++)
8 {
9 a = i + 1;
10 int b = 10/a;
# 运行代码直到遇到断点
(gdb) r
Starting program: /userdata/gdb_demo
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/libthread_db.so.1".
b = 10
b = 5
b = 3
b = 2
b = 2
b = 1
b = 1
b = 1
b = 1
b = 1
[Inferior 1 (process 2581) exited normally]
# 在 demo.c 的第 10 行设置断点
(gdb) b 10
Breakpoint 1 at 0x4005e8: file demo.c, line 10.
# 查看当前设置的断点
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000004005e8 in main at demo.c:10
(gdb) r
Starting program: /userdata/gdb_demo
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/libthread_db.so.1".
Breakpoint 1, main () at demo.c:10
10 int b = 10/a;
# 监控变量 'b' 的变化
(gdb) display b
1: b = 65535
# 继续运行
(gdb) c
Continuing.
b = 10
Breakpoint 1, main () at demo.c:10
10 int b = 10/a;
1: b = 10
(gdb) c
Continuing.
b = 5
Breakpoint 1, main () at demo.c:10
10 int b = 10/a;
1: b = 5
(gdb) c
Continuing.
b = 3
Breakpoint 1, main () at demo.c:10
10 int b = 10/a;
1: b = 3
# 退出 gdb 调试
(gdb) q
gdb 分析 Core Dump 文件
通过 gdb,我们
编写
#include <stdio.h>
int main() {
printf("Program will now crash due to null pointer dereferencing.\n");
// 创建一个空指针
int *ptr = NULL;
// 尝试解引用空指针
*ptr = 10; // 空指针解引用会导致崩溃
return 0;
}
编译:
arm_gcc -g crash_example.c -o crash_example
其中 arm_gcc 是.bashrc 中
# ~/.bashrc
alias arm_gcc='/opt/arm-gnu-toolchain-11.3.rel1-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-gcc'
将
1) 执行
root@buildroot:/userdata# ./crash_example
Program will now crash due to null pointer dereferencing.
Segmentation fault (core dumped)
2)取出
X5设备/userdata/log/coredump 目录/userdata 目录
root@buildroot:/userdata/log/coredump# ls
core-crash_example-2685-36246
root@buildroot:/userdata/log/coredump# cp core-crash_example-2685-36246 ../../
3)运行 gdb 分析 Core dump 文件
# 开始 gdb 分析
root@buildroot:/userdata# gdb crash_example core-crash_example-2685-36246
GNU gdb (GDB) 13.2
Copyright (C) 2023 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "aarch64-buildroot-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from crash_example...
[New LWP 2685]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/libthread_db.so.1".
Core was generated by `./crash_example'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x00000000004005e4 in main () at crash_example.c:11
11 *ptr = 10; // 空指针解引用会导致崩溃
# 显示报错行附件的代码
(gdb) l 10
5 printf("Program will now crash due to null pointer dereferencing.\n");
6
7 // 创建一个空指针
8 int *ptr = NULL;
9
10 // 尝试解引用空指针
11 *ptr = 10; // 空指针解引用会导致崩溃
12
13 return 0;
14 }
# 显示当前调用堆栈
(gdb) bt
#0 0x00000000004005e4 in main () at crash_example.c:11
# 显示当前所有变量值
(gdb) info locals
ptr = 0x0
4.6.3.5. 常见问题
GDB 调试
| 问题 | 描述 | 可能 |
解决方案 |
|---|---|---|---|
| 无法 |
启动 GDB 时,出现 |
GDB 与 |
确保 GDB 与sudo 权限-g 生成 |
| 调试 |
GDB 提示 |
编译 |
确保-g 选项-O0)编译 |
| GDB 无法 |
调试器 |
GDB 找 |
手动set solib-search-path 指定 |
| 调试 |
在 |
GDB 与 |
使用 info threads 查看thread <id> 切换 |
| 断点 |
设置 |
断点 |
使用 info breakpoints 查看 |
| 在 |
使用 GDB 调试 |
内核 |
在 |
| GDB 与 |
在 |
GDB 使用 |
确保 GDB 使用 |
| 远程 |
使用 GDB 进行 |
网络 |
检查 |
| 内存 |
调试 |
代码 |
使用 valgrind 检查 |
4.6.3.6. 参考文献
GDB: The GNU Project Debugger
gdb Debugging Full Example (Tutorial): ncurses