《Linux 设备驱动开发详解:基于最新的 Linux 4.0 内核》 附录 C 常用 Linux 命令与调试工具速查

《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年