removes code dupication by unifying elf file read

This commit is contained in:
Eyck Jentzsch 2024-09-23 09:28:27 +02:00
parent 76ea0db25d
commit a8f56b6e27
4 changed files with 83 additions and 230 deletions

View File

@ -35,6 +35,7 @@
#ifndef _RISCV_HART_COMMON #ifndef _RISCV_HART_COMMON
#define _RISCV_HART_COMMON #define _RISCV_HART_COMMON
#include "iss/vm_types.h"
#include <cstdint> #include <cstdint>
#include <elfio/elfio.hpp> #include <elfio/elfio.hpp>
#include <fmt/format.h> #include <fmt/format.h>
@ -314,29 +315,33 @@ struct riscv_hart_common {
riscv_hart_common(){}; riscv_hart_common(){};
~riscv_hart_common(){}; ~riscv_hart_common(){};
std::unordered_map<std::string, uint64_t> symbol_table; std::unordered_map<std::string, uint64_t> symbol_table;
uint64_t entry_address{0};
uint64_t tohost = tohost_dflt;
uint64_t fromhost = fromhost_dflt;
std::unordered_map<std::string, uint64_t> get_sym_table(std::string name) { bool read_elf_file(std::string name, uint8_t expected_elf_class, std::function<iss::status(uint64_t, uint64_t, const uint8_t* const)> cb) {
if(!symbol_table.empty())
return symbol_table;
FILE* fp = fopen(name.c_str(), "r");
if(fp) {
std::array<char, 5> buf;
auto n = fread(buf.data(), 1, 4, fp);
fclose(fp);
if(n != 4)
throw std::runtime_error("input file has insufficient size");
buf[4] = 0;
if(strcmp(buf.data() + 1, "ELF") == 0) {
// Create elfio reader // Create elfio reader
ELFIO::elfio reader; ELFIO::elfio reader;
// Load ELF data // Load ELF data
if(!reader.load(name)) if(reader.load(name)) {
throw std::runtime_error("could not process elf file");
// check elf properties // check elf properties
if(reader.get_class() != expected_elf_class)
return false;
if(reader.get_type() != ET_EXEC) if(reader.get_type() != ET_EXEC)
throw std::runtime_error("wrong elf type in file"); return false;
if(reader.get_machine() != EM_RISCV) if(reader.get_machine() != EM_RISCV)
throw std::runtime_error("wrong elf machine in file"); return false;
entry_address = reader.get_entry();
for(const auto pseg : reader.segments) {
const auto fsize = pseg->get_file_size(); // 0x42c/0x0
const auto seg_data = pseg->get_data();
const auto type = pseg->get_type();
if(type == 1 && fsize > 0) {
auto res = cb(pseg->get_physical_address(), fsize, reinterpret_cast<const uint8_t* const>(seg_data));
if(res != iss::Ok)
CPPLOG(ERR) << "problem writing " << fsize << "bytes to 0x" << std::hex << pseg->get_physical_address();
}
}
const auto sym_sec = reader.sections[".symtab"]; const auto sym_sec = reader.sections[".symtab"];
if(SHT_SYMTAB == sym_sec->get_type() || SHT_DYNSYM == sym_sec->get_type()) { if(SHT_SYMTAB == sym_sec->get_type() || SHT_DYNSYM == sym_sec->get_type()) {
ELFIO::symbol_section_accessor symbols(reader, sym_sec); ELFIO::symbol_section_accessor symbols(reader, sym_sec);
@ -350,19 +355,26 @@ struct riscv_hart_common {
unsigned char other = 0; unsigned char other = 0;
for(auto i = 0U; i < sym_no; ++i) { for(auto i = 0U; i < sym_no; ++i) {
symbols.get_symbol(i, name, value, size, bind, type, section, other); symbols.get_symbol(i, name, value, size, bind, type, section, other);
if(name != "") { if(type==0 && name != "") {
this->symbol_table[name] = value; this->symbol_table[name] = value;
#ifndef NDEBUG #ifndef NDEBUG
CPPLOG(DEBUG) << "Found Symbol " << name; CPPLOG(DEBUG) << "Found Symbol " << name;
#endif #endif
} }
} }
try {
tohost = symbol_table.at("tohost");
try {
fromhost = symbol_table.at("fromhost");
} catch(std::out_of_range& e) {
fromhost = tohost + 0x40;
} }
return symbol_table; } catch(std::out_of_range& e) {
} }
throw std::runtime_error(fmt::format("memory load file {} is not a valid elf file", name)); }
} else return true;
throw std::runtime_error(fmt::format("memory load file not found, check if {} is a valid file", name)); }
return false;
}; };
}; };

