44#include " common/logging.h"
55#include " simulator_exception.h"
66
7- #include < cerrno>
8- #include < cstring>
97#include < exception>
8+ #include < stdexcept>
9+ #include < sys/types.h>
1010
1111LOG_CATEGORY (" machine.ProgramLoader" );
1212
13- // TODO - document
14- #ifndef O_BINARY
15- #define O_BINARY 0
16- #endif
17-
1813using namespace machine ;
1914
20- ProgramLoader::ProgramLoader ( const QString &file) : elf_file(file) {
21- const GElf_Ehdr *elf_ehdr;
22- // Initialize elf library
23- if ( elf_version (EV_CURRENT) == EV_NONE) {
24- throw SIMULATOR_EXCEPTION (Input, " Elf library initialization failed " , elf_errmsg (- 1 ));
25- }
26- // Open source file - option QIODevice::ExistingOnly cannot be used on Qt
27- // <5.11
28- if (!elf_file. open (QIODevice::ReadOnly | QIODevice::Unbuffered)) {
29- throw SIMULATOR_EXCEPTION (
30- Input,
31- QString ( " Can't open input elf file for reading ( " ) + QString (file) + QString ( " ) " ),
32- std::strerror (errno));
33- }
34- // Initialize elf
35- if (!( this -> elf = elf_begin (elf_file. handle (), ELF_C_READ, nullptr ))) {
36- throw SIMULATOR_EXCEPTION (Input, " Elf read begin failed " , elf_errmsg (- 1 ));
15+ constexpr int EM_RISCV = 243 ;
16+
17+ class MemLoader : public elf ::loader {
18+ public:
19+ MemLoader ( const QString &fname) : file(fname) {
20+ if (!file. open (QIODevice::ReadOnly | QIODevice::Unbuffered)) {
21+ throw SIMULATOR_EXCEPTION (
22+ Input, QString ( " Can't open input elf file for reading ( " ) + fname + QString ( " ) " ),
23+ file. errorString ());
24+ }
25+ size = file. size ();
26+ mapped = file. map ( 0 , size);
27+ if (mapped == nullptr ) {
28+ throw SIMULATOR_EXCEPTION (
29+ Input, QString ( " Can't mmap input elf file ( " ) + fname + QString ( " ) " ),
30+ file. errorString ());
31+ }
3732 }
38- // Check elf kind
39- if (elf_kind (this ->elf ) != ELF_K_ELF) {
40- throw SIMULATOR_EXCEPTION (
41- Input, " Invalid input file elf format, plain elf file expected" , " " );
33+
34+ const void *load (off_t offset, size_t len) override {
35+ if ((size_t )offset + len > (size_t )size) {
36+ throw SANITY_EXCEPTION (" ELF loader requested offset exceeds file size" );
37+ }
38+ return mapped + offset;
4239 }
4340
44- elf_ehdr = gelf_getehdr (this ->elf , &this ->hdr );
45- if (!elf_ehdr) {
46- throw SIMULATOR_EXCEPTION (Input, " Getting elf file header failed" , elf_errmsg (-1 ));
41+ private:
42+ QFile file;
43+ unsigned char *mapped;
44+ std::int64_t size;
45+ };
46+
47+ ProgramLoader::ProgramLoader (const QString &file) {
48+ try {
49+ elf_file = elf::elf (std::make_shared<MemLoader>(file));
50+ } catch (const std::exception &e) {
51+ throw SIMULATOR_EXCEPTION (Input, " Elf library initialization failed" , e.what ());
4752 }
4853
49- executable_entry = Address (elf_ehdr->e_entry );
50- // Check elf file format, executable expected, nothing else.
51- if (this ->hdr .e_type != ET_EXEC) {
54+ const auto &hdr = elf_file.get_hdr ();
55+ executable_entry = Address (hdr.entry );
56+
57+ if (hdr.type != elf::et::exec) {
5258 throw SIMULATOR_EXCEPTION (Input, " Invalid input file type" , " " );
5359 }
54- // Check elf file architecture, of course only mips is supported.
55- // Note: This also checks that this is big endian as EM_MIPS is suppose to
56- // be: MIPS R3000 big-endian
57- if (this ->hdr .e_machine != EM_RISCV) {
60+
61+ if (hdr.machine != EM_RISCV) {
5862 throw SIMULATOR_EXCEPTION (Input, " Invalid input file architecture" , " " );
5963 }
60- // Check elf file class, only 32bit architecture is supported.
61- int elf_class;
62- if ((elf_class = gelf_getclass (this ->elf )) == ELFCLASSNONE) {
63- throw SIMULATOR_EXCEPTION (Input, " Getting elf class failed" , elf_errmsg (-1 ));
64- }
65- // Get number of program sections in elf file
66- if (elf_getphdrnum (this ->elf , &this ->n_secs )) {
67- throw SIMULATOR_EXCEPTION (Input, " Elf program sections count query failed" , elf_errmsg (-1 ));
68- }
6964
70- if (elf_class == ELFCLASS32 ) {
65+ if (hdr. ei_class == elf::elfclass::_32 ) {
7166 LOG (" Loaded executable: 32bit" );
7267 architecture_type = ARCH32;
73- // Get program sections headers
74- if (!(sections_headers.arch32 = elf32_getphdr (elf))) {
75- throw SIMULATOR_EXCEPTION (Input, " Elf program sections get failed" , elf_errmsg (-1 ));
76- }
77- // We want only LOAD sections so we create load_sections_indexes of those sections
78- for (unsigned i = 0 ; i < n_secs; i++) {
79- if (sections_headers.arch32 [i].p_type != PT_LOAD) { continue ; }
80- indexes_of_load_sections.push_back (i);
81- }
82- } else if (elf_class == ELFCLASS64) {
68+ } else if (hdr.ei_class == elf::elfclass::_64) {
8369 LOG (" Loaded executable: 64bit" );
8470 architecture_type = ARCH64;
8571 WARN (" 64bit simulation is not fully supported." );
86- // Get program sections headers
87- if (!(sections_headers.arch64 = elf64_getphdr (elf))) {
88- throw SIMULATOR_EXCEPTION (Input, " Elf program sections get failed" , elf_errmsg (-1 ));
89- }
90- // We want only LOAD sections so we create load_sections_indexes of those sections
91- for (unsigned i = 0 ; i < this ->n_secs ; i++) {
92- if (sections_headers.arch64 [i].p_type != PT_LOAD) { continue ; }
93- this ->indexes_of_load_sections .push_back (i);
94- }
95-
9672 } else {
97- WARN (" Unsupported elf class: %d" , elf_class);
9873 throw SIMULATOR_EXCEPTION (
9974 Input,
10075 " Unsupported architecture type."
10176 " This simulator only supports 32bit and 64bit CPUs." ,
10277 " " );
10378 }
79+
80+ for (const auto &seg : elf_file.segments ()) {
81+ if (seg.get_hdr ().type == elf::pt::load) { load_segments.push_back (seg); }
82+ }
10483}
10584
10685ProgramLoader::ProgramLoader (const char *file) : ProgramLoader(QString::fromLocal8Bit(file)) {}
10786
108- ProgramLoader::~ProgramLoader () {
109- // Close elf
110- elf_end (this ->elf );
111- // Close file
112- elf_file.close ();
113- }
87+ ProgramLoader::~ProgramLoader () {}
11488
11589void ProgramLoader::to_memory (Memory *mem) {
116- // Load program to memory (just dump it byte by byte)
117- if (architecture_type == ARCH32) {
118- for (size_t phdrs_i : this ->indexes_of_load_sections ) {
119- uint32_t base_address = this ->sections_headers .arch32 [phdrs_i].p_vaddr ;
120- char *f = elf_rawfile (this ->elf , nullptr );
121- for (unsigned y = 0 ; y < this ->sections_headers .arch32 [phdrs_i].p_filesz ; y++) {
122- const auto buffer = (uint8_t )f[this ->sections_headers .arch32 [phdrs_i].p_offset + y];
123- memory_write_u8 (mem, base_address + y, buffer);
124- }
125- }
126- } else if (architecture_type == ARCH64) {
127- for (size_t phdrs_i : this ->indexes_of_load_sections ) {
128- uint32_t base_address = this ->sections_headers .arch64 [phdrs_i].p_vaddr ;
129- char *f = elf_rawfile (this ->elf , nullptr );
130- for (unsigned y = 0 ; y < this ->sections_headers .arch64 [phdrs_i].p_filesz ; y++) {
131- const auto buffer = (uint8_t )f[this ->sections_headers .arch64 [phdrs_i].p_offset + y];
132- memory_write_u8 (mem, base_address + y, buffer);
133- }
90+ for (const auto &seg : load_segments) {
91+ uint64_t base_address = seg.get_hdr ().vaddr ;
92+ const char *data = (const char *)seg.data ();
93+ size_t filesz = seg.get_hdr ().filesz ;
94+ for (size_t i = 0 ; i < filesz; i++) {
95+ memory_write_u8 (mem, base_address + i, (uint8_t )data[i]);
13496 }
13597 }
13698}
13799
138100Address ProgramLoader::end () {
139- uint32_t last = 0 ;
140- // Go trough all sections and found out last one
141- if (architecture_type == ARCH32) {
142- for (size_t i : this ->indexes_of_load_sections ) {
143- Elf32_Phdr *phdr = &(this ->sections_headers .arch32 [i]);
144- if ((phdr->p_vaddr + phdr->p_filesz ) > last) { last = phdr->p_vaddr + phdr->p_filesz ; }
145- }
146- } else if (architecture_type == ARCH64) {
147- for (size_t i : this ->indexes_of_load_sections ) {
148- Elf64_Phdr *phdr = &(this ->sections_headers .arch64 [i]);
149- if ((phdr->p_vaddr + phdr->p_filesz ) > last) { last = phdr->p_vaddr + phdr->p_filesz ; }
150- }
101+ uint64_t last = 0 ;
102+ for (const auto &seg : load_segments) {
103+ uint64_t end_addr = seg.get_hdr ().vaddr + seg.get_hdr ().filesz ;
104+ if (end_addr > last) { last = end_addr; }
151105 }
152106 return Address (last + 0x10 ); // We add offset so we are sure that also
153107 // pipeline is empty TODO propagate address
@@ -160,42 +114,21 @@ Address ProgramLoader::get_executable_entry() const {
160114
161115SymbolTable *ProgramLoader::get_symbol_table () {
162116 auto *p_st = new SymbolTable ();
163- Elf_Scn *scn = nullptr ;
164- GElf_Shdr shdr;
165- Elf_Data *data;
166- int count, ii;
167-
168- elf_version (EV_CURRENT);
169-
170- while (true ) {
171- if ((scn = elf_nextscn (this ->elf , scn)) == nullptr ) { return p_st; }
172- gelf_getshdr (scn, &shdr);
173- if (shdr.sh_type == SHT_SYMTAB) {
174- /* found a symbol table, go print it. */
175- break ;
117+ for (const auto &sec : elf_file.sections ()) {
118+ if (sec.get_hdr ().type == elf::sht::symtab) {
119+ for (const auto &sym : sec.as_symtab ()) {
120+ const auto &d = sym.get_data ();
121+ p_st->add_symbol (sym.get_name ().c_str (), d.value , d.size , d.info , d.other );
122+ }
176123 }
177124 }
178-
179- data = elf_getdata (scn, nullptr );
180- count = shdr.sh_size / shdr.sh_entsize ;
181-
182- /* retrieve the symbol names */
183- for (ii = 0 ; ii < count; ++ii) {
184- GElf_Sym sym;
185- gelf_getsym (data, ii, &sym);
186- p_st->add_symbol (
187- elf_strptr (elf, shdr.sh_link , sym.st_name ), sym.st_value , sym.st_size , sym.st_info ,
188- sym.st_other );
189- }
190-
191125 return p_st;
192126}
127+
193128Endian ProgramLoader::get_endian () const {
194- // Reading elf endian_id_byte according to the ELF specs.
195- unsigned char endian_id_byte = this ->hdr .e_ident [EI_DATA];
196- if (endian_id_byte == ELFDATA2LSB) {
129+ if (elf_file.get_hdr ().ei_data == elf::elfdata::lsb) {
197130 return LITTLE;
198- } else if (endian_id_byte == ELFDATA2MSB ) {
131+ } else if (elf_file. get_hdr (). ei_data == elf::elfdata::msb ) {
199132 return BIG;
200133 } else {
201134 throw SIMULATOR_EXCEPTION (
@@ -206,6 +139,7 @@ Endian ProgramLoader::get_endian() const {
206139 " " );
207140 }
208141}
142+
209143ArchitectureType ProgramLoader::get_architecture_type () const {
210144 return architecture_type;
211145}
0 commit comments