Skip to content

KGDB / GDB 远程调试

KGDB 原理

KGDB(Kernel GNU Debugger)在内核中实现了 GDB 远程协议,通过串口或网络连接到宿主机的 GDB,实现源码级内核调试。

目标机(被调试)          宿主机(调试)
  Linux 内核
  KGDB stub    ←── 串口/网络 ──→  GDB
  /dev/ttyS0                      arm-linux-gnueabi-gdb vmlinux

内核配置

CONFIG_KGDB=y
CONFIG_KGDB_SERIAL_CONSOLE=y
CONFIG_KGDB_KDB=y          # 内核调试器(无需 GDB 客户端)
CONFIG_DEBUG_INFO=y         # 调试符号(必须)
CONFIG_FRAME_POINTER=y      # 准确的调用栈
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y

目标机配置

bash
# 内核启动参数(通过 bootargs 或 /proc/cmdline)
kgdboc=ttyS0,115200 kgdbwait

# kgdbwait:启动时等待 GDB 连接
# kgdboc:KGDB over console,指定串口和波特率

# 运行时触发断点(进入 KGDB)
echo g > /proc/sysrq-trigger
# 或
echo ttyS0 > /sys/module/kgdboc/parameters/kgdboc

宿主机 GDB 连接

bash
# 启动 GDB(使用带调试符号的 vmlinux)
arm-linux-gnueabi-gdb vmlinux

# 连接到目标机串口
(gdb) set remotebaud 115200
(gdb) target remote /dev/ttyUSB0

# 或通过网络(kgdboe)
(gdb) target remote 192.168.1.100:2345

常用 GDB 命令

bash
# 查看调用栈
(gdb) bt
(gdb) bt full   # 包含局部变量

# 查看当前代码
(gdb) list
(gdb) list my_driver_probe

# 设置断点
(gdb) break my_driver_probe
(gdb) break drivers/mydriver/my_driver.c:42
(gdb) break my_driver_write if len > 100   # 条件断点

# 查看变量
(gdb) print priv
(gdb) print *priv
(gdb) print priv->base_addr
(gdb) x/16xb priv->buf   # 以十六进制查看内存

# 单步执行
(gdb) step    # 进入函数
(gdb) next    # 不进入函数
(gdb) finish  # 执行到函数返回
(gdb) continue

# 查看寄存器
(gdb) info registers
(gdb) print $pc   # 程序计数器

# 查看内核线程
(gdb) info threads
(gdb) thread 3

# 查看模块加载地址(用于调试可加载模块)
(gdb) info sharedlibrary

调试可加载模块

bash
# 1. 在目标机上查看模块加载地址
cat /proc/modules | grep my_driver
# my_driver 16384 0 - Live 0xffffffffc0a00000

# 2. 在 GDB 中加载模块符号
(gdb) add-symbol-file my_driver.ko 0xffffffffc0a00000

# 3. 现在可以在模块函数上设置断点
(gdb) break my_driver_probe

KDB — 无需宿主机的内核调试器

KDB 是内置的命令行调试器,直接在目标机控制台操作:

bash
# 进入 KDB
echo g > /proc/sysrq-trigger

# KDB 命令
[0]kdb> help          # 帮助
[0]kdb> bt            # 调用栈
[0]kdb> ps            # 进程列表
[0]kdb> md 0xffff... 16  # 查看内存(16 字节)
[0]kdb> mm 0xffff... 0x1234  # 修改内存
[0]kdb> bp my_driver_probe   # 设置断点
[0]kdb> go            # 继续运行
[0]kdb> lsmod         # 模块列表

QEMU 调试(开发阶段推荐)

无需真实硬件,用 QEMU 模拟目标机:

bash
# 启动 QEMU,等待 GDB 连接(端口 1234)
qemu-system-arm \
    -M virt \
    -kernel arch/arm/boot/zImage \
    -dtb my_board.dtb \
    -append "kgdboc=ttyAMA0,115200 kgdbwait console=ttyAMA0" \
    -serial tcp::1234,server,nowait \
    -nographic

# 宿主机连接
arm-linux-gnueabi-gdb vmlinux
(gdb) target remote localhost:1234

褚成志的笔记