selfpatch-slr/finalize/symbol_collection.cpp

131 lines
3.1 KiB
C++

#include "symbol_collection.h"
#include "accumulation.h"
#include <iostream>
#define SPSLR_PINPOINT_CU_UID_LABEL "__spslr_cu_" /* suffixed with "<uid>" */
using namespace LIEF::ELF;
GlobalSymtab global_syms;
std::unordered_map<std::string, LocalSymtab> local_syms;
bool collect_symbols(const std::unique_ptr<LIEF::ELF::Binary>& bin) {
if (!bin)
return false;
bool cu_uid_found = false;
LocalSymtab tmp_local_syms;
auto finish_cu_symbols = [&]() -> bool {
if (cu_uid_found) {
if (local_syms.contains(tmp_local_syms.cu)) {
std::cerr << "Duplicate CU UID -> " << tmp_local_syms.cu << std::endl;
return false;
}
local_syms.emplace(tmp_local_syms.cu, std::move(tmp_local_syms));
}
tmp_local_syms.cu.clear();
tmp_local_syms.symbols.clear();
cu_uid_found = false;
return true;
};
for (const Symbol& sym : bin->symbols()) {
if (sym.type() == Symbol::TYPE::FILE) {
if (!finish_cu_symbols())
return false;
}
if (sym.name().empty())
continue;
if (sym.type() != Symbol::TYPE::OBJECT && sym.type() != Symbol::TYPE::NOTYPE)
continue;
VADDR vaddr = sym.value();
if (sym.binding() == Symbol::BINDING::GLOBAL) {
if (global_syms.symbols.contains(sym.name())) {
std::cerr << "Duplicate global symbol \"" << sym.name() << "\"!" << std::endl;
return false;
}
global_syms.symbols.emplace(sym.name(), vaddr);
continue;
}
if (sym.binding() != Symbol::BINDING::LOCAL)
continue;
if (sym.name().starts_with(SPSLR_PINPOINT_CU_UID_LABEL)) {
tmp_local_syms.cu = sym.name().substr(std::strlen(SPSLR_PINPOINT_CU_UID_LABEL));
cu_uid_found = true;
continue;
}
if (tmp_local_syms.symbols.contains(sym.name())) {
std::cerr << "Duplicate local symbol \"" << sym.name() << "\"!" << std::endl;
return false;
}
tmp_local_syms.symbols.emplace(sym.name(), vaddr);
continue;
}
if (!finish_cu_symbols())
return false;
return true;
}
bool associate_symbols() {
// Fetch symbols for each accumulated CU
for (auto& [cu_uid, cu] : units) {
if (!local_syms.contains(cu_uid)) {
std::cerr << "Could not find symbols for unit UID " << cu_uid << std::endl;
return false;
}
const LocalSymtab& lsyms = local_syms.at(cu_uid);
for (auto& [ipin_sym, ipin] : cu.ipins) {
if (!lsyms.symbols.contains(ipin_sym)) {
std::cerr << "Unable to locate symbol \"" << ipin_sym << "\" in unit " << cu_uid << std::endl;
return false;
}
ipin.hit.emplace();
ipin.hit->vaddr = lsyms.symbols.at(ipin_sym);
ipin.hit->imm_offset = 0;
ipin.hit->imm_size = 0;
}
for (auto& [dpin_sym, dpin] : cu.dpins) {
if (!lsyms.symbols.contains(dpin_sym)) {
std::cerr << "Unable to locate symbol \"" << dpin_sym << "\" in unit " << cu_uid << std::endl;
return false;
}
dpin.hit.emplace();
dpin.hit->vaddr = lsyms.symbols.at(dpin_sym);
}
}
// Fetch global symbols for global dpins
for (auto& [dpin_sym, dpin] : global_dpins) {
if (!global_syms.symbols.contains(dpin_sym)) {
std::cerr << "Unable to locate global symbol \"" << dpin_sym << "\"" << std::endl;
return false;
}
dpin.hit.emplace();
dpin.hit->vaddr = global_syms.symbols.at(dpin_sym);
}
return true;
}