《Linux 设备驱动开发详解:基于最新的 Linux 4.0 内核》
附录 C 常用 Linux 命令与调试工具速查
参考:宋宝华 著,机械工业出版社,2015年版
C.1 系统信息查看
C.1.1 内核与系统信息
bash
# 查看内核版本
uname -r # 只显示内核版本号:5.4.0-xxx
uname -a # 显示完整系统信息
uname -m # 显示机器架构:x86_64 / armv7l
# 查看发行版信息
lsb_release -a # 显示发行版详细信息
cat /etc/os-release # 查看 OS 信息文件
# 查看 CPU 信息
cat /proc/cpuinfo # 详细 CPU 信息
nproc # CPU 核心数
lscpu # CPU 架构信息摘要
# 查看内存信息
cat /proc/meminfo # 详细内存信息
free -h # 内存使用情况(人类可读格式)
# 输出示例:
# total used free shared buff/cache available
# Mem: 7.7G 2.1G 3.2G 234M 2.4G 5.1G
# Swap: 2.0G 0B 2.0G
# 查看磁盘信息
df -h # 磁盘使用情况
lsblk # 块设备列表
fdisk -l # 磁盘分区信息(需要 root)
# 查看系统运行时间
uptime # 系统运行时间和负载
# 输出:10:00:00 up 2 days, 3:45, 2 users, load average: 0.15, 0.10, 0.08
# 查看进程信息
ps aux # 所有进程
ps aux | grep my_driver # 过滤特定进程
top # 实时进程监控
htop # 增强版 top(需要安装)
C.1.2 硬件信息查看
bash
# 查看 PCI 设备
lspci # 列出所有 PCI 设备
lspci -v # 详细信息
lspci -k # 显示使用的内核驱动
lspci | grep -i network # 过滤网卡
# 查看 USB 设备
lsusb # 列出所有 USB 设备
lsusb -v # 详细信息
lsusb -t # 树形显示
lsusb | grep "1234:5678" # 查找特定 VID:PID 的设备
# 查看 I2C 设备
i2cdetect -l # 列出所有 I2C 总线
i2cdetect -y 1 # 扫描 I2C 总线1上的设备
i2cget -y 1 0x48 0x00 w # 读取 I2C 设备寄存器
i2cset -y 1 0x48 0x01 0x80 b # 写入 I2C 设备寄存器
# 查看 GPIO 信息
cat /sys/kernel/debug/gpio # GPIO 状态(需要 debugfs)
gpiodetect # 列出 GPIO 控制器(需要 libgpiod)
gpioinfo # 列出所有 GPIO 引脚
# 查看设备树
dtc -I fs /sys/firmware/devicetree/base 2>/dev/null | head -100
# 或
cat /sys/firmware/devicetree/base/model # 开发板型号
C.2 内核模块管理
C.2.1 模块操作命令
bash
# 加载模块
insmod my_driver.ko # 直接加载(不处理依赖)
insmod my_driver.ko param1=10 # 加载时传入参数
modprobe my_driver # 智能加载(自动处理依赖)
modprobe my_driver param1=10 # 加载时传入参数
# 卸载模块
rmmod my_driver # 卸载模块(模块名,不含 .ko)
modprobe -r my_driver # 卸载并移除不再需要的依赖
# 查看模块信息
lsmod # 列出所有已加载模块
lsmod | grep my_driver # 过滤特定模块
modinfo my_driver.ko # 查看模块详细信息
# 输出示例:
# filename: /path/to/my_driver.ko
# version: 1.0
# description: My Driver
# author: Developer
# license: GPL v2
# parm: param1:参数描述 (int)
# 查看模块参数
cat /sys/module/my_driver/parameters/param1
echo 20 | sudo tee /sys/module/my_driver/parameters/param1 # 修改参数
# 更新模块依赖数据库
depmod -a # 扫描所有模块,生成 modules.dep
depmod -n # 只显示,不写入文件
# 查看模块依赖
modprobe --show-depends my_driver # 显示依赖关系
# 自动加载配置
echo "my_driver" >> /etc/modules # 开机自动加载
echo "options my_driver param1=10" > /etc/modprobe.d/my_driver.conf # 加载参数
C.2.2 模块调试信息
bash
# 查看模块符号
nm my_driver.ko | grep " T " # 查看导出的函数符号
nm my_driver.ko | grep " U " # 查看未定义(依赖)的符号
cat /proc/kallsyms | grep my_driver # 查看内核符号表中的模块符号
# 查看模块内存地址
cat /proc/modules | grep my_driver
# my_driver 16384 0 - Live 0xffffffffc0001000
# 格式:模块名 大小 引用计数 状态 内存地址
# 查看模块的 section 地址(用于 GDB 调试)
cat /sys/module/my_driver/sections/.text
cat /sys/module/my_driver/sections/.data
cat /sys/module/my_driver/sections/.bss
# 反汇编模块
objdump -d my_driver.ko | head -50
objdump -d my_driver.ko | grep -A 20 "<my_driver_read>"
# 查看模块的 ELF 信息
readelf -h my_driver.ko # ELF 头信息
readelf -S my_driver.ko # Section 信息
readelf -s my_driver.ko # 符号表
C.3 设备文件操作
C.3.1 设备文件管理
bash
# 查看设备文件
ls -l /dev/ # 列出所有设备文件
ls -l /dev/ttyS* # 串口设备
ls -l /dev/sda* # 磁盘设备
ls -l /dev/input/ # 输入设备
ls -l /dev/i2c-* # I2C 设备
# 创建设备文件(手动,通常由 udev 自动创建)
mknod /dev/mydev c 240 0 # 创建字符设备(主设备号240,次设备号0)
mknod /dev/myblk b 253 0 # 创建块设备
# 查看设备号
cat /proc/devices # 查看已注册的设备号
# 输出:
# Character devices:
# 1 mem
# 4 tty
# 240 my_driver
# Block devices:
# 8 sd
# 253 my_block
# 查看 udev 规则
ls /etc/udev/rules.d/ # 用户自定义规则
ls /lib/udev/rules.d/ # 系统规则
udevadm info -a -n /dev/ttyUSB0 # 查看设备属性(用于编写规则)
udevadm monitor # 实时监控 udev 事件
udevadm control --reload-rules # 重新加载规则
udevadm trigger # 触发规则重新应用
# 读写设备文件
cat /dev/mydev # 读取字符设备
echo "hello" > /dev/mydev # 写入字符设备
dd if=/dev/zero of=/dev/myblk bs=512 count=1 # 写入块设备
hexdump -C /dev/mydev | head -5 # 十六进制查看设备数据
C.3.2 sysfs 操作
bash
# 查看 sysfs 结构
ls /sys/ # sysfs 根目录
ls /sys/bus/ # 总线目录
ls /sys/class/ # 设备类目录
ls /sys/devices/ # 设备目录
# 查看特定设备
ls /sys/class/gpio/ # GPIO 设备
ls /sys/class/leds/ # LED 设备
ls /sys/class/net/ # 网络设备
ls /sys/class/input/ # 输入设备
ls /sys/bus/i2c/devices/ # I2C 设备
ls /sys/bus/spi/devices/ # SPI 设备
ls /sys/bus/platform/devices/ # 平台设备
# 通过 sysfs 控制设备
# LED 控制
echo 1 > /sys/class/leds/heartbeat/brightness # 点亮 LED
echo 0 > /sys/class/leds/heartbeat/brightness # 熄灭 LED
echo timer > /sys/class/leds/heartbeat/trigger # 设置触发器
# GPIO 控制
echo 23 > /sys/class/gpio/export # 导出 GPIO23
echo out > /sys/class/gpio/gpio23/direction # 设置为输出
echo 1 > /sys/class/gpio/gpio23/value # 输出高电平
cat /sys/class/gpio/gpio23/value # 读取电平
echo 23 > /sys/class/gpio/unexport # 取消导出
# 查看驱动信息
ls /sys/bus/platform/drivers/my_driver/ # 驱动目录
cat /sys/bus/platform/drivers/my_driver/uevent # 驱动事件
C.4 内核日志与调试
C.4.1 dmesg 命令
bash
# 基本用法
dmesg # 显示所有内核日志
dmesg | tail -20 # 显示最后20行
dmesg | head -50 # 显示前50行
dmesg -w # 实时监控(类似 tail -f)
dmesg -c # 显示并清空缓冲区
dmesg -T # 显示人类可读的时间戳
dmesg -H # 人类友好格式(彩色+时间)
# 过滤日志
dmesg | grep "my_driver" # 过滤特定驱动的日志
dmesg | grep -i "error\|warn\|fail" # 过滤错误和警告
dmesg | grep "usb" # 过滤 USB 相关日志
dmesg | grep "i2c" # 过滤 I2C 相关日志
# 日志级别过滤
dmesg -l err # 只显示错误级别
dmesg -l warn,err # 显示警告和错误
dmesg -l debug # 显示调试信息
# 控制 printk 输出级别
cat /proc/sys/kernel/printk
# 7 4 1 7
# 当前控制台级别 / 默认消息级别 / 最低控制台级别 / 启动默认级别
echo 8 > /proc/sys/kernel/printk # 显示所有级别(包括 DEBUG)
echo 3 > /proc/sys/kernel/printk # 只显示错误及以上
# 设置内核日志缓冲区大小(启动参数)
# log_buf_len=16M
C.4.2 /proc 文件系统
bash
# 内核信息
cat /proc/version # 内核版本
cat /proc/cmdline # 内核启动参数
cat /proc/interrupts # 中断统计
cat /proc/iomem # I/O 内存映射
cat /proc/ioports # I/O 端口映射
cat /proc/modules # 已加载模块
cat /proc/devices # 设备号分配
cat /proc/filesystems # 支持的文件系统
cat /proc/mounts # 已挂载的文件系统
cat /proc/net/dev # 网络设备统计
# 进程信息
cat /proc/1234/maps # 进程内存映射
cat /proc/1234/status # 进程状态
cat /proc/1234/fd/ # 进程打开的文件描述符
ls -la /proc/1234/fd/ # 查看文件描述符
# 内存信息
cat /proc/meminfo # 内存详细信息
cat /proc/slabinfo # slab 缓存信息
cat /proc/buddyinfo # 伙伴系统信息
cat /proc/vmstat # 虚拟内存统计
# 中断信息
cat /proc/interrupts # 中断计数
# 输出示例:
# CPU0 CPU1
# 0: 12345 0 GIC 27 arch_timer
# 32: 1234 0 GIC 32 uart-pl011
# 查看特定中断
watch -n 1 "cat /proc/interrupts | grep uart" # 实时监控 UART 中断
C.4.3 动态调试控制
bash
# 查看动态调试控制文件
cat /sys/kernel/debug/dynamic_debug/control | head -20
# 开启特定模块的调试输出
echo "module my_driver +p" > /sys/kernel/debug/dynamic_debug/control
# 开启并显示文件名、行号、函数名
echo "module my_driver +pflm" > /sys/kernel/debug/dynamic_debug/control
# 按文件开启
echo "file drivers/my_driver.c +p" > /sys/kernel/debug/dynamic_debug/control
# 按函数开启
echo "func my_driver_probe +p" > /sys/kernel/debug/dynamic_debug/control
# 关闭调试输出
echo "module my_driver -p" > /sys/kernel/debug/dynamic_debug/control
# 开启所有调试(谨慎!输出量极大)
echo "all +p" > /sys/kernel/debug/dynamic_debug/control
echo "all -p" > /sys/kernel/debug/dynamic_debug/control
C.5 ftrace 跟踪工具
bash
# ftrace 基本操作
cd /sys/kernel/debug/tracing
# 查看可用跟踪器
cat available_tracers
# blk function_graph wakeup_dl wakeup_rt wakeup function nop
# 设置跟踪器
echo function > current_tracer # 函数跟踪
echo function_graph > current_tracer # 函数图跟踪
echo nop > current_tracer # 关闭跟踪
# 设置过滤函数
echo "my_driver_*" > set_ftrace_filter # 只跟踪 my_driver_ 开头的函数
echo "i2c_transfer" >> set_ftrace_filter
cat set_ftrace_filter # 查看当前过滤器
echo > set_ftrace_filter # 清除过滤器(跟踪所有函数)
# 开始/停止跟踪
echo 1 > tracing_on # 开始跟踪
echo 0 > tracing_on # 停止跟踪
# 查看跟踪结果
cat trace # 查看跟踪缓冲区
cat trace_pipe # 实时读取(流式)
# 清空跟踪缓冲区
echo > trace
# 事件跟踪
ls events/ # 查看可用事件类别
ls events/i2c/ # I2C 事件
echo 1 > events/i2c/enable # 使能所有 I2C 事件
echo 1 > events/i2c/i2c_write/enable # 使能特定事件
echo 0 > events/i2c/enable # 禁用所有 I2C 事件
# 使用 trace-cmd 工具(更方便)
trace-cmd record -p function -l "my_driver_*" cat /dev/my_device
trace-cmd report # 分析结果
trace-cmd record -e i2c sleep 5 # 记录 I2C 事件 5 秒
trace-cmd report | grep "i2c_write" # 过滤结果
# 函数图跟踪示例
echo function_graph > current_tracer
echo "my_driver_read" > set_graph_function
echo 1 > tracing_on
cat /dev/my_device
echo 0 > tracing_on
cat trace
# 输出示例:
# 0) | my_driver_read() {
# 0) 0.123 us | mutex_lock();
# 0) 0.456 us | copy_to_user();
# 0) 0.789 us | mutex_unlock();
# 0) 1.368 us | }
C.6 perf 性能分析工具
bash
# perf stat:性能统计
perf stat ./my_app # 统计程序性能
perf stat -e cycles,instructions ./my_app # 统计特定事件
perf stat -e cache-misses,cache-references ./my_app # Cache 统计
perf stat -a sleep 5 # 统计系统整体 5 秒
# perf top:实时热点
sudo perf top # 实时显示 CPU 热点函数
sudo perf top -p 1234 # 只分析特定进程
sudo perf top -K # 只显示内核函数
sudo perf top -e cache-misses # 按 Cache 缺失排序
# perf record + report:详细分析
sudo perf record -g ./my_app # 记录(-g 记录调用栈)
sudo perf record -g -a sleep 10 # 记录所有 CPU 10 秒
sudo perf report # 交互式分析
sudo perf report --stdio # 文本格式输出
sudo perf report --stdio | head -50 # 查看前50行
# perf trace:系统调用跟踪
sudo perf trace ./my_app # 跟踪系统调用
sudo perf trace -e open,read,write ./my_app # 只跟踪特定系统调用
# perf annotate:汇编级分析
sudo perf annotate my_driver_read # 显示热点函数的汇编
# 生成火焰图
git clone https://github.com/brendangregg/FlameGraph
sudo perf record -g -F 99 ./my_app
sudo perf script | ./FlameGraph/stackcollapse-perf.pl | \
./FlameGraph/flamegraph.pl > flamegraph.svg
# 用浏览器打开 flamegraph.svg
# 分析内核驱动
sudo perf record -g -e cycles:k -a sleep 10 # 只记录内核态
sudo perf report --stdio | grep "my_driver"
# 比较两次结果
sudo perf record -o before.data ./my_app_v1
sudo perf record -o after.data ./my_app_v2
sudo perf diff before.data after.data
C.7 strace 系统调用跟踪
bash
# 基本用法
strace ./my_app # 跟踪所有系统调用
strace -p 1234 # 跟踪已运行的进程
# 过滤系统调用
strace -e trace=open,read,write,ioctl ./my_app # 只跟踪特定系统调用
strace -e trace=file ./my_app # 跟踪文件相关系统调用
strace -e trace=network ./my_app # 跟踪网络相关系统调用
strace -e trace=signal ./my_app # 跟踪信号相关系统调用
# 显示时间信息
strace -t ./my_app # 显示时间戳
strace -T ./my_app # 显示每个系统调用的耗时
strace -r ./my_app # 显示相对时间
# 统计信息
strace -c ./my_app # 统计系统调用次数和耗时
# 输出示例:
# % time seconds usecs/call calls errors syscall
# ------ ----------- ----------- --------- --------- ----------------
# 45.23 0.001234 12 100 0 read
# 30.12 0.000823 82 10 0 ioctl
# 跟踪子进程
strace -f ./my_app # 跟踪 fork 的子进程
# 保存到文件
strace -o strace.log ./my_app # 输出到文件
strace -o strace.log -e trace=ioctl ./my_app
# 驱动调试示例
strace -e trace=open,read,write,ioctl,close ./test_my_driver
# 输出示例:
# open("/dev/my_device", O_RDWR) = 3
# ioctl(3, 0x1, 0) = 0
# write(3, "Hello", 5) = 5
# read(3, "Hello", 5) = 5
# close(3) = 0
C.8 GDB 调试工具
C.8.1 GDB 基本命令
bash
# 启动 GDB
gdb ./my_app # 调试用户空间程序
gdb vmlinux # 调试内核(配合 QEMU)
gdb -p 1234 # 附加到运行中的进程
# GDB 常用命令
(gdb) run # 运行程序
(gdb) run arg1 arg2 # 带参数运行
(gdb) quit # 退出 GDB
# 断点
(gdb) break main # 在 main 函数设置断点
(gdb) break my_driver.c:45 # 在文件第45行设置断点
(gdb) break my_driver_read # 在函数入口设置断点
(gdb) info breakpoints # 查看所有断点
(gdb) delete 1 # 删除断点1
(gdb) disable 1 # 禁用断点1
(gdb) enable 1 # 启用断点1
# 执行控制
(gdb) continue # 继续执行(c)
(gdb) next # 执行下一行,不进入函数(n)
(gdb) step # 执行下一行,进入函数(s)
(gdb) finish # 执行到当前函数返回
(gdb) until 50 # 执行到第50行
# 查看变量
(gdb) print val # 打印变量值(p)
(gdb) print *ptr # 打印指针指向的值
(gdb) print dev->count # 打印结构体成员
(gdb) display val # 每次停止时自动显示变量
(gdb) info locals # 显示所有局部变量
(gdb) info args # 显示函数参数
# 查看内存
(gdb) x/16xb 0xffff880007a80000 # 以十六进制字节显示16字节
(gdb) x/4xw dev->mem # 以十六进制字显示4个字
(gdb) x/s buf # 以字符串显示
# 查看调用栈
(gdb) backtrace # 显示调用栈(bt)
(gdb) frame 2 # 切换到第2帧
(gdb) info frame # 显示当前帧信息
# 查看寄存器
(gdb) info registers # 显示所有寄存器
(gdb) info registers rax rbx # 显示特定寄存器
# 修改变量
(gdb) set variable val = 10 # 修改变量值
(gdb) set *ptr = 0 # 修改指针指向的值
C.8.2 GDB 调试内核模块
bash
# 步骤1:启动 QEMU 并开启 GDB 服务
qemu-system-arm \
-M vexpress-a9 \
-kernel arch/arm/boot/zImage \
-dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb \
-initrd initramfs.img \
-nographic \
-s -S # -s: 监听 1234 端口,-S: 启动时暂停
# 步骤2:在另一个终端启动 GDB
arm-linux-gnueabihf-gdb vmlinux
# 步骤3:连接到 QEMU
(gdb) target remote :1234
# 步骤4:加载模块符号(模块加载后)
# 先在 QEMU 中加载模块,获取地址
# cat /sys/module/my_driver/sections/.text
# 0xbf001000
(gdb) add-symbol-file my_driver.ko 0xbf001000
# 步骤5:设置断点并调试
(gdb) break my_driver_probe
(gdb) continue
C.9 内存检测工具
C.9.1 Valgrind
bash
# Memcheck:内存错误检测
valgrind --leak-check=full ./my_app # 检测内存泄漏
valgrind --leak-check=full \
--show-leak-kinds=all \
--track-origins=yes \
./my_app # 详细内存检测
# 常见输出解读:
# ==1234== Invalid write of size 1 ← 越界写
# ==1234== Invalid read of size 4 ← 越界读
# ==1234== Use of uninitialised value ← 使用未初始化变量
# ==1234== definitely lost: 1024 bytes ← 内存泄漏
# Callgrind:函数调用分析
valgrind --tool=callgrind ./my_app
callgrind_annotate callgrind.out.1234 # 分析结果
# Helgrind:线程错误检测
valgrind --tool=helgrind ./my_app_threaded
# Massif:内存使用分析
valgrind --tool=massif ./my_app
ms_print massif.out.1234 # 分析结果
C.9.2 kmemleak(内核内存泄漏)
bash
# 触发扫描
echo scan > /sys/kernel/debug/kmemleak
# 查看泄漏报告
cat /sys/kernel/debug/kmemleak
# 清除已知泄漏
echo clear > /sys/kernel/debug/kmemleak
# 禁用 kmemleak
echo off > /sys/kernel/debug/kmemleak
C.10 网络调试工具
bash
# 查看网络接口
ip link show # 显示所有网络接口
ip addr show # 显示 IP 地址
ifconfig # 传统命令(需要 net-tools)
# 配置网络接口
ip link set eth0 up # 启动接口
ip link set eth0 down # 关闭接口
ip addr add 192.168.1.100/24 dev eth0 # 添加 IP 地址
ip route add default via 192.168.1.1 # 添加默认路由
# 网络测试
ping 192.168.1.1 # 测试连通性
ping -c 4 8.8.8.8 # 发送4个包
traceroute 8.8.8.8 # 路由跟踪
# 查看网络统计
cat /proc/net/dev # 网络设备统计
netstat -s # 协议统计
ss -tuln # 查看监听端口
# 抓包工具
tcpdump -i eth0 # 抓取 eth0 上的所有包
tcpdump -i eth0 port 80 # 只抓 HTTP 包
tcpdump -i eth0 -w capture.pcap # 保存到文件
tcpdump -r capture.pcap # 读取文件
# 网络驱动调试
ethtool eth0 # 查看网卡信息
ethtool -i eth0 # 查看驱动信息
ethtool -s eth0 speed 100 duplex full # 设置速率
ethtool -S eth0 # 查看统计信息
ip -s link show eth0 # 查看接口统计
C.11 存储设备调试工具
bash
# MTD 设备操作
cat /proc/mtd # 查看 MTD 设备
flash_erase /dev/mtd0 0 0 # 擦除整个分区
nandwrite -p /dev/mtd1 kernel.bin # 写入 NAND Flash
nanddump /dev/mtd1 -f kernel.bin # 读取 NAND Flash
nandtest /dev/mtd2 # 测试坏块
# 块设备操作
lsblk # 列出块设备
fdisk -l /dev/sda # 查看分区
mkfs.ext4 /dev/sdb1 # 格式化
mount /dev/sdb1 /mnt/usb # 挂载
umount /mnt/usb # 卸载
# 磁盘性能测试
dd if=/dev/zero of=/dev/sdb bs=4096 count=1000 # 写性能测试
dd if=/dev/sdb of=/dev/null bs=4096 count=1000 # 读性能测试
# 输出:1000+0 records in, 1000+0 records out, 4096000 bytes copied, 0.5 s, 8.2 MB/s
# I/O 统计
iostat -x 1 # 实时 I/O 统计
cat /sys/block/sda/stat # 块设备统计
C.12 串口调试工具
bash
# 查看串口设备
ls /dev/ttyS* # 标准串口
ls /dev/ttyUSB* # USB 转串口
ls /dev/ttyACM* # USB CDC 串口
# 配置串口
stty -F /dev/ttyS0 115200 # 设置波特率
stty -F /dev/ttyS0 115200 cs8 -cstopb -parenb # 完整配置(8N1)
stty -F /dev/ttyS0 -a # 查看当前配置
# 串口通信
cat /dev/ttyS0 # 接收数据
echo "hello" > /dev/ttyS0 # 发送数据
cat /dev/ttyS0 & echo "hello" > /dev/ttyS0 # 同时收发
# minicom(串口终端)
minicom -D /dev/ttyUSB0 -b 115200 # 连接串口
# Ctrl+A Z:帮助菜单
# Ctrl+A X:退出
# screen(串口终端)
screen /dev/ttyUSB0 115200 # 连接串口
# Ctrl+A K:退出
# picocom(轻量级串口终端)
picocom -b 115200 /dev/ttyUSB0 # 连接串口
# Ctrl+A Ctrl+X:退出
C.13 输入设备调试工具
bash
# 查看输入设备
cat /proc/bus/input/devices # 列出所有输入设备
ls /dev/input/ # 输入设备文件
# evtest:测试输入事件
sudo evtest /dev/input/event0 # 测试特定设备
sudo evtest # 列出所有设备并选择
# 输出示例:
# Event: time 1234567890.123456, type 3 (EV_ABS), code 53 (ABS_MT_POSITION_X), value 320
# Event: time 1234567890.123456, type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 240
# Event: time 1234567890.123456, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 1
# Event: time 1234567890.123456, type 0 (EV_SYN), code 0 (SYN_REPORT), value 0
# showkey:查看按键码
showkey # 显示按键的键码
showkey -a # 显示 ASCII 码
# hexdump 查看原始事件数据
hexdump -C /dev/input/event0
# 00000000 xx xx xx xx xx xx xx xx 02 00 01 00 01 00 00 00 |................|
# 时间戳(8B) + type(2B) + code(2B) + value(4B)
C.14 电源管理调试工具
bash
# CPUFreq 调试
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor # 当前调速器
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq # 当前频率
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies # 可用频率
echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor # 切换调速器
# CPUIdle 调试
cat /sys/devices/system/cpu/cpu0/cpuidle/state0/name # 空闲状态名称
cat /sys/devices/system/cpu/cpu0/cpuidle/state0/usage # 进入次数
cat /sys/devices/system/cpu/cpu0/cpuidle/state0/time # 停留时间(μs)
# Runtime PM 调试
cat /sys/bus/i2c/devices/1-0048/power/runtime_status # 运行时状态
cat /sys/bus/i2c/devices/1-0048/power/runtime_usage # 引用计数
cat /sys/bus/i2c/devices/1-0048/power/autosuspend_delay_ms # 自动挂起延迟
# 系统挂起调试
cat /sys/power/state # 支持的挂起状态
echo mem > /sys/power/state # 挂起到内存
echo freeze > /sys/power/state # 冻结
# PowerTOP:功耗分析
sudo powertop # 交互式功耗分析
sudo powertop --html=report.html # 生成 HTML 报告
sudo powertop --auto-tune # 自动优化功耗设置
# Regulator 调试
ls /sys/class/regulator/ # 列出所有调节器
cat /sys/class/regulator/regulator.0/name # 调节器名称
cat /sys/class/regulator/regulator.0/microvolts # 当前电压(μV)
cat /sys/class/regulator/regulator.0/state # 状态(enabled/disabled)
C.15 文件系统与权限
bash
# 文件操作
ls -la # 详细列表(含隐藏文件)
ls -lh # 人类可读大小
find /dev -name "ttyS*" # 查找文件
find . -name "*.ko" -type f # 查找内核模块文件
locate my_driver.ko # 快速查找(需要 updatedb)
# 文件权限
chmod 644 my_file # 设置权限(rw-r--r--)
chmod 755 my_script.sh # 设置权限(rwxr-xr-x)
chmod a+x my_script.sh # 所有用户添加执行权限
chown root:root my_file # 修改所有者
sudo chown -R driver:driver /dev/my_device # 递归修改
# 查看文件类型
file my_driver.ko # 查看文件类型
# my_driver.ko: ELF 32-bit LSB relocatable, ARM, EABI5 version 1 (SYSV)
# 文本处理
grep "error" dmesg.log # 搜索文本
grep -r "my_driver" /proc/ # 递归搜索
grep -n "printk" my_driver.c # 显示行号
grep -i "error" dmesg.log # 忽略大小写
awk '{print $1, $3}' /proc/interrupts # 提取列
sed 's/old/new/g' file.txt # 替换文本
sort /proc/modules | head -10 # 排序
wc -l my_driver.c # 统计行数
# 压缩和解压
tar -xf linux-4.0.tar.xz # 解压 .tar.xz
tar -czf backup.tar.gz my_driver/ # 压缩目录
gzip my_file # 压缩文件
gunzip my_file.gz # 解压文件
C.16 进程与任务管理
bash
# 进程管理
ps aux # 所有进程
ps aux | grep my_app # 过滤进程
kill 1234 # 发送 SIGTERM 信号
kill -9 1234 # 强制终止(SIGKILL)
killall my_app # 按名称终止
# 后台任务
./my_app & # 后台运行
nohup ./my_app & # 后台运行(忽略挂断信号)
jobs # 查看后台任务
fg 1 # 将任务1调到前台
bg 1 # 将任务1放到后台
# 优先级
nice -n 10 ./my_app # 以低优先级运行
renice -n -5 -p 1234 # 修改进程优先级
chrt -f 50 ./my_realtime_app # 以实时优先级运行(SCHED_FIFO)
# 系统调用跟踪
strace -p 1234 # 跟踪运行中的进程
ltrace -p 1234 # 跟踪库函数调用
# 内存使用
pmap 1234 # 查看进程内存映射
cat /proc/1234/status | grep VmRSS # 查看物理内存使用
C.17 编译与构建工具
bash
# GCC 编译
gcc -o my_app my_app.c # 编译
gcc -g -o my_app my_app.c # 编译(含调试信息)
gcc -O2 -o my_app my_app.c # 优化编译
gcc -Wall -Wextra -o my_app my_app.c # 开启所有警告
arm-linux-gnueabihf-gcc -o my_app my_app.c # 交叉编译
# 内核模块编译
make # 编译模块
make clean # 清理
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- # 交叉编译
# 内核编译
make defconfig # 默认配置
make menuconfig # 图形化配置
make -j$(nproc) # 编译(使用所有 CPU 核心)
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage # ARM 交叉编译
make dtbs # 编译设备树
# 查看编译依赖
ldd my_app # 查看动态库依赖
objdump -d my_app | head -50 # 反汇编
nm my_app | grep " T " # 查看符号表
readelf -h my_app # ELF 头信息
C.18 常用快捷键与技巧
bash
# Shell 快捷键
Ctrl+C # 中断当前命令
Ctrl+Z # 暂停当前命令(放到后台)
Ctrl+D # 退出当前 Shell
Ctrl+L # 清屏
Ctrl+A # 移到行首
Ctrl+E # 移到行尾
Ctrl+U # 删除到行首
Ctrl+K # 删除到行尾
Ctrl+R # 搜索历史命令
Tab # 自动补全
!! # 重复上一条命令
!grep # 重复上一条以 grep 开头的命令
sudo !! # 以 root 权限重复上一条命令
# 管道和重定向
command | grep "pattern" # 管道过滤
command > file.txt # 重定向输出到文件(覆盖)
command >> file.txt # 追加到文件
command 2>&1 | tee file.txt # 同时输出到终端和文件
command 2>/dev/null # 丢弃错误输出
# 常用组合命令
dmesg | tail -20 | grep -i error # 查看最近的错误日志
watch -n 1 "cat /proc/interrupts | grep uart" # 每秒刷新中断统计
while true; do cat /dev/my_device; sleep 1; done # 循环读取设备
# 别名设置(添加到 ~/.bashrc)
alias dmesg='dmesg -T' # dmesg 默认显示时间戳
alias ll='ls -la' # 详细列表
alias grep='grep --color=auto' # 彩色 grep
alias ..='cd ..' # 快速返回上级目录
C.19 调试工具速查表
Linux 驱动调试工具速查:
问题类型 推荐工具 关键命令
─────────────────────────────────────────────────────────────────────
内核日志查看 dmesg dmesg -T | tail -20
调试信息输出控制 动态调试 echo "module xxx +p" > .../control
函数调用链分析 ftrace echo function_graph > current_tracer
性能热点分析 perf perf top / perf record -g
系统调用跟踪 strace strace -e trace=ioctl ./app
内存越界/UAF KASAN(内核) CONFIG_KASAN=y
内存泄漏(内核) kmemleak echo scan > .../kmemleak
内存泄漏(用户空间) Valgrind valgrind --leak-check=full
死锁检测 lockdep CONFIG_PROVE_LOCKING=y
交互式调试 GDB + QEMU target remote :1234
模块信息查看 modinfo modinfo my_driver.ko
设备文件操作 ls/cat/echo/dd cat /dev/my_device
sysfs 操作 cat/echo cat /sys/class/gpio/gpio23/value
I2C 调试 i2c-tools i2cdetect -y 1
输入设备测试 evtest evtest /dev/input/event0
串口调试 minicom/picocom minicom -D /dev/ttyUSB0 -b 115200
网络调试 tcpdump/ethtool tcpdump -i eth0
功耗分析 PowerTOP/perf powertop
Flash 操作 mtd-utils flash_erase / nandwrite
参考文献:宋宝华《Linux设备驱动开发详解:基于最新的Linux 4.0内核》,机械工业出版社,2015年