3. 调试选项概述:内核调试配置项分类

内核调试选项是 Kconfig 中规模最大、对编译性能影响最直接的配置族。在默认的 defconfig 或发行版内核配置中,调试选项往往被大量开启,导致编译时间增加 30%~60%,生成的内核镜像体积膨胀 2~5 倍。本章从分类角度系统梳理内核调试配置项,为后续的裁剪优化建立知识基础。

3.1 调试选项的层次结构

内核调试配置项并非平铺罗列,而是通过 depends on 和 select 形成三层依赖树。顶层开关控制底层子选项的可见性,理解这一结构是精准裁剪的前提。

关键原则:关闭顶层开关(如 DEBUG_KERNEL)可一次性隐藏数十个依赖子选项,大幅简化裁剪工作。
内核调试选项三层依赖树 DEBUG_KERNEL DEBUG_INFO DYNAMIC_DEBUG LOCKDEP / STACKTRACE DEBUG_INFO_DWARF5 DEBUG_INFO_BTF DYNAMIC_DEBUG_CORE LOCK_STAT STACKTRACE 裁剪策略 关闭 DEBUG_KERNEL → 隐藏所有中层选项 → 底层子选项自动不可见 无需逐一手动关闭数十个底层选项,一次操作即可完成

3.2 核心调试配置项分类

根据功能属性和编译影响,内核调试选项可分为以下六大类。每类对编译时间和镜像大小的影响权重差异显著。

分类 代表配置项 编译时间影响 镜像体积影响 裁剪优先级
通用调试框架 DEBUG_KERNEL, DEBUG_FS 中(+10%~15%) 小(+2%~5%) 高
调试符号与元数据 DEBUG_INFO, DEBUG_INFO_DWARF5, DEBUG_INFO_BTF 极高(+30%~50%) 极大(+200%~400%) 最高
动态调试与日志 DYNAMIC_DEBUG, DYNAMIC_DEBUG_CORE 低(+3%~5%) 中(+5%~10%) 中
锁与并发调试 LOCKDEP, LOCK_STAT, DEBUG_ATOMIC_SLEEP 高(+15%~25%) 中(+10%~15%) 高
内存与错误检测 KASAN, UBSAN, DEBUG_PAGEALLOC 极高(+40%~80%) 大(+20%~30%) 最高
跟踪与性能分析 FTRACE, PERF_EVENTS, STACKTRACE 中(+8%~12%) 中(+5%~10%) 中
裁剪优先级说明:“最高”优先级的选项在生产环境内核中应无条件关闭;“高”优先级选项在非调试场景下应关闭;“中”优先级选项可根据实际需求选择性保留。

3.3 关键配置项详解

3.3.1 DEBUG_KERNEL — 调试选项的总闸

DEBUG_KERNEL 是内核调试选项的顶层开关,定义在 lib/Kconfig.debug 中。它本身不产生任何代码,但作为数十个子选项的 depends on 前置条件。关闭此选项后,绝大多数调试子选项将自动从菜单中消失,无法被选中。

# lib/Kconfig.debug 中的典型依赖模式
config DEBUG_KERNEL
    bool "Kernel debugging"
    help
      Say Y here if you are developing drivers or trying to debug.

config LOCKDEP
    bool "Lock dependency validator"
    depends on DEBUG_KERNEL && TRACE_IRQFLAGS
    select STACKTRACE
    help
      Runtime lock dependency checking.

3.3.2 DEBUG_INFO — 编译体积膨胀的元凶

DEBUG_INFO 控制是否生成 DWARF 调试符号。开启后,编译器会向每个编译单元插入完整的类型信息、变量位置和行号映射,导致 .ko 和 vmlinux 体积膨胀 3~5 倍。其子选项 DEBUG_INFO_DWARF5 使用更新的 DWARF5 格式,体积更大但调试体验更好。

性能影响数据:开启 DEBUG_INFO 后,单次全量编译时间增加约 35%~50%,磁盘占用增加 2~4 GB。对于不需要内核调试的嵌入式或生产环境,这是最应优先关闭的选项。

