Skip to content

Commit

Permalink
fdt-v2: allow to scan binary for multiple dtb instances
Browse files Browse the repository at this point in the history
Signed-off-by: Bartłomiej Burdukiewicz <bartlomiej.burdukiewicz@gmail.com>
  • Loading branch information
dev-0x7C6 committed Mar 4, 2025
1 parent 9c9bafa commit 2bb51bb
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 28 deletions.
12 changes: 10 additions & 2 deletions src/fdt/fdt-header.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
42 changes: 36 additions & 6 deletions src/fdt/fdt-parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ auto foreach_token_type(std::variant<Ts...>, const u32 token_id, fdt::parser::co
return (conditional_parse(Ts{}) || ...);
}

auto fdt::parser::parse(std::string_view view) -> std::expected<fdt::parser::tokens, fdt::parser::error> {
auto fdt::parser::parse(std::string_view view) -> std::expected<fdt::parser::result, fdt::parser::error> {
using error = fdt::parser::error;

if (view.size() < sizeof(decode::header))
Expand Down Expand Up @@ -117,15 +117,41 @@ auto fdt::parser::parse(std::string_view view) -> std::expected<fdt::parser::tok
if (std::holds_alternative<token_types::property>(tokens.back())) {
auto &prop = std::get<token_types::property>(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::expected<fdt::parser::result, fdt::parser::error>> {
std::vector<std::expected<fdt::parser::result, fdt::parser::error>> ret;

using namespace fdt::decode;

auto reference = view;

while (view.size() >= sizeof(decode::header)) {
const auto magic = byteorder(*reinterpret_cast<const std::uint32_t *>(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 {
Expand All @@ -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;

Expand Down
13 changes: 12 additions & 1 deletion src/fdt/fdt-parser.hpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
#pragma once

#include "fdt/fdt-header.hpp"
#include "fdt/fdt-parser-tokens.hpp"

#include <string_view>
#include <expected>
#include <vector>
#include <cstdint>

namespace fdt::parser {

Expand All @@ -16,7 +19,15 @@ enum class error {
unsupported_version,
};

auto parse(std::string_view data) -> std::expected<tokens, error>;
struct result {
std::uint64_t offset{};
fdt::decode::header header;
fdt::parser::tokens tokens;
};

auto parse(std::string_view data) -> std::expected<result, error>;
auto parse_multiple_offsets(std::string_view data) -> std::vector<std::expected<result, error>>;
auto validate(const result &) -> bool;
auto validate(const tokens &) -> bool;
auto rename_root(tokens &, std::string_view name) -> bool;

Expand Down
51 changes: 32 additions & 19 deletions src/fdt/fdt-view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::size_t>(data.size())});
auto results = parse_multiple_offsets({data.data(), static_cast<std::size_t>(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;
}

Expand Down

0 comments on commit 2bb51bb

Please sign in to comment.