Linux 内核调试工具使用案例

2次阅读

kdump捕获失败主因是crashkernel内存未预留或未跳转至capture kernel;perf调用缺失源于config_frame_pointer关闭、无调试符号或perf_event_paranoid过高;kgdb连不上多因串口参数不匹配或vmlinux符号不全;trace-cmd与ftrace结果差异由缓冲区模式及事件过滤时机导致。

Linux 内核调试工具使用案例

怎么用 kdump 抓到真正的内核 panic 崩溃现场

很多情况下 kdump 配置完却没生成 /var/crash/ 下的 vmcore,不是没崩溃,而是捕获失败了。关键得确认两件事:预留内存是否真被保留、崩溃时是否真的跳转到了 capture kernel。

  • 检查 /proc/cmdline 里有没有 crashkernel= 参数,比如 crashkernel=128M;没有就白配
  • systemctl status kdump 必须显示 active,且日志里不能有 Failed to reserve crashkernel memory
  • 手动触发 panic 测试:echo c > /proc/sysrq-trigger,然后立刻看 dmesg -T | tail -20 是否出现 Starting crashdump kernel...
  • 如果卡在原 kernel 不跳转,常见原因是 BIOS 中开启了 Secure Boot(部分发行版不兼容)或 IOMMU 导致预留内存映射失败

perf 抓不到函数调用栈?先看这三处配置

perf record -g 经常只显示 [unknown] 或扁平化符号,根本看不到调用链——这不是 perf 坏了,而是符号信息或权限没到位。

  • 确保内核编译时开了 CONFIG_FRAME_POINTER=y(x86_64 默认开,但某些裁剪版可能关)
  • 用户态程序必须带调试符号:gcc -g 编译,否则 perf script 解不出来函数名
  • /proc/sys/kernel/perf_event_paranoid 必须 ≤ 2,否则普通用户无法采集栈帧;设成 -1 最保险(需 root)
  • 注意:ARM64 上默认用 fp 栈回溯,但若内核启用了 CONFIG_UNWINDER_ORCperf 可能不兼容,此时临时切回 CONFIG_UNWINDER_FRAME_POINTER

kgdb 连不上?串口和内核参数缺一不可

kgdb 不是插上线就能断点,主机和目标机之间连通性、内核启动参数、GDB 加载符号三者必须严丝合缝。

  • 目标机启动参数必须含:kgdboc=ttyS0,115200 kgdbwait(注意串口号和波特率要和实际硬件一致)
  • 主机用 gdb vmlinux 后,执行 target remote /dev/ttyUSB0,别用 screenminicom 占着串口
  • vmlinux 文件必须和目标机运行的内核完全匹配(同一编译输出,不能是 distro 提供的 stripped 版)
  • 常见失败现象:Remote 'g' packet reply is too long —— 多半是 vmlinux 符号表损坏或 GDB 版本太老(建议用 10.2+)

trace-cmd 录下来的事件为什么和 ftrace 看到的对不上

trace-cmd record 和直接读 /sys/kernel/tracing/trace 行为不等价,核心差异在缓冲区模式和事件过滤时机。

  • trace-cmd 默认用 per-CPU ring buffer,而 cat /sys/kernel/tracing/trace 是 snapshot 模式,会清空 buffer;混用会导致丢失事件
  • 启用特定 tracepoint 前,必须先关掉其他高频率事件(如 sched_switch),否则 buffer 溢出后自动丢弃旧事件,trace-cmd report 就看不到开头部分
  • trace-cmd record -e sched:sched_wakeup 是动态使能,但若内核启动时已通过 ftrace_enabled=0 关闭整个 ftrace 子系统,则无效
  • 导出时别依赖 trace-cmd report -F 的默认格式,加 --ts 才能对齐时间戳,否则和 dmesg 时间无法交叉验证

真正难的不是启动工具,是判断哪一层丢了上下文:是硬件没上报、内核没记录、还是用户空间读取时被截断。每次怀疑抓漏了,先比对 /sys/kernel/tracing/buffer_size_kb 和事件速率,再查 /sys/kernel/tracing/trace_buffer_overrun 计数。

text=ZqhQzanResources