惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
博客园 - 【当耐特】
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - Franky
罗磊的独立博客
T
Tenable Blog
N
News and Events Feed by Topic
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Security Archives - TechRepublic
Security Archives - TechRepublic
博客园 - 司徒正美
L
LINUX DO - 最新话题
AI
AI
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
S
Secure Thoughts
IT之家
IT之家
aimingoo的专栏
aimingoo的专栏
Last Week in AI
Last Week in AI
W
WeLiveSecurity
博客园_首页
Forbes - Security
Forbes - Security
博客园 - 聂微东
宝玉的分享
宝玉的分享
Google DeepMind News
Google DeepMind News
V
Visual Studio Blog
Microsoft Security Blog
Microsoft Security Blog
Vercel News
Vercel News
小众软件
小众软件
Webroot Blog
Webroot Blog
V2EX - 技术
V2EX - 技术
博客园 - 叶小钗
T
The Exploit Database - CXSecurity.com
TaoSecurity Blog
TaoSecurity Blog
L
Lohrmann on Cybersecurity
I
InfoQ
J
Java Code Geeks
P
Privacy International News Feed
Spread Privacy
Spread Privacy
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
B
Blog RSS Feed
阮一峰的网络日志
阮一峰的网络日志
D
Docker
P
Proofpoint News Feed
B
Blog
Cisco Talos Blog
Cisco Talos Blog
M
MIT News - Artificial intelligence
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
T
Threat Research - Cisco Blogs
云风的 BLOG
云风的 BLOG
Recent Announcements
Recent Announcements

博客园 - PKICA

rust线程-std::thread::park和unpark 配合Builder实现轻量级的线程挂起与唤醒 rust自定义线程属性std::thread::Builder rust线程 rust关联函数 rust高并发设计实践进阶 rust高并发设计实践 rust性能优化与安全边界 联合体union在rust和C语言中有什么区别 rust并发与异步编程 如何预防rust不良的代码设计总结 rust类型系统与零成本抽象 rust内存模型 告别大显存依赖!用 Rust 新一代深度学习框架 Burn 打造纯 CPU 文本分类推理引擎 rust类型系统标记 编译配置解答 git实用命令 rust底层设计理念值得注意的几个地方总结 rust可变引用作为函数参数的机理详解 Rust内存重解释transmute C与Rust类型映射 Rust FFI 安全抽象范式 rust延迟初始化原语 rust重借用机制与原理 rust参数传递模型 汇编语言语法详解 gdb汇编调试 gdb-pwndbg的安装与使用指南 gdb调试插件gef C语言thread_local linux系统readelf命令使用指南 gcore转储进程内存 gdb查看命令 RGB与YUV颜色编码的区别 Rust原子类型 C++ STL求两个集合交集差集 ubuntu24.0.4使用root用户登录 ubuntu24.0.4输入密码后跳回登录界面 AI内存压缩技术TurboQuant及存疑 ubuntu切换到指定内核版本 在没有顶级科技大佬直接背书的情况下deepseek为啥能够异军突起? HuggingFace和deepseek的关系 当前主流AI大模型 Rust写时克隆Cow系列2
gdb调试集锦
PKICA · 2026-04-02 · via 博客园 - PKICA

1. gdb调试配置

这是一份标准化的GDB调试环境配置指南,包含了Debuginfod(第三方调试符号自动下载)和GDB历史记录持久化设置。

1.1 配置第三方调试符号下载 (Debuginfod)

为使所有用户都能自动下载调试符号,建议在系统配置文件中设置。

操作步骤:
编辑 /etc/profile 或在 /etc/profile.d/ 下新建 .sh 文件(推荐):

