Linux 内核 KGDB 以及内核驱动单串口调试笔记:telnet + agent-proxy + gdb-multiarch 实践

1. 背景与目标

  • 痛点:Linux 内核及驱动调试困难,依赖打印日志效率低下,且传统 KGDB 调试往往需要两个串口(一个用于日志,一个用于调试命令)。
  • 目标 :利用 telnet + agent-proxy + gdb-multiarch 工具链,仅使用开发板的一个物理串口资源,实现多架构(ARM/x86 等)的内核源码级调试。
  • 效果:通过 GDB 设置断点、单步执行,配合串口日志输出,"分层" 剖析内核子系统的工作流程。

2. 核心架构与原理

  • 核心思路 :agent-proxy 作为 "数据分发器",将单一的物理串口虚拟出两个逻辑通道:
    • 通道 0 (控制台):负责接收开发板输出的日志信息,替代 minicom。
    • 通道 1 (调试):负责发送 GDB 的调试命令给开发板。
  • 数据流向
  1. 开发板通过 UART 串口输出内核日志。
  2. 虚拟机上的 agent-proxy 读取串口数据,转发到本地的 5550 端口。
  3. 开发者通过 telnet localhost 5550 查看内核实时日志。
  4. 当需要调试时,gdb-multiarch 连接到 localhost:5551 端口。
  5. agent-proxy 将 GDB 的调试指令写入物理串口,发送给开发板的 KGDB 桩。
框架图

3. 环境准备与配置

  • 硬件
    • Linux 开发板(如 i.MX6ULL),确认串口(UART1)可用。
    • USB 转 TTL 串口线 / 开发板自带的 USB 串口口。
  • 开发板内核配置(重要)
  • 确保内核配置了 KGDB 支持,并关闭硬件看门狗。(自己打开内核配置,进行内核功能配置)
cpp 复制代码
# 必须选中的内核选项
CONFIG_KGDB=y
CONFIG_KGDB_SERIAL_CONSOLE=y
CONFIG_KGDB_KDB=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_KERNEL=y
CONFIG_FRAME_POINTER=y
# 务必关闭看门狗,否则调试停顿时会触发系统复位
# 对于 i.MX6,取消选中以下选项:
# CONFIG_IMX2_WDT is not set
  • 虚拟机工具安装

Ubuntu / Debian 环境 sudo apt update sudo apt install gdb-multiarch telnet # agent-proxy 需要手动下载编译(参考下文)

4. 操作步骤

  1. 获取并编译 agent-proxy
    git clone https://git.kernel.org/pub/scm/utils/kernel/kgdb/agent-proxy.git cd agent-proxy make # 编译后会生成 agent-proxy 可执行文件
  2. 连接硬件并确认设备节点
  • 使用 USB 串口线连接开发板和虚拟机。
  • 在虚拟机终端执行 ls /dev/ttyUSB*,记录对应的串口名称(如 /dev/ttyUSB0)。
  1. 启动 agent-proxy 进行端口分发
  • 关闭可能占用串口的其他程序(如 minicom)。
  • 执行命令(需 sudo 权限):
    sudo ./agent-proxy 5550^5551 0 /dev/ttyUSB0,115200
  • 5550^5551:端口对。5550 用于控制台(日志),5551 用于 GDB 调试。
  • /dev/ttyUSB0,115200:你的串口设备和波特率。
  1. 启动控制台,查看内核日志(替代 minicom)
  • 打开一个新的终端窗口,使用 telnet 连接本地 5550 端口:
    telnet localhost 5550
  • 此时你应该能看到开发板的启动日志。如果开发板尚未启动,上电后会在此窗口看到打印信息。
  1. 配置开发板启动参数(U-Boot 环境)
  • 在开发板启动进入 U-Boot 后,设置 bootargs 以启用 KGDB:
    setenv bootargs 'console=ttymxc0,115200 kgdboc=ttymxc0,115200 kgdbwait nokaslr' saveenv boot
  • kgdbwait 让内核在启动时主动等待 GDB 连接,建议初期使用。
  • kgdboc=ttymxc0,115200 指定调试串口和波特率(根据你的开发板串口设备名修改,如 ttymxc0 对应 UART1)。
  1. 使用 gdb-multiarch 连接调试
  • 编译好带调试符号的内核镜像(vmlinux),在虚拟机中启动 GDB:
    gdb-multiarch vmlinux
  • 在 GDB 界面中执行:
    set serial baud 115200 target remote localhost:5551
  • 如果连接成功,GDB 会停留在 kgdb_breakpoint() 函数处,此时可以开始调试:
    b start_kernel # 在内核入口设置断点 c # 继续执行

5. 常见问题与解决思路

|--------------------------|--------------------------------|-------------------------------------------------------------------|
| 现象 | 可能原因 | 解决方法 |
| target remote 超时 | agent-proxy 未启动;端口被占用;串口设备错误。 | ps aux | grep agent-proxy 检查进程; netstat -tlnp | grep 5551 检查端口。 |
| 连接后立即重启 | 硬件看门狗未关闭;串口通信不稳。 | 检查内核配置,关闭看门狗驱动;降低波特率;检查硬件连接。 |
| telnet 无输出 | 串口设备权限问题;agent-proxy 未正确连接到串口。 | 使用 sudo ; ls -l /dev/ttyUSB0 检查权限;检查 agent-proxy 启动命令中的波特率。 |
| GDB 无法设置断点 | 内核开启地址随机化(KASLR);缺少调试符号。 | U-Boot 中添加 nokaslr 参数;确认编译内核时开启了 CONFIG_DEBUG_INFO 。 |

上面是AI总结版本,下面是自己实操的简要必要的步骤

1.确保kgdb相关配置还有看门狗关闭


2.找到/dev下面的usb串口打开中间代理服务
sudo ./agent-proxy 5550^5551 0 /dev/ttyUSB1,115200

3.telnet连接开发板并且进入中断等待调试

4.gdb-multiarch进入调试模式

至此已经可以开始调试了,关于具体调试什么,怎么使用gdb,这个网上有很多,暂时不罗嗦。
声明:文章内容是我叫AI帮忙总结,具体这个架构操作流程和步骤都是我私下踩坑花了一段时间才搞明白开始上手的,该文章主要是为了自己而记录,如果能帮助到阅读了文章的人,我深感荣幸。

相关推荐
A小辣椒2 小时前
TShark:Wireshark CLI 功能
linux
A小辣椒6 小时前
TShark:基础知识
linux
AlfredZhao8 小时前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao1 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334661 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪1 天前
linux 拷贝文件或目录到指定的位置
linux
摇滚侠2 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
bush42 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
✎ ﹏梦醒͜ღ҉繁华落℘2 天前
单片机基础知识---stm32单片机的优先级
stm32·单片机·mongodb
载数而行5202 天前
Linux 11 动态监控指令top
linux