别再费劲了,驱动调试和开发看这篇就够了
一、内核日志快速排错:printk+dmesg 零基础上手,实时追踪运行状态

最基础、最常用的调试手段,用于打印内核/驱动运行状态、变量值、执行流程。

  1. printk(内核态打印)

内核代码中替代 printf,带日志级别(控制是否输出到控制台):

C// 内核代码中使用#include// 日志级别(优先级从高到低)printk(KERN_EMERG"紧急:系统崩溃\n");printk(KERN_ALERT"警报:需要立即处理\n");printk(KERN_CRIT"严重:硬件/软件错误\n");printk(KERN_ERR"错误:常规错误\n");printk(KERN_WARNING"警告:潜在问题\n");printk(KERN_NOTICE"通知:正常但重要信息\n");printk(KERN_INFO"信息:常规调试信息\n");printk(KERN_DEBUG"调试:仅调试用\n");// 简化写法(推荐)pr_info("驱动初始化成功,版本:%d\n",10);pr_err("寄存器写入失败!\n");pr_debug("变量 val = %#x\n",val);// 调试级别,默认不打印
  1. dmesg(查看内核日志)

用户态命令,读取内核环形缓冲区的 printk 日志:

Bash # 基础用法 dmesg # 查看所有日志 dmesg-w # 实时跟踪日志(类似 tail-f) dmesg-c # 查看并清空日志 dmesg-n8# 开启所有级别日志(包含DEBUG) dmesg|grep 驱动名 # 过滤自己的驱动日志 # 查看带时间戳的日志 dmesg-T
二、免代码查状态:procfs+sysfs 一键洞悉系统与设备底层信息

无需修改代码,实时查看内核/硬件/进程状态,是排查系统、驱动问题的首选。

  1. procfs(/proc):进程+内核运行时信息

经典虚拟文件系统,只读为主,用于查看系统状态:

Bash # 核心调试命令 cat/proc/cpuinfo # 查看CPU信息 cat/proc/meminfo # 查看内存状态 cat/proc/modules # 查看已加载内核模块(驱动) cat/proc/cmdline # 查看内核启动参数 cat/proc/interrupts # 查看中断分配(排查驱动中断问题) cat/proc/kmsg # 实时内核日志(同dmesg) cat/proc/[PID]/maps # 查看进程内存映射
  1. sysfs(/sys):设备+驱动+总线信息

Linux 统一设备模型,可读写,用于调试驱动、硬件寄存器、设备状态:

Bash # 驱动/设备调试常用路径 ls/sys/class/# 设备类(gpio、i2c、tty等) ls/sys/devices/# 所有硬件设备 ls/sys/module/# 内核模块信息 # 实战示例:调试GPIO驱动 cat/sys/class/gpio/gpio10/value # 读取GPIO电平 echo1>/sys/class/gpio/gpio10/value # 写入GPIO电平 # 查看驱动绑定状态 cat/sys/bus/platform/drivers/xxx_driver/xxx_device
三、硬件寄存器直调:devmem 硬核读写物理地址,跳过驱动速排硬件故障

嵌入式/驱动调试神器,直接读写物理地址,无需驱动即可调试硬件寄存器。

用法(busybox 自带工具)

Bash # 格式:devmem 物理地址[位宽][]devmem0x12340000# 读取0x12340000物理地址(默认32位) devmem0x123400008#8位读取 devmem0x12340000320x55# 写入0x55到该地址 # 场景:排查硬件寄存器配置错误、外设未响应问题

⚠️ 警告:随意读写物理地址会导致系统崩溃!仅用于硬件调试。

四、内核崩溃精准定位:Oops信息拆解,快速锁定崩溃代码行

内核/驱动崩溃时自动打印Oops(空指针、内存越界、非法指令),是定位崩溃代码的核心。

  1. 关键信息解读
Plain Text BUG:Unable to handle kernelNULLpointer dereference at virtual address00000000PC:[]test_driver+0x50/0x100# PC指针:崩溃的代码地址 LR:[]0xc0654321# 链接寄存器 Processbash(pid:1234,stack limit:0xcf000000)Stack:0xcf001000:...# 栈信息 •PC:崩溃的函数+偏移,直接定位代码行 •NULLpointer dereference:空指针访问(最常见) •invalid address:非法内存访问
  1. 定位代码行
Bash # 用addr2line解析PC地址 arm-linux-gnueabihf-addr2line-e vmlinux c0123456 # 输出:/driver/test/test.c:56→ 直接定位崩溃行
五、内存bug克星:KASAN 内核内存检测,越界/泄漏/野指针无所遁形

内核级内存越界、内存泄漏、野指针检测工具,比Oops更精准,是驱动稳定性调试必备。

  1. 开启方法(内核配置)
Plain Text CONFIG_KASAN=y # 开启KASAN CONFIG_KASAN_GENERIC=y # 通用模式(推荐) CONFIG_DEBUG_KERNEL=y
  1. 调试效果

KASAN 会直接打印越界代码行、内存类型(栈/堆/全局),无需手动分析:

Plain Text BUG:KASAN:stack-out-of-bounds in test_func+0x20/0x50Read of size4at addr0xffffffc000001234task bash

直接告诉你:栈内存越界,在test_func函数第XX行。

六、内核用户态交互:ioctl 调试利器,高效测试驱动命令与参数传递

用户态与内核驱动交互的核心接口,用于调试驱动命令、参数传递。

  1. 内核态(驱动实现)

驱动中实现 unlocked_ioctl 回调,处理用户态命令:

Clongtest_ioctl(structfile*file,unsignedintcmd,unsignedlongarg){switch(cmd){caseTEST_CMD_READ:// 自定义命令copy_to_user((void__user*)arg,&val,sizeof(val));break;caseTEST_CMD_WRITE:copy_from_user(&val,(void__user*)arg,sizeof(val));break;default:return-ENOTTY;}return0;}
  1. 用户态调试工具

编写简单C程序/使用 ioctl 工具测试驱动交互:

C// 用户态测试代码intfd=open("/dev/test_dev",O_RDWR);ioctl(fd,TEST_CMD_WRITE,&write_val);// 发送命令给驱动close(fd);

✅ 用途:调试驱动命令是否正常响应、参数传递是否正确。

七、调试流程标准化:一套实战流程,搞定内核驱动全场景调试

一套驱动开发标准调试流程,可以直接套用:

1.加载驱动:insmod xxx.ko

2.看日志:dmesg -w 查看printk输出,排查初始化错误

3.查状态:cat /proc/modules、ls /sys/class/xxx 确认设备注册成功

4.硬件调试:devmem 0xXX 读写寄存器,验证硬件

5.功能测试:用户态程序调用ioctl,测试驱动功能

6.崩溃排查:Oops + addr2line 定位崩溃代码

7.稳定性测试:开启KASAN,检测内存问题

调试技巧核心总结

1.基础调试:printk 打印 + dmesg 查看日志

2.系统/设备状态:/proc 看系统信息,/sys 调试驱动设备

3.硬件寄存器:devmem 直接读写物理地址

4.崩溃定位:Oops信息 + addr2line 快速找bug

5.内存安全:KASAN 检测越界/泄漏(必用)

6.驱动交互:ioctl 完成用户态与内核态通信

这些是 Linux 内核/驱动调试最核心、最高频的技能,覆盖90%以上调试场景。