View File

@ -41,6 +41,7 @@
#include "iss/vm_if.h" #include "iss/vm_if.h"
#include "iss/vm_types.h" #include "iss/vm_types.h"
#include "riscv_hart_common.h" #include "riscv_hart_common.h"
#include <elfio/elf_types.hpp>
#include <stdexcept> #include <stdexcept>
#ifndef FMT_HEADER_ONLY #ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY #define FMT_HEADER_ONLY
@ -321,7 +322,7 @@ protected:
unsigned get_reg_size(unsigned num) override { return traits<BASE>::reg_bit_widths[num]; } unsigned get_reg_size(unsigned num) override { return traits<BASE>::reg_bit_widths[num]; }
std::unordered_map<std::string, uint64_t> get_symbol_table(std::string name) override { return arch.get_sym_table(name); } std::unordered_map<std::string, uint64_t> const& get_symbol_table(std::string name) override { return arch.symbol_table; }
riscv_hart_m_p<BASE, FEAT, LOGCAT>& arch; riscv_hart_m_p<BASE, FEAT, LOGCAT>& arch;
}; };
@ -343,8 +344,6 @@ protected:
int64_t instret_offset{0}; int64_t instret_offset{0};
uint64_t minstret_csr{0}; uint64_t minstret_csr{0};
reg_t fault_data; reg_t fault_data;
uint64_t tohost = tohost_dflt;
uint64_t fromhost = fromhost_dflt;
bool tohost_lower_written = false; bool tohost_lower_written = false;
riscv_instrumentation_if instr_if; riscv_instrumentation_if instr_if;
@ -573,57 +572,15 @@ riscv_hart_m_p<BASE, FEAT, LOGCAT>::riscv_hart_m_p(feature_config cfg)
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT, typename LOGCAT>
std::pair<uint64_t, bool> riscv_hart_m_p<BASE, FEAT, LOGCAT>::load_file(std::string name, int type) { std::pair<uint64_t, bool> riscv_hart_m_p<BASE, FEAT, LOGCAT>::load_file(std::string name, int type) {
get_sym_table(name); if(read_elf_file(name,sizeof(reg_t)==4?ELFCLASS32:ELFCLASS64,
try { [this](uint64_t addr, uint64_t size, const uint8_t* const data) -> iss::status {
tohost = symbol_table.at("tohost"); return this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits<BASE>::MEM,
fromhost = symbol_table.at("fromhost"); addr, size, data);
} catch(std::out_of_range& e) {
})) {
return std::make_pair(entry_address, true);
} }
FILE* fp = fopen(name.c_str(), "r"); return std::make_pair(entry_address, false);
if(fp) {
std::array<char, 5> buf;
auto n = fread(buf.data(), 1, 4, fp);
fclose(fp);
if(n != 4)
throw std::runtime_error("input file has insufficient size");
buf[4] = 0;
if(strcmp(buf.data() + 1, "ELF") == 0) {
// Create elfio reader
ELFIO::elfio reader;
// Load ELF data
if(!reader.load(name))
throw std::runtime_error("could not process elf file");
// check elf properties
if(reader.get_class() != ELFCLASS32)
if(sizeof(reg_t) == 4)
throw std::runtime_error("wrong elf class in file");
if(reader.get_type() != ET_EXEC)
throw std::runtime_error("wrong elf type in file");
if(reader.get_machine() != EM_RISCV)
throw std::runtime_error("wrong elf machine in file");
auto entry = reader.get_entry();
for(const auto& pseg : reader.segments) {
const auto fsize = pseg->get_file_size(); // 0x42c/0x0
const auto seg_data = pseg->get_data();
const auto type = pseg->get_type();
if(type == 1 && fsize > 0) {
auto res = this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits<BASE>::MEM,
pseg->get_physical_address(), fsize, reinterpret_cast<const uint8_t* const>(seg_data));
if(res != iss::Ok)
CPPLOG(ERR) << "problem writing " << fsize << "bytes to 0x" << std::hex << pseg->get_physical_address();
}
}
for(const auto& sec : reader.sections) {
if(sec->get_name() == ".tohost") {
tohost = sec->get_address();
fromhost = tohost + 0x40;
}
}
return std::make_pair(entry, true);
}
throw std::runtime_error(fmt::format("memory load file {} is not a valid elf file", name));
}
throw std::runtime_error(fmt::format("memory load file not found, check if {} is a valid file", name));
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT, typename LOGCAT>

View File

