当前位置:

首页 > 编程开发 > c++如何读取Linux内核生成的Device Tree二进制流【深度】

c++如何读取Linux内核生成的Device Tree二进制流【深度】

C++如何读取Linux内核生成的Device Tree二进制流【深度】 Linux用户态如何解析内核加载的dtb文件 内核启动时加载的dtb(Device Tree Blob)文件,在系统运行后通常已经被解压并转换成了内核内部的结构体(比如struct device_node)。这里有个关键点:*

C++如何读取Linux内核生成的Device Tree二进制流【深度】

c++如何读取Linux内核生成的Device Tree二进制流【深度】

Linux用户态如何解析内核加载的dtb文件

内核启动时加载的dtb(Device Tree Blob)文件,在系统运行后通常已经被解压并转换成了内核内部的结构体(比如struct device_node)。这里有个关键点:**用户态程序是无法直接访问这些内核内存数据的**。所以,如果你想在用户空间读取设备树的内容,就得换个思路,从源头找起。无非两条路:要么去读取启动时传入的那个原始dtb二进制文件本身,要么就利用内核已经为我们准备好的一个接口——/proc/device-tree这个伪文件系统。

一个常见的误区是,试图用mmap去映射/sys/firmware/devicetree/base或者/proc/device-tree下的某个文件。这行不通。这些文件是特殊的只读文件,没有传统意义上的“长度”,你用stat()去查,会发现st_size返回0。正确的姿势是使用read()系统调用来读取内容。

  • /proc/device-tree是首选方案:它以目录树的形式直观地暴露了所有设备树节点和属性。你不需要自己解析任何二进制格式,直接按文件操作就行,而且兼容性很好(主流内核版本>=3.10都支持)。
  • 如果确实需要原始的dtb文件(比如为了做签名验证或者离线分析),那就得确认你的启动环境里是否还保留着这个文件。它可能存在于U-Boot的环境变量fdt_addr_r指向的内存地址,也可能被打包进了initramfs里(例如放在/dtb路径下)。
  • 尽量不要依赖/sys/firmware/devicetree/base:在某些ARM64平台上它可能不可见,而且部分Linux发行版默认并不会挂载这个路径。

用C++递归遍历/proc/device-tree提取节点信息

这是最轻量、也最可靠的方法。逻辑很直观:/proc/device-tree下的每一个子目录,就对应设备树里的一个节点(device node);而目录里的每一个普通文件,则对应一个属性(property),文件的内容就是这个属性的值(注意,内容里可能包含'\0'字符,所以必须用read(),不能用fgets这类字符串函数)。

操作起来有几个关键点:

立即学习“C++免费学习笔记(深入)”;

  • 使用opendir()readdir()来遍历目录,记得跳过“.”和“..”这两个特殊条目。
  • 对每个条目调用stat()来判断其类型:如果是目录(S_ISDIR()),就递归进入,处理子节点;如果是普通文件(S_ISREG()),就读取其内容作为属性值。
  • 属性值的末尾并不自动附加'\0',其真实长度需要通过stat()得到的st_size来获取。对于字符串类属性(比如compatible),其内容本身会以'\0'结尾;但对于二进制属性(比如reg),它就是原始的字节流。
  • 设备树路径可能很深,为了输出清晰,建议用栈结构或者递归来控制缩进显示,避免在代码里硬编码层级限制。

来看一个简单的代码片段,演示如何读取/proc/device-tree/cpus/cpu@0/compatible这个属性:

int fd = open("/proc/device-tree/cpus/cpu@0/compatible", O_RDONLY);
struct stat st;
fstat(fd, &st);
std::vector buf(st.st_size);
read(fd, buf.data(), st.st_size);
// 此时,buf[0]...buf[st.st_size-1] 就是原始的属性值字节
close(fd);

