fxos/lib/binary.cpp

269 lines
7.7 KiB
C++

//---------------------------------------------------------------------------//
// 1100101 |_ mov #0, r4 __ //
// 11 |_ <0xb380 %5c4> / _|_ _____ ___ //
// 0110 |_ 3.50 -> 3.60 | _\ \ / _ (_-< //
// |_ base# + offset |_| /_\_\___/__/ //
//---------------------------------------------------------------------------//
#include <fxos/binary.h>
#include <fxos/function.h>
#include <fxos/analysis.h>
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<Mark>(*this, address, 0);
ptr->deserialize(obj);
m_objects.emplace(address, std::move(ptr));
}
else if(type == "Variable") {
auto ptr = std::make_unique<Variable>(*this, address, "");
ptr->deserialize(obj);
m_objects.emplace(address, std::move(ptr));
}
else if(type == "Function") {
auto ptr = std::make_unique<Function>(*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<OS>(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<BinaryObject> &&obj)
{
m_objects.insert({obj->address(), std::move(obj)});
};
std::optional<u32> 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<BinaryObject *> Binary::objectsAt(u32 address)
{
std::vector<BinaryObject *> objects;
for(auto [it, end] = m_objects.equal_range(address); it != end; ++it)
objects.push_back(it->second.get());
return objects;
}
std::vector<BinaryObject const *> Binary::objectsAt(u32 address) const
{
std::vector<BinaryObject const *> objects;
for(auto [it, end] = m_objects.equal_range(address); it != end; ++it)
objects.push_back(it->second.get());
return objects;
}
std::vector<BinaryObject *> Binary::objectsCovering(u32 address)
{
std::vector<BinaryObject *> 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<BinaryObject const *> Binary::objectsCovering(u32 address) const
{
std::vector<BinaryObject const *> 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<Function *> Binary::functionsAt(u32 address)
{
std::vector<Function *> funcs;
for(auto obj: objectsAt(address)) {
if(obj->isFunction())
funcs.push_back(&obj->getFunction());
}
return funcs;
}
std::vector<Function const *> Binary::functionsAt(u32 address) const
{
std::vector<Function const *> 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());
}