Implement loading ELF files into simulator
MODIFY
src/edittab.cpp
src/edittab.cpp
#include "edittab.h"
#include "ui_edittab.h"
+#include "elfio/elfio.hpp"
+
#include <QCheckBox>
#include <QLabel>
#include <QLineEdit>
@@ -170,17 +172,29 @@ bool EditTab::loadAssemblyFile(Program&, QFile& file) {
}
bool EditTab::loadElfFile(Program& program, QFile& file) {
- bool success = true;
+ ELFIO::elfio reader;
+
+ // No file validity checking is performed - it is expected that Loaddialog has done all validity
+ // checking.
+ if (!reader.load(file.fileName().toStdString())) {
+ assert(false);
+ }
+
+ for (const auto& elfSection : reader.sections) {
+ ProgramSection& section = program.sections.emplace_back();
+ section.name = QString::fromStdString(elfSection->get_name());
+ section.address = elfSection->get_address();
+ // QByteArray performs a deep copy of the data when the data array is initialized at construction
+ section.data = QByteArray(elfSection->get_data(), elfSection->get_size());
+ }
+
+ program.entryPoint = reader.get_entry();
+
m_ui->curInputSrcLabel->setText("Executable (ELF)");
m_ui->inputSrcPath->setText(file.fileName());
- clearAssemblyEditor();
- if (success) {
disableEditor();
return true;
- } else {
- return false;
- }
}
} // namespace Ripes

MODIFY
src/isainfo.h
src/isainfo.h
@@ -26,6 +26,14 @@ public:
virtual unsigned elfMachineId() const = 0;
+ /**
+ * @brief elfSupportsFlags
+ * The instructcion set should determine whether the provided @p flags, as retrieved from an ELF file, are valid
+ * flags for the instruction set. If a mismatch is found, an error message describing the
+ * mismatch is returned. Else, returns an empty QString(), validating the flags.
+ */
+ virtual QString elfSupportsFlags(unsigned flags) const = 0;
+
protected:
ISAInfoBase() {}
};
@@ -86,6 +94,18 @@ const static QStringList RVRegDescs = QStringList() << "Hard-Wired zero"
<< "Temporary register\nSaver: Caller"
<< "Temporary register\nSaver: Caller"
<< "Temporary register\nSaver: Caller";
+// RISC-V ELF info
+
+// Elf flag masks
+enum RVElfFlags {
+ RVC = 0b1,
+ FloatABI = 0b110,
+ RVE = 0b1000,
+ TSO = 0b10000
+};
+
+const static std::map<RVElfFlags, QString> RVELFFlagStrings {{RVC, "RVC"}, {FloatABI, "Float ABI"}, {RVE, "RVE"}, {TSO, "TSO"}};
+
// clang-format on
} // namespace
@@ -109,5 +129,21 @@ public:
int spReg() const override { return 2; }
int gpReg() const override { return 3; }
unsigned elfMachineId() const override { return EM_RISCV; }
+
+ QString elfSupportsFlags(unsigned flags) const override {
+ /** We expect no flags for RV32IM compiled RISC-V executables.
+ * Refer to: https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#-elf-object-files
+ */
+ if (flags == 0)
+ return QString();
+ QString err;
+ for (const auto& flag : RVELFFlagStrings) {
+ if (flags & flag.first) {
+ err += "ELF flag '" + RVELFFlagStrings.at(flag.first) + "' unsupported<br/>";
+ }
+ }
+ return err;
+ }
};
+
} // namespace Ripes

MODIFY
src/loaddialog.cpp
src/loaddialog.cpp
@@ -145,6 +145,8 @@ void LoadDialog::setElfInfo(const ELFInfo& info) {
bool LoadDialog::validateELFFile(const QFile& file) {
ELFIO::elfio reader;
ELFInfo info;
+ QString flagErr;
+ unsigned elfbits;
info.valid = true;
// Is it an ELF file?
@@ -153,6 +155,7 @@ bool LoadDialog::validateELFFile(const QFile& file) {
info.valid = false;
goto finish;
}
+
// Is it a compatible machine format?
if (reader.get_machine() != ProcessorHandler::get()->currentISA()->elfMachineId()) {
info.errorMessage = "Incompatible ELF machine type (ISA).<br/><br/>Expected machine type:<br/>'" +
@@ -164,15 +167,31 @@ bool LoadDialog::validateELFFile(const QFile& file) {
goto finish;
}
+ // Is it a compatible file class?
+ elfbits = reader.get_class() == ELFCLASS32 ? 32 : 64;
+ if (elfbits != ProcessorHandler::get()->currentISA()->bits()) {
+ const QString bitSize = elfbits == 32 ? "32" : "64";
+ info.errorMessage = "Expected " + QString::number(ProcessorHandler::get()->currentISA()->bits()) +
+ " bit executable, but input file is a " + bitSize + " bit executable.";
+ }
+
// executable? (Not dynamically linked nor relocateable)
if (!(reader.get_type() == ET_EXEC)) {
- info.errorMessage = "Only executable files are supported.<br/><br/>File type is<br/>" +
+ info.errorMessage = "Only executable ELF files are supported.<br/><br/>File type is<br/>" +
QString::number(reader.get_type()) + " (" + getNameForElfType(reader.get_type()) +
")<br/>Expected<br/>" + QString::number(ET_EXEC) + " (" + getNameForElfType(ET_EXEC) + ")";
info.valid = false;
goto finish;
}
+ // Supported flags?
+ flagErr = ProcessorHandler::get()->currentISA()->elfSupportsFlags(reader.get_flags());
+ if (!flagErr.isEmpty()) {
+ info.errorMessage = flagErr;
+ info.valid = false;
+ goto finish;
+ }
+
// All checks successfull. Generate string indicating which segments will be loaded.
for (const auto& s : reader.sections) {
info.sectionInfo.push_back(QString::fromStdString(s->get_name()) + ": " + s->get_address());

MODIFY
src/processorhandler.cpp
src/processorhandler.cpp
@@ -86,6 +86,7 @@ void ProcessorHandler::clearBreakpoints() {
}
void ProcessorHandler::selectProcessor(const ProcessorID& id, RegisterSetup setup) {
+ m_program = nullptr;
m_currentID = id;
// Processor initializations

Implement loading ELF files into simulator