用libfdt解析原始dtb文件(需链接libfdt

当你不得不处理原始的dtb二进制文件时(例如从Flash存储中直接dump出来,或者需要与内核启动参数进行一致性校验),libfdt库就成了事实上的标准工具。它被dtc(设备树编译器)、u-boot等广泛使用,头文件是,所有函数都有统一的fdt_前缀。

典型的解析流程是这样的:

  • 首先,用fdt_open_into()fdt_load()这样的函数,将完整的dtb文件加载到内存中。这里要特别注意:你提供的dtb数据必须是完整且未被截断的二进制流。
  • 接着,可以使用fdt_first_subnode()fdt_next_subnode()这对组合来遍历设备树的子节点。
  • 读取属性则使用fdt_getprop()函数。它返回一个指向dtb内部缓冲区的指针,**这个指针绝对不能手动free,并且它的生命周期完全依赖于fdt blob本身的有效性**。属性的实际长度会通过一个输出参数(lenp)传回。

使用libfdt时,有几个容易踩坑的地方:

  • 在进行任何其他操作之前,必须先调用fdt_check_header()来校验dtb头的合法性,否则一个非法的dtb文件很可能导致程序段错误(Segmentation Fault)。
  • fdt结构体本身并不管理内存,所以承载dtb数据的那个缓冲区(buffer)在整个使用周期内都必须保持有效,不能是栈上的临时变量,也不能被realloc这类操作移动。
  • 如果在多线程环境下使用,需要自行加锁,因为libfdt本身不是线程安全的,同一个fdt实例不能支持并发访问。

为什么不用libdevicetree或自己写解析器

或许有人会问,有没有其他库,或者干脆自己写一个解析器?答案是,通常不建议。

libdevicetree这类非主流的库,往往缺乏持续维护,API可能不稳定。而自己动手写一个解析器,风险则非常高。dtb的二进制格式包含了magic number、总长度、结构体偏移量、字符串表偏移量等多个字段,并且存在版本差异(如v17/v18)、对齐要求(通常是8字节)、以及复杂的字符串表引用机制。即便你跳过了严格的校验,仅仅是想正确识别节点和属性的边界,也极易发生数组越界读取的错误。

在真实的开发场景中,大约95%的需求,通过/proc/device-tree这个接口就能完美解决。剩下的那5%,比如进行bootloader调试或者固件签名校验,才是libfdt的用武之地。如果非要绕过这两条成熟路径,大概率会在自己实现的fdt_next_tag()循环里卡住,或者读出一堆乱码。

说到底,真正有挑战性的从来不是“怎么把数据读出来”这个动作,而是搞清楚你需要的数据究竟在哪一层:是启动时传给内核的原始硬件描述,还是内核解析后生成的运行时视图,又或者是驱动实际看到的platform_device资源?这三者的语义各不相同,绝对不能混为一谈。

本文内容来源于互联网,如有侵权请联系删除。
作者最新文章
编程开发 Linux
相关文章 更多
在 Kali Linux 中验证 Hashcat 安装
在 Kali Linux 中验证 Hashcat 安装

引言 Hashcat 被广泛认为是世界上最快、最先进的密码恢复工具。它是渗透测试人员和安全专业人员武器库中的必备工具。在使用它破解哈希(hashes)之前,你必须首先确保它已在你的系统上正确安装并完全可用。 在本实验(lab)中,你将执行一系列简单的检查,以验证 Hashcat 在你的 Kali L

在 Kali Linux 上安装和验证 Gobuster
在 Kali Linux 上安装和验证 Gobuster

引言 Gobuster 是一个强大的工具,用于目录和文件暴力破解、DNS 子域暴力破解以及 S3 存储桶枚举。它是渗透测试人员和安全爱好者发现 Web 服务器上隐藏路径和资源的重要实用程序。 在本实验中,你将学习在 Kali Linux 环境中安装 Gobuster 的基本步骤。你将使用 CODE_

(G-G) Pixel 手机或将进行重要底层升级Linux 内核有望更新
(G-G) Pixel 手机或将进行重要底层升级Linux 内核有望更新

谷歌计划为Pixel7至10系列进行Linux内核重大升级,从旧版本统一跃升至Linux6.12。新内核优化了CPU调度和内存管理,有望提升流畅度、安全性与发热控制,并可能改善Pixel10的GPU性能。该更新预计随Android17QPR2年底推送,Pixel6因支持终止无缘升级。

火狐浏览器自定义主页
火狐浏览器自定义主页

火狐浏览器可通过五种方式自定义默认主页:一、设置中手动输入网址;二、用当前页面一键设为主页;三、从书签中选取;四、移动端通过新标签页模拟;五、高级用户修改about:config配置项。 想让火狐浏览器一打开就直奔你心仪的网站,而不是那个空白页或默认的官方主页?这事儿其实不难,通过浏览器内置的设置就

淘宝网页版入口查找教程
淘宝网页版入口查找教程

淘宝官方网页登录入口 对于如何找到淘宝网页版的入口,很多朋友都感到有点摸不着头脑。别急,这篇文章就来为你拆解清楚整个登录流程。官方的登录入口很明确,就在官网首页的左上角。 淘宝网页版入口位于官网首页左上角,点击“亲,请登录”即可跳转至统一的验证页面。登录支持密码、短信验证码和手机APP扫码三种方式,

WMV转MP4方法
WMV转MP4方法

WMV视频压缩指南:如何高效“瘦身”释放硬盘空间 在日常处理和收藏视频时,不少人会发现一个有趣的现象:WMV格式的文件,在画质相当的情况下,体积往往比MP4更小巧。这原本是它的优势,但架不住日积月累,一堆WMV文件同样会悄悄吃掉大量的硬盘空间。因此,如何给WMV视频“减减肥”,就成了优化存储、提升效

打字鸭官方网址登录入口
打字鸭官方网址登录入口

打字鸭官方网址是https://www.daziya.com/,提供科学分层课程、沉浸式交互体验、精准数据追踪、灵活教学角色及稳定轻量技术架构。 提到在线打字练习,很多朋友第一时间会问:打字鸭的官方入口到底在哪?不用再四处搜索了,它的直达地址就在这里。 https://www.daziya.com/

C++类构造与析构函数详解
C++类构造与析构函数详解

C++类构造与析构函数详解 C++这门语言,可以说是从C语言这棵大树上衍生出的高级果实,如今的应用普及度有目共睹。作为一种静态类型的通用编程语言,它厉害的地方在于融合了多种编程哲学——无论是传统的面向过程,还是主流的面向对象,乃至数据抽象、泛型编程这些高级概念,它都能很好地支持。正因为这份卓越的扩展

米侠浏览器打不开网页
米侠浏览器打不开网页

米侠浏览器页面打不开,或者干脆显示一片空白?问题根源大概率出在内核上。比如内核和当前网页的兼容性出了岔子、页面渲染模块意外损坏,再或者,内核版本实在太旧了。别急,沿着切换内核、清理缓存、关闭硬件加速、替换核心文件这四步走,通常都能解决。 用米侠浏览器上网,碰到页面死活刷不出来,或者只显示一个空白屏幕

steam正版官网入口地址
steam正版官网入口地址

Steam正版官网入口与完整使用指引 Steam的全球统一官方商店入口是:https://store.steampowered.com/。认准这个地址,页面具备HTTPS加密、Valve版权标识及安全锁标志,能有效保障访问安全。 还在四处搜索Steam的正版官网地址?其实不必那么麻烦。下面这份从官网

查看更多
精品专题 更多
装机必备
装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows
Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

macOS软件
macOS软件

正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

Mac软件 更多
灵活计算器
灵活计算器
macOS/iOS/Android

灵活计算器是一款笔记式算数应用,支持实时计算、动态关联和云端同步功能。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

赤友清理大师
赤友清理大师
macOS

赤友清理大师是一款为 Mac 设计的智能清理优化工具,可精准扫描垃圾、大文件、重复文件等,释放磁盘空间。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

极度公式
极度公式
Windows/macOS/Linux

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

WINDOWS 更多
Windows 10
Windows 10
Windows

Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

极度公式
极度公式
Windows/macOS/Linux

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

密码键盘
密码键盘
Windows/macOS/iOS/Android

密码键盘是一款兼具安全性与便捷性的高效密码管理器。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。