From 2bb51bbfc2c5dfc1088f4fa935a43d9039d48ac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Burdukiewicz?= Date: Wed, 5 Mar 2025 00:39:09 +0100 Subject: [PATCH] fdt-v2: allow to scan binary for multiple dtb instances MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bartłomiej Burdukiewicz --- src/fdt/fdt-header.hpp | 12 ++++++++-- src/fdt/fdt-parser.cpp | 42 +++++++++++++++++++++++++++++----- src/fdt/fdt-parser.hpp | 13 ++++++++++- src/fdt/fdt-view.cpp | 51 ++++++++++++++++++++++++++---------------- 4 files changed, 90 insertions(+), 28 deletions(-) diff --git a/src/fdt/fdt-header.hpp b/src/fdt/fdt-header.hpp index 7a6a79a..272a6a8 100644 --- a/src/fdt/fdt-header.hpp +++ b/src/fdt/fdt-header.hpp @@ -22,9 +22,17 @@ struct property { u32 nameoff; }; -constexpr auto is_magic_invalid(const header &v) -> bool { +constexpr auto is_magic_valid(const std::uint32_t value) noexcept { constexpr auto header_magic_value = 0xD00DFEED; - return v.magic != header_magic_value; + return value == header_magic_value; +} + +constexpr auto is_magic_valid(const header &v) noexcept -> bool { + return is_magic_valid(v.magic); +} + +constexpr auto is_magic_invalid(const header &v) noexcept -> bool { + return !is_magic_valid(v.magic); } constexpr auto is_data_truncated(const header &v, const std::size_t size) -> bool { diff --git a/src/fdt/fdt-parser.cpp b/src/fdt/fdt-parser.cpp index 2f5c3b3..7d7c2c0 100644 --- a/src/fdt/fdt-parser.cpp +++ b/src/fdt/fdt-parser.cpp @@ -69,7 +69,7 @@ auto foreach_token_type(std::variant, const u32 token_id, fdt::parser::co return (conditional_parse(Ts{}) || ...); } -auto fdt::parser::parse(std::string_view view) -> std::expected { +auto fdt::parser::parse(std::string_view view) -> std::expected { using error = fdt::parser::error; if (view.size() < sizeof(decode::header)) @@ -117,15 +117,41 @@ auto fdt::parser::parse(std::string_view view) -> std::expected(tokens.back())) { auto &prop = std::get(tokens.back()); - if (auto dtb = fdt::parser::parse(prop.data); dtb.has_value()) { - auto &embedded_tokens = dtb.value(); - rename_root(embedded_tokens, prop.name); - std::move(std::begin(embedded_tokens), std::end(embedded_tokens), std::back_inserter(tokens)); + if (auto inner_dtb = fdt::parser::parse(prop.data); inner_dtb.has_value()) { + rename_root(inner_dtb.value().tokens, prop.name); + std::move(std::begin(inner_dtb.value().tokens), std::end(inner_dtb.value().tokens), std::back_inserter(tokens)); } } } - return tokens; + return fdt::parser::result{ + .header = header, + .tokens = std::move(tokens), + }; +} + +auto fdt::parser::parse_multiple_offsets(std::string_view view) -> std::vector> { + std::vector> ret; + + using namespace fdt::decode; + + auto reference = view; + + while (view.size() >= sizeof(decode::header)) { + const auto magic = byteorder(*reinterpret_cast(view.data())); + + if (is_magic_valid(magic)) + if (auto dtb = fdt::parser::parse(view); dtb.has_value()) { + dtb->offset = std::distance(reference.begin(), view.begin()); + view = std::string_view(view.begin() + dtb.value().header.totalsize, view.end()); + ret.emplace_back(std::move(dtb)); + continue; + } + + view = std::string_view(view.begin() + 1, view.end()); + } + + return ret; } auto fdt::parser::rename_root(fdt::parser::tokens &tokens, std::string_view name) -> bool { @@ -143,6 +169,10 @@ struct overloaded : Ts... { using Ts::operator()...; }; +auto fdt::parser::validate(const fdt::parser::result &fdt) -> bool { + return validate(fdt.tokens); +} + auto fdt::parser::validate(const fdt::parser::tokens &tokens) -> bool { using namespace fdt::parser; diff --git a/src/fdt/fdt-parser.hpp b/src/fdt/fdt-parser.hpp index d6e335b..74d9dd3 100644 --- a/src/fdt/fdt-parser.hpp +++ b/src/fdt/fdt-parser.hpp @@ -1,9 +1,12 @@ #pragma once +#include "fdt/fdt-header.hpp" #include "fdt/fdt-parser-tokens.hpp" #include #include +#include +#include namespace fdt::parser { @@ -16,7 +19,15 @@ enum class error { unsupported_version, }; -auto parse(std::string_view data) -> std::expected; +struct result { + std::uint64_t offset{}; + fdt::decode::header header; + fdt::parser::tokens tokens; +}; + +auto parse(std::string_view data) -> std::expected; +auto parse_multiple_offsets(std::string_view data) -> std::vector>; +auto validate(const result &) -> bool; auto validate(const tokens &) -> bool; auto rename_root(tokens &, std::string_view name) -> bool; diff --git a/src/fdt/fdt-view.cpp b/src/fdt/fdt-view.cpp index 8771014..7531d7a 100644 --- a/src/fdt/fdt-view.cpp +++ b/src/fdt/fdt-view.cpp @@ -103,31 +103,44 @@ bool fdt::viewer::load(QByteArray &&data, QString &&name, QString &&id) { using namespace fdt::parser; using namespace fdt::qt_wrappers; - auto tokens = parse({data.data(), static_cast(data.size())}); + auto results = parse_multiple_offsets({data.data(), static_cast(data.size())}); - if (!tokens) - return false; + for (auto &&result : results) { + if (!result) + return false; - if (!validate(tokens.value())) - return false; + if (!validate(result.value())) + return false; + + auto &&tokens = result.value().tokens; + + QString root_id = id; + QString root_name = name; - fdt::parser::rename_root(tokens.value(), name.toStdString()); + if (result->offset) { + root_name += "@" + QString::number(result->offset, 16); + root_id += "@" + QString::number(result->offset, 16); + } + + fdt::parser::rename_root(tokens, root_name.toStdString()); - m_target->blockSignals(true); - tree_generator generator(m_tree[id], m_target, std::move(name), std::move(id)); - m_target->blockSignals(false); + m_target->blockSignals(true); + tree_generator generator(m_tree[root_id], m_target, std::move(root_name), std::move(id)); + m_target->blockSignals(false); - for (auto &&token : tokens.value()) - std::visit(overloaded{ - [&](const token_types::node_begin &arg) { generator.begin_node(arg.name); }, - [&](const token_types::node_end &) { generator.end_node(); }, - [&](const token_types::property &arg) { generator.insert_property(arg); }, - [&](const token_types::nop &) {}, - [&](const token_types::end &) {}, - }, - token); + for (auto &&token : tokens) + std::visit(overloaded{ + [&](const token_types::node_begin &arg) { generator.begin_node(arg.name); }, + [&](const token_types::node_end &) { generator.end_node(); }, + [&](const token_types::property &arg) { generator.insert_property(arg); }, + [&](const token_types::nop &) {}, + [&](const token_types::end &) {}, + }, + token); + + generator.root()->setData(0, Qt::UserRole + 1000, std::move(data)); + } - generator.root()->setData(0, Qt::UserRole + 1000, std::move(data)); return true; }