Format for Android DTB/DTBO partitions. It's kind of archive with dtb/dtbo files. Used only when there is a separate unique partition (dtb, dtbo) on an android device to organize device tree files. The format consists of a header with info about size and number of device tree entries and the entries themselves. This format description could be used to extract device tree entries from a partition images and decompile them with dtc (device tree compiler).
This page hosts a formal specification of Android DTB/DTBO Partition using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.
All parsing code for C++11/STL generated by Kaitai Struct depends on the C++/STL runtime library. You have to install it before you can parse data.
For C++, the easiest way is to clone the runtime library sources and build them along with your project.
Using Kaitai Struct in C++/STL usually consists of 3 steps.
std::istream
). One can open local file for that, or use existing std::string
or char*
buffer.
#include <fstream>
std::ifstream is("path/to/local/file.img", std::ifstream::binary);
#include <sstream>
std::istringstream is(str);
#include <sstream>
const char buf[] = { ... };
std::string str(buf, sizeof buf);
std::istringstream is(str);
#include "kaitai/kaitaistream.h"
kaitai::kstream ks(&is);
android_dto_t data(&ks);
After that, one can get various attributes from the structure by invoking getter methods like:
data.header() // => get header
#pragma once
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
#include "kaitai/kaitaistruct.h"
#include <stdint.h>
#include <memory>
#include <vector>
#if KAITAI_STRUCT_VERSION < 9000L
#error "Incompatible Kaitai Struct C++/STL API: version 0.9 or later is required"
#endif
/**
* Format for Android DTB/DTBO partitions. It's kind of archive with
* dtb/dtbo files. Used only when there is a separate unique partition
* (dtb, dtbo) on an android device to organize device tree files.
* The format consists of a header with info about size and number
* of device tree entries and the entries themselves. This format
* description could be used to extract device tree entries from a
* partition images and decompile them with dtc (device tree compiler).
* \sa https://source.android.com/docs/core/architecture/dto/partitions Source
* \sa https://android.googlesource.com/platform/system/libufdt/+/refs/tags/android-10.0.0_r47 Source
*/
class android_dto_t : public kaitai::kstruct {
public:
class dt_table_header_t;
class dt_table_entry_t;
android_dto_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, android_dto_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~android_dto_t();
class dt_table_header_t : public kaitai::kstruct {
public:
dt_table_header_t(kaitai::kstream* p__io, android_dto_t* p__parent = nullptr, android_dto_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~dt_table_header_t();
private:
std::string m_magic;
uint32_t m_total_size;
uint32_t m_header_size;
uint32_t m_dt_entry_size;
uint32_t m_dt_entry_count;
uint32_t m_dt_entries_offset;
uint32_t m_page_size;
uint32_t m_version;
android_dto_t* m__root;
android_dto_t* m__parent;
public:
std::string magic() const { return m_magic; }
/**
* includes dt_table_header + all dt_table_entry and all dtb/dtbo
*/
uint32_t total_size() const { return m_total_size; }
/**
* sizeof(dt_table_header)
*/
uint32_t header_size() const { return m_header_size; }
/**
* sizeof(dt_table_entry)
*/
uint32_t dt_entry_size() const { return m_dt_entry_size; }
/**
* number of dt_table_entry
*/
uint32_t dt_entry_count() const { return m_dt_entry_count; }
/**
* offset to the first dt_table_entry from head of dt_table_header
*/
uint32_t dt_entries_offset() const { return m_dt_entries_offset; }
/**
* flash page size
*/
uint32_t page_size() const { return m_page_size; }
/**
* DTBO image version
*/
uint32_t version() const { return m_version; }
android_dto_t* _root() const { return m__root; }
android_dto_t* _parent() const { return m__parent; }
};
class dt_table_entry_t : public kaitai::kstruct {
public:
dt_table_entry_t(kaitai::kstream* p__io, android_dto_t* p__parent = nullptr, android_dto_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~dt_table_entry_t();
private:
bool f_body;
std::string m_body;
public:
/**
* DTB/DTBO file
*/
std::string body();
private:
uint32_t m_dt_size;
uint32_t m_dt_offset;
uint32_t m_id;
uint32_t m_rev;
std::unique_ptr<std::vector<uint32_t>> m_custom;
android_dto_t* m__root;
android_dto_t* m__parent;
public:
/**
* size of this entry
*/
uint32_t dt_size() const { return m_dt_size; }
/**
* offset from head of dt_table_header
*/
uint32_t dt_offset() const { return m_dt_offset; }
/**
* optional, must be zero if unused
*/
uint32_t id() const { return m_id; }
/**
* optional, must be zero if unused
*/
uint32_t rev() const { return m_rev; }
/**
* optional, must be zero if unused
*/
std::vector<uint32_t>* custom() const { return m_custom.get(); }
android_dto_t* _root() const { return m__root; }
android_dto_t* _parent() const { return m__parent; }
};
private:
std::unique_ptr<dt_table_header_t> m_header;
std::unique_ptr<std::vector<std::unique_ptr<dt_table_entry_t>>> m_entries;
android_dto_t* m__root;
kaitai::kstruct* m__parent;
public:
dt_table_header_t* header() const { return m_header.get(); }
std::vector<std::unique_ptr<dt_table_entry_t>>* entries() const { return m_entries.get(); }
android_dto_t* _root() const { return m__root; }
kaitai::kstruct* _parent() const { return m__parent; }
};
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
#include "android_dto.h"
#include "kaitai/exceptions.h"
android_dto_t::android_dto_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, android_dto_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = this;
m_header = nullptr;
m_entries = nullptr;
_read();
}
void android_dto_t::_read() {
m_header = std::unique_ptr<dt_table_header_t>(new dt_table_header_t(m__io, this, m__root));
m_entries = std::unique_ptr<std::vector<std::unique_ptr<dt_table_entry_t>>>(new std::vector<std::unique_ptr<dt_table_entry_t>>());
const int l_entries = header()->dt_entry_count();
for (int i = 0; i < l_entries; i++) {
m_entries->push_back(std::move(std::unique_ptr<dt_table_entry_t>(new dt_table_entry_t(m__io, this, m__root))));
}
}
android_dto_t::~android_dto_t() {
_clean_up();
}
void android_dto_t::_clean_up() {
}
android_dto_t::dt_table_header_t::dt_table_header_t(kaitai::kstream* p__io, android_dto_t* p__parent, android_dto_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
_read();
}
void android_dto_t::dt_table_header_t::_read() {
m_magic = m__io->read_bytes(4);
if (!(magic() == std::string("\xD7\xB7\xAB\x1E", 4))) {
throw kaitai::validation_not_equal_error<std::string>(std::string("\xD7\xB7\xAB\x1E", 4), magic(), _io(), std::string("/types/dt_table_header/seq/0"));
}
m_total_size = m__io->read_u4be();
m_header_size = m__io->read_u4be();
m_dt_entry_size = m__io->read_u4be();
m_dt_entry_count = m__io->read_u4be();
m_dt_entries_offset = m__io->read_u4be();
m_page_size = m__io->read_u4be();
m_version = m__io->read_u4be();
}
android_dto_t::dt_table_header_t::~dt_table_header_t() {
_clean_up();
}
void android_dto_t::dt_table_header_t::_clean_up() {
}
android_dto_t::dt_table_entry_t::dt_table_entry_t(kaitai::kstream* p__io, android_dto_t* p__parent, android_dto_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m_custom = nullptr;
f_body = false;
_read();
}
void android_dto_t::dt_table_entry_t::_read() {
m_dt_size = m__io->read_u4be();
m_dt_offset = m__io->read_u4be();
m_id = m__io->read_u4be();
m_rev = m__io->read_u4be();
m_custom = std::unique_ptr<std::vector<uint32_t>>(new std::vector<uint32_t>());
const int l_custom = 4;
for (int i = 0; i < l_custom; i++) {
m_custom->push_back(std::move(m__io->read_u4be()));
}
}
android_dto_t::dt_table_entry_t::~dt_table_entry_t() {
_clean_up();
}
void android_dto_t::dt_table_entry_t::_clean_up() {
if (f_body) {
}
}
std::string android_dto_t::dt_table_entry_t::body() {
if (f_body)
return m_body;
kaitai::kstream *io = _root()->_io();
std::streampos _pos = io->pos();
io->seek(dt_offset());
m_body = io->read_bytes(dt_size());
io->seek(_pos);
f_body = true;
return m_body;
}