@ -371,7 +371,7 @@ protected:
unsigned get_reg_size(unsigned num) override { return traits<BASE>::reg_bit_widths[num]; } unsigned get_reg_size(unsigned num) override { return traits<BASE>::reg_bit_widths[num]; }
std::unordered_map<std::string, uint64_t> get_symbol_table(std::string name) override { return arch.get_sym_table(name); } std::unordered_map<std::string, uint64_t> const& get_symbol_table(std::string name) override { return arch.symbol_table; }
riscv_hart_msu_vp<BASE>& arch; riscv_hart_msu_vp<BASE>& arch;
}; };
@ -393,8 +393,6 @@ protected:
uint64_t minstret_csr{0}; uint64_t minstret_csr{0};
reg_t fault_data; reg_t fault_data;
std::array<vm_info, 2> vm; std::array<vm_info, 2> vm;
uint64_t tohost = tohost_dflt;
uint64_t fromhost = fromhost_dflt;
bool tohost_lower_written = false; bool tohost_lower_written = false;
riscv_instrumentation_if instr_if; riscv_instrumentation_if instr_if;
@ -557,71 +555,15 @@ riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp()
} }
template <typename BASE> std::pair<uint64_t, bool> riscv_hart_msu_vp<BASE>::load_file(std::string name, int type) { template <typename BASE> std::pair<uint64_t, bool> riscv_hart_msu_vp<BASE>::load_file(std::string name, int type) {
FILE* fp = fopen(name.c_str(), "r"); if(read_elf_file(name,sizeof(reg_t)==4?ELFCLASS32:ELFCLASS64,
if(fp) { [this](uint64_t addr, uint64_t size, const uint8_t* const data) -> iss::status {
std::array<char, 5> buf; return this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits<BASE>::MEM,
auto n = fread(buf.data(), 1, 4, fp); addr, size, data);
fclose(fp);
if(n != 4) })) {
throw std::runtime_error("input file has insufficient size"); return std::make_pair(entry_address, true);
buf[4] = 0;
if(strcmp(buf.data() + 1, "ELF") == 0) {
// Create elfio reader
ELFIO::elfio reader;
// Load ELF data
if(!reader.load(name))
throw std::runtime_error("could not process elf file");
// check elf properties
if(reader.get_class() != ELFCLASS32)
if(sizeof(reg_t) == 4)
throw std::runtime_error("wrong elf class in file");
if(reader.get_type() != ET_EXEC)
throw std::runtime_error("wrong elf type in file");
if(reader.get_machine() != EM_RISCV)
throw std::runtime_error("wrong elf machine in file");
auto entry = reader.get_entry();
for(const auto pseg : reader.segments) {
const auto fsize = pseg->get_file_size(); // 0x42c/0x0
const auto seg_data = pseg->get_data();
const auto type = pseg->get_type();
if(type == 1 && fsize > 0) {
auto res = this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits<BASE>::MEM,
pseg->get_physical_address(), fsize, reinterpret_cast<const uint8_t* const>(seg_data));
if(res != iss::Ok)
CPPLOG(ERR) << "problem writing " << fsize << "bytes to 0x" << std::hex << pseg->get_physical_address();
} }
} return std::make_pair(entry_address, false);
for(const auto sec : reader.sections) {
if(sec->get_name() == ".symtab") {
if(SHT_SYMTAB == sec->get_type() || SHT_DYNSYM == sec->get_type()) {
ELFIO::symbol_section_accessor symbols(reader, sec);
auto sym_no = symbols.get_symbols_num();
std::string name;
ELFIO::Elf64_Addr value = 0;
ELFIO::Elf_Xword size = 0;
unsigned char bind = 0;
unsigned char type = 0;
ELFIO::Elf_Half section = 0;
unsigned char other = 0;
for(auto i = 0U; i < sym_no; ++i) {
symbols.get_symbol(i, name, value, size, bind, type, section, other);
if(name == "tohost") {
tohost = value;
} else if(name == "fromhost") {
fromhost = value;
}
}
}
} else if(sec->get_name() == ".tohost") {
tohost = sec->get_address();
fromhost = tohost + 0x40;
}
}
return std::make_pair(entry, true);
}
throw std::runtime_error(fmt::format("memory load file {} is not a valid elf file", name));
}
throw std::runtime_error(fmt::format("memory load file not found, check if {} is a valid file", name));
} }
template <typename BASE> template <typename BASE>

View File

