当前位置: 首页 > web >正文

Linux驱动模块双机调试详细步骤

下面是调试Linux驱动模块的全面详细步骤,涵盖从环境准备到实际调试的完整流程:

一、环境准备

1. 硬件准备

  • 两台计算机
    • 目标机:运行被调试的Linux系统及驱动模块
    • 主机:运行调试器(GDB),可以是Linux、Windows(WSL)或macOS
  • 连接方式
    • 串口线:推荐使用USB转串口适配器
    • 网络连接:确保两机在同一网络

2. 目标机内核配置

确保目标机内核已启用以下配置:

CONFIG_DEBUG_INFO=y           # 保留调试信息
CONFIG_GDB_SCRIPTS=y          # 支持GDB脚本
CONFIG_KGDB=y                 # 内核GDB支持
CONFIG_KGDB_SERIAL_CONSOLE=y  # 串口KGDB支持
CONFIG_KGDB_KDB=y             # KDB支持(可选但推荐)
CONFIG_KALLSYMS=y             # 内核符号支持
CONFIG_KALLSYMS_ALL=y         # 导出所有符号
CONFIG_FRAME_POINTER=y        # 启用帧指针(改善堆栈跟踪)
CONFIG_RANDOMIZE_BASE=n       # 禁用内核地址随机化

如果无法重新编译内核,可以查看当前配置:

cat /boot/config-$(uname -r) | grep KGDB
cat /proc/config.gz | zcat | grep KGDB  # 部分系统

二、驱动模块准备

1. 修改驱动源码(可选)

添加调试辅助代码:

// 在关键点添加调试断点
#include <linux/kgdb.h>
...
void my_critical_function(void) {kgdb_breakpoint();  // 主动触发断点...
}// 添加调试打印
#define DEBUG
#include <linux/kernel.h>
...
pr_debug("Debug value: %d\n", value);

2. 编译带调试信息的模块

修改Makefile:

# 添加调试标志
ccflags-y += -g -DDEBUG -O1

编译模块:

make -C /lib/modules/$(uname -r)/build M=$(pwd) modules

3. 保存调试符号

复制未压缩的模块到安全位置:

cp mydriver.ko /path/to/debug/symbols/

三、配置目标机

1. 启动KGDB

方法1:内核启动参数(需重启):

# 在GRUB引导参数或/etc/default/grub中添加
kgdboc=ttyS0,115200 kgdbwait

方法2:运行时启用(无需重启):

# 加载kgdb模块(如果编译为模块)
modprobe kgdboc# 配置KGDB使用串口
echo ttyS0,115200 > /sys/module/kgdboc/parameters/kgdboc# 或配置KGDB使用网络(需内核支持)
echo udp://192.168.1.100:5551 > /sys/module/kgdboc/parameters/kgdboc

2. 加载驱动模块

# 先插入模块
insmod /path/to/mydriver.ko# 获取模块加载地址和各段地址
cat /sys/module/mydriver/sections/.text
cat /sys/module/mydriver/sections/.data
cat /sys/module/mydriver/sections/.bss

记录下这些地址,例如:

  • .text: 0xffffffffc0567000
  • .data: 0xffffffffc0569000
  • .bss: 0xffffffffc056a000

3. 触发KGDB断点

方法1:使用sysrq:

# 通过sysrq触发KGDB
echo g > /proc/sysrq-trigger

方法2:在代码中主动触发:

kgdb_breakpoint();  // 当执行到此处时会暂停

此时目标机应显示:

KGDB: Entering KGDB

四、主机端调试设置

1. 启动GDB

在主机上(Linux环境或Windows的WSL中):

# 使用与目标机内核版本匹配的GDB
gdb# 或者指定内核符号文件
gdb /path/to/vmlinux

2. 配置GDB会话

# 设置串口连接(Linux主机)
target remote /dev/ttyUSB0# 或网络连接
target remote 192.168.1.200:5551# Windows主机使用COM端口
target remote com1

3. 加载驱动模块符号

使用前面记录的地址:

add-symbol-file /path/to/mydriver.ko 0xffffffffc0567000 \-s .data 0xffffffffc0569000 \-s .bss 0xffffffffc056a000

五、驱动调试流程

1. 设置断点

