diff --git a/view/sharedcache/api/MetadataSerializable.hpp b/view/sharedcache/api/MetadataSerializable.hpp deleted file mode 100644 index dd3951ea7f..0000000000 --- a/view/sharedcache/api/MetadataSerializable.hpp +++ /dev/null @@ -1,500 +0,0 @@ -// -// Created by kat on 5/31/23. -// - -/* - * Welcome to, this file. - * - * This is a metadata serialization helper. - * - * Have you ever wished turning a complex datastructure into a Metadata object was as easy in C++ as it is in python? - * Do you like macros and templates? - * - * Great news. - * - * Implement these on your `public MetadataSerializable` subclass: - * ``` - void Store() override { - MSS(m_someVariable); - MSS(m_someOtherVariable); - } - void Load() override { - MSL(m_someVariable); - MSL(m_someOtherVariable); - } - ``` - * Then, you can turn your object into a Metadata object with `AsMetadata()`, and load it back with - `LoadFromMetadata()`. - * - * Serialized fields will be automatically repopulated. - * - * Other ser/deser formats (rapidjson objects, strings) also exist. You can use these to achieve nesting, but probably - avoid that. - * */ - -#include "binaryninjaapi.h" -#include "rapidjson/document.h" -#include "rapidjson/stringbuffer.h" -#include "rapidjson/prettywriter.h" - -#ifndef SHAREDCACHE_METADATASERIALIZABLE_HPP -#define SHAREDCACHE_METADATASERIALIZABLE_HPP - -#define MSS(name) store(#name, name) -#define MSS_CAST(name, type) store(#name, (type) name) -#define MSS_SUBCLASS(name) Serialize(#name, name) -#define MSL(name) name = load(#name, name) -#define MSL_CAST(name, storedType, type) name = (type)load(#name, (storedType) name) -#define MSL_SUBCLASS(name) Deserialize(#name, name) - -using namespace BinaryNinja; - -class MetadataSerializable -{ -protected: - struct SerialContext - { - rapidjson::Document doc; - rapidjson::Document::AllocatorType allocator; - }; - struct DeserContext - { - rapidjson::Document doc; - }; - - DeserContext m_activeDeserContext; - SerialContext m_activeContext; - -public: - MetadataSerializable() - { - m_activeContext.doc.SetObject(); - m_activeContext.allocator = m_activeContext.doc.GetAllocator(); - } - - // copy constructor - MetadataSerializable(const MetadataSerializable& other) - { - m_activeContext.doc.CopyFrom(other.m_activeContext.doc, m_activeContext.doc.GetAllocator()); - } - - // copy assignment - MetadataSerializable& operator=(const MetadataSerializable& other) - { - m_activeContext.doc.CopyFrom(other.m_activeContext.doc, m_activeContext.doc.GetAllocator()); - return *this; - } - - virtual ~MetadataSerializable() - { - } - - void SetupSerContext(rapidjson::Document::AllocatorType* alloc = nullptr) - { - m_activeContext.doc.SetObject(); - m_activeContext.allocator = m_activeContext.doc.GetAllocator(); - } - void S() - { - // fixme factor out - } - void Serialize(std::string& name, bool b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - m_activeContext.doc.AddMember(key, b, m_activeContext.allocator); - } - void Deserialize(std::string& name, bool& b) { b = m_activeDeserContext.doc[name.c_str()].GetBool(); } - - void Serialize(std::string& name, uint8_t b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - m_activeContext.doc.AddMember(key, b, m_activeContext.allocator); - } - void Deserialize(std::string& name, uint8_t& b) - { - b = static_cast(m_activeDeserContext.doc[name.c_str()].GetUint64()); - } - - void Serialize(std::string& name, uint16_t b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - m_activeContext.doc.AddMember(key, b, m_activeContext.allocator); - } - void Deserialize(std::string& name, uint16_t& b) - { - b = static_cast(m_activeDeserContext.doc[name.c_str()].GetUint64()); - } - - void Serialize(std::string& name, uint32_t b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - m_activeContext.doc.AddMember(key, b, m_activeContext.allocator); - } - void Deserialize(std::string& name, uint32_t& b) - { - b = static_cast(m_activeDeserContext.doc[name.c_str()].GetUint64()); - } - - void Serialize(std::string& name, uint64_t b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - m_activeContext.doc.AddMember(key, b, m_activeContext.allocator); - } - void Deserialize(std::string& name, uint64_t& b) - { - b = m_activeDeserContext.doc[name.c_str()].GetUint64(); - } - - void Serialize(std::string& name, int8_t b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - m_activeContext.doc.AddMember(key, b, m_activeContext.allocator); - } - void Deserialize(std::string& name, int8_t& b) - { - b = m_activeDeserContext.doc[name.c_str()].GetInt64(); - } - - void Serialize(std::string& name, int16_t b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - m_activeContext.doc.AddMember(key, b, m_activeContext.allocator); - } - void Deserialize(std::string& name, int16_t& b) - { - b = m_activeDeserContext.doc[name.c_str()].GetInt64(); - } - - void Serialize(std::string& name, int32_t b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - m_activeContext.doc.AddMember(key, b, m_activeContext.allocator); - } - void Deserialize(std::string& name, int32_t& b) - { - b = m_activeDeserContext.doc[name.c_str()].GetInt(); - } - - void Serialize(std::string& name, int64_t b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - m_activeContext.doc.AddMember(key, b, m_activeContext.allocator); - } - void Deserialize(std::string& name, int64_t& b) - { - b = m_activeDeserContext.doc[name.c_str()].GetInt64(); - } - - void Serialize(std::string& name, std::string b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value value(b.c_str(), m_activeContext.allocator); - m_activeContext.doc.AddMember(key, value, m_activeContext.allocator); - } - void Deserialize(std::string& name, std::string& b) - { - b = m_activeDeserContext.doc[name.c_str()].GetString(); - } - - void Serialize(std::string& name, std::map b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - for (auto& i : b) - { - rapidjson::Value p(rapidjson::kArrayType); - p.PushBack(i.first, m_activeContext.allocator); - rapidjson::Value value(i.second.c_str(), m_activeContext.allocator); - p.PushBack(value, m_activeContext.allocator); - bArr.PushBack(p, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - void Deserialize(std::string& name, std::map& b) - { - for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray()) - b[i.GetArray()[0].GetUint64()] = i.GetArray()[1].GetString(); - } - - void Serialize(std::string& name, std::unordered_map b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - for (auto& i : b) - { - rapidjson::Value p(rapidjson::kArrayType); - p.PushBack(i.first, m_activeContext.allocator); - rapidjson::Value value(i.second.c_str(), m_activeContext.allocator); - p.PushBack(value, m_activeContext.allocator); - bArr.PushBack(p, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - - void Serialize(std::string& name, std::unordered_map b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - for (auto& i : b) - { - rapidjson::Value p(rapidjson::kArrayType); - rapidjson::Value key(i.first.c_str(), m_activeContext.allocator); - rapidjson::Value value(i.second.c_str(), m_activeContext.allocator); - p.PushBack(key, m_activeContext.allocator); - p.PushBack(value, m_activeContext.allocator); - bArr.PushBack(p, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - void Deserialize(std::string& name, std::unordered_map& b) - { - for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray()) - b[i.GetArray()[0].GetUint64()] = i.GetArray()[1].GetString(); - } - - void Serialize(std::string& name, std::unordered_map b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - for (auto& i : b) - { - rapidjson::Value p(rapidjson::kArrayType); - p.PushBack(i.first, m_activeContext.allocator); - p.PushBack(i.second, m_activeContext.allocator); - bArr.PushBack(p, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - void Deserialize(std::string& name, std::unordered_map& b) - { - for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray()) - b[i.GetArray()[0].GetUint64()] = i.GetArray()[1].GetUint64(); - } - - // std::unordered_map> - void Serialize(std::string& name, std::unordered_map> b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value classes(rapidjson::kArrayType); - for (auto& i : b) - { - rapidjson::Value classArr(rapidjson::kArrayType); - rapidjson::Value classKey(i.first.c_str(), m_activeContext.allocator); - classArr.PushBack(classKey, m_activeContext.allocator); - rapidjson::Value membersArr(rapidjson::kArrayType); - for (auto& j : i.second) - { - rapidjson::Value member(rapidjson::kArrayType); - member.PushBack(j.first, m_activeContext.allocator); - member.PushBack(j.second, m_activeContext.allocator); - membersArr.PushBack(member, m_activeContext.allocator); - } - classArr.PushBack(membersArr, m_activeContext.allocator); - classes.PushBack(classArr, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, classes, m_activeContext.allocator); - } - void Deserialize(std::string& name, std::unordered_map>& b) - { - for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray()) - { - std::string key = i.GetArray()[0].GetString(); - std::unordered_map memArray; - for (auto& member : i.GetArray()[1].GetArray()) - { - memArray[member.GetArray()[0].GetUint64()] = member.GetArray()[1].GetUint64(); - } - b[key] = memArray; - } - } - - void Deserialize(std::string& name, std::unordered_map& b) - { - for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray()) - b[i.GetArray()[0].GetString()] = i.GetArray()[1].GetString(); - } - - void Serialize(std::string& name, std::vector b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - for (const auto& s : b) - { - rapidjson::Value value(s.c_str(), m_activeContext.allocator); - bArr.PushBack(value, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - void Deserialize(std::string& name, std::vector& b) - { - for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray()) - b.emplace_back(i.GetString()); - } - - void Serialize(std::string& name, std::vector>> b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - for (auto& i : b) - { - rapidjson::Value segV(rapidjson::kArrayType); - segV.PushBack(i.first, m_activeContext.allocator); - segV.PushBack(i.second.first, m_activeContext.allocator); - segV.PushBack(i.second.second, m_activeContext.allocator); - bArr.PushBack(segV, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - void Deserialize(std::string& name, std::vector>>& b) - { - for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray()) - { - std::pair> j; - j.first = i.GetArray()[0].GetUint64(); - j.second.first = i.GetArray()[1].GetUint64(); - j.second.second = i.GetArray()[2].GetUint64(); - b.push_back(j); - } - } - - void Serialize(std::string& name, std::vector> b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - for (auto& i : b) - { - rapidjson::Value segV(rapidjson::kArrayType); - segV.PushBack(i.first, m_activeContext.allocator); - segV.PushBack(i.second, m_activeContext.allocator); - bArr.PushBack(segV, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - void Deserialize(std::string& name, std::vector>& b) - { - for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray()) - { - std::pair j; - j.first = i.GetArray()[0].GetUint64(); - j.second = i.GetArray()[1].GetBool(); - b.push_back(j); - } - } - - void Serialize(std::string& name, std::vector b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - for (auto& i : b) - { - bArr.PushBack(i, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - void Deserialize(std::string& name, std::vector& b) - { - for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray()) - { - b.push_back(i.GetUint64()); - } - } - - // std::unordered_map - void Serialize(std::string& name, std::unordered_map b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - for (auto& i : b) - { - rapidjson::Value p(rapidjson::kArrayType); - rapidjson::Value key(i.first.c_str(), m_activeContext.allocator); - p.PushBack(key, m_activeContext.allocator); - p.PushBack(i.second, m_activeContext.allocator); - bArr.PushBack(p, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - void Deserialize(std::string& name, std::unordered_map& b) - { - for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray()) - { - b[i.GetArray()[0].GetString()] = i.GetArray()[1].GetUint64(); - } - } - - template - void store(std::string x, T y) - { - Serialize(x, y); - } - - template - T load(std::string x, T y) - { - T val; - Deserialize(x, val); - return val; - } - - rapidjson::Document& GetDoc() - { - S(); - Store(); - return m_activeContext.doc; - } - -public: - virtual void Store() = 0; - virtual void Load() = 0; - - std::string AsString() - { - rapidjson::StringBuffer strbuf; - rapidjson::PrettyWriter writer(strbuf); - GetDoc().Accept(writer); - - std::string s = strbuf.GetString(); - return s; - } - rapidjson::Document& AsDocument() { return GetDoc(); } - void LoadFromString(const std::string& s) - { - m_activeDeserContext.doc.Parse(s.c_str()); - Load(); - } - void LoadFromValue(rapidjson::Value& s) - { - m_activeDeserContext.doc.CopyFrom(s, m_activeDeserContext.doc.GetAllocator()); - Load(); - } - Ref AsMetadata() { return new Metadata(AsString()); } - bool LoadFromMetadata(const Ref& meta) - { - if (!meta->IsString()) - return false; - LoadFromString(meta->GetString()); - return true; - } -}; - -#endif // SHAREDCACHE_METADATASERIALIZABLE_HPP diff --git a/view/sharedcache/api/sharedcache.cpp b/view/sharedcache/api/sharedcache.cpp index 5ca7c480eb..71d190da21 100644 --- a/view/sharedcache/api/sharedcache.cpp +++ b/view/sharedcache/api/sharedcache.cpp @@ -221,4 +221,5 @@ namespace SharedCacheAPI { { BNDSCFindSymbolAtAddressAndApplyToAddress(m_object, symbolLocation, targetLocation, triggerReanalysis); } + } // namespace SharedCacheAPI diff --git a/view/sharedcache/api/sharedcacheapi.h b/view/sharedcache/api/sharedcacheapi.h index 19f021e7c4..7b049bc423 100644 --- a/view/sharedcache/api/sharedcacheapi.h +++ b/view/sharedcache/api/sharedcacheapi.h @@ -1,7 +1,7 @@ #pragma once #include -#include "MetadataSerializable.hpp" +#include "../core/MetadataSerializable.hpp" #include "view/macho/machoview.h" #include "sharedcachecore.h" @@ -131,7 +131,7 @@ namespace SharedCacheAPI { }; using namespace BinaryNinja; - struct SharedCacheMachOHeader : public MetadataSerializable { + struct SharedCacheMachOHeader : public SharedCacheCore::MetadataSerializable { uint64_t textBase = 0; uint64_t loadCommandOffset = 0; mach_header_64 ident; @@ -174,412 +174,8 @@ namespace SharedCacheAPI { bool routinesPresent = false; bool functionStartsPresent = false; bool relocatable = false; - void Serialize(const std::string& name, mach_header_64 b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - bArr.PushBack(b.magic, m_activeContext.allocator); - bArr.PushBack(b.cputype, m_activeContext.allocator); - bArr.PushBack(b.cpusubtype, m_activeContext.allocator); - bArr.PushBack(b.filetype, m_activeContext.allocator); - bArr.PushBack(b.ncmds, m_activeContext.allocator); - bArr.PushBack(b.sizeofcmds, m_activeContext.allocator); - bArr.PushBack(b.flags, m_activeContext.allocator); - bArr.PushBack(b.reserved, m_activeContext.allocator); - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - - void Deserialize(const std::string& name, mach_header_64& b) - { - auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray(); - b.magic = bArr[0].GetInt64(); - b.cputype = bArr[1].GetInt64(); - b.cpusubtype = bArr[2].GetInt64(); - b.filetype = bArr[3].GetInt64(); - b.ncmds = bArr[4].GetInt64(); - b.sizeofcmds = bArr[5].GetInt64(); - b.flags = bArr[6].GetInt64(); - b.reserved = bArr[7].GetInt64(); - } - - void Serialize(const std::string& name, symtab_command b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - bArr.PushBack(b.cmd, m_activeContext.allocator); - bArr.PushBack(b.cmdsize, m_activeContext.allocator); - bArr.PushBack(b.symoff, m_activeContext.allocator); - bArr.PushBack(b.nsyms, m_activeContext.allocator); - bArr.PushBack(b.stroff, m_activeContext.allocator); - bArr.PushBack(b.strsize, m_activeContext.allocator); - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - - void Deserialize(const std::string& name, symtab_command& b) - { - auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray(); - b.cmd = bArr[0].GetUint(); - b.cmdsize = bArr[1].GetUint(); - b.symoff = bArr[2].GetUint(); - b.nsyms = bArr[3].GetUint(); - b.stroff = bArr[4].GetUint(); - b.strsize = bArr[5].GetUint(); - } - - void Serialize(const std::string& name, dysymtab_command b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - bArr.PushBack(b.cmd, m_activeContext.allocator); - bArr.PushBack(b.cmdsize, m_activeContext.allocator); - bArr.PushBack(b.ilocalsym, m_activeContext.allocator); - bArr.PushBack(b.nlocalsym, m_activeContext.allocator); - bArr.PushBack(b.iextdefsym, m_activeContext.allocator); - bArr.PushBack(b.nextdefsym, m_activeContext.allocator); - bArr.PushBack(b.iundefsym, m_activeContext.allocator); - bArr.PushBack(b.nundefsym, m_activeContext.allocator); - bArr.PushBack(b.tocoff, m_activeContext.allocator); - bArr.PushBack(b.ntoc, m_activeContext.allocator); - bArr.PushBack(b.modtaboff, m_activeContext.allocator); - bArr.PushBack(b.nmodtab, m_activeContext.allocator); - bArr.PushBack(b.extrefsymoff, m_activeContext.allocator); - bArr.PushBack(b.nextrefsyms, m_activeContext.allocator); - bArr.PushBack(b.indirectsymoff, m_activeContext.allocator); - bArr.PushBack(b.nindirectsyms, m_activeContext.allocator); - bArr.PushBack(b.extreloff, m_activeContext.allocator); - bArr.PushBack(b.nextrel, m_activeContext.allocator); - bArr.PushBack(b.locreloff, m_activeContext.allocator); - bArr.PushBack(b.nlocrel, m_activeContext.allocator); - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - - void Deserialize(const std::string& name, dysymtab_command& b) - { - auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray(); - b.cmd = bArr[0].GetUint(); - b.cmdsize = bArr[1].GetUint(); - b.ilocalsym = bArr[2].GetUint(); - b.nlocalsym = bArr[3].GetUint(); - b.iextdefsym = bArr[4].GetUint(); - b.nextdefsym = bArr[5].GetUint(); - b.iundefsym = bArr[6].GetUint(); - b.nundefsym = bArr[7].GetUint(); - b.tocoff = bArr[8].GetUint(); - b.ntoc = bArr[9].GetUint(); - b.modtaboff = bArr[10].GetUint(); - b.nmodtab = bArr[11].GetUint(); - b.extrefsymoff = bArr[12].GetUint(); - b.nextrefsyms = bArr[13].GetUint(); - b.indirectsymoff = bArr[14].GetUint(); - b.nindirectsyms = bArr[15].GetUint(); - b.extreloff = bArr[16].GetUint(); - b.nextrel = bArr[17].GetUint(); - b.locreloff = bArr[18].GetUint(); - b.nlocrel = bArr[19].GetUint(); - } - - void Serialize(const std::string& name, dyld_info_command b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - bArr.PushBack(b.cmd, m_activeContext.allocator); - bArr.PushBack(b.cmdsize, m_activeContext.allocator); - bArr.PushBack(b.rebase_off, m_activeContext.allocator); - bArr.PushBack(b.rebase_size, m_activeContext.allocator); - bArr.PushBack(b.bind_off, m_activeContext.allocator); - bArr.PushBack(b.bind_size, m_activeContext.allocator); - bArr.PushBack(b.weak_bind_off, m_activeContext.allocator); - bArr.PushBack(b.weak_bind_size, m_activeContext.allocator); - bArr.PushBack(b.lazy_bind_off, m_activeContext.allocator); - bArr.PushBack(b.lazy_bind_size, m_activeContext.allocator); - bArr.PushBack(b.export_off, m_activeContext.allocator); - bArr.PushBack(b.export_size, m_activeContext.allocator); - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - - void Deserialize(const std::string& name, dyld_info_command& b) - { - auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray(); - b.cmd = bArr[0].GetUint(); - b.cmdsize = bArr[1].GetUint(); - b.rebase_off = bArr[2].GetUint(); - b.rebase_size = bArr[3].GetUint(); - b.bind_off = bArr[4].GetUint(); - b.bind_size = bArr[5].GetUint(); - b.weak_bind_off = bArr[6].GetUint(); - b.weak_bind_size = bArr[7].GetUint(); - b.lazy_bind_off = bArr[8].GetUint(); - b.lazy_bind_size = bArr[9].GetUint(); - b.export_off = bArr[10].GetUint(); - b.export_size = bArr[11].GetUint(); - } - - void Serialize(const std::string& name, routines_command_64 b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - bArr.PushBack(b.cmd, m_activeContext.allocator); - bArr.PushBack(b.cmdsize, m_activeContext.allocator); - bArr.PushBack(b.init_address, m_activeContext.allocator); - bArr.PushBack(b.init_module, m_activeContext.allocator); - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - - void Deserialize(const std::string& name, routines_command_64& b) - { - auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray(); - b.cmd = bArr[0].GetUint(); - b.cmdsize = bArr[1].GetUint(); - b.init_address = bArr[2].GetUint(); - b.init_module = bArr[3].GetUint(); - } - - void Serialize(const std::string& name, function_starts_command b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - bArr.PushBack(b.cmd, m_activeContext.allocator); - bArr.PushBack(b.cmdsize, m_activeContext.allocator); - bArr.PushBack(b.funcoff, m_activeContext.allocator); - bArr.PushBack(b.funcsize, m_activeContext.allocator); - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - - void Deserialize(const std::string& name, function_starts_command& b) - { - auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray(); - b.cmd = bArr[0].GetUint(); - b.cmdsize = bArr[1].GetUint(); - b.funcoff = bArr[2].GetUint(); - b.funcsize = bArr[3].GetUint(); - } - - void Serialize(const std::string& name, std::vector b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - for (auto& s : b) - { - rapidjson::Value sArr(rapidjson::kArrayType); - std::string sectNameStr; - char sectName[16]; - memcpy(sectName, s.sectname, 16); - sectName[15] = 0; - sectNameStr = std::string(sectName); - sArr.PushBack(rapidjson::Value(sectNameStr.c_str(), m_activeContext.allocator), m_activeContext.allocator); - std::string segNameStr; - char segName[16]; - memcpy(segName, s.segname, 16); - segName[15] = 0; - segNameStr = std::string(segName); - sArr.PushBack(rapidjson::Value(segNameStr.c_str(), m_activeContext.allocator), m_activeContext.allocator); - sArr.PushBack(s.addr, m_activeContext.allocator); - sArr.PushBack(s.size, m_activeContext.allocator); - sArr.PushBack(s.offset, m_activeContext.allocator); - sArr.PushBack(s.align, m_activeContext.allocator); - sArr.PushBack(s.reloff, m_activeContext.allocator); - sArr.PushBack(s.nreloc, m_activeContext.allocator); - sArr.PushBack(s.flags, m_activeContext.allocator); - sArr.PushBack(s.reserved1, m_activeContext.allocator); - sArr.PushBack(s.reserved2, m_activeContext.allocator); - sArr.PushBack(s.reserved3, m_activeContext.allocator); - bArr.PushBack(sArr, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - - void Deserialize(const std::string& name, std::vector& b) - { - auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray(); - for (auto& s : bArr) - { - section_64 sec; - auto s2 = s.GetArray(); - std::string sectNameStr = s2[0].GetString(); - memcpy(sec.sectname, sectNameStr.c_str(), sectNameStr.size()); - std::string segNameStr = s2[1].GetString(); - memcpy(sec.segname, segNameStr.c_str(), segNameStr.size()); - sec.addr = s2[2].GetUint64(); - sec.size = s2[3].GetUint64(); - sec.offset = s2[4].GetUint(); - sec.align = s2[5].GetUint(); - sec.reloff = s2[6].GetUint(); - sec.nreloc = s2[7].GetUint(); - sec.flags = s2[8].GetUint(); - sec.reserved1 = s2[9].GetUint(); - sec.reserved2 = s2[10].GetUint(); - sec.reserved3 = s2[11].GetUint(); - b.push_back(sec); - } - } - - void Serialize(const std::string& name, linkedit_data_command b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - bArr.PushBack(b.cmd, m_activeContext.allocator); - bArr.PushBack(b.cmdsize, m_activeContext.allocator); - bArr.PushBack(b.dataoff, m_activeContext.allocator); - bArr.PushBack(b.datasize, m_activeContext.allocator); - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - - void Deserialize(const std::string& name, linkedit_data_command& b) - { - auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray(); - b.cmd = bArr[0].GetUint(); - b.cmdsize = bArr[1].GetUint(); - b.dataoff = bArr[2].GetUint(); - b.datasize = bArr[3].GetUint(); - } - - void Serialize(const std::string& name, segment_command_64 b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - std::string segNameStr; - char segName[16]; - memcpy(segName, b.segname, 16); - segName[15] = 0; - segNameStr = std::string(segName); - bArr.PushBack(rapidjson::Value(segNameStr.c_str(), m_activeContext.allocator), m_activeContext.allocator); - bArr.PushBack(b.vmaddr, m_activeContext.allocator); - bArr.PushBack(b.vmsize, m_activeContext.allocator); - bArr.PushBack(b.fileoff, m_activeContext.allocator); - bArr.PushBack(b.filesize, m_activeContext.allocator); - bArr.PushBack(b.maxprot, m_activeContext.allocator); - bArr.PushBack(b.initprot, m_activeContext.allocator); - bArr.PushBack(b.nsects, m_activeContext.allocator); - bArr.PushBack(b.flags, m_activeContext.allocator); - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - - void Deserialize(const std::string& name, segment_command_64& b) - { - auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray(); - std::string segNameStr = bArr[0].GetString(); - memcpy(b.segname, segNameStr.c_str(), segNameStr.size()); - b.vmaddr = bArr[1].GetUint64(); - b.vmsize = bArr[2].GetUint64(); - b.fileoff = bArr[3].GetUint64(); - b.filesize = bArr[4].GetUint64(); - b.maxprot = bArr[5].GetUint(); - b.initprot = bArr[6].GetUint(); - b.nsects = bArr[7].GetUint(); - b.flags = bArr[8].GetUint(); - } - void Serialize(const std::string& name, std::vector b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - for (auto& s : b) - { - rapidjson::Value sArr(rapidjson::kArrayType); - std::string segNameStr; - char segName[16]; - memcpy(segName, s.segname, 16); - segName[15] = 0; - segNameStr = std::string(segName); - sArr.PushBack(rapidjson::Value(segNameStr.c_str(), m_activeContext.allocator), m_activeContext.allocator); - sArr.PushBack(s.vmaddr, m_activeContext.allocator); - sArr.PushBack(s.vmsize, m_activeContext.allocator); - sArr.PushBack(s.fileoff, m_activeContext.allocator); - sArr.PushBack(s.filesize, m_activeContext.allocator); - sArr.PushBack(s.maxprot, m_activeContext.allocator); - sArr.PushBack(s.initprot, m_activeContext.allocator); - sArr.PushBack(s.nsects, m_activeContext.allocator); - sArr.PushBack(s.flags, m_activeContext.allocator); - bArr.PushBack(sArr, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - - void Deserialize(const std::string& name, std::vector& b) - { - auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray(); - for (auto& s : bArr) - { - segment_command_64 sec; - auto s2 = s.GetArray(); - std::string segNameStr = s2[0].GetString(); - memcpy(sec.segname, segNameStr.c_str(), segNameStr.size()); - sec.vmaddr = s2[1].GetUint64(); - sec.vmsize = s2[2].GetUint64(); - sec.fileoff = s2[3].GetUint64(); - sec.filesize = s2[4].GetUint64(); - sec.maxprot = s2[5].GetUint(); - sec.initprot = s2[6].GetUint(); - sec.nsects = s2[7].GetUint(); - sec.flags = s2[8].GetUint(); - b.push_back(sec); - } - } - - void Serialize(const std::string& name, build_version_command b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - bArr.PushBack(b.cmd, m_activeContext.allocator); - bArr.PushBack(b.cmdsize, m_activeContext.allocator); - bArr.PushBack(b.platform, m_activeContext.allocator); - bArr.PushBack(b.minos, m_activeContext.allocator); - bArr.PushBack(b.sdk, m_activeContext.allocator); - bArr.PushBack(b.ntools, m_activeContext.allocator); - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - - void Deserialize(const std::string& name, build_version_command& b) - { - auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray(); - b.cmd = bArr[0].GetUint(); - b.cmdsize = bArr[1].GetUint(); - b.platform = bArr[2].GetUint(); - b.minos = bArr[3].GetUint(); - b.sdk = bArr[4].GetUint(); - b.ntools = bArr[5].GetUint(); - } - - void Serialize(const std::string& name, std::vector b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - for (auto& s : b) - { - rapidjson::Value sArr(rapidjson::kArrayType); - sArr.PushBack(s.tool, m_activeContext.allocator); - sArr.PushBack(s.version, m_activeContext.allocator); - bArr.PushBack(sArr, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - - void Deserialize(const std::string& name, std::vector& b) - { - auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray(); - for (auto& s : bArr) - { - build_tool_version sec; - auto s2 = s.GetArray(); - sec.tool = s2[0].GetUint(); - sec.version = s2[1].GetUint(); - b.push_back(sec); - } - } - - void Store() override { + void Store(SharedCacheCore::SerializationContext& context) const { MSS(textBase); MSS(loadCommandOffset); MSS_SUBCLASS(ident); @@ -614,7 +210,8 @@ namespace SharedCacheAPI { MSS(functionStartsPresent); MSS(relocatable); } - void Load() override { + + void Load(SharedCacheCore::DeserializationContext& context) { MSL(textBase); MSL(loadCommandOffset); MSL_SUBCLASS(ident); diff --git a/view/sharedcache/core/MetadataSerializable.cpp b/view/sharedcache/core/MetadataSerializable.cpp new file mode 100644 index 0000000000..ad8959f262 --- /dev/null +++ b/view/sharedcache/core/MetadataSerializable.cpp @@ -0,0 +1,548 @@ +#include "MetadataSerializable.hpp" + +namespace SharedCacheCore { + +void Serialize(SerializationContext& context, std::string_view str) { + context.writer.String(str.data(), str.length()); +} + +void Serialize(SerializationContext& context, const char* value) { + Serialize(context, std::string_view(value)); +} + +void Serialize(SerializationContext& context, bool b) +{ + context.writer.Bool(b); +} + +void Serialize(SerializationContext& context, int8_t value) { + context.writer.Int(value); +} + +void Serialize(SerializationContext& context, uint8_t value) { + context.writer.Uint(value); +} + +void Serialize(SerializationContext& context, int16_t value) { + context.writer.Int(value); +} + +void Serialize(SerializationContext& context, uint16_t value) { + context.writer.Uint(value); +} + +void Serialize(SerializationContext& context, int32_t value) { + context.writer.Int(value); +} + +void Serialize(SerializationContext& context, uint32_t value) { + context.writer.Uint(value); +} + +void Serialize(SerializationContext& context, int64_t value) { + context.writer.Int64(value); +} + +void Serialize(SerializationContext& context, uint64_t value) { + context.writer.Uint64(value); +} + +void Deserialize(DeserializationContext& context, std::string_view name, bool& b) { + b = context.doc[name.data()].GetBool(); +} + +void Deserialize(DeserializationContext& context, std::string_view name, uint8_t& b) +{ + b = static_cast(context.doc[name.data()].GetUint64()); +} + +void Deserialize(DeserializationContext& context, std::string_view name, uint16_t& b) +{ + b = static_cast(context.doc[name.data()].GetUint64()); +} + +void Deserialize(DeserializationContext& context, std::string_view name, uint32_t& b) +{ + b = static_cast(context.doc[name.data()].GetUint64()); +} + +void Deserialize(DeserializationContext& context, std::string_view name, uint64_t& b) +{ + b = context.doc[name.data()].GetUint64(); +} + +void Deserialize(DeserializationContext& context, std::string_view name, int8_t& b) +{ + b = context.doc[name.data()].GetInt64(); +} + +void Deserialize(DeserializationContext& context, std::string_view name, int16_t& b) +{ + b = context.doc[name.data()].GetInt64(); +} + +void Deserialize(DeserializationContext& context, std::string_view name, int32_t& b) +{ + b = context.doc[name.data()].GetInt(); +} + +void Deserialize(DeserializationContext& context, std::string_view name, int64_t& b) +{ + b = context.doc[name.data()].GetInt64(); +} + +void Deserialize(DeserializationContext& context, std::string_view name, std::string& b) +{ + b = context.doc[name.data()].GetString(); +} + +void Deserialize(DeserializationContext& context, std::string_view name, std::map& b) +{ + for (auto& i : context.doc[name.data()].GetArray()) + b[i.GetArray()[0].GetUint64()] = i.GetArray()[1].GetString(); +} + +void Deserialize(DeserializationContext& context, std::string_view name, std::unordered_map& b) +{ + for (auto& i : context.doc[name.data()].GetArray()) + b[i.GetArray()[0].GetUint64()] = i.GetArray()[1].GetString(); +} + +void Deserialize(DeserializationContext& context, std::string_view name, std::unordered_map& b) +{ + for (auto& i : context.doc[name.data()].GetArray()) + b[i.GetArray()[0].GetUint64()] = i.GetArray()[1].GetUint64(); +} + +void Deserialize(DeserializationContext& context, std::string_view name, std::unordered_map>& b) +{ + for (auto& i : context.doc[name.data()].GetArray()) + { + std::string key = i.GetArray()[0].GetString(); + std::unordered_map memArray; + for (auto& member : i.GetArray()[1].GetArray()) + { + memArray[member.GetArray()[0].GetUint64()] = member.GetArray()[1].GetUint64(); + } + b[key] = memArray; + } +} + +void Deserialize(DeserializationContext& context, std::string_view name, std::unordered_map& b) +{ + for (auto& i : context.doc[name.data()].GetArray()) + b[i.GetArray()[0].GetString()] = i.GetArray()[1].GetString(); +} + +void Deserialize(DeserializationContext& context, std::string_view name, std::vector& b) +{ + for (auto& i : context.doc[name.data()].GetArray()) + b.emplace_back(i.GetString()); +} + +// Note: This flattens the pair into [first, second.first, second.second] with no nested arrays. +void Serialize(SerializationContext& context, const std::pair>& value) +{ + context.writer.StartArray(); + Serialize(context, value.first); + Serialize(context, value.second.first); + Serialize(context, value.second.second); + context.writer.EndArray(); +} + +void Deserialize(DeserializationContext& context, std::string_view name, std::vector>>& b) +{ + for (auto& i : context.doc[name.data()].GetArray()) + { + std::pair> j; + j.first = i.GetArray()[0].GetUint64(); + j.second.first = i.GetArray()[1].GetUint64(); + j.second.second = i.GetArray()[2].GetUint64(); + b.push_back(j); + } +} + +void Deserialize(DeserializationContext& context, std::string_view name, std::vector>& b) +{ + for (auto& i : context.doc[name.data()].GetArray()) + { + std::pair j; + j.first = i.GetArray()[0].GetUint64(); + j.second = i.GetArray()[1].GetBool(); + b.push_back(j); + } +} + +void Deserialize(DeserializationContext& context, std::string_view name, std::vector& b) +{ + for (auto& i : context.doc[name.data()].GetArray()) + { + b.push_back(i.GetUint64()); + } +} + +void Deserialize(DeserializationContext& context, std::string_view name, std::unordered_map& b) +{ + for (auto& i : context.doc[name.data()].GetArray()) + { + b[i.GetArray()[0].GetString()] = i.GetArray()[1].GetUint64(); + } +} + +void Deserialize(DeserializationContext& context, std::string_view name, std::vector>>>& b) +{ + for (auto& i : context.doc[name.data()].GetArray()) + { + std::pair>> j; + j.first = i.GetArray()[0].GetUint64(); + for (auto& k : i.GetArray()[1].GetArray()) + { + j.second.push_back({k.GetArray()[0].GetUint64(), k.GetArray()[1].GetString()}); + } + b.push_back(j); + } +} + +void Serialize(SerializationContext& context, const mach_header_64& value) { + context.writer.StartArray(); + Serialize(context, value.magic); + // cputype and cpusubtype are signed but were serialized as unsigned in + // v4.2 (metadata version 2). We continue serializing them as unsigned + // so we don't need to bump the metadata version. + Serialize(context, static_cast(value.cputype)); + Serialize(context, static_cast(value.cpusubtype)); + Serialize(context, value.filetype); + Serialize(context, value.ncmds); + Serialize(context, value.sizeofcmds); + Serialize(context, value.flags); + Serialize(context, value.reserved); + context.writer.EndArray(); +} + +void Deserialize(DeserializationContext& context, std::string_view name, mach_header_64& b) +{ + auto bArr = context.doc[name.data()].GetArray(); + b.magic = bArr[0].GetUint(); + b.cputype = bArr[1].GetUint(); + b.cpusubtype = bArr[2].GetUint(); + b.filetype = bArr[3].GetUint(); + b.ncmds = bArr[4].GetUint(); + b.sizeofcmds = bArr[5].GetUint(); + b.flags = bArr[6].GetUint(); + b.reserved = bArr[7].GetUint(); +} + +void Serialize(SerializationContext& context, const symtab_command& value) +{ + context.writer.StartArray(); + Serialize(context, value.cmd); + Serialize(context, value.cmdsize); + Serialize(context, value.symoff); + Serialize(context, value.nsyms); + Serialize(context, value.stroff); + Serialize(context, value.strsize); + context.writer.EndArray(); +} + +void Deserialize(DeserializationContext& context, std::string_view name, symtab_command& b) +{ + auto bArr = context.doc[name.data()].GetArray(); + b.cmd = bArr[0].GetUint(); + b.cmdsize = bArr[1].GetUint(); + b.symoff = bArr[2].GetUint(); + b.nsyms = bArr[3].GetUint(); + b.stroff = bArr[4].GetUint(); + b.strsize = bArr[5].GetUint(); +} + +void Serialize(SerializationContext& context, const dysymtab_command& value) +{ + context.writer.StartArray(); + Serialize(context, value.cmd); + Serialize(context, value.cmdsize); + Serialize(context, value.ilocalsym); + Serialize(context, value.nlocalsym); + Serialize(context, value.iextdefsym); + Serialize(context, value.nextdefsym); + Serialize(context, value.iundefsym); + Serialize(context, value.nundefsym); + Serialize(context, value.tocoff); + Serialize(context, value.ntoc); + Serialize(context, value.modtaboff); + Serialize(context, value.nmodtab); + Serialize(context, value.extrefsymoff); + Serialize(context, value.nextrefsyms); + Serialize(context, value.indirectsymoff); + Serialize(context, value.nindirectsyms); + Serialize(context, value.extreloff); + Serialize(context, value.nextrel); + Serialize(context, value.locreloff); + Serialize(context, value.nlocrel); + context.writer.EndArray(); +} + +void Deserialize(DeserializationContext& context, std::string_view name, dysymtab_command& b) +{ + auto bArr = context.doc[name.data()].GetArray(); + b.cmd = bArr[0].GetUint(); + b.cmdsize = bArr[1].GetUint(); + b.ilocalsym = bArr[2].GetUint(); + b.nlocalsym = bArr[3].GetUint(); + b.iextdefsym = bArr[4].GetUint(); + b.nextdefsym = bArr[5].GetUint(); + b.iundefsym = bArr[6].GetUint(); + b.nundefsym = bArr[7].GetUint(); + b.tocoff = bArr[8].GetUint(); + b.ntoc = bArr[9].GetUint(); + b.modtaboff = bArr[10].GetUint(); + b.nmodtab = bArr[11].GetUint(); + b.extrefsymoff = bArr[12].GetUint(); + b.nextrefsyms = bArr[13].GetUint(); + b.indirectsymoff = bArr[14].GetUint(); + b.nindirectsyms = bArr[15].GetUint(); + b.extreloff = bArr[16].GetUint(); + b.nextrel = bArr[17].GetUint(); + b.locreloff = bArr[18].GetUint(); + b.nlocrel = bArr[19].GetUint(); +} + +void Serialize(SerializationContext& context, const dyld_info_command& value) +{ + context.writer.StartArray(); + Serialize(context, value.cmd); + Serialize(context, value.cmdsize); + Serialize(context, value.rebase_off); + Serialize(context, value.rebase_size); + Serialize(context, value.bind_off); + Serialize(context, value.bind_size); + Serialize(context, value.weak_bind_off); + Serialize(context, value.weak_bind_size); + Serialize(context, value.lazy_bind_off); + Serialize(context, value.lazy_bind_size); + Serialize(context, value.export_off); + Serialize(context, value.export_size); + context.writer.EndArray(); +} + +void Deserialize(DeserializationContext& context, std::string_view name, dyld_info_command& b) +{ + auto bArr = context.doc[name.data()].GetArray(); + b.cmd = bArr[0].GetUint(); + b.cmdsize = bArr[1].GetUint(); + b.rebase_off = bArr[2].GetUint(); + b.rebase_size = bArr[3].GetUint(); + b.bind_off = bArr[4].GetUint(); + b.bind_size = bArr[5].GetUint(); + b.weak_bind_off = bArr[6].GetUint(); + b.weak_bind_size = bArr[7].GetUint(); + b.lazy_bind_off = bArr[8].GetUint(); + b.lazy_bind_size = bArr[9].GetUint(); + b.export_off = bArr[10].GetUint(); + b.export_size = bArr[11].GetUint(); +} + +void Serialize(SerializationContext& context, const routines_command_64& value) +{ + context.writer.StartArray(); + Serialize(context, value.cmd); + Serialize(context, value.cmdsize); + Serialize(context, value.init_address); + Serialize(context, value.init_module); + context.writer.EndArray(); +} + +void Deserialize(DeserializationContext& context, std::string_view name, routines_command_64& b) +{ + auto bArr = context.doc[name.data()].GetArray(); + b.cmd = bArr[0].GetUint(); + b.cmdsize = bArr[1].GetUint(); + b.init_address = bArr[2].GetUint(); + b.init_module = bArr[3].GetUint(); +} + +void Serialize(SerializationContext& context, const function_starts_command& value) +{ + context.writer.StartArray(); + Serialize(context, value.cmd); + Serialize(context, value.cmdsize); + Serialize(context, value.funcoff); + Serialize(context, value.funcsize); + context.writer.EndArray(); +} + +void Deserialize(DeserializationContext& context, std::string_view name, function_starts_command& b) +{ + auto bArr = context.doc[name.data()].GetArray(); + b.cmd = bArr[0].GetUint(); + b.cmdsize = bArr[1].GetUint(); + b.funcoff = bArr[2].GetUint(); + b.funcsize = bArr[3].GetUint(); +} + +void Serialize(SerializationContext& context, const section_64& value) +{ + context.writer.StartArray(); + + std::string_view sectname(value.sectname, 16); + std::string_view segname(value.segname, 16); + + Serialize(context, sectname.substr(0, sectname.find('\0'))); + Serialize(context, segname.substr(0, segname.find('\0'))); + Serialize(context, value.addr); + Serialize(context, value.size); + Serialize(context, value.offset); + Serialize(context, value.align); + Serialize(context, value.reloff); + Serialize(context, value.nreloc); + Serialize(context, value.flags); + Serialize(context, value.reserved1); + Serialize(context, value.reserved2); + Serialize(context, value.reserved3); + context.writer.EndArray(); +} + +void Deserialize(DeserializationContext& context, std::string_view name, std::vector& b) +{ + auto bArr = context.doc[name.data()].GetArray(); + for (auto& s : bArr) + { + section_64 sec; + auto s2 = s.GetArray(); + std::string sectNameStr = s2[0].GetString(); + memset(sec.sectname, 0, 16); + memcpy(sec.sectname, sectNameStr.c_str(), sectNameStr.size()); + std::string segNameStr = s2[1].GetString(); + memset(sec.segname, 0, 16); + memcpy(sec.segname, segNameStr.c_str(), segNameStr.size()); + sec.addr = s2[2].GetUint64(); + sec.size = s2[3].GetUint64(); + sec.offset = s2[4].GetUint(); + sec.align = s2[5].GetUint(); + sec.reloff = s2[6].GetUint(); + sec.nreloc = s2[7].GetUint(); + sec.flags = s2[8].GetUint(); + sec.reserved1 = s2[9].GetUint(); + sec.reserved2 = s2[10].GetUint(); + sec.reserved3 = s2[11].GetUint(); + b.push_back(std::move(sec)); + } +} + +void Serialize(SerializationContext& context, const linkedit_data_command& value) +{ + context.writer.StartArray(); + Serialize(context, value.cmd); + Serialize(context, value.cmdsize); + Serialize(context, value.dataoff); + Serialize(context, value.datasize); + context.writer.EndArray(); +} + +void Deserialize(DeserializationContext& context, std::string_view name, linkedit_data_command& b) +{ + auto bArr = context.doc[name.data()].GetArray(); + b.cmd = bArr[0].GetUint(); + b.cmdsize = bArr[1].GetUint(); + b.dataoff = bArr[2].GetUint(); + b.datasize = bArr[3].GetUint(); +} + +void Serialize(SerializationContext& context, const segment_command_64& value) +{ + context.writer.StartArray(); + std::string_view segname(value.segname, 16); + Serialize(context, segname.substr(0, segname.find('\0'))); + Serialize(context, value.vmaddr); + Serialize(context, value.vmsize); + Serialize(context, value.fileoff); + Serialize(context, value.filesize); + Serialize(context, value.maxprot); + Serialize(context, value.initprot); + Serialize(context, value.nsects); + Serialize(context, value.flags); + context.writer.EndArray(); +} + +void Deserialize(DeserializationContext& context, std::string_view name, segment_command_64& b) +{ + auto bArr = context.doc[name.data()].GetArray(); + std::string segNameStr = bArr[0].GetString(); + memset(b.segname, 0, 16); + memcpy(b.segname, segNameStr.c_str(), segNameStr.size()); + b.vmaddr = bArr[1].GetUint64(); + b.vmsize = bArr[2].GetUint64(); + b.fileoff = bArr[3].GetUint64(); + b.filesize = bArr[4].GetUint64(); + b.maxprot = bArr[5].GetUint(); + b.initprot = bArr[6].GetUint(); + b.nsects = bArr[7].GetUint(); + b.flags = bArr[8].GetUint(); +} + +void Deserialize(DeserializationContext& context, std::string_view name, std::vector& b) +{ + auto bArr = context.doc[name.data()].GetArray(); + for (auto& s : bArr) + { + segment_command_64 sec; + auto s2 = s.GetArray(); + std::string segNameStr = s2[0].GetString(); + memset(sec.segname, 0, 16); + memcpy(sec.segname, segNameStr.c_str(), segNameStr.size()); + sec.vmaddr = s2[1].GetUint64(); + sec.vmsize = s2[2].GetUint64(); + sec.fileoff = s2[3].GetUint64(); + sec.filesize = s2[4].GetUint64(); + sec.maxprot = s2[5].GetUint(); + sec.initprot = s2[6].GetUint(); + sec.nsects = s2[7].GetUint(); + sec.flags = s2[8].GetUint(); + b.push_back(std::move(sec)); + } +} + +void Serialize(SerializationContext& context, const build_version_command& value) +{ + context.writer.StartArray(); + Serialize(context, value.cmd); + Serialize(context, value.cmdsize); + Serialize(context, value.platform); + Serialize(context, value.minos); + Serialize(context, value.sdk); + Serialize(context, value.ntools); + context.writer.EndArray(); +} + +void Deserialize(DeserializationContext& context, std::string_view name, build_version_command& b) +{ + auto bArr = context.doc[name.data()].GetArray(); + b.cmd = bArr[0].GetUint(); + b.cmdsize = bArr[1].GetUint(); + b.platform = bArr[2].GetUint(); + b.minos = bArr[3].GetUint(); + b.sdk = bArr[4].GetUint(); + b.ntools = bArr[5].GetUint(); +} + +void Serialize(SerializationContext& context, const build_tool_version& value) +{ + context.writer.StartArray(); + Serialize(context, value.tool); + Serialize(context, value.version); + context.writer.EndArray(); +} + +void Deserialize(DeserializationContext& context, std::string_view name, std::vector& b) +{ + auto bArr = context.doc[name.data()].GetArray(); + for (auto& s : bArr) + { + build_tool_version sec; + auto s2 = s.GetArray(); + sec.tool = s2[0].GetUint(); + sec.version = s2[1].GetUint(); + b.push_back(sec); + } +} + +} // namespace SharedCacheCore diff --git a/view/sharedcache/core/MetadataSerializable.hpp b/view/sharedcache/core/MetadataSerializable.hpp index c49a9e8c47..7b44ccbdbf 100644 --- a/view/sharedcache/core/MetadataSerializable.hpp +++ b/view/sharedcache/core/MetadataSerializable.hpp @@ -12,15 +12,17 @@ * * Great news. * - * Implement these on your `public MetadataSerializable` subclass: + * Implement these on your `public MetadataSerializable` subclass: * ``` - void Store() override { - MSS(m_someVariable); - MSS(m_someOtherVariable); - } - void Load() override { - MSL(m_someVariable); - MSL(m_someOtherVariable); + class MyClass : public MetadataSerializable { + void Store(SerializationContext& context) const { + MSS(m_someVariable); + MSS(m_someOtherVariable); + } + void Load(DeserializationContext& context) { + MSL(m_someVariable); + MSL(m_someOtherVariable); + } } ``` * Then, you can turn your object into a Metadata object with `AsMetadata()`, and load it back with @@ -36,502 +38,216 @@ #include "rapidjson/document.h" #include "rapidjson/stringbuffer.h" #include "rapidjson/prettywriter.h" +#include "../api/sharedcachecore.h" +#include "view/macho/machoview.h" -#ifndef SHAREDCACHE_METADATASERIALIZABLE_HPP -#define SHAREDCACHE_METADATASERIALIZABLE_HPP - -#define MSS(name) store(#name, name) -#define MSS_CAST(name, type) store(#name, (type) name) -#define MSS_SUBCLASS(name) Serialize(#name, name) -#define MSL(name) name = load(#name, name) -#define MSL_CAST(name, storedType, type) name = (type)load(#name, (storedType) name) -#define MSL_SUBCLASS(name) Deserialize(#name, name) - -using namespace BinaryNinja; - -class MetadataSerializable -{ -protected: - struct SerialContext - { - rapidjson::Document doc; - rapidjson::Document::AllocatorType allocator; - }; - struct DeserContext - { - rapidjson::Document doc; - }; - - DeserContext m_activeDeserContext; - SerialContext m_activeContext; - -public: - MetadataSerializable() - { - m_activeContext.doc.SetObject(); - m_activeContext.allocator = m_activeContext.doc.GetAllocator(); - } - - // copy constructor - MetadataSerializable(const MetadataSerializable& other) - { - m_activeContext.doc.CopyFrom(other.m_activeContext.doc, m_activeContext.doc.GetAllocator()); - } - - // copy assignment - MetadataSerializable& operator=(const MetadataSerializable& other) - { - m_activeContext.doc.CopyFrom(other.m_activeContext.doc, m_activeContext.doc.GetAllocator()); - return *this; - } - - virtual ~MetadataSerializable() - { - } - - void SetupSerContext(rapidjson::Document::AllocatorType* alloc = nullptr) - { - m_activeContext.doc.SetObject(); - m_activeContext.allocator = m_activeContext.doc.GetAllocator(); - } - void S() - { - // fixme factor out - } - void Serialize(std::string& name, bool b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - m_activeContext.doc.AddMember(key, b, m_activeContext.allocator); - } - void Deserialize(std::string& name, bool& b) { b = m_activeDeserContext.doc[name.c_str()].GetBool(); } +#ifndef SHAREDCACHE_CORE_METADATASERIALIZABLE_HPP +#define SHAREDCACHE_CORE_METADATASERIALIZABLE_HPP - void Serialize(std::string& name, uint8_t b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - m_activeContext.doc.AddMember(key, b, m_activeContext.allocator); - } - void Deserialize(std::string& name, uint8_t& b) - { - b = static_cast(m_activeDeserContext.doc[name.c_str()].GetUint64()); - } +namespace SharedCacheCore { - void Serialize(std::string& name, uint16_t b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - m_activeContext.doc.AddMember(key, b, m_activeContext.allocator); - } - void Deserialize(std::string& name, uint16_t& b) - { - b = static_cast(m_activeDeserContext.doc[name.c_str()].GetUint64()); - } +#define MSS(name) context.store(#name, name) +#define MSS_CAST(name, type) context.store(#name, (type) name) +#define MSS_SUBCLASS(name) Serialize(context, #name, name) +#define MSL(name) name = context.load(#name) +#define MSL_CAST(name, storedType, type) name = (type)context.load(#name) +#define MSL_SUBCLASS(name) Deserialize(context, #name, name) - void Serialize(std::string& name, uint32_t b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - m_activeContext.doc.AddMember(key, b, m_activeContext.allocator); - } - void Deserialize(std::string& name, uint32_t& b) - { - b = static_cast(m_activeDeserContext.doc[name.c_str()].GetUint64()); - } +using namespace BinaryNinja; - void Serialize(std::string& name, uint64_t b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - m_activeContext.doc.AddMember(key, b, m_activeContext.allocator); - } - void Deserialize(std::string& name, uint64_t& b) - { - b = m_activeDeserContext.doc[name.c_str()].GetUint64(); - } +struct DeserializationContext; - void Serialize(std::string& name, int8_t b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - m_activeContext.doc.AddMember(key, b, m_activeContext.allocator); - } - void Deserialize(std::string& name, int8_t& b) - { - b = m_activeDeserContext.doc[name.c_str()].GetInt64(); - } +struct SerializationContext { + rapidjson::StringBuffer buffer; + rapidjson::PrettyWriter writer; - void Serialize(std::string& name, int16_t b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - m_activeContext.doc.AddMember(key, b, m_activeContext.allocator); - } - void Deserialize(std::string& name, int16_t& b) - { - b = m_activeDeserContext.doc[name.c_str()].GetInt64(); + SerializationContext() : buffer(), writer(buffer) { } - void Serialize(std::string& name, int32_t b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - m_activeContext.doc.AddMember(key, b, m_activeContext.allocator); - } - void Deserialize(std::string& name, int32_t& b) + template + void store(std::string_view x, const T& y) { - b = m_activeDeserContext.doc[name.c_str()].GetInt(); + Serialize(*this, x, y); } +}; - void Serialize(std::string& name, int64_t b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - m_activeContext.doc.AddMember(key, b, m_activeContext.allocator); - } - void Deserialize(std::string& name, int64_t& b) - { - b = m_activeDeserContext.doc[name.c_str()].GetInt64(); - } +struct DeserializationContext { + rapidjson::Document doc; - void Serialize(std::string& name, std::string b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value value(b.c_str(), m_activeContext.allocator); - m_activeContext.doc.AddMember(key, value, m_activeContext.allocator); - } - void Deserialize(std::string& name, std::string& b) + template + T load(std::string_view x) { - b = m_activeDeserContext.doc[name.c_str()].GetString(); + T value; + Deserialize(*this, x, value); + return value; } +}; - void Serialize(std::string& name, std::map b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - for (auto& i : b) - { - rapidjson::Value p(rapidjson::kArrayType); - p.PushBack(i.first, m_activeContext.allocator); - rapidjson::Value value(i.second.c_str(), m_activeContext.allocator); - p.PushBack(value, m_activeContext.allocator); - bArr.PushBack(p, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - void Deserialize(std::string& name, std::map& b) +template +class MetadataSerializable +{ +public: + std::string AsString() const { - for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray()) - b[i.GetArray()[0].GetUint64()] = i.GetArray()[1].GetString(); - } + SerializationContext context; + Store(context); - void Serialize(std::string& name, std::unordered_map b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - for (auto& i : b) - { - rapidjson::Value p(rapidjson::kArrayType); - p.PushBack(i.first, m_activeContext.allocator); - rapidjson::Value value(i.second.c_str(), m_activeContext.allocator); - p.PushBack(value, m_activeContext.allocator); - bArr.PushBack(p, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); + return context.buffer.GetString(); } - void Serialize(std::string& name, std::unordered_map b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - for (auto& i : b) - { - rapidjson::Value p(rapidjson::kArrayType); - rapidjson::Value _key(i.first.c_str(), m_activeContext.allocator); - rapidjson::Value value(i.second.c_str(), m_activeContext.allocator); - p.PushBack(_key, m_activeContext.allocator); - p.PushBack(value, m_activeContext.allocator); - bArr.PushBack(p, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - void Deserialize(std::string& name, std::unordered_map& b) + void LoadFromString(const std::string& s) { - for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray()) - b[i.GetArray()[0].GetUint64()] = i.GetArray()[1].GetString(); + DeserializationContext context; + context.doc.Parse(s.c_str()); + AsDerived().Load(context); } - void Serialize(std::string& name, std::unordered_map b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - for (auto& i : b) - { - rapidjson::Value p(rapidjson::kArrayType); - p.PushBack(i.first, m_activeContext.allocator); - p.PushBack(i.second, m_activeContext.allocator); - bArr.PushBack(p, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - void Deserialize(std::string& name, std::unordered_map& b) + void LoadFromValue(rapidjson::Value& s) { - for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray()) - b[i.GetArray()[0].GetUint64()] = i.GetArray()[1].GetUint64(); + DeserializationContext context; + context.doc.CopyFrom(s, context.doc.GetAllocator()); + AsDerived().Load(context); } - // std::unordered_map> - void Serialize(std::string& name, std::unordered_map> b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value classes(rapidjson::kArrayType); - for (auto& i : b) - { - rapidjson::Value classArr(rapidjson::kArrayType); - rapidjson::Value classKey(i.first.c_str(), m_activeContext.allocator); - classArr.PushBack(classKey, m_activeContext.allocator); - rapidjson::Value membersArr(rapidjson::kArrayType); - for (auto& j : i.second) - { - rapidjson::Value member(rapidjson::kArrayType); - member.PushBack(j.first, m_activeContext.allocator); - member.PushBack(j.second, m_activeContext.allocator); - membersArr.PushBack(member, m_activeContext.allocator); - } - classArr.PushBack(membersArr, m_activeContext.allocator); - classes.PushBack(classArr, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, classes, m_activeContext.allocator); - } - void Deserialize(std::string& name, std::unordered_map>& b) - { - for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray()) - { - std::string key = i.GetArray()[0].GetString(); - std::unordered_map memArray; - for (auto& member : i.GetArray()[1].GetArray()) - { - memArray[member.GetArray()[0].GetUint64()] = member.GetArray()[1].GetUint64(); - } - b[key] = memArray; - } + Ref AsMetadata() { + return new Metadata(AsString()); } - void Deserialize(std::string& name, std::unordered_map& b) + bool LoadFromMetadata(const Ref& meta) { - for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray()) - b[i.GetArray()[0].GetString()] = i.GetArray()[1].GetString(); + if (!meta->IsString()) + return false; + LoadFromString(meta->GetString()); + return true; } - void Serialize(std::string& name, std::vector b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - for (const auto& s : b) - { - rapidjson::Value value(s.c_str(), m_activeContext.allocator); - bArr.PushBack(value, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - void Deserialize(std::string& name, std::vector& b) - { - for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray()) - b.emplace_back(i.GetString()); + void Store(SerializationContext& context) const { + context.writer.StartObject(); + AsDerived().Store(context); + context.writer.EndObject(); } - void Serialize(std::string& name, std::vector>> b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - for (auto& i : b) - { - rapidjson::Value segV(rapidjson::kArrayType); - segV.PushBack(i.first, m_activeContext.allocator); - segV.PushBack(i.second.first, m_activeContext.allocator); - segV.PushBack(i.second.second, m_activeContext.allocator); - bArr.PushBack(segV, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - void Deserialize(std::string& name, std::vector>>& b) - { - for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray()) - { - std::pair> j; - j.first = i.GetArray()[0].GetUint64(); - j.second.first = i.GetArray()[1].GetUint64(); - j.second.second = i.GetArray()[2].GetUint64(); - b.push_back(j); - } - } +private: + const Derived& AsDerived() const { return static_cast(*this); } + Derived& AsDerived() { return static_cast(*this); } +}; - void Serialize(std::string& name, std::vector> b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - for (auto& i : b) - { - rapidjson::Value segV(rapidjson::kArrayType); - segV.PushBack(i.first, m_activeContext.allocator); - segV.PushBack(i.second, m_activeContext.allocator); - bArr.PushBack(segV, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - void Deserialize(std::string& name, std::vector>& b) - { - for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray()) - { - std::pair j; - j.first = i.GetArray()[0].GetUint64(); - j.second = i.GetArray()[1].GetBool(); - b.push_back(j); - } - } +// The functions below are not part of the FFI API, but are exported so they can be shared with sharedcacheui. - void Serialize(std::string& name, std::vector b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - for (auto& i : b) - { - bArr.PushBack(i, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - void Deserialize(std::string& name, std::vector& b) - { - for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray()) - { - b.push_back(i.GetUint64()); - } - } +SHAREDCACHE_FFI_API void Serialize(SerializationContext& context, std::string_view str); - // std::unordered_map - void Serialize(std::string& name, std::unordered_map b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - for (auto& i : b) - { - rapidjson::Value p(rapidjson::kArrayType); - rapidjson::Value _key(i.first.c_str(), m_activeContext.allocator); - p.PushBack(_key, m_activeContext.allocator); - p.PushBack(i.second, m_activeContext.allocator); - bArr.PushBack(p, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - void Deserialize(std::string& name, std::unordered_map& b) - { - for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray()) - { - b[i.GetArray()[0].GetString()] = i.GetArray()[1].GetUint64(); - } - } - // std::vector>>> - void Serialize(std::string& name, std::vector>>> b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - for (auto& i : b) - { - rapidjson::Value segV(rapidjson::kArrayType); - segV.PushBack(i.first, m_activeContext.allocator); - rapidjson::Value segArr(rapidjson::kArrayType); - for (auto& j : i.second) - { - rapidjson::Value segPair(rapidjson::kArrayType); - segPair.PushBack(j.first, m_activeContext.allocator); - rapidjson::Value segStr(j.second.c_str(), m_activeContext.allocator); - segPair.PushBack(segStr, m_activeContext.allocator); - segArr.PushBack(segPair, m_activeContext.allocator); - } - segV.PushBack(segArr, m_activeContext.allocator); - bArr.PushBack(segV, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - void Deserialize(std::string& name, std::vector>>>& b) - { - for (auto& i : m_activeDeserContext.doc[name.c_str()].GetArray()) - { - std::pair>> j; - j.first = i.GetArray()[0].GetUint64(); - for (auto& k : i.GetArray()[1].GetArray()) - { - j.second.push_back({k.GetArray()[0].GetUint64(), k.GetArray()[1].GetString()}); - } - b.push_back(j); - } - } +template +inline void Serialize(SerializationContext& context, const MetadataSerializable& value) +{ + value.Store(context); +} - template - void store(std::string x, T y) - { - Serialize(x, y); - } +template +inline void Serialize(SerializationContext& context, std::string_view name, const T& value) +{ + Serialize(context, name); + Serialize(context, value); +} - template - T load(std::string x, T y) +template +void Serialize(SerializationContext& context, const std::pair& value) +{ + context.writer.StartArray(); + Serialize(context, value.first); + Serialize(context, value.second); + context.writer.EndArray(); +} + +template +void Serialize(SerializationContext& context, const std::map& value) +{ + context.writer.StartArray(); + for (auto& pair : value) { - T val; - Deserialize(x, val); - return val; + Serialize(context, pair); } + context.writer.EndArray(); +} - rapidjson::Document& GetDoc() +template +void Serialize(SerializationContext& context, const std::unordered_map& value) +{ + context.writer.StartArray(); + for (auto& pair : value) { - S(); - Store(); - return m_activeContext.doc; + Serialize(context, pair); } + context.writer.EndArray(); +} -public: - virtual void Store() = 0; - virtual void Load() = 0; - - std::string AsString() - { - rapidjson::StringBuffer strbuf; - rapidjson::PrettyWriter writer(strbuf); - GetDoc().Accept(writer); - - std::string s = strbuf.GetString(); - return s; - } - rapidjson::Document& AsDocument() { return GetDoc(); } - void LoadFromString(const std::string& s) - { - m_activeDeserContext.doc.Parse(s.c_str()); - Load(); - } - void LoadFromValue(rapidjson::Value& s) - { - m_activeDeserContext.doc.CopyFrom(s, m_activeDeserContext.doc.GetAllocator()); - Load(); - } - Ref AsMetadata() { return new Metadata(AsString()); } - bool LoadFromMetadata(const Ref& meta) - { - if (!meta->IsString()) - return false; - LoadFromString(meta->GetString()); - return true; - } -}; +template +void Serialize(SerializationContext& context, const std::vector& values) +{ + context.writer.StartArray(); + for (const auto& value : values) + { + Serialize(context, value); + } + context.writer.EndArray(); +} + +SHAREDCACHE_FFI_API void Serialize(SerializationContext& context, const char*); +SHAREDCACHE_FFI_API void Serialize(SerializationContext& context, bool b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, bool& b); +SHAREDCACHE_FFI_API void Serialize(SerializationContext& context, uint8_t b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, uint8_t& b); +SHAREDCACHE_FFI_API void Serialize(SerializationContext& context, uint16_t b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, uint16_t& b); +SHAREDCACHE_FFI_API void Serialize(SerializationContext& context, uint32_t b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, uint32_t& b); +SHAREDCACHE_FFI_API void Serialize(SerializationContext& context, uint64_t b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, uint64_t& b); +SHAREDCACHE_FFI_API void Serialize(SerializationContext& context, int8_t b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, int8_t& b); +SHAREDCACHE_FFI_API void Serialize(SerializationContext& context, int16_t b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, int16_t& b); +SHAREDCACHE_FFI_API void Serialize(SerializationContext& context, int32_t b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, int32_t& b); +SHAREDCACHE_FFI_API void Serialize(SerializationContext& context, int64_t b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, int64_t& b); +SHAREDCACHE_FFI_API void Serialize(SerializationContext& context, std::string_view b); +SHAREDCACHE_FFI_API void Serialize(SerializationContext& context, const std::pair>& value); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, std::string& b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, std::map& b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, std::unordered_map& b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, std::unordered_map& b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, std::unordered_map>& b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, std::unordered_map& b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, std::vector& b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, std::vector>>& b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, std::vector>& b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, std::vector& b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, std::unordered_map& b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext& context, std::string_view name, std::vector>>>& b); +SHAREDCACHE_FFI_API void Serialize(SerializationContext&, const mach_header_64& b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext&, std::string_view name, mach_header_64& b); +SHAREDCACHE_FFI_API void Serialize(SerializationContext&, const symtab_command& b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext&, std::string_view name, symtab_command& b); +SHAREDCACHE_FFI_API void Serialize(SerializationContext&, const dysymtab_command& b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext&, std::string_view name, dysymtab_command& b); +SHAREDCACHE_FFI_API void Serialize(SerializationContext&, const dyld_info_command& b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext&, std::string_view name, dyld_info_command& b); +SHAREDCACHE_FFI_API void Serialize(SerializationContext&, const routines_command_64& b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext&, std::string_view name, routines_command_64& b); +SHAREDCACHE_FFI_API void Serialize(SerializationContext&, const function_starts_command& b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext&, std::string_view name, function_starts_command& b); +SHAREDCACHE_FFI_API void Serialize(SerializationContext&, const section_64& b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext&, std::string_view name, std::vector& b); +SHAREDCACHE_FFI_API void Serialize(SerializationContext&, const linkedit_data_command& b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext&, std::string_view name, linkedit_data_command& b); +SHAREDCACHE_FFI_API void Serialize(SerializationContext&, const segment_command_64& b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext&, std::string_view name, segment_command_64& b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext&, std::string_view name, std::vector& b); +SHAREDCACHE_FFI_API void Serialize(SerializationContext&, const build_version_command& b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext&, std::string_view name, build_version_command& b); +SHAREDCACHE_FFI_API void Serialize(SerializationContext&, const build_tool_version& b); +SHAREDCACHE_FFI_API void Deserialize(DeserializationContext&, std::string_view name, std::vector& b); + +} // namespace SharedCacheCore #endif // SHAREDCACHE_METADATASERIALIZABLE_HPP diff --git a/view/sharedcache/core/SharedCache.cpp b/view/sharedcache/core/SharedCache.cpp index a7c7ffb016..5f0a304c9d 100644 --- a/view/sharedcache/core/SharedCache.cpp +++ b/view/sharedcache/core/SharedCache.cpp @@ -53,30 +53,33 @@ int count_trailing_zeros(uint64_t value) { } #endif -struct ViewStateCacheStore { - SharedCache::SharedCacheFormat m_cacheFormat; +struct SharedCache::State +{ + std::unordered_map>>> + exportInfos; + std::unordered_map>>> + symbolInfos; - DSCViewState m_viewState; + std::unordered_map imageStarts; + std::unordered_map headers; - std::unordered_map m_imageStarts; - std::unordered_map m_headers; + std::vector images; - std::vector m_images; - std::vector m_regionsMappedIntoMemory; + std::vector regionsMappedIntoMemory; - std::vector m_backingCaches; - std::vector m_stubIslandRegions; // TODO honestly both of these should be refactored into nonImageRegions. :p - std::vector m_dyldDataRegions; - std::vector m_nonImageRegions; + std::vector backingCaches; - std::string m_baseFilePath; + std::vector stubIslandRegions; // TODO honestly both of these should be refactored into nonImageRegions. :p + std::vector dyldDataRegions; + std::vector nonImageRegions; - std::unordered_map>>> m_exportInfos; - std::unordered_map>>> m_symbolInfos; + std::string baseFilePath; + SharedCacheFormat cacheFormat; + DSCViewState viewState = DSCViewStateUnloaded; }; static std::recursive_mutex viewStateMutex; -static std::unordered_map viewStateCache; +static std::unordered_map> viewStateCache; std::mutex progressMutex; std::unordered_map progressMap; @@ -221,7 +224,9 @@ void SharedCache::PerformInitialLoad() progressMap[m_dscView->GetFile()->GetSessionId()] = LoadProgressLoadingCaches; progressMutex.unlock(); - m_baseFilePath = path; + WillMutateState(); + + MutableState().baseFilePath = path; DataBuffer sig = baseFile->ReadBuffer(0, 4); if (sig.GetLength() != 4) @@ -230,14 +235,14 @@ void SharedCache::PerformInitialLoad() if (strncmp(magic, "dyld", 4) != 0) abort(); - m_cacheFormat = RegularCacheFormat; + MutableState().cacheFormat = RegularCacheFormat; dyld_cache_header primaryCacheHeader {}; size_t header_size = baseFile->ReadUInt32(16); baseFile->Read(&primaryCacheHeader, 0, std::min(header_size, sizeof(dyld_cache_header))); if (primaryCacheHeader.imagesCountOld != 0) - m_cacheFormat = RegularCacheFormat; + MutableState().cacheFormat = RegularCacheFormat; size_t subCacheOff = offsetof(struct dyld_cache_header, subCacheArrayOffset); size_t headerEnd = primaryCacheHeader.mappingOffset; @@ -246,15 +251,15 @@ void SharedCache::PerformInitialLoad() if (primaryCacheHeader.cacheType != 2) { if (std::filesystem::exists(ResolveFilePath(m_dscView, baseFile->Path() + ".01"))) - m_cacheFormat = LargeCacheFormat; + MutableState().cacheFormat = LargeCacheFormat; else - m_cacheFormat = SplitCacheFormat; + MutableState().cacheFormat = SplitCacheFormat; } else - m_cacheFormat = iOS16CacheFormat; + MutableState().cacheFormat = iOS16CacheFormat; } - switch (m_cacheFormat) + switch (State().cacheFormat) { case RegularCacheFormat: { @@ -272,7 +277,7 @@ void SharedCache::PerformInitialLoad() mapRawToAddrAndSize.second.second = mapping.size; cache.mappings.push_back(mapRawToAddrAndSize); } - m_backingCaches.push_back(cache); + MutableState().backingCaches.push_back(std::move(cache)); dyld_cache_image_info img {}; @@ -280,7 +285,7 @@ void SharedCache::PerformInitialLoad() { baseFile->Read(&img, primaryCacheHeader.imagesOffsetOld + (i * sizeof(img)), sizeof(img)); auto iname = baseFile->ReadNullTermString(img.pathFileOffset); - m_imageStarts[iname] = img.address; + MutableState().imageStarts[iname] = img.address; } m_logger->LogInfo("Found %d images in the shared cache", primaryCacheHeader.imagesCountOld); @@ -312,7 +317,7 @@ void SharedCache::PerformInitialLoad() std::string segNameStr = std::string(segName); stubIslandRegion.prettyName = "dyld_shared_cache_branch_islands_" + std::to_string(i) + "::" + segNameStr; stubIslandRegion.flags = (BNSegmentFlag)(BNSegmentFlag::SegmentReadable | BNSegmentFlag::SegmentExecutable); - m_stubIslandRegions.push_back(stubIslandRegion); + MutableState().stubIslandRegions.push_back(std::move(stubIslandRegion)); } } } @@ -338,9 +343,9 @@ void SharedCache::PerformInitialLoad() mapRawToAddrAndSize.first = mapping.fileOffset; mapRawToAddrAndSize.second.first = mapping.address; mapRawToAddrAndSize.second.second = mapping.size; - cache.mappings.push_back(mapRawToAddrAndSize); + cache.mappings.push_back(std::move(mapRawToAddrAndSize)); } - m_backingCaches.push_back(cache); + MutableState().backingCaches.push_back(std::move(cache)); dyld_cache_image_info img {}; @@ -348,7 +353,7 @@ void SharedCache::PerformInitialLoad() { baseFile->Read(&img, primaryCacheHeader.imagesOffset + (i * sizeof(img)), sizeof(img)); auto iname = baseFile->ReadNullTermString(img.pathFileOffset); - m_imageStarts[iname] = img.address; + MutableState().imageStarts[iname] = img.address; } if (primaryCacheHeader.branchPoolsCount) @@ -356,7 +361,8 @@ void SharedCache::PerformInitialLoad() std::vector pool {}; for (size_t i = 0; i < primaryCacheHeader.branchPoolsCount; i++) { - m_imageStarts["dyld_shared_cache_branch_islands_" + std::to_string(i)] = baseFile->ReadULong(primaryCacheHeader.branchPoolsOffset + (i * m_dscView->GetAddressSize())); + MutableState().imageStarts["dyld_shared_cache_branch_islands_" + std::to_string(i)] = + baseFile->ReadULong(primaryCacheHeader.branchPoolsOffset + (i * m_dscView->GetAddressSize())); } } std::string mainFileName = base_name(path); @@ -413,7 +419,7 @@ void SharedCache::PerformInitialLoad() mapRawToAddrAndSize.first = subCacheMapping.fileOffset; mapRawToAddrAndSize.second.first = subCacheMapping.address; mapRawToAddrAndSize.second.second = subCacheMapping.size; - subCache.mappings.push_back(mapRawToAddrAndSize); + subCache.mappings.push_back(std::move(mapRawToAddrAndSize)); } if (subCacheHeader.mappingCount == 1 && subCacheHeader.imagesCountOld == 0 && subCacheHeader.imagesCount == 0 @@ -427,10 +433,10 @@ void SharedCache::PerformInitialLoad() stubIslandRegion.size = size; stubIslandRegion.prettyName = subCacheFilename + "::_stubs"; stubIslandRegion.flags = (BNSegmentFlag)(BNSegmentFlag::SegmentReadable | BNSegmentFlag::SegmentExecutable); - m_stubIslandRegions.push_back(stubIslandRegion); + MutableState().stubIslandRegions.push_back(std::move(stubIslandRegion)); } - m_backingCaches.push_back(subCache); + MutableState().backingCaches.push_back(std::move(subCache)); } break; } @@ -449,9 +455,9 @@ void SharedCache::PerformInitialLoad() mapRawToAddrAndSize.first = mapping.fileOffset; mapRawToAddrAndSize.second.first = mapping.address; mapRawToAddrAndSize.second.second = mapping.size; - cache.mappings.push_back(mapRawToAddrAndSize); + cache.mappings.push_back(std::move(mapRawToAddrAndSize)); } - m_backingCaches.push_back(cache); + MutableState().backingCaches.push_back(std::move(cache)); dyld_cache_image_info img {}; @@ -459,7 +465,7 @@ void SharedCache::PerformInitialLoad() { baseFile->Read(&img, primaryCacheHeader.imagesOffset + (i * sizeof(img)), sizeof(img)); auto iname = baseFile->ReadNullTermString(img.pathFileOffset); - m_imageStarts[iname] = img.address; + MutableState().imageStarts[iname] = img.address; } if (primaryCacheHeader.branchPoolsCount) @@ -467,7 +473,8 @@ void SharedCache::PerformInitialLoad() std::vector pool {}; for (size_t i = 0; i < primaryCacheHeader.branchPoolsCount; i++) { - m_imageStarts["dyld_shared_cache_branch_islands_" + std::to_string(i)] = baseFile->ReadULong(primaryCacheHeader.branchPoolsOffset + (i * m_dscView->GetAddressSize())); + MutableState().imageStarts["dyld_shared_cache_branch_islands_" + std::to_string(i)] = + baseFile->ReadULong(primaryCacheHeader.branchPoolsOffset + (i * m_dscView->GetAddressSize())); } } @@ -508,10 +515,10 @@ void SharedCache::PerformInitialLoad() mapRawToAddrAndSize.first = subCacheMapping.fileOffset; mapRawToAddrAndSize.second.first = subCacheMapping.address; mapRawToAddrAndSize.second.second = subCacheMapping.size; - subCache.mappings.push_back(mapRawToAddrAndSize); + subCache.mappings.push_back(std::move(mapRawToAddrAndSize)); } - m_backingCaches.push_back(subCache); + MutableState().backingCaches.push_back(std::move(subCache)); if (subCacheHeader.mappingCount == 1 && subCacheHeader.imagesCountOld == 0 && subCacheHeader.imagesCount == 0 && subCacheHeader.imagesTextOffset == 0) @@ -524,7 +531,7 @@ void SharedCache::PerformInitialLoad() stubIslandRegion.size = size; stubIslandRegion.prettyName = subCacheFilename + "::_stubs"; stubIslandRegion.flags = (BNSegmentFlag)(BNSegmentFlag::SegmentReadable | BNSegmentFlag::SegmentExecutable); - m_stubIslandRegions.push_back(stubIslandRegion); + MutableState().stubIslandRegions.push_back(std::move(stubIslandRegion)); } } @@ -554,10 +561,10 @@ void SharedCache::PerformInitialLoad() mapRawToAddrAndSize.first = subCacheMapping.fileOffset; mapRawToAddrAndSize.second.first = subCacheMapping.address; mapRawToAddrAndSize.second.second = subCacheMapping.size; - subCache.mappings.push_back(mapRawToAddrAndSize); + subCache.mappings.push_back(std::move(mapRawToAddrAndSize)); } - m_backingCaches.push_back(subCache); + MutableState().backingCaches.push_back(std::move(subCache)); break; } case iOS16CacheFormat: @@ -575,10 +582,10 @@ void SharedCache::PerformInitialLoad() mapRawToAddrAndSize.first = mapping.fileOffset; mapRawToAddrAndSize.second.first = mapping.address; mapRawToAddrAndSize.second.second = mapping.size; - cache.mappings.push_back(mapRawToAddrAndSize); + cache.mappings.push_back(std::move(mapRawToAddrAndSize)); } - m_backingCaches.push_back(cache); + MutableState().backingCaches.push_back(std::move(cache)); dyld_cache_image_info img {}; @@ -586,7 +593,7 @@ void SharedCache::PerformInitialLoad() { baseFile->Read(&img, primaryCacheHeader.imagesOffset + (i * sizeof(img)), sizeof(img)); auto iname = baseFile->ReadNullTermString(img.pathFileOffset); - m_imageStarts[iname] = img.address; + MutableState().imageStarts[iname] = img.address; } if (primaryCacheHeader.branchPoolsCount) @@ -594,7 +601,8 @@ void SharedCache::PerformInitialLoad() std::vector pool {}; for (size_t i = 0; i < primaryCacheHeader.branchPoolsCount; i++) { - m_imageStarts["dyld_shared_cache_branch_islands_" + std::to_string(i)] = baseFile->ReadULong(primaryCacheHeader.branchPoolsOffset + (i * m_dscView->GetAddressSize())); + MutableState().imageStarts["dyld_shared_cache_branch_islands_" + std::to_string(i)] = + baseFile->ReadULong(primaryCacheHeader.branchPoolsOffset + (i * m_dscView->GetAddressSize())); } } @@ -657,7 +665,7 @@ void SharedCache::PerformInitialLoad() mapRawToAddrAndSize.first = subCacheMapping.fileOffset; mapRawToAddrAndSize.second.first = subCacheMapping.address; mapRawToAddrAndSize.second.second = subCacheMapping.size; - subCache.mappings.push_back(mapRawToAddrAndSize); + subCache.mappings.push_back(std::move(mapRawToAddrAndSize)); if (subCachePath.find(".dylddata") != std::string::npos) { @@ -669,11 +677,11 @@ void SharedCache::PerformInitialLoad() dyldDataRegion.size = size; dyldDataRegion.prettyName = subCacheFilename + "::_data" + std::to_string(j); dyldDataRegion.flags = (BNSegmentFlag)(BNSegmentFlag::SegmentReadable); - m_dyldDataRegions.push_back(dyldDataRegion); + MutableState().dyldDataRegions.push_back(std::move(dyldDataRegion)); } } - m_backingCaches.push_back(subCache); + MutableState().backingCaches.push_back(std::move(subCache)); if (subCacheHeader.mappingCount == 1 && subCacheHeader.imagesCountOld == 0 && subCacheHeader.imagesCount == 0 && subCacheHeader.imagesTextOffset == 0) @@ -686,7 +694,7 @@ void SharedCache::PerformInitialLoad() stubIslandRegion.size = size; stubIslandRegion.prettyName = subCacheFilename + "::_stubs"; stubIslandRegion.flags = (BNSegmentFlag)(BNSegmentFlag::SegmentReadable | BNSegmentFlag::SegmentExecutable); - m_stubIslandRegions.push_back(stubIslandRegion); + MutableState().stubIslandRegions.push_back(std::move(stubIslandRegion)); } } @@ -718,10 +726,10 @@ void SharedCache::PerformInitialLoad() mapRawToAddrAndSize.first = subCacheMapping.fileOffset; mapRawToAddrAndSize.second.first = subCacheMapping.address; mapRawToAddrAndSize.second.second = subCacheMapping.size; - subCache.mappings.push_back(mapRawToAddrAndSize); + subCache.mappings.push_back(std::move(mapRawToAddrAndSize)); } - m_backingCaches.push_back(subCache); + MutableState().backingCaches.push_back(std::move(subCache)); } catch (...) {} @@ -741,7 +749,7 @@ void SharedCache::PerformInitialLoad() m_logger->LogError("Failed to map VM pages for Shared Cache on initial load, this is fatal."); return; } - for (const auto &start : m_imageStarts) + for (const auto& start : State().imageStarts) { try { auto imageHeader = SharedCache::LoadHeaderForAddress(vm, start.second, start.first); @@ -752,7 +760,7 @@ void SharedCache::PerformInitialLoad() auto mapping = vm->MappingAtAddress(imageHeader->linkeditSegment.vmaddr); imageHeader->exportTriePath = mapping.first.filePath; } - m_headers[start.second] = imageHeader.value(); + MutableState().headers[start.second] = imageHeader.value(); CacheImage image; image.installName = start.first; image.headerLocation = start.second; @@ -781,14 +789,14 @@ void SharedCache::PerformInitialLoad() // if we're positive we have an entry point for some reason, force the segment // executable. this helps with kernel images. - for (auto &entryPoint: imageHeader->m_entryPoints) + for (auto &entryPoint : imageHeader->m_entryPoints) if (segment.vmaddr <= entryPoint && (entryPoint < (segment.vmaddr + segment.filesize))) flags |= SegmentExecutable; sectionRegion.flags = (BNSegmentFlag)flags; image.regions.push_back(sectionRegion); } - m_images.push_back(image); + MutableState().images.push_back(image); } else { @@ -801,9 +809,9 @@ void SharedCache::PerformInitialLoad() } } - m_logger->LogInfo("Loaded %d Mach-O headers", m_headers.size()); + m_logger->LogInfo("Loaded %d Mach-O headers", State().headers.size()); - for (const auto& cache : m_backingCaches) + for (const auto& cache : State().backingCaches) { size_t i = 0; for (const auto& mapping : cache.mappings) @@ -814,15 +822,15 @@ void SharedCache::PerformInitialLoad() region.prettyName = base_name(cache.path) + "::" + std::to_string(i); // FIXME flags!!! BackingCache.mapping needs refactored to store this information! region.flags = (BNSegmentFlag)(BNSegmentFlag::SegmentReadable | BNSegmentFlag::SegmentExecutable); - m_nonImageRegions.push_back(region); + MutableState().nonImageRegions.push_back(std::move(region)); i++; } } // Iterate through each Mach-O header - if (!m_dyldDataRegions.empty()) + if (!State().dyldDataRegions.empty()) { - for (const auto& [headerKey, header] : m_headers) + for (const auto& [headerKey, header] : State().headers) { // Iterate through each segment of the header for (const auto& segment : header.segments) @@ -831,7 +839,7 @@ void SharedCache::PerformInitialLoad() uint64_t segmentEnd = segmentStart + segment.vmsize; // Iterate through each region in m_dyldDataRegions - for (auto it = m_dyldDataRegions.begin(); it != m_dyldDataRegions.end();) + for (auto it = State().dyldDataRegions.begin(); it != State().dyldDataRegions.end();) { uint64_t regionStart = it->start; uint64_t regionSize = it->size; @@ -864,12 +872,12 @@ void SharedCache::PerformInitialLoad() } // Erase the original region - it = m_dyldDataRegions.erase(it); + it = MutableState().dyldDataRegions.erase(it); // Insert the new regions (if any) for (const auto& newRegion : newRegions) { - it = m_dyldDataRegions.insert(it, newRegion); + it = MutableState().dyldDataRegions.insert(it, newRegion); ++it; // Move iterator to the next position } } @@ -883,9 +891,9 @@ void SharedCache::PerformInitialLoad() } // Iterate through each Mach-O header - if (!m_nonImageRegions.empty()) + if (!State().nonImageRegions.empty()) { - for (const auto& [headerKey, header] : m_headers) + for (const auto& [headerKey, header] : State().headers) { // Iterate through each segment of the header for (const auto& segment : header.segments) @@ -894,7 +902,7 @@ void SharedCache::PerformInitialLoad() uint64_t segmentEnd = segmentStart + segment.vmsize; // Iterate through each region in m_dyldDataRegions - for (auto it = m_nonImageRegions.begin(); it != m_nonImageRegions.end();) + for (auto it = State().nonImageRegions.begin(); it != State().nonImageRegions.end();) { uint64_t regionStart = it->start; uint64_t regionSize = it->size; @@ -927,12 +935,12 @@ void SharedCache::PerformInitialLoad() } // Erase the original region - it = m_nonImageRegions.erase(it); + it = MutableState().nonImageRegions.erase(it); // Insert the new regions (if any) for (const auto& newRegion : newRegions) { - it = m_nonImageRegions.insert(it, newRegion); + it = MutableState().nonImageRegions.insert(it, newRegion); ++it; // Move iterator to the next position } } @@ -959,7 +967,7 @@ std::shared_ptr SharedCache::GetVMMap(bool mapPages) if (mapPages) { - for (const auto& cache : m_backingCaches) + for (const auto& cache : State().backingCaches) { for (const auto& mapping : cache.mappings) { @@ -980,22 +988,10 @@ void SharedCache::DeserializeFromRawView() if (m_dscView->QueryMetadata(SharedCacheMetadataTag)) { std::unique_lock viewStateCacheLock(viewStateMutex); - if (viewStateCache.find(m_dscView->GetFile()->GetSessionId()) != viewStateCache.end()) - { - auto c = viewStateCache[m_dscView->GetFile()->GetSessionId()]; - m_imageStarts = c.m_imageStarts; - m_cacheFormat = c.m_cacheFormat; - m_backingCaches = c.m_backingCaches; - m_viewState = c.m_viewState; - m_headers = c.m_headers; - m_images = c.m_images; - m_regionsMappedIntoMemory = c.m_regionsMappedIntoMemory; - m_stubIslandRegions = c.m_stubIslandRegions; - m_dyldDataRegions = c.m_dyldDataRegions; - m_nonImageRegions = c.m_nonImageRegions; - m_baseFilePath = c.m_baseFilePath; - m_exportInfos = c.m_exportInfos; - m_symbolInfos = c.m_symbolInfos; + if (auto it = viewStateCache.find(m_dscView->GetFile()->GetSessionId()); it != viewStateCache.end()) + { + m_state = it->second; + m_stateIsShared = true; m_metadataValid = true; } else @@ -1005,14 +1001,16 @@ void SharedCache::DeserializeFromRawView() if (!m_metadataValid) { m_logger->LogError("Failed to deserialize Shared Cache metadata"); - m_viewState = DSCViewStateUnloaded; + WillMutateState(); + MutableState().viewState = DSCViewStateUnloaded; } } else { m_metadataValid = true; - m_viewState = DSCViewStateUnloaded; - m_images.clear(); // fixme ?? + WillMutateState(); + MutableState().viewState = DSCViewStateUnloaded; + MutableState().images.clear(); // fixme ?? } } @@ -1029,12 +1027,14 @@ void SharedCache::ParseAndApplySlideInfoForFile(std::shared_ptrSlideInfoWasApplied()) return; + + WillMutateState(); std::vector> rewrites; dyld_cache_header baseHeader; file->Read(&baseHeader, 0, sizeof(dyld_cache_header)); uint64_t base = UINT64_MAX; - for (const auto& backingCache : m_backingCaches) + for (const auto& backingCache : State().backingCaches) { for (const auto& mapping : backingCache.mappings) { @@ -1365,42 +1365,39 @@ SharedCache::SharedCache(BinaryNinja::Ref dscView) : m_ DeserializeFromRawView(); if (!m_metadataValid) return; - if (m_viewState == DSCViewStateUnloaded) + if (State().viewState == DSCViewStateUnloaded) { - if (m_viewState == DSCViewStateUnloaded) + std::unique_lock lock(viewSpecificMutexes[m_dscView->GetFile()->GetSessionId()].viewOperationsThatInfluenceMetadataMutex); + try { + PerformInitialLoad(); + } + catch (...) { - std::unique_lock lock(viewSpecificMutexes[m_dscView->GetFile()->GetSessionId()].viewOperationsThatInfluenceMetadataMutex); - try { - PerformInitialLoad(); - } - catch (...) - { - m_logger->LogError("Failed to perform initial load of Shared Cache"); - } + m_logger->LogError("Failed to perform initial load of Shared Cache"); + } - auto settings = m_dscView->GetLoadSettings(VIEW_NAME); - bool autoLoadLibsystem = true; - if (settings && settings->Contains("loader.dsc.autoLoadLibSystem")) - { - autoLoadLibsystem = settings->Get("loader.dsc.autoLoadLibSystem", m_dscView); - } - if (autoLoadLibsystem) + auto settings = m_dscView->GetLoadSettings(VIEW_NAME); + bool autoLoadLibsystem = true; + if (settings && settings->Contains("loader.dsc.autoLoadLibSystem")) + { + autoLoadLibsystem = settings->Get("loader.dsc.autoLoadLibSystem", m_dscView); + } + if (autoLoadLibsystem) + { + for (const auto& [_, header] : State().headers) { - for (const auto& [_, header] : m_headers) + if (header.installName.find("libsystem_c.dylib") != std::string::npos) { - if (header.installName.find("libsystem_c.dylib") != std::string::npos) - { - lock.unlock(); - m_logger->LogInfo("Loading core libsystem_c.dylib library"); - LoadImageWithInstallName(header.installName); - lock.lock(); - break; - } + lock.unlock(); + m_logger->LogInfo("Loading core libsystem_c.dylib library"); + LoadImageWithInstallName(header.installName); + lock.lock(); + break; } } - m_viewState = DSCViewStateLoaded; - SaveToDSCView(); } + MutableState().viewState = DSCViewStateLoaded; + SaveToDSCView(); } else { @@ -1430,7 +1427,7 @@ SharedCache* SharedCache::GetFromDSCView(BinaryNinja::Ref SharedCache::GetImageStart(std::string installName) { - for (const auto& [name, start] : m_imageStarts) + for (const auto& [name, start] : State().imageStarts) { if (name == installName) { @@ -1445,7 +1442,7 @@ std::optional SharedCache::HeaderForAddress(uint64_t add // We _could_ mark each page with the image start? :grimacing emoji: // But that'd require mapping pages :grimacing emoji: :grimacing emoji: // There's not really any other hacks that could make this faster, that I can think of... - for (const auto& [start, header] : m_headers) + for (const auto& [start, header] : State().headers) { for (const auto& segment : header.segments) { @@ -1460,21 +1457,21 @@ std::optional SharedCache::HeaderForAddress(uint64_t add std::string SharedCache::NameForAddress(uint64_t address) { - for (const auto& stubIsland : m_stubIslandRegions) + for (const auto& stubIsland : State().stubIslandRegions) { if (stubIsland.start <= address && stubIsland.start + stubIsland.size > address) { return stubIsland.prettyName; } } - for (const auto& dyldData : m_dyldDataRegions) + for (const auto& dyldData : State().dyldDataRegions) { if (dyldData.start <= address && dyldData.start + dyldData.size > address) { return dyldData.prettyName; } } - for (const auto& nonImageRegion : m_nonImageRegions) + for (const auto& nonImageRegion : State().nonImageRegions) { if (nonImageRegion.start <= address && nonImageRegion.start + nonImageRegion.size > address) { @@ -1508,7 +1505,7 @@ std::string SharedCache::ImageNameForAddress(uint64_t address) bool SharedCache::LoadImageContainingAddress(uint64_t address) { - for (const auto& [start, header] : m_headers) + for (const auto& [start, header] : State().headers) { for (const auto& segment : header.segments) { @@ -1526,6 +1523,8 @@ bool SharedCache::LoadSectionAtAddress(uint64_t address) { std::unique_lock lock(viewSpecificMutexes[m_dscView->GetFile()->GetSessionId()].viewOperationsThatInfluenceMetadataMutex); DeserializeFromRawView(); + WillMutateState(); + auto vm = GetVMMap(); if (!vm) { @@ -1537,13 +1536,13 @@ bool SharedCache::LoadSectionAtAddress(uint64_t address) CacheImage* targetImage = nullptr; MemoryRegion* targetSegment = nullptr; - for (auto& image : m_images) + for (auto& image : MutableState().images) { for (auto& region : image.regions) { if (region.start <= address && region.start + region.size > address) { - targetHeader = m_headers[image.headerLocation]; + targetHeader = MutableState().headers[image.headerLocation]; targetImage = ℑ targetSegment = ®ion; break; @@ -1554,7 +1553,7 @@ bool SharedCache::LoadSectionAtAddress(uint64_t address) } if (!targetSegment) { - for (auto& stubIsland : m_stubIslandRegions) + for (auto& stubIsland : MutableState().stubIslandRegions) { if (stubIsland.start <= address && stubIsland.start + stubIsland.size > address) { @@ -1583,7 +1582,7 @@ bool SharedCache::LoadSectionAtAddress(uint64_t address) stubIsland.rawViewOffsetIfLoaded = rawViewEnd; - m_regionsMappedIntoMemory.push_back(stubIsland); + MutableState().regionsMappedIntoMemory.push_back(stubIsland); SaveToDSCView(); @@ -1594,7 +1593,7 @@ bool SharedCache::LoadSectionAtAddress(uint64_t address) } } - for (auto& dyldData : m_dyldDataRegions) + for (auto& dyldData : MutableState().dyldDataRegions) { if (dyldData.start <= address && dyldData.start + dyldData.size > address) { @@ -1622,7 +1621,7 @@ bool SharedCache::LoadSectionAtAddress(uint64_t address) dyldData.loaded = true; dyldData.rawViewOffsetIfLoaded = rawViewEnd; - m_regionsMappedIntoMemory.push_back(dyldData); + MutableState().regionsMappedIntoMemory.push_back(dyldData); SaveToDSCView(); @@ -1633,7 +1632,7 @@ bool SharedCache::LoadSectionAtAddress(uint64_t address) } } - for (auto& region : m_nonImageRegions) + for (auto& region : MutableState().nonImageRegions) { if (region.start <= address && region.start + region.size > address) { @@ -1660,7 +1659,7 @@ bool SharedCache::LoadSectionAtAddress(uint64_t address) region.loaded = true; region.rawViewOffsetIfLoaded = rawViewEnd; - m_regionsMappedIntoMemory.push_back(region); + MutableState().regionsMappedIntoMemory.push_back(region); SaveToDSCView(); @@ -1696,7 +1695,7 @@ bool SharedCache::LoadSectionAtAddress(uint64_t address) targetSegment->loaded = true; targetSegment->rawViewOffsetIfLoaded = rawViewEnd; - m_regionsMappedIntoMemory.push_back(*targetSegment); + MutableState().regionsMappedIntoMemory.push_back(*targetSegment); SaveToDSCView(); @@ -1720,12 +1719,14 @@ bool SharedCache::LoadImageWithInstallName(std::string installName) std::unique_lock lock(viewSpecificMutexes[m_dscView->GetFile()->GetSessionId()].viewOperationsThatInfluenceMetadataMutex); DeserializeFromRawView(); + WillMutateState(); + m_logger->LogInfo("Loading image %s", installName.c_str()); auto vm = GetVMMap(); CacheImage* targetImage = nullptr; - for (auto& cacheImage : m_images) + for (auto& cacheImage : MutableState().images) { if (cacheImage.installName == installName) { @@ -1733,11 +1734,15 @@ bool SharedCache::LoadImageWithInstallName(std::string installName) break; } } - - auto header = m_headers[targetImage->headerLocation]; + auto it = State().headers.find(targetImage->headerLocation); + if (it == State().headers.end()) + { + return false; + } + const auto& header = it->second; auto id = m_dscView->BeginUndoActions(); - m_viewState = DSCViewStateLoadedWithImages; + MutableState().viewState = DSCViewStateLoadedWithImages; auto reader = VMReader(vm); reader.Seek(targetImage->headerLocation); @@ -1770,7 +1775,7 @@ bool SharedCache::LoadImageWithInstallName(std::string installName) region.loaded = true; region.rawViewOffsetIfLoaded = rawViewEnd; - m_regionsMappedIntoMemory.push_back(region); + MutableState().regionsMappedIntoMemory.push_back(region); m_dscView->GetParentView()->AddAutoSegment(rawViewEnd, region.size, rawViewEnd, region.size, region.flags); m_dscView->AddUserSegment(region.start, region.size, rawViewEnd, region.size, region.flags); @@ -2260,6 +2265,7 @@ std::optional SharedCache::LoadHeaderForAddress(std::sha void SharedCache::InitializeHeader( Ref view, VM* vm, SharedCacheMachOHeader header, std::vector regionsToLoad) { + WillMutateState(); Ref settings = view->GetLoadSettings(VIEW_NAME); bool applyFunctionStarts = true; @@ -2629,7 +2635,7 @@ void SharedCache::InitializeHeader( view->DefineAutoSymbol(symbolObj); symbolInfos.push_back({sym.n_value, {type, symbol}}); } - m_symbolInfos[header.textBase] = symbolInfos; + MutableState().symbolInfos[header.textBase] = symbolInfos; } if (header.exportTriePresent && header.linkeditPresent && vm->AddressIsMapped(header.linkeditSegment.vmaddr)) @@ -2675,7 +2681,7 @@ void SharedCache::InitializeHeader( else view->DefineAutoSymbol(symbol); } - m_exportInfos[header.textBase] = exportMapping; + MutableState().exportInfos[header.textBase] = std::move(exportMapping); } view->EndBulkModifySymbols(); @@ -2782,7 +2788,7 @@ std::vector> SharedCache::ParseExportTrie(std::shared_ptr SharedCache::GetAvailableImages() { std::vector installNames; - for (const auto& header : m_headers) + for (const auto& header : State().headers) { installNames.push_back(header.second.installName); } @@ -2792,10 +2798,12 @@ std::vector SharedCache::GetAvailableImages() std::vector>> SharedCache::LoadAllSymbolsAndWait() { + WillMutateState(); + std::unique_lock initialLoadBlock(viewSpecificMutexes[m_dscView->GetFile()->GetSessionId()].viewOperationsThatInfluenceMetadataMutex); std::vector>> symbols; - for (const auto& img : m_images) + for (const auto& img : State().images) { auto header = HeaderForAddress(img.headerLocation); std::shared_ptr mapping; @@ -2814,7 +2822,7 @@ std::vector>> SharedCache::LoadAllSymbolsAndW exportMapping.push_back({sym->GetAddress(), {sym->GetType(), sym->GetRawName()}}); symbols.push_back({img.installName, sym}); } - m_exportInfos[header->textBase] = exportMapping; + MutableState().exportInfos[header->textBase] = std::move(exportMapping); } SaveToDSCView(); @@ -2836,17 +2844,22 @@ std::string SharedCache::SerializedImageHeaderForAddress(uint64_t address) std::string SharedCache::SerializedImageHeaderForName(std::string name) { - auto header = HeaderForAddress(m_imageStarts[name]); - if (header) + if (auto it = State().imageStarts.find(name); it != State().imageStarts.end()) { - return header->AsString(); + if (auto header = HeaderForAddress(it->second)) + { + return header->AsString(); + } } return ""; } -void SharedCache::FindSymbolAtAddrAndApplyToAddr(uint64_t symbolLocation, uint64_t targetLocation, bool triggerReanalysis) +void SharedCache::FindSymbolAtAddrAndApplyToAddr( + uint64_t symbolLocation, uint64_t targetLocation, bool triggerReanalysis) { + WillMutateState(); + std::string prefix = ""; if (symbolLocation != targetLocation) prefix = "j_"; @@ -2933,7 +2946,7 @@ void SharedCache::FindSymbolAtAddrAndApplyToAddr(uint64_t symbolLocation, uint64 } { std::unique_lock _lock(viewSpecificMutexes[m_dscView->GetFile()->GetSessionId()].viewOperationsThatInfluenceMetadataMutex); - m_exportInfos[header->textBase] = exportMapping; + MutableState().exportInfos[header->textBase] = std::move(exportMapping); } m_dscView->EndBulkModifySymbols(); m_dscView->ForgetUndoActions(id); @@ -2948,22 +2961,16 @@ bool SharedCache::SaveToDSCView() auto data = AsMetadata(); m_dscView->StoreMetadata(SharedCacheMetadataTag, data); m_dscView->GetParentView()->GetParentView()->StoreMetadata(SharedCacheMetadataTag, data); + + // By moving our state the to cache we can avoid creating a copy in the case + // that no further mutations are made to `this`. If we're not done being mutated, + // the data will be copied on the first mutation. + auto cachedState = std::make_shared(std::move(*m_state)); + m_state = cachedState; + m_stateIsShared = true; + std::unique_lock viewStateCacheLock(viewStateMutex); - ViewStateCacheStore c; - c.m_imageStarts = m_imageStarts; - c.m_cacheFormat = m_cacheFormat; - c.m_backingCaches = m_backingCaches; - c.m_viewState = m_viewState; - c.m_headers = m_headers; - c.m_images = m_images; - c.m_regionsMappedIntoMemory = m_regionsMappedIntoMemory; - c.m_stubIslandRegions = m_stubIslandRegions; - c.m_dyldDataRegions = m_dyldDataRegions; - c.m_nonImageRegions = m_nonImageRegions; - c.m_baseFilePath = m_baseFilePath; - c.m_exportInfos = m_exportInfos; - c.m_symbolInfos = m_symbolInfos; - viewStateCache[m_dscView->GetFile()->GetSessionId()] = c; + viewStateCache[m_dscView->GetFile()->GetSessionId()] = std::move(cachedState); m_metadataValid = true; @@ -2974,7 +2981,7 @@ bool SharedCache::SaveToDSCView() std::vector SharedCache::GetMappedRegions() const { std::unique_lock lock(viewSpecificMutexes[m_dscView->GetFile()->GetSessionId()].viewOperationsThatInfluenceMetadataMutex); - return m_regionsMappedIntoMemory; + return State().regionsMappedIntoMemory; } extern "C" @@ -3120,7 +3127,7 @@ extern "C" { if (cache->object) { - return (BNDSCViewState)cache->object->State(); + return (BNDSCViewState)cache->object->ViewState(); } return BNDSCViewState::Unloaded; @@ -3320,3 +3327,198 @@ void InitDSCViewType() g_dscViewType = &type; g_dscRawViewType = &rawType; } + +namespace SharedCacheCore { + +void SharedCache::Store(SerializationContext& context) const +{ + Serialize(context, "metadataVersion", METADATA_VERSION); + + Serialize(context, "m_viewState", State().viewState); + Serialize(context, "m_cacheFormat", State().cacheFormat); + Serialize(context, "m_imageStarts", State().imageStarts); + Serialize(context, "m_baseFilePath", State().baseFilePath); + + Serialize(context, "headers"); + context.writer.StartArray(); + for (auto& [k, v] : State().headers) + { + context.writer.StartObject(); + v.Store(context); + context.writer.EndObject(); + } + context.writer.EndArray(); + + Serialize(context, "exportInfos"); + context.writer.StartArray(); + for (const auto& pair1 : State().exportInfos) + { + context.writer.StartObject(); + Serialize(context, "key", pair1.first); + Serialize(context, "value"); + context.writer.StartArray(); + for (const auto& pair2 : pair1.second) + { + context.writer.StartObject(); + Serialize(context, "key", pair2.first); + Serialize(context, "val1", pair2.second.first); + Serialize(context, "val2", pair2.second.second); + context.writer.EndObject(); + } + context.writer.EndArray(); + context.writer.EndObject(); + } + context.writer.EndArray(); + + Serialize(context, "backingCaches", State().backingCaches); + Serialize(context, "stubIslands", State().stubIslandRegions); + Serialize(context, "images", State().images); + Serialize(context, "regionsMappedIntoMemory", State().regionsMappedIntoMemory); + Serialize(context, "dyldDataSections", State().dyldDataRegions); + Serialize(context, "nonImageRegions", State().nonImageRegions); +} + +void SharedCache::Load(DeserializationContext& context) +{ + if (context.doc.HasMember("metadataVersion")) + { + if (context.doc["metadataVersion"].GetUint() != METADATA_VERSION) + { + m_logger->LogError("Shared Cache metadata version mismatch"); + return; + } + } + else + { + m_logger->LogError("Shared Cache metadata version missing"); + return; + } + + m_stateIsShared = false; + m_state = std::make_shared(); + + MutableState().viewState = static_cast(context.load("m_viewState")); + MutableState().cacheFormat = static_cast(context.load("m_cacheFormat")); + + for (auto& startAndHeader : context.doc["headers"].GetArray()) + { + SharedCacheMachOHeader header; + header.LoadFromValue(startAndHeader); + MutableState().headers[header.textBase] = std::move(header); + } + + Deserialize(context, "m_imageStarts", MutableState().imageStarts); + Deserialize(context, "m_baseFilePath", MutableState().baseFilePath); + + for (const auto& obj1 : context.doc["exportInfos"].GetArray()) + { + std::vector>> innerVec; + for (const auto& obj2 : obj1["value"].GetArray()) + { + std::pair innerPair = { + (BNSymbolType)obj2["val1"].GetUint64(), obj2["val2"].GetString()}; + innerVec.push_back({obj2["key"].GetUint64(), innerPair}); + } + + MutableState().exportInfos[obj1["key"].GetUint64()] = std::move(innerVec); + } + + for (auto& symbolInfo : context.doc["symbolInfos"].GetArray()) + { + std::vector>> symbolInfoVec; + for (auto& symbolInfoPair : symbolInfo.GetArray()) + { + symbolInfoVec.push_back({symbolInfoPair[0].GetUint64(), + {(BNSymbolType)symbolInfoPair[1].GetUint(), symbolInfoPair[2].GetString()}}); + } + MutableState().symbolInfos[symbolInfo[0].GetUint64()] = std::move(symbolInfoVec); + } + + for (auto& bcV : context.doc["backingCaches"].GetArray()) + { + BackingCache bc; + bc.LoadFromValue(bcV); + MutableState().backingCaches.push_back(std::move(bc)); + } + + for (auto& imgV : context.doc["images"].GetArray()) + { + CacheImage img; + img.LoadFromValue(imgV); + MutableState().images.push_back(std::move(img)); + } + + for (auto& rV : context.doc["regionsMappedIntoMemory"].GetArray()) + { + MemoryRegion r; + r.LoadFromValue(rV); + MutableState().regionsMappedIntoMemory.push_back(std::move(r)); + } + + for (auto& siV : context.doc["stubIslands"].GetArray()) + { + MemoryRegion si; + si.LoadFromValue(siV); + MutableState().stubIslandRegions.push_back(std::move(si)); + } + + for (auto& siV : context.doc["dyldDataSections"].GetArray()) + { + MemoryRegion si; + si.LoadFromValue(siV); + MutableState().dyldDataRegions.push_back(std::move(si)); + } + + for (auto& siV : context.doc["nonImageRegions"].GetArray()) + { + MemoryRegion si; + si.LoadFromValue(siV); + MutableState().nonImageRegions.push_back(std::move(si)); + } + + m_metadataValid = true; +} + +__attribute__((always_inline)) void SharedCache::AssertMutable() const +{ + if (m_stateIsShared) + { + abort(); + } +} + +void SharedCache::WillMutateState() +{ + if (!m_state) + { + m_state = std::make_shared(); + } + else if (m_stateIsShared) + { + m_state = std::make_shared(*m_state); + } + m_stateIsShared = false; +} + + +const std::vector& SharedCache::BackingCaches() const +{ + return State().backingCaches; +} + +DSCViewState SharedCache::ViewState() const +{ + return State().viewState; +} + +const std::unordered_map& SharedCache::AllImageStarts() const +{ + return State().imageStarts; +} + +const std::unordered_map& SharedCache::AllImageHeaders() const +{ + return State().headers; +} + +} // namespace SharedCacheCore diff --git a/view/sharedcache/core/SharedCache.h b/view/sharedcache/core/SharedCache.h index 81c0262039..ac24b529f4 100644 --- a/view/sharedcache/core/SharedCache.h +++ b/view/sharedcache/core/SharedCache.h @@ -26,7 +26,7 @@ namespace SharedCacheCore { const std::string SharedCacheMetadataTag = "SHAREDCACHE-SharedCacheData"; - struct MemoryRegion : public MetadataSerializable + struct MemoryRegion : public MetadataSerializable { std::string prettyName; uint64_t start; @@ -36,7 +36,7 @@ namespace SharedCacheCore { bool headerInitialized = false; BNSegmentFlag flags; - void Store() override + void Store(SerializationContext& context) const { MSS(prettyName); MSS(start); @@ -46,7 +46,7 @@ namespace SharedCacheCore { MSS_CAST(flags, uint64_t); } - void Load() override + void Load(DeserializationContext& context) { MSL(prettyName); MSL(start); @@ -57,30 +57,30 @@ namespace SharedCacheCore { } }; - struct CacheImage : public MetadataSerializable + struct CacheImage : public MetadataSerializable { std::string installName; uint64_t headerLocation; std::vector regions; - void Store() override + void Store(SerializationContext& context) const { MSS(installName); MSS(headerLocation); - rapidjson::Value key("regions", m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); + Serialize(context, "regions"); + context.writer.StartArray(); for (auto& region : regions) { - bArr.PushBack(rapidjson::Value(region.AsString().c_str(), m_activeContext.allocator), m_activeContext.allocator); + Serialize(context, region.AsString()); } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); + context.writer.EndArray(); } - void Load() override + void Load(DeserializationContext& context) { MSL(installName); MSL(headerLocation); - auto bArr = m_activeDeserContext.doc["regions"].GetArray(); + auto bArr = context.doc["regions"].GetArray(); regions.clear(); for (auto& region : bArr) { @@ -91,19 +91,19 @@ namespace SharedCacheCore { } }; - struct BackingCache : public MetadataSerializable + struct BackingCache : public MetadataSerializable { std::string path; bool isPrimary = false; std::vector>> mappings; - void Store() override + void Store(SerializationContext& context) const { MSS(path); MSS(isPrimary); MSS(mappings); } - void Load() override + void Load(DeserializationContext& context) { MSL(path); MSL(isPrimary); @@ -357,7 +357,7 @@ namespace SharedCacheCore { #endif using namespace BinaryNinja; - struct SharedCacheMachOHeader : public MetadataSerializable + struct SharedCacheMachOHeader : public MetadataSerializable { uint64_t textBase = 0; uint64_t loadCommandOffset = 0; @@ -402,419 +402,8 @@ namespace SharedCacheCore { bool routinesPresent = false; bool functionStartsPresent = false; bool relocatable = false; - void Serialize(const std::string& name, mach_header_64 b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - bArr.PushBack(b.magic, m_activeContext.allocator); - bArr.PushBack(b.cputype, m_activeContext.allocator); - bArr.PushBack(b.cpusubtype, m_activeContext.allocator); - bArr.PushBack(b.filetype, m_activeContext.allocator); - bArr.PushBack(b.ncmds, m_activeContext.allocator); - bArr.PushBack(b.sizeofcmds, m_activeContext.allocator); - bArr.PushBack(b.flags, m_activeContext.allocator); - bArr.PushBack(b.reserved, m_activeContext.allocator); - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - - void Deserialize(const std::string& name, mach_header_64& b) - { - auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray(); - b.magic = bArr[0].GetUint(); - b.cputype = bArr[1].GetUint(); - b.cpusubtype = bArr[2].GetUint(); - b.filetype = bArr[3].GetUint(); - b.ncmds = bArr[4].GetUint(); - b.sizeofcmds = bArr[5].GetUint(); - b.flags = bArr[6].GetUint(); - b.reserved = bArr[7].GetUint(); - } - - void Serialize(const std::string& name, symtab_command b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - bArr.PushBack(b.cmd, m_activeContext.allocator); - bArr.PushBack(b.cmdsize, m_activeContext.allocator); - bArr.PushBack(b.symoff, m_activeContext.allocator); - bArr.PushBack(b.nsyms, m_activeContext.allocator); - bArr.PushBack(b.stroff, m_activeContext.allocator); - bArr.PushBack(b.strsize, m_activeContext.allocator); - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - - void Deserialize(const std::string& name, symtab_command& b) - { - auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray(); - b.cmd = bArr[0].GetUint(); - b.cmdsize = bArr[1].GetUint(); - b.symoff = bArr[2].GetUint(); - b.nsyms = bArr[3].GetUint(); - b.stroff = bArr[4].GetUint(); - b.strsize = bArr[5].GetUint(); - } - - void Serialize(const std::string& name, dysymtab_command b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - bArr.PushBack(b.cmd, m_activeContext.allocator); - bArr.PushBack(b.cmdsize, m_activeContext.allocator); - bArr.PushBack(b.ilocalsym, m_activeContext.allocator); - bArr.PushBack(b.nlocalsym, m_activeContext.allocator); - bArr.PushBack(b.iextdefsym, m_activeContext.allocator); - bArr.PushBack(b.nextdefsym, m_activeContext.allocator); - bArr.PushBack(b.iundefsym, m_activeContext.allocator); - bArr.PushBack(b.nundefsym, m_activeContext.allocator); - bArr.PushBack(b.tocoff, m_activeContext.allocator); - bArr.PushBack(b.ntoc, m_activeContext.allocator); - bArr.PushBack(b.modtaboff, m_activeContext.allocator); - bArr.PushBack(b.nmodtab, m_activeContext.allocator); - bArr.PushBack(b.extrefsymoff, m_activeContext.allocator); - bArr.PushBack(b.nextrefsyms, m_activeContext.allocator); - bArr.PushBack(b.indirectsymoff, m_activeContext.allocator); - bArr.PushBack(b.nindirectsyms, m_activeContext.allocator); - bArr.PushBack(b.extreloff, m_activeContext.allocator); - bArr.PushBack(b.nextrel, m_activeContext.allocator); - bArr.PushBack(b.locreloff, m_activeContext.allocator); - bArr.PushBack(b.nlocrel, m_activeContext.allocator); - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - - void Deserialize(const std::string& name, dysymtab_command& b) - { - auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray(); - b.cmd = bArr[0].GetUint(); - b.cmdsize = bArr[1].GetUint(); - b.ilocalsym = bArr[2].GetUint(); - b.nlocalsym = bArr[3].GetUint(); - b.iextdefsym = bArr[4].GetUint(); - b.nextdefsym = bArr[5].GetUint(); - b.iundefsym = bArr[6].GetUint(); - b.nundefsym = bArr[7].GetUint(); - b.tocoff = bArr[8].GetUint(); - b.ntoc = bArr[9].GetUint(); - b.modtaboff = bArr[10].GetUint(); - b.nmodtab = bArr[11].GetUint(); - b.extrefsymoff = bArr[12].GetUint(); - b.nextrefsyms = bArr[13].GetUint(); - b.indirectsymoff = bArr[14].GetUint(); - b.nindirectsyms = bArr[15].GetUint(); - b.extreloff = bArr[16].GetUint(); - b.nextrel = bArr[17].GetUint(); - b.locreloff = bArr[18].GetUint(); - b.nlocrel = bArr[19].GetUint(); - } - - void Serialize(const std::string& name, dyld_info_command b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - bArr.PushBack(b.cmd, m_activeContext.allocator); - bArr.PushBack(b.cmdsize, m_activeContext.allocator); - bArr.PushBack(b.rebase_off, m_activeContext.allocator); - bArr.PushBack(b.rebase_size, m_activeContext.allocator); - bArr.PushBack(b.bind_off, m_activeContext.allocator); - bArr.PushBack(b.bind_size, m_activeContext.allocator); - bArr.PushBack(b.weak_bind_off, m_activeContext.allocator); - bArr.PushBack(b.weak_bind_size, m_activeContext.allocator); - bArr.PushBack(b.lazy_bind_off, m_activeContext.allocator); - bArr.PushBack(b.lazy_bind_size, m_activeContext.allocator); - bArr.PushBack(b.export_off, m_activeContext.allocator); - bArr.PushBack(b.export_size, m_activeContext.allocator); - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - - void Deserialize(const std::string& name, dyld_info_command& b) - { - auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray(); - b.cmd = bArr[0].GetUint(); - b.cmdsize = bArr[1].GetUint(); - b.rebase_off = bArr[2].GetUint(); - b.rebase_size = bArr[3].GetUint(); - b.bind_off = bArr[4].GetUint(); - b.bind_size = bArr[5].GetUint(); - b.weak_bind_off = bArr[6].GetUint(); - b.weak_bind_size = bArr[7].GetUint(); - b.lazy_bind_off = bArr[8].GetUint(); - b.lazy_bind_size = bArr[9].GetUint(); - b.export_off = bArr[10].GetUint(); - b.export_size = bArr[11].GetUint(); - } - - void Serialize(const std::string& name, routines_command_64 b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - bArr.PushBack(b.cmd, m_activeContext.allocator); - bArr.PushBack(b.cmdsize, m_activeContext.allocator); - bArr.PushBack(b.init_address, m_activeContext.allocator); - bArr.PushBack(b.init_module, m_activeContext.allocator); - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - - void Deserialize(const std::string& name, routines_command_64& b) - { - auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray(); - b.cmd = bArr[0].GetUint(); - b.cmdsize = bArr[1].GetUint(); - b.init_address = bArr[2].GetUint(); - b.init_module = bArr[3].GetUint(); - } - - void Serialize(const std::string& name, function_starts_command b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - bArr.PushBack(b.cmd, m_activeContext.allocator); - bArr.PushBack(b.cmdsize, m_activeContext.allocator); - bArr.PushBack(b.funcoff, m_activeContext.allocator); - bArr.PushBack(b.funcsize, m_activeContext.allocator); - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - - void Deserialize(const std::string& name, function_starts_command& b) - { - auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray(); - b.cmd = bArr[0].GetUint(); - b.cmdsize = bArr[1].GetUint(); - b.funcoff = bArr[2].GetUint(); - b.funcsize = bArr[3].GetUint(); - } - - void Serialize(const std::string& name, std::vector b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - for (auto& s : b) - { - rapidjson::Value sArr(rapidjson::kArrayType); - std::string sectNameStr; - char sectName[16]; - memcpy(sectName, s.sectname, 16); - sectName[15] = 0; - sectNameStr = std::string(sectName); - sArr.PushBack( - rapidjson::Value(sectNameStr.c_str(), m_activeContext.allocator), m_activeContext.allocator); - std::string segNameStr; - char segName[16]; - memcpy(segName, s.segname, 16); - segName[15] = 0; - segNameStr = std::string(segName); - sArr.PushBack( - rapidjson::Value(segNameStr.c_str(), m_activeContext.allocator), m_activeContext.allocator); - sArr.PushBack(s.addr, m_activeContext.allocator); - sArr.PushBack(s.size, m_activeContext.allocator); - sArr.PushBack(s.offset, m_activeContext.allocator); - sArr.PushBack(s.align, m_activeContext.allocator); - sArr.PushBack(s.reloff, m_activeContext.allocator); - sArr.PushBack(s.nreloc, m_activeContext.allocator); - sArr.PushBack(s.flags, m_activeContext.allocator); - sArr.PushBack(s.reserved1, m_activeContext.allocator); - sArr.PushBack(s.reserved2, m_activeContext.allocator); - sArr.PushBack(s.reserved3, m_activeContext.allocator); - bArr.PushBack(sArr, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - - void Deserialize(const std::string& name, std::vector& b) - { - auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray(); - for (auto& s : bArr) - { - section_64 sec; - auto s2 = s.GetArray(); - std::string sectNameStr = s2[0].GetString(); - memset(sec.sectname, 0, 16); - memcpy(sec.sectname, sectNameStr.c_str(), sectNameStr.size()); - std::string segNameStr = s2[1].GetString(); - memset(sec.segname, 0, 16); - memcpy(sec.segname, segNameStr.c_str(), segNameStr.size()); - sec.addr = s2[2].GetUint64(); - sec.size = s2[3].GetUint64(); - sec.offset = s2[4].GetUint(); - sec.align = s2[5].GetUint(); - sec.reloff = s2[6].GetUint(); - sec.nreloc = s2[7].GetUint(); - sec.flags = s2[8].GetUint(); - sec.reserved1 = s2[9].GetUint(); - sec.reserved2 = s2[10].GetUint(); - sec.reserved3 = s2[11].GetUint(); - b.push_back(sec); - } - } - - void Serialize(const std::string& name, linkedit_data_command b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - bArr.PushBack(b.cmd, m_activeContext.allocator); - bArr.PushBack(b.cmdsize, m_activeContext.allocator); - bArr.PushBack(b.dataoff, m_activeContext.allocator); - bArr.PushBack(b.datasize, m_activeContext.allocator); - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - - void Deserialize(const std::string& name, linkedit_data_command& b) - { - auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray(); - b.cmd = bArr[0].GetUint(); - b.cmdsize = bArr[1].GetUint(); - b.dataoff = bArr[2].GetUint(); - b.datasize = bArr[3].GetUint(); - } - - void Serialize(const std::string& name, segment_command_64 b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - std::string segNameStr; - char segName[16]; - memcpy(segName, b.segname, 16); - segName[15] = 0; - segNameStr = std::string(segName); - bArr.PushBack(rapidjson::Value(segNameStr.c_str(), m_activeContext.allocator), m_activeContext.allocator); - bArr.PushBack(b.vmaddr, m_activeContext.allocator); - bArr.PushBack(b.vmsize, m_activeContext.allocator); - bArr.PushBack(b.fileoff, m_activeContext.allocator); - bArr.PushBack(b.filesize, m_activeContext.allocator); - bArr.PushBack(b.maxprot, m_activeContext.allocator); - bArr.PushBack(b.initprot, m_activeContext.allocator); - bArr.PushBack(b.nsects, m_activeContext.allocator); - bArr.PushBack(b.flags, m_activeContext.allocator); - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - - void Deserialize(const std::string& name, segment_command_64& b) - { - auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray(); - std::string segNameStr = bArr[0].GetString(); - memset(b.segname, 0, 16); - memcpy(b.segname, segNameStr.c_str(), segNameStr.size()); - b.vmaddr = bArr[1].GetUint64(); - b.vmsize = bArr[2].GetUint64(); - b.fileoff = bArr[3].GetUint64(); - b.filesize = bArr[4].GetUint64(); - b.maxprot = bArr[5].GetUint(); - b.initprot = bArr[6].GetUint(); - b.nsects = bArr[7].GetUint(); - b.flags = bArr[8].GetUint(); - } - - void Serialize(const std::string& name, std::vector b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - for (auto& s : b) - { - rapidjson::Value sArr(rapidjson::kArrayType); - std::string segNameStr; - char segName[16]; - memcpy(segName, s.segname, 16); - segName[15] = 0; - segNameStr = std::string(segName); - sArr.PushBack( - rapidjson::Value(segNameStr.c_str(), m_activeContext.allocator), m_activeContext.allocator); - sArr.PushBack(s.vmaddr, m_activeContext.allocator); - sArr.PushBack(s.vmsize, m_activeContext.allocator); - sArr.PushBack(s.fileoff, m_activeContext.allocator); - sArr.PushBack(s.filesize, m_activeContext.allocator); - sArr.PushBack(s.maxprot, m_activeContext.allocator); - sArr.PushBack(s.initprot, m_activeContext.allocator); - sArr.PushBack(s.nsects, m_activeContext.allocator); - sArr.PushBack(s.flags, m_activeContext.allocator); - bArr.PushBack(sArr, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - - void Deserialize(const std::string& name, std::vector& b) - { - auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray(); - for (auto& s : bArr) - { - segment_command_64 sec; - auto s2 = s.GetArray(); - std::string segNameStr = s2[0].GetString(); - memset(sec.segname, 0, 16); - memcpy(sec.segname, segNameStr.c_str(), segNameStr.size()); - sec.vmaddr = s2[1].GetUint64(); - sec.vmsize = s2[2].GetUint64(); - sec.fileoff = s2[3].GetUint64(); - sec.filesize = s2[4].GetUint64(); - sec.maxprot = s2[5].GetUint(); - sec.initprot = s2[6].GetUint(); - sec.nsects = s2[7].GetUint(); - sec.flags = s2[8].GetUint(); - b.push_back(sec); - } - } - - void Serialize(const std::string& name, build_version_command b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - bArr.PushBack(b.cmd, m_activeContext.allocator); - bArr.PushBack(b.cmdsize, m_activeContext.allocator); - bArr.PushBack(b.platform, m_activeContext.allocator); - bArr.PushBack(b.minos, m_activeContext.allocator); - bArr.PushBack(b.sdk, m_activeContext.allocator); - bArr.PushBack(b.ntools, m_activeContext.allocator); - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - void Deserialize(const std::string& name, build_version_command& b) - { - auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray(); - b.cmd = bArr[0].GetUint(); - b.cmdsize = bArr[1].GetUint(); - b.platform = bArr[2].GetUint(); - b.minos = bArr[3].GetUint(); - b.sdk = bArr[4].GetUint(); - b.ntools = bArr[5].GetUint(); - } - - void Serialize(const std::string& name, std::vector b) - { - S(); - rapidjson::Value key(name.c_str(), m_activeContext.allocator); - rapidjson::Value bArr(rapidjson::kArrayType); - for (auto& s : b) - { - rapidjson::Value sArr(rapidjson::kArrayType); - sArr.PushBack(s.tool, m_activeContext.allocator); - sArr.PushBack(s.version, m_activeContext.allocator); - bArr.PushBack(sArr, m_activeContext.allocator); - } - m_activeContext.doc.AddMember(key, bArr, m_activeContext.allocator); - } - - void Deserialize(const std::string& name, std::vector& b) - { - auto bArr = m_activeDeserContext.doc[name.c_str()].GetArray(); - for (auto& s : bArr) - { - build_tool_version sec; - auto s2 = s.GetArray(); - sec.tool = s2[0].GetUint(); - sec.version = s2[1].GetUint(); - b.push_back(sec); - } - } - - void Store() override + void Store(SerializationContext& context) const { MSS(textBase); MSS(loadCommandOffset); @@ -851,7 +440,7 @@ namespace SharedCacheCore { MSS(functionStartsPresent); MSS(relocatable); } - void Load() override + void Load(DeserializationContext& context) { MSL(textBase); MSL(loadCommandOffset); @@ -906,7 +495,7 @@ namespace SharedCacheCore { static std::atomic sharedCacheReferences = 0; - class SharedCache : public MetadataSerializable + class SharedCache : public MetadataSerializable { IMPLEMENT_SHAREDCACHE_API_OBJECT(BNSharedCache); @@ -938,207 +527,24 @@ namespace SharedCacheCore { iOS16CacheFormat, }; - void Store() override - { - m_activeContext.doc.AddMember("metadataVersion", METADATA_VERSION, m_activeContext.allocator); - - MSS(m_viewState); - MSS_CAST(m_cacheFormat, uint8_t); - MSS(m_imageStarts); - MSS(m_baseFilePath); - rapidjson::Value headers(rapidjson::kArrayType); - for (auto [k, v] : m_headers) - { - headers.PushBack(v.AsDocument(), m_activeContext.allocator); - } - m_activeContext.doc.AddMember("headers", headers, m_activeContext.allocator); - // std::vector>>>> m_exportInfos - // std::vector>>>> exportInfos; - rapidjson::Document exportInfos(rapidjson::kArrayType); - - for (const auto& pair1 : m_exportInfos) - { - rapidjson::Value subObj(rapidjson::kObjectType); - rapidjson::Value subArr(rapidjson::kArrayType); - for (const auto& pair2 : pair1.second) - { - rapidjson::Value subSubObj(rapidjson::kObjectType); - subSubObj.AddMember("key", pair2.first, m_activeContext.allocator); - subSubObj.AddMember("val1", pair2.second.first, m_activeContext.allocator); - subSubObj.AddMember("val2", pair2.second.second, m_activeContext.allocator); - subArr.PushBack(subSubObj, m_activeContext.allocator); - } - - subObj.AddMember("key", pair1.first, m_activeContext.allocator); - subObj.AddMember("value", subArr, m_activeContext.allocator); - - exportInfos.PushBack(subObj, m_activeContext.allocator); - } - m_activeContext.doc.AddMember("exportInfos", exportInfos, m_activeContext.allocator); - - rapidjson::Value backingCaches(rapidjson::kArrayType); - for (auto bc : m_backingCaches) - { - backingCaches.PushBack(bc.AsDocument(), m_activeContext.allocator); - } - m_activeContext.doc.AddMember("backingCaches", backingCaches, m_activeContext.allocator); - rapidjson::Value stubIslands(rapidjson::kArrayType); - for (auto si : m_stubIslandRegions) - { - stubIslands.PushBack(si.AsDocument(), m_activeContext.allocator); - } - rapidjson::Value images(rapidjson::kArrayType); - for (auto img : m_images) - { - images.PushBack(img.AsDocument(), m_activeContext.allocator); - } - m_activeContext.doc.AddMember("images", images, m_activeContext.allocator); - rapidjson::Value regionsMappedIntoMemory(rapidjson::kArrayType); - for (auto r : m_regionsMappedIntoMemory) - { - regionsMappedIntoMemory.PushBack(r.AsDocument(), m_activeContext.allocator); - } - m_activeContext.doc.AddMember("regionsMappedIntoMemory", regionsMappedIntoMemory, m_activeContext.allocator); - m_activeContext.doc.AddMember("stubIslands", stubIslands, m_activeContext.allocator); - rapidjson::Value dyldDataSections(rapidjson::kArrayType); - for (auto si : m_dyldDataRegions) - { - dyldDataSections.PushBack(si.AsDocument(), m_activeContext.allocator); - } - m_activeContext.doc.AddMember("dyldDataSections", dyldDataSections, m_activeContext.allocator); - rapidjson::Value nonImageRegions(rapidjson::kArrayType); - for (auto si : m_nonImageRegions) - { - nonImageRegions.PushBack(si.AsDocument(), m_activeContext.allocator); - } - m_activeContext.doc.AddMember("nonImageRegions", nonImageRegions, m_activeContext.allocator); - } - void Load() override - { - if (m_activeDeserContext.doc.HasMember("metadataVersion")) - { - if (m_activeDeserContext.doc["metadataVersion"].GetUint() != METADATA_VERSION) - { - m_logger->LogError("Shared Cache metadata version mismatch"); - return; - } - } - else - { - m_logger->LogError("Shared Cache metadata version missing"); - return; - } - m_viewState = MSL_CAST(m_viewState, uint8_t, DSCViewState); - m_cacheFormat = MSL_CAST(m_cacheFormat, uint8_t, SharedCacheFormat); - m_headers.clear(); - for (auto& startAndHeader : m_activeDeserContext.doc["headers"].GetArray()) - { - SharedCacheMachOHeader header; - header.LoadFromValue(startAndHeader); - m_headers[header.textBase] = header; - } - MSL(m_imageStarts); - MSL(m_baseFilePath); - m_exportInfos.clear(); - for (const auto& obj1 : m_activeDeserContext.doc["exportInfos"].GetArray()) - { - std::vector>> innerVec; - for (const auto& obj2 : obj1["value"].GetArray()) - { - std::pair innerPair = { (BNSymbolType)obj2["val1"].GetUint64(), obj2["val2"].GetString() }; - innerVec.push_back({ obj2["key"].GetUint64(), innerPair }); - } - - m_exportInfos[obj1["key"].GetUint64()] = innerVec; - } - m_symbolInfos.clear(); - for (auto& symbolInfo : m_activeDeserContext.doc["symbolInfos"].GetArray()) - { - std::vector>> symbolInfoVec; - for (auto& symbolInfoPair : symbolInfo.GetArray()) - { - symbolInfoVec.push_back({symbolInfoPair[0].GetUint64(), - {(BNSymbolType)symbolInfoPair[1].GetUint(), symbolInfoPair[2].GetString()}}); - } - m_symbolInfos[symbolInfo[0].GetUint64()] = symbolInfoVec; - } - m_backingCaches.clear(); - for (auto& bcV : m_activeDeserContext.doc["backingCaches"].GetArray()) - { - BackingCache bc; - bc.LoadFromValue(bcV); - m_backingCaches.push_back(bc); - } - m_images.clear(); - for (auto& imgV : m_activeDeserContext.doc["images"].GetArray()) - { - CacheImage img; - img.LoadFromValue(imgV); - m_images.push_back(img); - } - m_regionsMappedIntoMemory.clear(); - for (auto& rV : m_activeDeserContext.doc["regionsMappedIntoMemory"].GetArray()) - { - MemoryRegion r; - r.LoadFromValue(rV); - m_regionsMappedIntoMemory.push_back(r); - } - m_stubIslandRegions.clear(); - for (auto& siV : m_activeDeserContext.doc["stubIslands"].GetArray()) - { - MemoryRegion si; - si.LoadFromValue(siV); - m_stubIslandRegions.push_back(si); - } - m_dyldDataRegions.clear(); - for (auto& siV : m_activeDeserContext.doc["dyldDataSections"].GetArray()) - { - MemoryRegion si; - si.LoadFromValue(siV); - m_dyldDataRegions.push_back(si); - } - m_nonImageRegions.clear(); - for (auto& siV : m_activeDeserContext.doc["nonImageRegions"].GetArray()) - { - MemoryRegion si; - si.LoadFromValue(siV); - m_nonImageRegions.push_back(si); - } + void Store(SerializationContext& context) const; + void Load(DeserializationContext& context); - m_metadataValid = true; - } + struct State; private: Ref m_logger; /* VIEW STATE BEGIN -- SERIALIZE ALL OF THIS AND STORE IT IN RAW VIEW */ // Updated as the view is loaded further, more images are added, etc - DSCViewState m_viewState = DSCViewStateUnloaded; - std::unordered_map>>> - m_exportInfos; - std::unordered_map>>> - m_symbolInfos; - // --- + // NOTE: Access via `State()` or `MutableState()` below. + // `WillMutateState()` must be called before the first access to `MutableState()`. + std::shared_ptr m_state; + bool m_stateIsShared = false; // Serialized once by PerformInitialLoad and available after m_viewState == Loaded bool m_metadataValid = false; - std::string m_baseFilePath; - SharedCacheFormat m_cacheFormat; - - std::unordered_map m_imageStarts; - std::unordered_map m_headers; - - std::vector m_images; - - std::vector m_regionsMappedIntoMemory; - - std::vector m_backingCaches; - - std::vector m_stubIslandRegions; - std::vector m_dyldDataRegions; - std::vector m_nonImageRegions; - /* VIEWSTATE END -- NOTHING PAST THIS IS SERIALIZED */ /* API VIEW START */ @@ -1170,34 +576,40 @@ namespace SharedCacheCore { std::vector>> LoadAllSymbolsAndWait(); - std::unordered_map AllImageStarts() const { return m_imageStarts; } - std::unordered_map AllImageHeaders() const { return m_headers; } + const std::unordered_map& AllImageStarts() const; + const std::unordered_map& AllImageHeaders() const; std::string SerializedImageHeaderForAddress(uint64_t address); std::string SerializedImageHeaderForName(std::string name); void FindSymbolAtAddrAndApplyToAddr(uint64_t symbolLocation, uint64_t targetLocation, bool triggerReanalysis); - std::vector BackingCaches() const { - - return m_backingCaches; - } + const std::vector& BackingCaches() const; - DSCViewState State() const { return m_viewState; } + DSCViewState ViewState() const; explicit SharedCache(BinaryNinja::Ref rawView); - ~SharedCache() override; + virtual ~SharedCache(); std::optional LoadHeaderForAddress( std::shared_ptr vm, uint64_t address, std::string installName); void InitializeHeader( Ref view, VM* vm, SharedCacheMachOHeader header, std::vector regionsToLoad); - void ReadExportNode(std::vector>& symbolList, SharedCacheMachOHeader& header, DataBuffer& buffer, uint64_t textBase, - const std::string& currentText, size_t cursor, uint32_t endGuard); + void ReadExportNode(std::vector>& symbolList, SharedCacheMachOHeader& header, DataBuffer& buffer, + uint64_t textBase, const std::string& currentText, size_t cursor, uint32_t endGuard); std::vector> ParseExportTrie( std::shared_ptr linkeditFile, SharedCacheMachOHeader header); - }; + const State& State() const { return *m_state; } + struct State& MutableState() { AssertMutable(); return *m_state; } + + void AssertMutable() const; + + // Ensures that the state is uniquely owned, copying it if it is not. + // Must be called before first access to `MutableState()` after the state + // is loaded from the cache. Can safely be called multiple times. + void WillMutateState(); + }; }