# 编辑文件
sudo vim /etc/profile.d/debuginfod.sh
# 添加以下内容
export DEBUGINFOD_URLS="https://debuginfod.ubuntu.com"
export DEBUGINFOD_CACHE_PATH="$HOME/.debuginfod_cache"
  • DEBUGINFOD_URLS: 指定调试符号服务器地址(此处为Ubuntu官方)。(建议所有用户可用)
  • DEBUGINFOD_CACHE_PATH: 设置本地缓存路径,避免重复下载。(建议用户自用)

部分三方调试库有警告提示,安装时提示:e: unable to locate package libcap2-dbgsym

调试符号包(-dbgsym)托管在独立仓库(ddebs.ubuntu.com),执行下述命令前先执行:

lsb_release -cs
如果没有错误,则继续执行下面命令添加调试符号包:
echo "deb http://ddebs.ubuntu.com $(lsb_release -cs) main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/ddebs.list
echo "deb http://ddebs.ubuntu.com $(lsb_release -cs)-updates main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/ddebs.list
echo "deb http://ddebs.ubuntu.com $(lsb_release -cs)-proposed main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/ddebs.list

否则执行获取系统代号的命令:

lsb_release -sc 2>/dev/null

上述命令如果得到:noble

则直接执行下述命令添加调试符号包:

直接手动指定 noble,避免脚本解析错误:

echo "deb http://ddebs.ubuntu.com noble main restricted universe multiverse" | sudo tee /etc/apt/sources.list.d/ddebs.list
echo "deb http://ddebs.ubuntu.com noble-updates main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/ddebs.list
echo "deb http://ddebs.ubuntu.com noble-proposed main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/ddebs.list

ddebs 仓库需要 GPG 密钥来验证包:

sudo apt install ubuntu-dbgsym-keyring

如果上述命令失败,请尝试: sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C8CAB6595FDFF622

然后安装cap2调试包:

sudo apt update
sudo apt install libcap2-dbgsym

1.2 配置GDB历史命令回显与持久化

修改全局GDB配置文件,使历史记录在退出后依然保存。

操作步骤:
编辑 /etc/gdb/gdbinit

sudo vim /etc/gdb/gdbinit

在文件中添加以下内容:

# --- GDB History Configuration ---

# 开启命令历史保存功能
set history save on

# 设置历史文件保存路径
set history filename ~/.gdb_history

# 设置保存的命令条数 (设为较大值)
set history size 10000

# 记录命令参数
set history remove-duplicates unlimited

# ---------------------------------
# 备注:根据需要,此处可选择是否开启debuginfod
# set debuginfod enabled off

1.3 使配置生效

执行以下命令或重新登录终端:

2.一些寄存器

2.1 程序计数器$pc

在 GDB 中,$pc 代表 Program Counter(程序计数器)。

它是 CPU 中的一个特殊寄存器,存放的是下一条即将执行的指令的内存地址

核心作用:

  • 定位进度:它告诉 GDB 此时程序运行到了哪一行汇编代码。
  • 控制流:当你执行 step (s) 或 next (n) 时,硬件实际上是在更新 $pc 的值。

常用操作:

  • 查看当前地址:
    (gdb) print $pc
    # 或者查看十六进制
    (gdb) p/x $pc 
    
  • 查看当前地址对应的汇编代码:
  • 修改执行顺序(慎用):
    你可以通过修改 $pc 让程序跳过某段代码或重复执行某行:
    (gdb) set $pc = 0x400506  # 强行让程序跳转到这个地址执行
    

提示:

在不同的 CPU 架构上,这个寄存器的名字不同(比如在 x86-64 上叫 rip,在 32 位 x86 上叫 eip,在 ARM 上叫 R15)。但 GDB 为了方便跨平台使用,统一提供了一个通用的别名 $pc

 2.2 栈指针$sp

在 GDB 中,$sp 代表 Stack Pointer(栈指针)。

它是 CPU 中的一个核心寄存器,指向当前函数调用栈的栈顶(即当前正在使用的内存区域的边缘)。

