269 lines
7.7 KiB
C++
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());
|
|
}
|