Finalizer spslr file parsing
This commit is contained in:
parent
9576893b00
commit
d33896ecd2
@ -1,4 +1,5 @@
|
||||
find_package(LIEF REQUIRED)
|
||||
|
||||
add_executable(spslr_finalize finalize.cpp)
|
||||
add_executable(spslr_finalize finalize.cpp accumulation.cpp)
|
||||
target_link_libraries(spslr_finalize PRIVATE LIEF::LIEF)
|
||||
set_target_properties(spslr_finalize PROPERTIES CXX_STANDARD 20 CXX_STANDARD_REQUIRED YES CXX_EXTENSIONS NO)
|
||||
|
||||
232
finalize/accumulation.cpp
Normal file
232
finalize/accumulation.cpp
Normal file
@ -0,0 +1,232 @@
|
||||
#include "accumulation.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
static std::size_t next_global_target_uid = 0;
|
||||
|
||||
std::unordered_map<std::size_t, TARGET> targets;
|
||||
std::unordered_map<std::string, DPIN> global_dpins;
|
||||
std::unordered_map<std::string, CU> units;
|
||||
|
||||
static bool global_target_field_cmp(const TARGET& a, const TARGET& b) {
|
||||
// TODO
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool global_target_cmp(const TARGET& a, const TARGET& b) {
|
||||
// Note -> Later, use hash of type (generated by pinpoint plugin)
|
||||
|
||||
if (a.name != b.name)
|
||||
return false;
|
||||
|
||||
if (a.size != b.size || !global_target_field_cmp(a, b)) {
|
||||
std::cerr << "WARNING: Got different definitions of \"" << a.name << "\" -> detached randomization" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::size_t accumulate_global_target(TARGET&& target) {
|
||||
for (const auto& [guid, gtarget] : targets) {
|
||||
if (global_target_cmp(gtarget, target))
|
||||
return guid;
|
||||
}
|
||||
|
||||
std::size_t guid = next_global_target_uid++;
|
||||
targets.emplace(guid, std::move(target));
|
||||
return guid;
|
||||
}
|
||||
|
||||
/*
|
||||
<sourcefile>.spslr:
|
||||
|
||||
SPSLR <CU filename> <CU uid symbol>
|
||||
target <name> <local uid> <size> <field count>
|
||||
f <offset> <size> <alignment> <flags>
|
||||
f <offset> <size> <alignment> <flags>
|
||||
...
|
||||
ipin <label> <target uid> <field offset>
|
||||
ipin <label> <target uid> <field offset>
|
||||
ipin <label> <target uid> <field offset>
|
||||
...
|
||||
dpin <local/global> <symbol> <offset> <level> <target uid>
|
||||
dpin <local/global> <symbol> <offset> <level> <target uid>
|
||||
...
|
||||
*/
|
||||
static bool accumulate_file(const fs::path& path) {
|
||||
std::ifstream infile(path);
|
||||
if (!infile)
|
||||
return false;
|
||||
|
||||
std::string hdr_line;
|
||||
if (!std::getline(infile, hdr_line))
|
||||
return false;
|
||||
|
||||
std::istringstream hdr_iss(hdr_line);
|
||||
|
||||
std::string hdr_magic, hdr_cu_file, hdr_cu_uid;
|
||||
|
||||
if (!(hdr_iss >> hdr_magic) || hdr_magic != "SPSLR")
|
||||
return false;
|
||||
|
||||
if (!(hdr_iss >> hdr_cu_file) || !(hdr_iss >> hdr_cu_uid))
|
||||
return false;
|
||||
|
||||
std::cout << "Parsing " << path << std::endl;
|
||||
std::cout << " Source file -> " << hdr_cu_file << std::endl;
|
||||
std::cout << " Unit UID -> " << hdr_cu_uid << std::endl;
|
||||
|
||||
if (units.contains(hdr_cu_uid)) {
|
||||
std::cerr << "Duplicate unit UID -> " << hdr_cu_uid << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
units.emplace(hdr_cu_uid, CU{});
|
||||
CU& cu = units.at(hdr_cu_uid);
|
||||
|
||||
std::string line;
|
||||
while (std::getline(infile, line)) {
|
||||
if (line.empty())
|
||||
continue;
|
||||
|
||||
std::istringstream iss(line);
|
||||
std::string type;
|
||||
|
||||
if (!(iss >> type))
|
||||
return false;
|
||||
|
||||
if (type == "target") {
|
||||
TARGET target;
|
||||
|
||||
std::size_t local_uid, field_count;
|
||||
|
||||
if (!(iss >> target.name) || !(iss >> local_uid) || !(iss >> target.size) || !(iss >> field_count)) {
|
||||
std::cerr << "Invalid target line" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cu.local_targets.contains(local_uid)) {
|
||||
std::cerr << "Duplicate local target uid -> " << local_uid << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < field_count; i++) {
|
||||
std::string fline;
|
||||
if (!std::getline(infile, fline)) {
|
||||
std::cerr << "Missing field declaration line!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::istringstream fiss(fline);
|
||||
|
||||
std::string ftype;
|
||||
if (!(fiss >> ftype) || ftype != "f") {
|
||||
std::cerr << "Missing field declaration line, got \"" << ftype << "\" instead!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
FIELD field;
|
||||
if (!(fiss >> field.offset) || !(fiss >> field.size) || !(fiss >> field.alignment) || !(fiss >> field.flags)) {
|
||||
std::cerr << "Failed to parse field declaration line!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Note -> could do sanity checks here
|
||||
|
||||
target.fields.emplace(field.offset, field);
|
||||
}
|
||||
|
||||
std::size_t global_target_uid = accumulate_global_target(std::move(target));
|
||||
cu.local_targets.emplace(local_uid, global_target_uid);
|
||||
continue;
|
||||
} else if (type == "ipin") {
|
||||
IPIN ipin;
|
||||
if (!(iss >> ipin.symbol) || !(iss >> ipin.local_target) || !(iss >> ipin.field_offset)) {
|
||||
std::cerr << "Failed to parse ipin declaration!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cu.ipins.contains(ipin.symbol)) {
|
||||
std::cerr << "Duplicate ipin for symbol \"" << ipin.symbol << "\"!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
cu.ipins.emplace(ipin.symbol, ipin);
|
||||
continue;
|
||||
} else if (type == "dpin") {
|
||||
std::string symbol;
|
||||
std::string scope;
|
||||
DPIN::COMPONENT comp;
|
||||
std::size_t local_target;
|
||||
|
||||
if (!(iss >> scope) || !(iss >> symbol) || !(iss >> comp.offset) ||
|
||||
!(iss >> comp.level) || !(iss >> local_target)) {
|
||||
std::cerr << "Failed to parse dpin declaration!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (scope == "l" || scope == "L") {
|
||||
if (!cu.dpins.contains(symbol))
|
||||
cu.dpins.emplace(symbol, DPIN{ .symbol=symbol });
|
||||
|
||||
DPIN& dpin = cu.dpins.at(symbol);
|
||||
|
||||
if (!cu.local_targets.contains(local_target)) {
|
||||
std::cerr << "Local datapin references target that has not yet been parsed!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
comp.target = local_target;
|
||||
dpin.components.push_back(comp);
|
||||
} else if (scope == "g" || scope == "G") {
|
||||
if (!global_dpins.contains(symbol))
|
||||
global_dpins.emplace(symbol, DPIN{ .symbol=symbol });
|
||||
|
||||
DPIN& dpin = global_dpins.at(symbol);
|
||||
|
||||
if (!cu.local_targets.contains(local_target)) {
|
||||
std::cerr << "Global datapin references target that has not yet been parsed!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
comp.target = cu.local_targets.at(local_target);
|
||||
dpin.components.push_back(comp);
|
||||
} else {
|
||||
std::cerr << "Unexpected scope of dpin (\"" << scope << "\"), expected \"l\" or \"g\"!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
continue;
|
||||
} else {
|
||||
std::cerr << "Invalid spslr file line beginning: \"" << type << "\"" << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool accumulate(const std::string& spslr_dir) {
|
||||
fs::path spslr_root { spslr_dir };
|
||||
|
||||
if (!fs::exists(spslr_root) || !fs::is_directory(spslr_root))
|
||||
return false;
|
||||
|
||||
for (const auto& dir_entry : fs::recursive_directory_iterator(spslr_root)) {
|
||||
if (!dir_entry.is_regular_file())
|
||||
continue;
|
||||
|
||||
if (!dir_entry.path().string().ends_with(".spslr"))
|
||||
continue;
|
||||
|
||||
if (!accumulate_file(dir_entry.path()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
48
finalize/accumulation.h
Normal file
48
finalize/accumulation.h
Normal file
@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <cstddef>
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
struct IPIN {
|
||||
std::string symbol;
|
||||
std::size_t local_target;
|
||||
std::size_t field_offset;
|
||||
};
|
||||
|
||||
struct DPIN {
|
||||
struct COMPONENT {
|
||||
std::size_t offset;
|
||||
std::size_t level;
|
||||
std::size_t target; // local pin -> local target, global pin -> global target
|
||||
};
|
||||
|
||||
std::string symbol;
|
||||
std::list<COMPONENT> components;
|
||||
};
|
||||
|
||||
struct FIELD {
|
||||
std::size_t offset;
|
||||
std::size_t size;
|
||||
std::size_t alignment;
|
||||
std::size_t flags;
|
||||
};
|
||||
|
||||
struct TARGET {
|
||||
std::string name;
|
||||
std::size_t size;
|
||||
std::map<std::size_t, FIELD> fields;
|
||||
};
|
||||
|
||||
struct CU {
|
||||
std::unordered_map<std::size_t, std::size_t> local_targets;
|
||||
std::unordered_map<std::string, IPIN> ipins;
|
||||
std::unordered_map<std::string, DPIN> dpins;
|
||||
};
|
||||
|
||||
extern std::unordered_map<std::size_t, TARGET> targets;
|
||||
extern std::unordered_map<std::string, DPIN> global_dpins;
|
||||
extern std::unordered_map<std::string, CU> units;
|
||||
|
||||
bool accumulate(const std::string& spslr_dir);
|
||||
@ -2,48 +2,14 @@
|
||||
#include <string>
|
||||
#include <getopt.h>
|
||||
|
||||
/*
|
||||
TODO
|
||||
1. Recursively gather all spslr CU files
|
||||
cu uid -> data {
|
||||
target uid -> fields
|
||||
ipin label -> data
|
||||
dpin symbol -> data (list of sub dpins)
|
||||
}
|
||||
2. Merge types between CUs (per CU mapping to global target UIDs)
|
||||
3. Find dpatch application order based on levels (high level (very nested) to low level (root))
|
||||
4. Loop over all symbols of the binary
|
||||
-> associate blocks via CU uid symbol
|
||||
-> find __spslr_program symbol (spslr vaddr pivot)
|
||||
5. Find virtual address and file address for all pins
|
||||
6. Emit patcher program into final executable and set __spslr_program
|
||||
*/
|
||||
#include "accumulation.h"
|
||||
|
||||
/*
|
||||
<sourcefile>.spslr:
|
||||
|
||||
SPSLR <CU filename> <CU uid symbol>
|
||||
target <name> <local uid> <size> <field count>
|
||||
f <offset> <size> <flags>
|
||||
f <offset> <size> <flags>
|
||||
...
|
||||
ipin <label> <target uid> <field offset>
|
||||
ipin <label> <target uid> <field offset>
|
||||
ipin <label> <target uid> <field offset>
|
||||
...
|
||||
dpin <local/global> <symbol> <offset> <level> <target uid>
|
||||
dpin <local/global> <symbol> <offset> <level> <target uid>
|
||||
...
|
||||
|
||||
|
||||
|
||||
Datapins for same var/symbol are randomized in order of their level, from bottom of nest to top
|
||||
The CU uid symbol helps differentiating between e.g. "file.c" and "sub/file.c" (symbtab has no idea)
|
||||
Between CUs, types with the same name HAVE TO HAVE the same layout -> randomized together
|
||||
To begin with, anonymous types are not allowed for randomization (later solved with hash(type) instead of name)!
|
||||
|
||||
Note -> field alignment should probably be gathered by pinpoint plugin!
|
||||
|
||||
Notes:
|
||||
Datapins for same var/symbol are randomized in order of their level, from bottom of nest to top
|
||||
The CU uid symbol helps differentiating between e.g. "file.c" and "sub/file.c" (symbtab has no idea)
|
||||
Between CUs, types with the same name HAVE TO HAVE the same layout -> randomized together
|
||||
To begin with, anonymous types are not allowed for randomization (later solved with hash(type) instead of name)!
|
||||
*/
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
@ -101,7 +67,22 @@ int main(int argc, char** argv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!accumulate(spslr_dir)) {
|
||||
std::cerr << "Failed to accumulate data from spslr directory!" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::cout << "Gathered a total of " << targets.size() << " distinct targets from "
|
||||
<< units.size() << " compilation units!" << std::endl;
|
||||
|
||||
// TODO
|
||||
std::cout << "Hello World!" << std::endl;
|
||||
/*
|
||||
1. Find dpatch application order based on levels (high level (very nested) to low level (root))
|
||||
2. Loop over all symbols of the binary
|
||||
-> associate blocks via CU uid symbol
|
||||
-> find __spslr_program symbol (spslr vaddr pivot)
|
||||
3. Find virtual address and file address for all pins
|
||||
4. Emit patcher program into final executable and set __spslr_program
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
@ -135,8 +135,9 @@ void on_finish_unit(void* plugin_data, void* user_data) {
|
||||
pinpoint_fatal("on_finish_unit encountered incomplete target type");
|
||||
|
||||
for (const auto& [off, field] : target.fields()) {
|
||||
// f <offset> <size> <flags>
|
||||
out << "f " << field.offset << " " << field.size << " " << field.flags << std::endl;
|
||||
// f <offset> <size> <alignment> <flags>
|
||||
std::size_t field_alignment = field.size; // TODO
|
||||
out << "f " << field.offset << " " << field.size << " " << field_alignment << " " << field.flags << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user