核心作用

  • 管理内存:每当你进入一个函数,系统会通过移动 $sp 来为局部变量(比如 struct quantum **p)和返回地址分配空间。
  • 压栈与出栈:当你执行 pushpop 指令时,$sp 的值会自动增加或减少。

常见操作

如果你想看当前的栈顶地址或内容,可以在 GDB 中输入:

  • 查看栈顶地址:p/x $sp
  • 查看栈顶存放的数据(前 4 个字):x/4wx $sp
  • 跨平台通用性:就像 $pc 一样,$sp 是 GDB 提供的通用别名。在 x86-64 架构上,它实际对应的是 rsp 寄存器;在 ARM 上对应的是 R13

想看看当前函数调用的完整“足迹”,可以配合使用 bt (backtrace) 命令,它会基于 $sp$fp(栈帧指针)解析出整个调用链。

 2.3 栈帧指针$fp

在 GDB 中,$fp 代表 Frame Pointer(栈帧指针)。

它是指向当前函数栈帧(Stack Frame)起始位置的寄存器

核心作用:定位局部变量

虽然 $sp 指向栈顶(变动频繁),但 $fp 在一个函数执行期间通常是固定不变的。

  • 局部变量(如: struct quantum **p)通常存储在 $fp 减去一个偏移量的地方。
  • 函数参数通常存储在 $fp 加上一个偏移量的地方。

关系对比

可以将栈看作一个文件夹:

  • $fp (Frame Pointer):文件夹的顶部(起始处)。它标记了当前函数空间的开始。
  • $sp (Stack Pointer):文件夹的底部(当前位置)。随着你往文件夹里塞入更多临时数据,底部会不断伸缩。

常见操作

在 GDB 中,你可以通过以下命令查看:

  • 查看地址:p/x $fp
  • 查看当前函数所有局部变量的值info locals(GDB 会自动根据 $fp 的偏移量帮你找出来)。
  • 架构对应:在 x86-64 架构中,它对应的硬件寄存器是 $rbp;在 ARM 中通常是 R11

调试意义

如果你发现代码在 if (p == NULL) 处逻辑跑偏了,通过查看 $fp 附近的内存,你可以确认 p 到底被编译器分配到了哪个具体的内存地址。

注意:如果编译时开启了高等级优化(如 -O2),编译器为了节省寄存器,可能会去掉栈帧指针(Omit Frame Pointer)。在这种情况下,$fp 的值可能不可靠或不可用。

 3.内存问题

AddressSanitizer (ASan) 是一款强大的内存错误检测工具,集成在 GCC 和 Clang 编译器中。它能够实时捕获诸如堆栈越界内存泄漏以及释放后使用 (Use-After-Free) 等常见 C 语言内存问题。

以下是一个包含“释放后使用”错误的完整示例及调试步骤:

3.1 编写 C 代码示例 (memOverWriteT.c)

这段代码申请了一块堆内存,释放后又尝试修改其中的数据,这是典型的内存安全漏洞。

#include <stdio.h>
#include <stdlib.h>

int main() {
    // 1. 在堆上分配内存
    int *ptr = (int *)malloc(10 * sizeof(int));
    ptr[0] = 100;
    printf("Value before free: %d\n", ptr[0]);

    // 2. 释放内存
    free(ptr);

    // 3. 错误操作:访问已释放的内存 (Use-After-Free)
    // ASan 将在这里捕获错误并停止程序
    ptr[0] = 200; 
    
    printf("Value after free: %d\n", ptr[0]);
    return 0;
}

3.2 编译代码

使用编译器提供的 -fsanitize=address 标志来开启 ASan。建议同时配合以下标志以获得更清晰的报错信息:

  • -g: 生成调试符号,报错时显示具体的源代码行号。
  • -fno-omit-frame-pointer: 确保函数调用栈(Stack Trace)的准确性。

编译命令:

gcc -fsanitize=address -g -fno-omit-frame-pointer memOverWriteT.c -o example

