fxos: save binary objects (currently functions) in project
This commit is contained in:
parent
f5ad03152d
commit
80d6001417
|
@ -142,7 +142,7 @@ struct Binary
|
|||
/* Empty binary with an empty virtual space. */
|
||||
Binary() = default;
|
||||
BSON serialize() const;
|
||||
void deserialize(BSON const &);
|
||||
void deserialize(BSON const &, bool verbose = false);
|
||||
|
||||
VirtualSpace &vspace()
|
||||
{
|
||||
|
@ -243,9 +243,15 @@ private:
|
|||
alias with other binary objects. */
|
||||
struct Mark: public BinaryObject
|
||||
{
|
||||
Mark(Binary &binary, u32 address, u32 size):
|
||||
BinaryObject(binary, Type::Mark, address, size)
|
||||
{
|
||||
}
|
||||
|
||||
// TODO: Tags/colors in marks
|
||||
|
||||
// TODO: BinaryObject serialization
|
||||
BSON serialize() const;
|
||||
void deserialize(BSON const &);
|
||||
};
|
||||
|
||||
/* Binary object representing a non-empty piece of data. */
|
||||
|
@ -255,6 +261,9 @@ struct Variable: public BinaryObject
|
|||
type defaults to an unsigned machine word (u32). */
|
||||
Variable(Binary &binary, u32 address, std::string const &name);
|
||||
|
||||
BSON serialize() const;
|
||||
void deserialize(BSON const &);
|
||||
|
||||
#if 0
|
||||
DataType const *type() const
|
||||
{
|
||||
|
|
|
@ -34,6 +34,9 @@ struct Function: public BinaryObject
|
|||
{
|
||||
Function(Binary &binary, u32 address);
|
||||
|
||||
BSON serialize() const;
|
||||
void deserialize(BSON const &);
|
||||
|
||||
/* Number of basic blocks. */
|
||||
uint blockCount() const
|
||||
{
|
||||
|
|
|
@ -51,7 +51,7 @@ struct Project
|
|||
/* Save; prints on stderr and returns false in case of error. */
|
||||
bool save();
|
||||
/* Load from a folder. */
|
||||
bool load(std::string const &path);
|
||||
bool load(std::string const &path, bool verbose = false);
|
||||
|
||||
/* Create a binary based on the provided name. If there is a conflict, the
|
||||
name will get a suffix like "_0", "_1", etc. Final name is returned. */
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
//---------------------------------------------------------------------------//
|
||||
|
||||
#include <fxos/binary.h>
|
||||
#include <fxos/function.h>
|
||||
#include <fxos/analysis.h>
|
||||
using namespace FxOS;
|
||||
|
||||
//=== Binary ===//
|
||||
|
@ -17,9 +19,14 @@ BSON Binary::serialize() const
|
|||
for(auto const &[address, obj]: m_objects) {
|
||||
char str[32];
|
||||
sprintf(str, "%08x", address);
|
||||
// TODO: Serialize BinaryObjects
|
||||
// new(&fields[i]) BSONField(str, obj->serialize());
|
||||
new(&fields[i]) BSONField(str, BSON::mkNull());
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
|
@ -30,7 +37,7 @@ BSON Binary::serialize() const
|
|||
});
|
||||
}
|
||||
|
||||
void Binary::deserialize(BSON const &b)
|
||||
void Binary::deserialize(BSON const &b, bool verbose)
|
||||
{
|
||||
assert(b.isDocument() && b["*"].getString() == "Binary");
|
||||
m_vspace.deserialize(b["vspace"]);
|
||||
|
@ -39,9 +46,38 @@ void Binary::deserialize(BSON const &b)
|
|||
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);
|
||||
// TODO: Deserialize BinaryObject from fields[i].value()
|
||||
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
|
||||
|
@ -178,6 +214,29 @@ bool BinaryObject::contains(BinaryObject const &other) const
|
|||
&& 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):
|
||||
|
@ -186,3 +245,24 @@ Variable::Variable(Binary &binary, u32 address, std::string const &name):
|
|||
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());
|
||||
}
|
||||
|
|
|
@ -27,6 +27,28 @@ Function::Function(Binary &binary, u32 address):
|
|||
setName(format("fun.%08x", address));
|
||||
}
|
||||
|
||||
BSON Function::serialize() const
|
||||
{
|
||||
// TODO: Function: Serialize certain analysis results?
|
||||
return BSON::mkDocument({
|
||||
{"*", BSON::mkString("Function")},
|
||||
{"address", BSON::mkI32(address())},
|
||||
{"name", BSON::mkString(name())},
|
||||
{"comm", comment() != "" ? BSON::mkString(comment()) : BSON::mkNull()},
|
||||
});
|
||||
}
|
||||
|
||||
void Function::deserialize(BSON const &b)
|
||||
{
|
||||
assert(b.isDocument() && b["*"].getString() == "Function");
|
||||
|
||||
exploreFunctionAt(address());
|
||||
setName(b["name"].getString());
|
||||
setComment(b["comm"].isNull() ? "" : b["comment"].getString());
|
||||
|
||||
runAnalysis();
|
||||
}
|
||||
|
||||
BasicBlock &Function::basicBlockByAddress(u32 pc)
|
||||
{
|
||||
for(BasicBlock &bb: *this) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <fxos/project.h>
|
||||
#include <fxos/util/log.h>
|
||||
#include <fxos/util/Timer.h>
|
||||
#include <filesystem>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
@ -164,10 +165,13 @@ bool Project::save()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Project::load(std::string const &path0)
|
||||
bool Project::load(std::string const &path0, bool verbose)
|
||||
{
|
||||
fs::path path = path0;
|
||||
|
||||
Timer t;
|
||||
t.start();
|
||||
|
||||
BSON metadata
|
||||
= BSON::loadDocumentFromFile(path / "project", true, true, "Project");
|
||||
if(metadata.isNull())
|
||||
|
@ -177,21 +181,24 @@ bool Project::load(std::string const &path0)
|
|||
m_name = metadata["name"].getString();
|
||||
m_dirty = false;
|
||||
|
||||
if(!metadata.hasField("binaries"))
|
||||
return true;
|
||||
if(metadata.hasField("binaries")) {
|
||||
for(size_t i = 0; i < metadata["binaries"].size(); i++) {
|
||||
std::string name = metadata["binaries"][i].getString();
|
||||
BSON bin = BSON::loadDocumentFromFile(
|
||||
path / (name + ".bin"), true, true, "Binary");
|
||||
if(bin.isNull())
|
||||
continue;
|
||||
|
||||
for(size_t i = 0; i < metadata["binaries"].size(); i++) {
|
||||
std::string name = metadata["binaries"][i].getString();
|
||||
BSON bin = BSON::loadDocumentFromFile(
|
||||
path / (name + ".bin"), true, true, "Binary");
|
||||
if(bin.isNull())
|
||||
continue;
|
||||
|
||||
assert(m_binaries.count(name) == 0);
|
||||
m_binaries[name];
|
||||
m_binaries[name].deserialize(bin);
|
||||
assert(m_binaries.count(name) == 0);
|
||||
m_binaries[name];
|
||||
m_binaries[name].deserialize(bin, verbose);
|
||||
}
|
||||
}
|
||||
|
||||
t.stop();
|
||||
if(verbose)
|
||||
printf("Loaded %s in %s\n", m_name.c_str(), t.format_time().c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ void Session::switchToNewProject(
|
|||
bool Session::loadProject(std::string const &path)
|
||||
{
|
||||
auto p = std::make_unique<Project>();
|
||||
if(!p->load(path))
|
||||
if(!p->load(path, true))
|
||||
return false;
|
||||
|
||||
/* Unload current project - any unsaved data is lost. */
|
||||
|
|
Loading…
Reference in New Issue