3.3.3 DYNAMIC_DEBUG — 运行时日志控制

DYNAMIC_DEBUG 允许在运行时动态开启/关闭内核中的 pr_debug() 和 dev_dbg() 输出,无需重新编译。它通过 debugfs 接口暴露控制文件,对编译时间影响较小,但会引入少量运行时开销。

# 运行时控制示例(挂载 debugfs 后)
# 开启所有动态调试输出
echo "file * +p" > /sys/kernel/debug/dynamic_debug/control

# 仅开启特定文件的调试输出
echo "file drivers/net/ethernet/* +p" > /sys/kernel/debug/dynamic_debug/control

# 关闭所有动态调试输出
echo "file * -p" > /sys/kernel/debug/dynamic_debug/control

3.4 调试选项的编译时间权重分析

不同调试选项对编译时间的影响差异巨大。以下基于 Linux 6.x 内核在 8 核 x86_64 平台上的实测数据,展示各选项的编译时间增量权重。

各调试选项编译时间增量权重(相对基准) +80% +60% +40% +20% +0% KASAN +80% DEBUG_INFO +50% UBSAN +40% LOCKDEP +25% DEBUG_KERNEL +12% DYNAMIC_DEBUG +5% FTRACE +10% 基准:关闭所有调试选项的 defconfig 编译时间(约 12 分钟) 关闭 KASAN + DEBUG_INFO + UBSAN 三项即可减少约 60% 的调试编译开销

3.5 调试选项的依赖关系与裁剪陷阱

调试选项之间存在复杂的 select 和 imply 关系,盲目关闭可能导致内核编译失败或功能异常。以下是常见的依赖陷阱及应对策略。

  • 陷阱1:LOCKDEP 自动 select STACKTRACE,关闭 STACKTRACE 前必须先关闭 LOCKDEP。
  • 陷阱2:KASAN 依赖 SLUB 或 SLAB 分配器,切换为 SLOB 后 KASAN 自动不可用。
  • 陷阱3:DEBUG_INFO_BTF 需要 DEBUG_INFO 和 PAHOLE 工具链支持,关闭 DEBUG_INFO 后 BTF 也会消失。
  • 陷阱4:DYNAMIC_DEBUG 依赖 DEBUG_FS,关闭 DEBUG_FS 后动态调试接口不可用,但内核代码中的 pr_debug() 仍会被编译。
最佳实践:使用 make menuconfig 的搜索功能(/ 键)查看每个选项的依赖链。输入 /DEBUG_INFO 可看到所有依赖和反向依赖关系,避免遗漏。

3.6 调试选项裁剪清单速查

以下清单按裁剪优先级排序,适用于生产环境或嵌入式系统的内核编译加速。每项均标注了关闭后的影响评估。

优先级 配置项 关闭影响 适用场景
P0(必须关) DEBUG_INFO, KASAN, UBSAN 无法使用 gdb/kgdb 调试,无内存错误检测 所有生产环境、嵌入式发布版
P1(建议关) LOCKDEP, DEBUG_ATOMIC_SLEEP, DEBUG_PAGEALLOC 无法检测死锁和原子上下文睡眠,无页分配器调试 非驱动开发环境、稳定内核
P2(按需关) DYNAMIC_DEBUG, FTRACE, PERF_EVENTS 无法动态控制日志,无跟踪和性能分析能力 极小化嵌入式系统、资源受限设备
P3(保留) DEBUG_FS, STACKTRACE 部分调试工具和内核模块可能无法正常工作 需要基本诊断能力的系统
快速裁剪命令:在 .config 文件中直接执行以下 sed 命令可批量关闭 P0 和 P1 选项:
sed -i '/CONFIG_DEBUG_INFO/d; /CONFIG_KASAN/d; /CONFIG_UBSAN/d; /CONFIG_LOCKDEP/d' .config
然后运行 make olddefconfig 自动处理依赖关系。

3.7 本章小结