欢迎光临
我们一直在努力

GDB 调试原理

在这里插入图片描述

笔记整理自 b 站 up 主,谢谢 up 分享 :https://www.bilibili.com/video/BV1r4itBNEF2

一、GDB 简介

GDB(GNU Debugger) 是一款开源调试工具,支持多种编程语言(如 C、C++、Python 等),主要用于在程序运行时检查其状态,包括变量值、内存布局、调用堆栈等。它可以帮助开发者定位逻辑错误、内存泄漏、段错误等问题。

使用 GDB 调试程序的前提:

  • 操作系统内核通过 ptrace 提供对其他进程内存的读写能力
  • 使用 CPU 提供的调试指令修改内存的位置
  • CPU 执行产生调试异常,操作系统把异常转发给 GDB 处理
架构断点指令
x86 / x86_64 int3
ARM (32-bit) BKPT
ARM64 BRK
RISC-V EBREAK
MIPS BREAK

二、ptrace 系统调用

‌ptrace 是 Linux/Unix 系统里的一个核心系统调用‌,主要用来让一个进程去‌跟踪和控制另一个进程‌的执行。
在这里插入图片描述

如何实现得到变量的值

假设使用 GDB 调试程序 ./a

  • Tracee(被跟踪者/子进程):
    • 启动目标程序 ./a 作为子进程。
    • 调用 ptrace(PTRACE_TRACEME, …) 将自身标记为可被跟踪状态。
  • Tracer(跟踪者/父进程):
    • GDB 作为父进程运行,负责接收用户的调试指令。
    • GDB 通过调用 ptrace 系列 API(如 PTRACE_PEEKTEXT, PTRACE_GETREGS 等)来读取子进程的内存或寄存器状态。

    在这里插入图片描述

    如何实现打断点

    将目标地址处的原始指令的第一个字节替换为 0xCC(即 x86 架构下的 int3 指令)。当 CPU 执行到该指令时,会触发 #BP (Breakpoint) 异常,从而陷入内核态。

  • 读取目标地址原始指令
  • 写入断点指令
  • 断点触发与调试器交互流程
    CPU 触发中断 —— 内核处理中断 —— 还原原始代码 —— 调整指令指针(RIP)
    • CPU 触发中断:CPU 执行到 0xCC,触发 #BP 异常,控制权移交操作系统内核。
    • 内核处理中断:内核识别出这是由调试器设置的断点(通过检查进程状态),暂停目标进程(Tracee),并向调试器(Tracer,如 GDB)发送 SIGTRAP 信号。
    • 还原原始代码:调试器收到信号后,先将之前备份的原始指令写回内存地址,覆盖掉 0xCC。
    • 调整指令指针(RIP):将程序计数器(RIP/EIP)回退 1 个字节(因为 CPU 已经执行了 int3,RIP 指向了下一条指令,必须指回原指令开头)。

    三、DWARF 调试信息格式

    • debug_line:记录行和行数的映射关系
      在这里插入图片描述– 程序信息记录
      在这里插入图片描述

    MI 协议

    GDB/MI(GDB Machine Interface) 是GDB提供的一种面向程序、而不是人类的调试接口协议。它的目标是:让IDE、调试前端、自动化工具能可靠可解析地控制GDB,而不需要去解析人类可读的CLI输出。
    在这里插入图片描述

    RSP 远程串行协议

    RSP 是 GDB 与远程目标之间通信的标准协议。在远程调试场景中,GDB 作为客户端(Host),GDB Server 作为服务端(Target),两者通过 TCP/IP 或串口交换 RSP 数据包。

  • GDB
    • 将用户的CLI命令(break a.c:6)转换为 RSP 命令(Z0,addr,kind)
    • 解析DWARF,管理符号
    • 计算栈回溯
    • 解析来自 GDB Server 的结果,展示出来
  • GDB Server:
    • 解析来自 RSP 的命令,转换执行对应的 ptrace 命令
    • 再把结果发送回 GDB

    在这里插入图片描述

    四、补充

    现代处理器可以同时多发射指令

    在这里插入图片描述
    使用处理器精确中断解决该问题(ROB 重排缓冲区),该功能实现在最后修改值时判断前面的指令是否执行完。

    在这里插入图片描述

    解释型语言的调试

    Python

    • 核心 API:sys.settrace(func),通过该函数注册一个跟踪回调函数,VM 会在特定事件发生时调用它。
    • 调试原理
  • 注册断点:用户设置断点后,底层逻辑转化为对 VM 的检查条件。
  • VM 检查:Python 解释器在执行字节码时,会频繁检查当前是否满足 Trace 条件(如行号匹配)。
  • 触发回调:一旦满足条件,解释器暂停执行,调用注册的 func 进行交互,从而实现“停住”的效果。
  • Java (JVM 体系)

    • 调试器前端 (Debugger)
      工具:IntelliJ IDEA, Eclipse, jdb 等。
      接口:JDI (Java Debug Interface)。这是给开发者使用的高级 API。
    • 传输层 (Transport)
      协议:JDWP (Java Debug Wire Protocol)。
      作用:定义调试器与目标 JVM 之间通信的数据包格式(如“设置断点”、“读取变量”的具体二进制指令)。
    • 后端代理 (Agent & VM)
      JVM Debug Agent:运行在目标 JVM 进程中的组件。
      JVMTI (JVM Tool Interface):Agent 通过此接口与 JVM 内核交互。它是 JVM 暴露给外部工具的标准原生接口。
      JVM 内核:包含解释器和 JIT 编译器。

    当内核执行到特定位置(如断点指令),触发事件回调 -> 上报给 JVMTI -> Agent 封装为 JDWP 消息 -> 发送给前端调试器。

    赞(0)
    未经允许不得转载:171主机测评 » GDB 调试原理
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址