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

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - PKICA

汇编语言语法详解 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 使配置生效

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

source /etc/profile

2.一些寄存器

2.1 程序计数器$pc

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

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

核心作用:

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

常用操作:

  • 查看当前地址:
    (gdb) print $pc
    # 或者查看十六进制
    (gdb) p/x $pc 
    
  • 查看当前地址对应的汇编代码:
    (gdb) x/i $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线程调试指南