diff options
author | Karel Kočí <cynerd@email.cz> | 2017-08-30 21:37:53 +0200 |
---|---|---|
committer | Karel Kočí <cynerd@email.cz> | 2017-08-30 21:42:02 +0200 |
commit | 9cf92379d5fcf0076c25dae0935daab446c992cd (patch) | |
tree | dd09a2e996db1e5a8117f01bec76f1e93eaca6e1 /qtmips_machine/programloader.cpp | |
download | qtmips-9cf92379d5fcf0076c25dae0935daab446c992cd.tar.gz qtmips-9cf92379d5fcf0076c25dae0935daab446c992cd.tar.bz2 qtmips-9cf92379d5fcf0076c25dae0935daab446c992cd.zip |
Initial commit
Adding work done so far.
Diffstat (limited to 'qtmips_machine/programloader.cpp')
-rw-r--r-- | qtmips_machine/programloader.cpp | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/qtmips_machine/programloader.cpp b/qtmips_machine/programloader.cpp new file mode 100644 index 0000000..0b0e294 --- /dev/null +++ b/qtmips_machine/programloader.cpp @@ -0,0 +1,81 @@ +#include "programloader.h" +#include <exception> +#include <unistd.h> +#include <fcntl.h> +#include <iostream> +#include <errno.h> +#include <cstring> +#include "qtmipsexception.h" + +ProgramLoader::ProgramLoader(char *file) { + // Initialize elf library + if (elf_version(EV_CURRENT) == EV_NONE) + throw QTMIPS_EXCEPTION(Input, "Elf library initialization failed", elf_errmsg(-1)); + // Open source file + if ((this->fd = open(file, O_RDONLY, 0)) < 0) + throw QTMIPS_EXCEPTION(Input, "Can't open input elf file for reading", std::strerror(errno)); + // Initialize elf + if (!(this->elf = elf_begin(this->fd, ELF_C_READ, NULL))) + throw QTMIPS_EXCEPTION(Input, "Elf read begin failed", elf_errmsg(-1)); + // Check elf kind + if (elf_kind(this->elf) != ELF_K_ELF) + throw QTMIPS_EXCEPTION(Input, "Invalid input file elf format, plain elf file expected", ""); + + if (!gelf_getehdr(this->elf, &this->hdr)) + throw QTMIPS_EXCEPTION(Input, "Getting elf file header failed", elf_errmsg(-1)); + // Check elf file format, executable expected, nothing else. + if (this->hdr.e_type != ET_EXEC) + throw QTMIPS_EXCEPTION(Input, "Invalid input file type", ""); + // Check elf file architecture, of course only mips is supported. + if (this->hdr.e_machine != EM_MIPS) + throw QTMIPS_EXCEPTION(Input, "Invalid input file architecture", ""); + // Check elf file class, only 32bit architecture is supported. + int elf_class; + if ((elf_class = gelf_getclass(this->elf)) == ELFCLASSNONE) + throw QTMIPS_EXCEPTION(Input, "Getting elf class failed", elf_errmsg(-1)); + if (elf_class != ELFCLASS32) + throw QTMIPS_EXCEPTION(Input, "Only supported architecture is 32bit", ""); + // TODO check endianity! + + // Get number of program sections in elf file + if (elf_getphdrnum(this->elf, &this->n_secs)) + throw QTMIPS_EXCEPTION(Input, "Elf program sections count query failed", elf_errmsg(-1)); + // Get program sections headers + if (!(this->phdrs = elf32_getphdr(this->elf))) + throw QTMIPS_EXCEPTION(Input, "Elf program sections get failed", elf_errmsg(-1)); + // We want only LOAD sections so we create map of those sections + for (unsigned i = 1; i < this->n_secs; i++) { + // TODO handle endianity + if (this->phdrs[i].p_type != PT_LOAD) + continue; + this->map.push_back(i); + } + // TODO instead of direct access should we be using sections and elf_data? And if so how to link program header and section? +} + +ProgramLoader::~ProgramLoader() { + // Close elf + elf_end(this->elf); + // Close file + close(this->fd); +} + +size_t ProgramLoader::get_nsec() { + return this->map.size(); +} + +std::uint32_t ProgramLoader::get_address(size_t sec) { + SANITY_ASSERT(sec > this->get_nsec(), "Requesting too big section"); + return this->phdrs[this->map[sec]].p_vaddr; +} + +std::vector<std::uint8_t> ProgramLoader::get_data(size_t sec) { + SANITY_ASSERT(sec > this->get_nsec(), "Requesting too big section"); + std::vector<std::uint8_t> d; + char *f = elf_rawfile(this->elf, NULL); + size_t phdrs_i = this->map[sec]; + for (unsigned i = 0; i < this->phdrs[phdrs_i].p_filesz; i++) { + d.push_back((std::uint8_t) f[this->phdrs[phdrs_i].p_offset + i]); + } + return d; +} |