//---------------------------------------------------------------------------// // 1100101 |_ mov #0, r4 __ // // 11 |_ <0xb380 %5c4> / _|_ _____ ___ // // 0110 |_ 3.50 -> 3.60 | _\ \ / _ (_-< // // |_ base# + offset |_| /_\_\___/__/ // //---------------------------------------------------------------------------// #include #include #include using namespace FxOS; //=== Binary ===// BSON Binary::serialize() const { BSONField *fields = (BSONField *)malloc(m_objects.size() * sizeof *fields); int i = 0; for(auto const &[address, obj]: m_objects) { char str[32]; sprintf(str, "%08x", address); if(obj->isMark()) new(&fields[i]) BSONField(str, obj->getMark().serialize()); else if(obj->isVariable()) new(&fields[i]) BSONField(str, obj->getVariable().serialize()); else if(obj->isFunction()) new(&fields[i]) BSONField(str, obj->getFunction().serialize()); i++; } return BSON::mkDocument({ {"*", BSON::mkString("Binary")}, {"vspace", m_vspace.serialize()}, {"objects", BSON::mkDocumentFromFieldArray(fields, m_objects.size())}, }); } void Binary::deserialize(BSON const &b, bool verbose) { assert(b.isDocument() && b["*"].getString() == "Binary"); m_vspace.deserialize(b["vspace"]); BSONField const *fields = b["objects"].getDocumentFields(); int N = b["objects"].size(); for(int i = 0; i < N; i++) { if(verbose) { printf("[%04d/%04d] Loading objects...", i, N); fflush(stdout); printf("\r\e[K"); } // TODO: This is redundant, the object stores it better already uint32_t address = std::stoul(fields[i].getName(), nullptr, 16); BSON const &obj = fields[i].value(); assert(address == (u32)obj["address"].getI32()); /* Because we have to create a different class for each object type, we skip BinaryObject and go to derived classes immediately. */ std::string type = obj["*"].getString(); if(type == "Mark") { auto ptr = std::make_unique(*this, address, 0); ptr->deserialize(obj); m_objects.emplace(address, std::move(ptr)); } else if(type == "Variable") { auto ptr = std::make_unique(*this, address, ""); ptr->deserialize(obj); m_objects.emplace(address, std::move(ptr)); } else if(type == "Function") { auto ptr = std::make_unique(*this, address); ptr->deserialize(obj); m_objects.emplace(address, std::move(ptr)); } } fflush(stdout); } OS *Binary::OSAnalysis(bool force) const { if(!m_os || force) { m_os = std::make_unique(m_vspace); /* We don't keep an OS analysis result that failed */ if(m_os->type == OS::UNKNOWN) m_os = nullptr; } return m_os.get(); } void Binary::addObject(std::unique_ptr &&obj) { m_objects.insert({obj->address(), std::move(obj)}); }; std::optional Binary::objectAddress(std::string const &name) const { for(auto const &[address, obj]: m_objects) { if(obj->name() == name) return address; } return {}; } BinaryObject *Binary::objectAt(u32 address) { auto it = m_objects.find(address); return (it == m_objects.end()) ? nullptr : it->second.get(); } BinaryObject const *Binary::objectAt(u32 address) const { auto it = m_objects.find(address); return (it == m_objects.end()) ? nullptr : it->second.get(); } std::vector Binary::objectsAt(u32 address) { std::vector objects; for(auto [it, end] = m_objects.equal_range(address); it != end; ++it) objects.push_back(it->second.get()); return objects; } std::vector Binary::objectsAt(u32 address) const { std::vector objects; for(auto [it, end] = m_objects.equal_range(address); it != end; ++it) objects.push_back(it->second.get()); return objects; } std::vector Binary::objectsCovering(u32 address) { std::vector objects; for(auto const &[obj_address, obj]: m_objects) { if(obj_address <= address && obj_address + obj->size() > address) objects.push_back(obj.get()); } return objects; } std::vector Binary::objectsCovering(u32 address) const { std::vector objects; for(auto const &[obj_address, obj]: m_objects) { if(obj_address <= address && obj_address + obj->size() > address) objects.push_back(obj.get()); } return objects; } Function *Binary::functionAt(u32 address) { for(auto obj: objectsAt(address)) { if(obj->isFunction()) return &obj->getFunction(); } return nullptr; } Function const *Binary::functionAt(u32 address) const { for(auto obj: objectsAt(address)) { if(obj->isFunction()) return &obj->getFunction(); } return nullptr; } std::vector Binary::functionsAt(u32 address) { std::vector funcs; for(auto obj: objectsAt(address)) { if(obj->isFunction()) funcs.push_back(&obj->getFunction()); } return funcs; } std::vector Binary::functionsAt(u32 address) const { std::vector funcs; for(auto obj: objectsAt(address)) { if(obj->isFunction()) funcs.push_back(&obj->getFunction()); } return funcs; } //=== BinaryObject ===// bool BinaryObject::intersects(BinaryObject const &other) const { uint32_t inter_start = std::max(m_address, other.address()); uint32_t inter_end = std::min(m_address + m_size, other.address() + other.size()); return inter_start < inter_end; } bool BinaryObject::contains(BinaryObject const &other) const { return m_address <= other.address() && m_address + m_size >= other.address() + other.size(); } //=== Mark ===// BSON Mark::serialize() const { // TODO: Serialize Mark is a non-trivial way return BSON::mkDocument({ {"*", BSON::mkString("Mark")}, {"address", BSON::mkI32(address())}, {"size", BSON::mkI32(size())}, {"name", BSON::mkString(name())}, {"comm", comment() != "" ? BSON::mkString(comment()) : BSON::mkNull()}, }); } void Mark::deserialize(BSON const &b) { // TODO: Serialize Mark is a non-trivial way assert(b.isDocument() && b["*"].getString() == "Mark"); setSize(b["size"].getI32()); setName(b["name"].getString()); setComment(b["comm"].isNull() ? "" : b["comment"].getString()); } //=== Variable ===// Variable::Variable(Binary &binary, u32 address, std::string const &name): BinaryObject(binary, BinaryObject::Variable, address, 4) { setName(name); // m_type = IntegerType(4, false); } BSON Variable::serialize() const { // TODO: Serialize Variable is a non-trivial way return BSON::mkDocument({ {"*", BSON::mkString("Variable")}, {"address", BSON::mkI32(address())}, {"size", BSON::mkI32(size())}, {"name", BSON::mkString(name())}, {"comm", comment() != "" ? BSON::mkString(comment()) : BSON::mkNull()}, }); } void Variable::deserialize(BSON const &b) { // TODO: Serialize Variable is a non-trivial way assert(b.isDocument() && b["*"].getString() == "Variable"); setSize(b["size"].getI32()); setName(b["name"].getString()); setComment(b["comm"].isNull() ? "" : b["comment"].getString()); }