@ -348,7 +348,7 @@ protected:
unsigned get_reg_size(unsigned num) override { return traits<BASE>::reg_bit_widths[num]; } unsigned get_reg_size(unsigned num) override { return traits<BASE>::reg_bit_widths[num]; }
std::unordered_map<std::string, uint64_t> get_symbol_table(std::string name) override { return arch.get_sym_table(name); } std::unordered_map<std::string, uint64_t> const& get_symbol_table(std::string name) override { return arch.symbol_table; }
riscv_hart_mu_p<BASE, FEAT, LOGCAT>& arch; riscv_hart_mu_p<BASE, FEAT, LOGCAT>& arch;
}; };
@ -370,8 +370,6 @@ protected:
int64_t instret_offset{0}; int64_t instret_offset{0};
uint64_t minstret_csr{0}; uint64_t minstret_csr{0};
reg_t fault_data; reg_t fault_data;
uint64_t tohost = tohost_dflt;
uint64_t fromhost = fromhost_dflt;
bool tohost_lower_written = false; bool tohost_lower_written = false;
riscv_instrumentation_if instr_if; riscv_instrumentation_if instr_if;
@ -651,71 +649,15 @@ riscv_hart_mu_p<BASE, FEAT, LOGCAT>::riscv_hart_mu_p(feature_config cfg)
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT, typename LOGCAT>
std::pair<uint64_t, bool> riscv_hart_mu_p<BASE, FEAT, LOGCAT>::load_file(std::string name, int type) { std::pair<uint64_t, bool> riscv_hart_mu_p<BASE, FEAT, LOGCAT>::load_file(std::string name, int type) {
FILE* fp = fopen(name.c_str(), "r"); if(read_elf_file(name,sizeof(reg_t)==4?ELFCLASS32:ELFCLASS64,
if(fp) { [this](uint64_t addr, uint64_t size, const uint8_t* const data) -> iss::status {
std::array<char, 5> buf; return this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits<BASE>::MEM,
auto n = fread(buf.data(), 1, 4, fp); addr, size, data);
fclose(fp);
if(n != 4) })) {
throw std::runtime_error("input file has insufficient size"); return std::make_pair(entry_address, true);
buf[4] = 0;
if(strcmp(buf.data() + 1, "ELF") == 0) {
// Create elfio reader
ELFIO::elfio reader;
// Load ELF data
if(!reader.load(name))
throw std::runtime_error("could not process elf file");
// check elf properties
if(reader.get_class() != ELFCLASS32)
if(sizeof(reg_t) == 4)
throw std::runtime_error("wrong elf class in file");
if(reader.get_type() != ET_EXEC)
throw std::runtime_error("wrong elf type in file");
if(reader.get_machine() != EM_RISCV)
throw std::runtime_error("wrong elf machine in file");
auto entry = reader.get_entry();
for(const auto& pseg : reader.segments) {
const auto fsize = pseg->get_file_size(); // 0x42c/0x0
const auto seg_data = pseg->get_data();
const auto type = pseg->get_type();
if(type == 1 && fsize > 0) {
auto res = this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits<BASE>::MEM,
pseg->get_physical_address(), fsize, reinterpret_cast<const uint8_t* const>(seg_data));
if(res != iss::Ok)
CPPLOG(ERR) << "problem writing " << fsize << "bytes to 0x" << std::hex << pseg->get_physical_address();
} }
} return std::make_pair(entry_address, false);
for(const auto& sec : reader.sections) {
if(sec->get_name() == ".symtab") {
if(SHT_SYMTAB == sec->get_type() || SHT_DYNSYM == sec->get_type()) {
ELFIO::symbol_section_accessor symbols(reader, sec);
auto sym_no = symbols.get_symbols_num();
std::string name;
ELFIO::Elf64_Addr value = 0;
ELFIO::Elf_Xword size = 0;
unsigned char bind = 0;
unsigned char type = 0;
ELFIO::Elf_Half section = 0;
unsigned char other = 0;
for(auto i = 0U; i < sym_no; ++i) {
symbols.get_symbol(i, name, value, size, bind, type, section, other);
if(name == "tohost") {
tohost = value;
} else if(name == "fromhost") {
fromhost = value;
}
}
}
} else if(sec->get_name() == ".tohost") {
tohost = sec->get_address();
fromhost = tohost + 0x40;
}
}
return std::make_pair(entry, true);
}
throw std::runtime_error(fmt::format("memory load file {} is not a valid elf file", name));
}
throw std::runtime_error(fmt::format("memory load file not found, check if {} is a valid file", name));
} }
template <typename BASE, features_e FEAT, typename LOGCAT> template <typename BASE, features_e FEAT, typename LOGCAT>