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的完整数据流与中间表示层:
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 将编译日志保存到文件,便于回溯分析。