内核调试
一、printk
1. 基本用法
printk(KERN_INFO "msg\n"); // 老 API
pr_info("msg %d\n", x); // 推荐
pr_err("error %d\n", x);
pr_warn("warning\n");
dev_info(dev, "msg"); // 自动加设备名
dev_err(dev, "msg");
// 日志级别
#define KERN_EMERG "<0>" // 系统不可用
#define KERN_ALERT "<1>" // 必须立即处理
#define KERN_CRIT "<2>" // 严重
#define KERN_ERR "<3>" // 错误
#define KERN_WARNING "<4>" // 警告
#define KERN_NOTICE "<5>" // 正常但重要
#define KERN_INFO "<6>" // 信息
#define KERN_DEBUG "<7>" // 调试
2. 控制台日志级别
# 查看 / 设置
cat /proc/sys/kernel/printk
echo 8 > /proc/sys/kernel/printk # 所有级别都打
dmesg -n 8
dmesg -w # 实时
dmesg -c # 清空
# 内核启动参数
loglevel=7
ignore_loglevel
quiet
3. ratelimited(防刷屏)
pr_info_ratelimited("...");
dev_info_ratelimited(dev, "...");
二、Dynamic Debug
# 启用
echo "file drivers/gpio/gpiolib.c +p" > /sys/kernel/debug/dynamic_debug/control
echo "module mymodule +p" > /sys/kernel/debug/dynamic_debug/control
echo "func my_probe +p" > /sys/kernel/debug/dynamic_debug/control
# 全部
echo "+p" > /sys/kernel/debug/dynamic_debug/control
# 关闭
echo "file gpiolib.c -p" > /sys/kernel/debug/dynamic_debug/control
源码中:
pr_debug("value: %d\n", val); // 需要 CONFIG_DYNAMIC_DEBUG
三、dump_stack
WARN_ON(condition);
BUG_ON(condition);
dump_stack(); // 打印调用栈
WARN(1, "msg");
四、kgdb / kdb
- 通过串口 + gdb 远程调试内核
- 需要
CONFIG_KGDB=y、CONFIG_KGDB_SERIAL_CONSOLE=y - 触发:
echo g > /proc/sysrq-trigger - gdb:
(gdb) target remote /dev/ttyS0
五、oops / panic 分析
# 内核配置
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_INFO=y
# 保存 oops
dmesg > oops.txt
# 用 addr2line / decode
addr2line -e vmlinux 0xc0123456
gdb vmlinux
(gdb) list *0xc0123456
六、ftrace
mount -t tracefs none /sys/kernel/tracing
# 函数跟踪
echo function > /sys/kernel/tracing/current_tracer
echo my_func > /sys/kernel/tracing/set_ftrace_filter
echo 1 > /sys/kernel/tracing/tracing_on
cat /sys/kernel/tracing/trace
echo 0 > /sys/kernel/tracing/tracing_on
# trace-cmd(推荐工具)
trace-cmd record -p function -l my_func ls
trace-cmd report
# 其他 tracer
function_graph
wakeup_rt
irqsoff
preemptoff
七、perf
# 列出事件
perf list
# record / report
perf record -g -e cycles -a sleep 5
perf report
# 调度延迟
perf sched record sleep 5
perf sched latency
# cache 命中率
perf stat -e cache-misses,cache-references ls
# 函数采样
perf top
perf top -e cpu-clock
# tracepoint
perf record -e sched:sched_switch -a
perf script
# 锁竞争
perf lock contention -a
八、eBPF / bcc / bpftrace
- 现代内核追踪利器
- 安全、高效、可编程
# bpftrace
bpftrace -e 'kprobe:do_sys_open { printf("%s\n", argstr(1)); }'
# bcc 工具
opensnoop-bpfcc
execsnoop-bpfcc
tcpconnect-bpfcc
biolatency-bpfcc
runqlat-bpfcc
softirqs-bpfcc
九、kprobes / uprobes
// 内核模块动态追踪
// 见 samples/kprobes/
十、Crashdump / kdump
# 安装
apt install kdump-tools
# 配置 /etc/default/kdump-tools
USE_KDUMP=1
# 触发
echo c > /proc/sysrq-trigger # SysRq-C:触发 panic
# 分析
crash /usr/lib/debug/vmlinux /var/crash/2026*/vmcore
crash> bt
crash> log
crash> ps
十一、SysRq
# 启用
echo 1 > /proc/sys/kernel/sysrq
# 远程触发
echo t > /proc/sysrq-trigger # 任务状态
echo m > /proc/sysrq-trigger # 内存
echo w > /proc/sysrq-trigger # 阻塞任务
echo l > /proc/sysrq-trigger # CPU 注册
echo s > /proc/sysrq-trigger # 同步
echo u > /proc/sysrq-trigger # 重挂载只读
echo b > /proc/sysrq-trigger # 重启(慎用!)
echo c > /proc/sysrq-trigger # panic(触发 crashdump)
echo h > /proc/sysrq-trigger # 帮助
十二、strace / ltrace
strace -e openat,read,write -p PID
strace -c -p PID # 统计
strace -f -e trace=network cmd
十三、devmem
# 读物理地址
devmem 0x40010000 32
devmem 0x40010000 16
# 写
devmem 0x40010000 32 0x12345678
十四、lockdep
# 启用
echo 1 > /proc/sys/kernel/lock_stat
cat /proc/lock_stat
# 锁错误会打印调用链
十五、UBSan / KASan / KMSan
# 内核配置
CONFIG_UBSAN=y
CONFIG_KASAN=y
CONFIG_KMSAN=y
CONFIG_KCSAN=y # 数据竞争检测
# 报告
dmesg | grep -E "KASAN|UBSAN|KMSAN"
十六、调试工具汇总
| 工具 | 用途 |
|---|---|
| printk | 日志 |
| dmesg | 看内核日志 |
| ftrace | 函数追踪、延迟 |
| perf | 性能分析、采样 |
| bpftrace | 高级追踪 |
| kgdb | 远程调试 |
| crash | core dump 分析 |
| devmem | 物理内存读 |
| devlink | 设备调试 |
| i2c-tools / spidev / spidev_test | 总线调试 |
| strace | 用户态跟踪 |