Finalizer spslr file parsing

This commit is contained in:
York Jasper Niebuhr 2025-10-27 18:27:59 +01:00
parent 9576893b00
commit d33896ecd2
5 changed files with 307 additions and 44 deletions

View File

@ -1,4 +1,5 @@
find_package(LIEF REQUIRED) 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) 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
View 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
View 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);

View File

@ -2,48 +2,14 @@
#include <string> #include <string>
#include <getopt.h> #include <getopt.h>
/* #include "accumulation.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
*/
/* /*
<sourcefile>.spslr: Notes:
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 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) 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 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)! 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!
*/ */
int main(int argc, char** argv) { int main(int argc, char** argv) {
@ -101,7 +67,22 @@ int main(int argc, char** argv) {
return 1; return 1;
} }
// TODO if (!accumulate(spslr_dir)) {
std::cout << "Hello World!" << std::endl; 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
/*
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
*/
} }

View File

@ -135,8 +135,9 @@ void on_finish_unit(void* plugin_data, void* user_data) {
pinpoint_fatal("on_finish_unit encountered incomplete target type"); pinpoint_fatal("on_finish_unit encountered incomplete target type");
for (const auto& [off, field] : target.fields()) { for (const auto& [off, field] : target.fields()) {
// f <offset> <size> <flags> // f <offset> <size> <alignment> <flags>
out << "f " << field.offset << " " << field.size << " " << field.flags << std::endl; std::size_t field_alignment = field.size; // TODO
out << "f " << field.offset << " " << field.size << " " << field_alignment << " " << field.flags << std::endl;
} }
} }