3. 设备树编译与反编译:DTC工具使用、DTS到DTB的编译、DTB反编译为DTS、反编译实战

设备树源文件(.dts)是人类可读的文本描述,而内核引导时实际使用的是二进制格式的设备树二进制文件(.dtb)。设备树编译器(DTC) 是完成这两种格式之间转换的核心工具。掌握 DTC 的使用,是嵌入式 Linux 驱动开发者的基本功。

核心概念: DTC 不仅负责将 .dts 编译为 .dtb,还支持将 .dtb 反编译回 .dts,以及将 .dts 预处理为包含所有 #include 文件的单一文件。这一能力在调试、逆向分析、验证设备树正确性时极为关键。

3.1 DTC工具概述与安装

DTC 工具通常随内核源码一起发布,位于 scripts/dtc/ 目录下。大多数 Linux 发行版也提供独立的软件包。

平台 安装命令 说明
Ubuntu/Debian sudo apt-get install device-tree-compiler 安装独立 DTC 包
Fedora/CentOS sudo dnf install dtc 安装独立 DTC 包
内核源码编译 make scripts 或 make dtc 在内核根目录下编译生成

验证安装是否成功:

$ dtc --version
Version: DTC 1.6.1
版本注意: 不同版本 DTC 对设备树语法的检查严格程度不同。建议使用内核源码自带的 DTC 版本(通常与内核版本匹配),以避免因编译器版本差异导致的兼容性问题。

3.2 DTS到DTB的编译流程

将 .dts 源文件编译为 .dtb 二进制文件,是设备树开发中最常用的操作。编译过程包括预处理、解析、语法检查、二进制生成四个阶段。

编译命令格式:
dtc -I dts -O dtb -o <输出文件.dtb> <输入文件.dts>
  • -I dts:指定输入格式为 DTS 文本
  • -O dtb:指定输出格式为 DTB 二进制
  • -o:指定输出文件名

实战示例:

$ dtc -I dts -O dtb -o myboard.dtb myboard.dts
$ ls -lh myboard.dtb
-rw-rw-r-- 1 user user 8.2K Mar 15 10:30 myboard.dtb

编译过程中,DTC 会执行以下检查:

  • 语法检查: 验证分号、花括号、引号是否匹配
  • 节点唯一性检查: 确保同一层级没有重复的节点名
  • 属性值类型检查: 验证 reg、interrupts 等属性的格式
  • 引用检查: 验证 &label 引用的标签是否存在
DTS → DTB 编译流程 .dts 源文件 文本描述 预处理 展开 #include 语法解析 检查合法性 .dtb 二进制 扁平化结构 关键编译选项: -@ :生成符号节点(支持插件覆盖) -H :生成特定格式的头部(epapr/uboot) -Wno-unit_address_vs_reg :忽略地址格式警告

3.3 DTB反编译为DTS

反编译是将二进制 .dtb 文件还原为可读的 .dts 文本。这在以下场景中非常有用:

  • 逆向分析: 查看第三方板卡或闭源内核中的设备树配置
  • 调试验证: 确认编译后的 .dtb 是否包含预期的节点和属性
  • 格式转换: 将 .dtb 转换为 .dts 后进行修改再重新编译
反编译命令格式:
dtc -I dtb -O dts -o <输出文件.dts> <输入文件.dtb>
  • -I dtb:指定输入格式为 DTB 二进制
  • -O dts:指定输出格式为 DTS 文本

实战示例:

$ dtc -I dtb -O dts -o myboard_reverse.dts myboard.dtb
$ head -30 myboard_reverse.dts
/dts-v1/;

/ {
    #address-cells = <1>;
    #size-cells = <1>;
    model = "My Custom Board";
    compatible = "vendor,myboard";
    ...
};
反编译局限性:
  • 反编译结果会丢失原始 .dts 中的注释和宏定义
  • 标签(label)名称可能被替换为自动生成的名称(如 __symbols__ 节点)
  • 二进制文件中不包含 #include 信息,反编译结果是一个单一文件
  • 某些属性值(如 phandle)可能以原始数值形式出现

3.4 反编译实战:从目标板提取设备树

在实际嵌入式开发中,经常需要从正在运行的目标板上提取设备树。以下是完整的操作流程:

步骤 操作 命令/说明
1 连接目标板 通过串口或 SSH 登录到嵌入式设备
2 定位 DTB 文件 ls /sys/firmware/devicetree/base/ 或 find / -name "*.dtb"
3 复制到主机 scp root@target:/sys/firmware/fdt ./target.dtb
4 反编译 dtc -I dtb -O dts -o target.dts target.dtb
5 查看结果 less target.dts 或使用文本编辑器打开

从 /sys 文件系统直接读取:

# 在目标板上执行
# 将当前运行的设备树导出为二进制文件
cat /sys/firmware/fdt > /tmp/running.dtb

# 复制到开发主机后反编译
$ dtc -I dtb -O dts -o running.dts running.dtb
DTB 反编译实战流程 目标嵌入式板 /sys/firmware/fdt 运行中的 DTB scp 复制 开发主机 target.dtb 二进制文件 dtc 反编译 target.dts 可读文本 可修改、分析 实战要点: 1. /sys/firmware/fdt 是内核运行时导出的原始 DTB 二进制快照 2. 反编译结果可用于对比分析:验证自己编写的 DTS 是否与硬件实际配置一致

3.5 常用DTC选项速查表

选项 功能 使用场景
-I dts 指定输入为 DTS 文本格式 编译源文件
-I dtb 指定输入为 DTB 二进制格式 反编译二进制文件
-O dts 指定输出为 DTS 文本格式 反编译输出
-O dtb 指定输出为 DTB 二进制格式 编译输出
-@ 生成符号节点(__symbols__) 支持设备树覆盖(overlay)
-H epapr 生成 ePAPR 标准头部 PowerPC 等架构
-V 17 指定 DTB 版本为 17 兼容旧版内核
-Wno-unit_address_vs_reg 忽略单元地址与 reg 不匹配警告 处理遗留设备树
-E no 禁用错误检查 快速编译(不推荐生产使用)

3.6 常见编译错误与解决方案

错误1: Error: myboard.dts:10.3-11 syntax error

原因: 第10行附近存在语法错误,常见于缺少分号、花括号不匹配、属性值格式错误。

解决: 检查对应行附近的语法,确保每个属性以分号结尾,节点以花括号包裹。

错误2: FATAL ERROR: Unable to parse input tree

原因: 输入文件格式与 -I 参数不匹配,或文件损坏。

解决: 确认输入文件类型,使用 file 命令检查:file myboard.dtb。

错误3: Warning (unit_address_vs_reg): /soc/gpio@... node has a unit name, but no reg property

原因: 节点名包含地址后缀(如 gpio@ff000000),但缺少对应的 reg 属性。

解决: 添加 reg 属性,或使用 -Wno-unit_address_vs_reg 忽略警告。

3.7 本章小结

设备树的编译与反编译是嵌入式开发中的基础操作。通过 DTC 工具,开发者可以:

  • 将可读的 .dts 源文件编译为内核可解析的 .dtb 二进制文件
  • 从运行中的系统提取 .dtb 并反编译为 .dts,用于逆向分析或验证
  • 利用 DTC 的语法检查功能,在开发早期发现设备树中的错误

熟练掌握这些操作,能够显著提高设备树开发和调试的效率,为后续的中断控制器配置、外设驱动匹配等高级主题打下坚实基础。