2. 设备树编译与反编译:DTC工具的使用

设备树编译器(Device Tree Compiler,DTC)是嵌入式Linux开发中最基础也最关键的调试工具之一。它将人类可读的.dts(Device Tree Source)源文件编译为内核引导时使用的二进制.dtb(Device Tree Blob)文件;同时支持将.dtb反编译回.dts,用于逆向分析或调试已部署的设备树。

2.1 DTC工具安装与版本确认

DTC通常随内核源码树提供,路径为 scripts/dtc/dtc。也可通过系统包管理器独立安装:

# Ubuntu / Debian
sudo apt-get install device-tree-compiler

# CentOS / RHEL / Fedora
sudo yum install dtc

# 验证安装
dtc --version
# 输出示例:Version DTC 1.6.1
版本建议:推荐使用 DTC 1.5.0 及以上版本。旧版本(1.4.x)对 #include 路径解析、/delete-node/ 和 /delete-property/ 等高级语法的支持不完整,可能导致编译或反编译结果不一致。

2.2 编译流程:从DTS到DTB

标准编译命令格式如下:

dtc -I dts -O dtb -o <输出.dtb> <输入.dts>

常用参数说明:

参数 含义 示例
-I dts 指定输入格式为DTS源码 默认值,可省略
-O dtb 指定输出格式为DTB二进制 默认值,可省略
-o 指定输出文件名 -o myboard.dtb
-@ 生成符号节点(用于overlay) 设备树插件编译时必须添加
-W no-unit_address_vs_reg 关闭特定警告 兼容老旧DTS时使用

实际编译示例:

# 基本编译
dtc -I dts -O dtb -o imx6ull.dtb imx6ull.dts

# 带符号表(用于overlay)
dtc -@ -I dts -O dtb -o imx6ull-overlay.dtb imx6ull.dts

# 从内核源码树编译
make ARCH=arm dtbs  # 批量编译所有板级DTB
编译检查要点:
  • DTC默认输出警告(warning)和错误(error)。警告可以忽略,但错误必须修复,否则不会生成DTB。
  • 常见错误:语法错误(缺少分号/大括号)、标签重复、引用的节点不存在。
  • 使用 -Werror 可将所有警告升级为错误,适合CI/CD流水线。

2.3 反编译流程:从DTB到DTS

反编译用于查看已部署的DTB内容,或验证编译前后是否一致:

dtc -I dtb -O dts -o <输出.dts> <输入.dtb>

反编译示例:

# 基本反编译
dtc -I dtb -O dts -o imx6ull-decompiled.dts imx6ull.dtb

# 从运行中的系统提取DTB并反编译
cp /sys/firmware/fdt /tmp/current.dtb
dtc -I dtb -O dts -o /tmp/current.dts /tmp/current.dtb
反编译精度说明:反编译得到的DTS与原始DTS在格式和注释上会有差异。原始DTS中的注释、宏定义、#include 引用、标签别名等信息在编译为DTB时已丢失。反编译结果仅保留节点结构、属性名和属性值,适合用于结构分析和值验证,不适合直接作为源码回编。

2.4 编译与反编译流程对比

对比维度 编译 (DTS → DTB) 反编译 (DTB → DTS)
输入格式 文本源码 (.dts / .dtsi) 二进制Blob (.dtb)
输出格式 二进制Blob (.dtb) 文本源码 (.dts)
信息完整性 保留所有结构、属性、标签 丢失注释、宏、#include、标签别名
主要用途 生成内核可加载的设备树 调试、逆向分析、验证DTB内容
常见问题 语法错误、路径引用错误 节点顺序可能重排,地址格式可能变化

2.5 编译与反编译数据流

下图展示了DTS源码经过DTC编译生成DTB,以及DTB反编译回DTS的完整数据流与中间表示层:

DTC 编译与反编译数据流 DTS 源码 .dts / .dtsi (人类可读文本) DTC 编译器 dtc -I dts -O dtb (词法/语法/语义分析) DTB 二进制 .dtb (扁平化二进制Blob) DTC 反编译器 dtc -I dtb -O dts (结构还原/值格式化) 反编译 DTS .dts (无注释) (结构完整/注释丢失) ⚠ 反编译DTS不可直接回编:丢失注释、宏定义、#include引用和标签别名 反编译结果仅用于结构分析和值验证,不可替代原始DTS源码

2.6 常用调试选项与技巧

  • 查看DTB内部结构(不反编译):
    dtc -I dtb -O dts --sort myboard.dtb | head -50
    --sort 按字母顺序排序节点,便于对比不同版本的DTB。
  • 检查DTB中特定属性值:
    dtc -I dtb -O dts myboard.dtb | grep "compatible\|reg\|interrupts"
  • 编译时保留符号表(用于overlay调试):
    dtc -@ -I dts -O dtb -o myboard.dtb myboard.dts
  • 从内核启动日志提取DTB:
    # 内核启动时打印DTB基地址
    dmesg | grep -i "fdt\|device tree"
    # 若内核支持,可通过debugfs导出
    cat /sys/kernel/debug/device_tree/fdt > /tmp/debug.dtb

2.7 常见编译错误与排查

错误信息 原因 解决方案
ERROR: Input tree has errors DTS语法错误 检查大括号、分号、引号是否匹配
WARNING: node has a unit name but no reg property 节点地址格式不匹配 添加 reg 属性或移除地址后缀
FATAL: Cannot open input file 文件路径错误或权限不足 检查文件是否存在及读取权限
ERROR: label or path not found 引用的标签或节点路径不存在 检查 &label 或 &/path 是否正确
WARNING: Property 'status' has invalid value status 属性值不是 okay/disabled/fail 修正为标准值
调试最佳实践:在修改DTS后,先执行 dtc -I dts -O dtb -o /dev/null myboard.dts 进行语法检查(输出到空设备),确认无错误后再生成正式DTB。对于大型DTS,可使用 dtc -I dts -O dtb -o myboard.dtb myboard.dts 2>&1 | tee build.log 将编译日志保存到文件,便于回溯分析。