3.3 运行并查看结果

直接运行生成的可执行文件,ASan 会在检测到错误时立即终止程序并打印详细报告。

运行输出(关键部分):

Value before free: 100
==12345==ERROR: AddressSanitizer: heap-use-after-free on address 0x604000000010 ...
WRITE of size 4 at 0x604000000010 thread T0
    #0 0x... in main memOverWriteT.c:15  <-- 报错的具体行号 (第15行)
    ...
0x604000000010 is located 0 bytes inside of 40-byte region ...
freed by thread T0 here:
    #0 0x... in free ...
    #1 0x... in main memOverWriteT.c:11  <-- 内存被释放的地方 (第11行)
...

报告解读

  • 错误类型:明确指出了 heap-use-after-free(堆内存释放后访问)。
  • 出错与释放位置:通过 memOverWriteT.c:15(第15行报错)和 memOverWriteT.c:11(第11行释放)精准定位问题。

4.内存断点

在GDB中,内存断点(通常称为观察点 Watchpoint或硬件断点)是一种非常有用的调试手段。它允许你在特定内存地址的数据被读取、写入或修改时暂停程序执行,而无需预先知道哪一行代码修改了该内存。

以下是GDB内存断点(观察点)的详细使用指南:

4.1 核心命令 (Watchpoints)

  • watch <变量名|地址> (写断点)
    • 当该表达式(变量)的值被写入或修改时暂停。
    • 示例:watch global_var
  • rwatch <变量名|地址> (读断点)
    • 当该表达式(变量)的值被读取时暂停。
  • awatch <变量名|地址> (读写断点)
    • 当该表达式(变量)的值被读取或写入时暂停。

4.2 实战用法

A. 监控变量变化
(gdb) start
(gdb) watch my_variable  # 监控局部或全局变量
(gdb) continue
B. 监控特定内存地址 (重点)

若想监控内存地址 0x601050 处的前4个字节,使用指针强制转换:

(gdb) watch *(int *)0x601050
C. 监控复杂的内存结构

如果需要监控类成员或结构体成员,为了避免无效的变量出栈导致断点消失,使用 -location

(gdb) watch -location pObject->member
# 或者使用简写
(gdb) watch -l pObject->member

4.3 断点管理与信息

  • 查看断点: info breakinfo watchpoints
  • 删除断点: delete <编号>
  • 禁用/启用: disable <编号> / enable <编号> 

4.4 关键原理与注意事项

  • 硬件与软件断点: GDB 优先使用硬件断点实现 watch,这几乎不影响程序速度。如果硬件断点资源不足(通常仅支持 4-8 个),GDB 会尝试用软件模拟,这会极其缓慢。
  • 数据类型: watch 作用于变量名时,它监控的是对应的值。作用于地址时,如 *(int*)0x...,监控的是该大小的内存单元
  • 多线程监控: 如果想监控多线程中同一个全局变量,使用 watch
  • 局部变量作用域: 局部变量出了作用域,其对应的 watch 断点会自动被删除。

总结

当调试内存崩溃(例如 SIGSEGV)、变量莫名其妙被修改,或者在多线程环境中查找数据竞争时,watch 是比普通行断点(break)高效得多的工具。

其他参考文章:

1.使用系统日志定位coredump

2.应用程序或动态库中与加载的其他动态库的类或者函数重名问题

3.valgrind检查C/C++内存泄漏     Yosimite10.10(Mac os)安装c/c++内存检测工具valgrind

4.pstack与strace命令

5.Linux上调试core文件(Good) 

6.gdb调试1--包括反汇编及文件编码设置

7.gdb调试2—单步执行和跟踪函数

8.gdb调试遇到的问题

9.gdb调试3_显示变量 和 数组

10.gdb调试4--回退

11.gdb调试5--工程项目的断点调试

12.gdb调试线程

13.gdb带参调试

14.GDB 

15.gdb线程调试指南