# 在驱动初始化函数设置断点
break mydriver_init# 在特定源码行设置断点
break mydriver.c:123# 在文件操作函数设置断点
break mydriver_read
break mydriver_write
break mydriver_ioctl

2. 开始调试

# 继续执行直到遇到断点
continue# 或简写为
c

3. 在断点处进行调试

# 查看变量值
print my_variable# 查看数据结构
print *device_struct# 单步执行
next    # 不进入函数
step    # 进入函数# 查看调用栈
backtrace# 查看寄存器
info registers# 切换栈帧
frame 2# 查看源码
list# 设置变量值(谨慎使用)
set my_variable = 123

4. 监控特定内存

# 监视内存地址变化
watch *0xffffffffc0569100# 监视变量变化
watch my_global_variable

5. 触发驱动行为

在另一个终端连接到目标机,执行会触发驱动的操作:

# 例如读写设备
echo "test" > /dev/mydevice
cat /dev/mydevice# 或使用ioctl
./my_test_app

6. 结束调试

# 解除连接但保持目标机运行
detach# 完全退出GDB
quit

六、高级调试技巧

1. 动态重新加载模块

如需修改代码并重新调试:

# 目标机上卸载模块
rmmod mydriver# 重新编译并加载
insmod mydriver.ko# 获取新地址并在GDB中更新
cat /sys/module/mydriver/sections/.text

在GDB中:

# 移除旧符号
remove-symbol-file# 添加新符号
add-symbol-file /path/to/mydriver.ko 新地址

2. 自动化调试脚本

创建.gdbinit文件:

# 连接设置
target remote /dev/ttyUSB0# 加载符号
add-symbol-file /path/to/mydriver.ko 0xffffffffc0567000# 设置常用断点
break mydriver_init
break mydriver_ioctl# 自定义命令
define reload_moduleremove-symbol-fileadd-symbol-file /path/to/mydriver.ko $arg0break mydriver_init
end

3. 调试通过内核访问的用户数据

# 检查用户空间数据(copy_from_user目标)
x/10x 0xabcd1234# 查看字符串
x/s 0xabcd1234

4. 断点条件设置

# 只在特定条件触发断点
break mydriver_ioctl if cmd == 0x8001

这个详细指南涵盖了Linux驱动模块双机调试的完整过程,从环境准备到实际调试操作。通过这些步骤,您应该能够有效地调试Linux内核驱动模块。对于复杂的驱动问题,这种方法能提供比简单的printk日志更详细的运行时信息。

http://www.xdnf.cn/news/1047.html

相关文章:

  • Linux学习——UDP
  • PowerQuery逆透视将二维表转换为一维表
  • 【家政平台开发(67)】家政平台移动端性能优化:打造极致用户体验
  • Spring集合注入Bean
  • Oracle数据库学习之路-目录
  • PyTorch与自然语言处理:从零构建基于LSTM的词性标注器
  • Docker离线安装与配置指南
  • 安装 Conda 环境
  • Linux 一些常用的命令记录
  • pdf多文件合并
  • Elasticsearch性能优化实践
  • SQL简介
  • SystemV-消息队列与责任链模式
  • 神经网络的 “成长密码”:正向传播与反向传播深度解析(四)
  • 联邦元学习实现个性化物联网的框架
  • 【开关电源】关于GaN反激电源开关噪声
  • 微信小程序拖拽排序有效果图
  • C++学习之类与对象
  • Redis的数据持久化是怎么做的?
  • 【无人机】问题分析。查看电机转速时,四个电机转速不一致,QGC中检测到电机转速不均衡
  • webpack详细打包配置,包含性能优化、资源处理...
  • 简述大疆无人机对接
  • Python爬虫从入门到实战详细版教程
  • 【AI提示词】投资策略专家
  • 蓝耘平台介绍:算力赋能AI创新的智算云平台
  • Android RecyclerView 多布局场景下的设计思考:SRP 与 OCP 的权衡与优化
  • 服务网格在DevOps中的落地:如何让微服务更智能、更稳定?
  • 597页PPT丨流程合集:流程梳理方法、流程现状分析,流程管理规范及应用,流程绩效的管理,流程实施与优化,流程责任人的角色认知等
  • Python+区块链:如何打造智能化资产管理系统?
  • [预备知识]3. 自动求导机制