77#include < cerrno>
88#include < cstring>
99#include < exception>
10+ #include < fcntl.h>
11+ #include < unistd.h>
1012
1113LOG_CATEGORY (" machine.ProgramLoader" );
1214
@@ -17,141 +19,83 @@ LOG_CATEGORY("machine.ProgramLoader");
1719
1820using namespace machine ;
1921
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)) {
22+ ProgramLoader::ProgramLoader (const QString &file) {
23+ fd = open (file.toLocal8Bit ().constData (), O_RDONLY | O_BINARY);
24+ if (fd < 0 ) {
2925 throw SIMULATOR_EXCEPTION (
3026 Input,
3127 QString (" Can't open input elf file for reading (" ) + QString (file) + QString (" )" ),
3228 std::strerror (errno));
3329 }
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 ));
37- }
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" , " " );
42- }
4330
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 ));
31+ try {
32+ elf_file = elf::elf (elf::create_mmap_loader (fd));
33+ } catch (const std::exception &e) {
34+ close (fd);
35+ throw SIMULATOR_EXCEPTION (Input, " Elf library initialization failed" , e.what ());
4736 }
4837
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) {
38+ const auto &hdr = elf_file.get_hdr ();
39+ executable_entry = Address (hdr.entry );
40+
41+ if (hdr.type != elf::et::exec) {
5242 throw SIMULATOR_EXCEPTION (Input, " Invalid input file type" , " " );
5343 }
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) {
44+
45+ if (hdr.machine != 243 ) { // EM_RISCV
5846 throw SIMULATOR_EXCEPTION (Input, " Invalid input file architecture" , " " );
5947 }
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- }
6948
70- if (elf_class == ELFCLASS32 ) {
49+ if (hdr. ei_class == elf::elfclass::_32 ) {
7150 LOG (" Loaded executable: 32bit" );
7251 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) {
52+ } else if (hdr.ei_class == elf::elfclass::_64) {
8353 LOG (" Loaded executable: 64bit" );
8454 architecture_type = ARCH64;
8555 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-
9656 } else {
97- WARN (" Unsupported elf class: %d" , elf_class);
9857 throw SIMULATOR_EXCEPTION (
9958 Input,
10059 " Unsupported architecture type."
10160 " This simulator only supports 32bit and 64bit CPUs." ,
10261 " " );
10362 }
63+
64+ for (const auto &seg : elf_file.segments ()) {
65+ if (seg.get_hdr ().type == elf::pt::load) {
66+ load_segments.push_back (seg);
67+ }
68+ }
10469}
10570
10671ProgramLoader::ProgramLoader (const char *file) : ProgramLoader(QString::fromLocal8Bit(file)) {}
10772
10873ProgramLoader::~ProgramLoader () {
109- // Close elf
110- elf_end (this ->elf );
111- // Close file
112- elf_file.close ();
74+ if (fd >= 0 ) {
75+ close (fd);
76+ }
11377}
11478
11579void 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- }
80+ for (const auto &seg : load_segments) {
81+ uint64_t base_address = seg.get_hdr ().vaddr ;
82+ const char *data = (const char *)seg.data ();
83+ size_t filesz = seg.get_hdr ().filesz ;
84+ for (size_t i = 0 ; i < filesz; i++) {
85+ memory_write_u8 (mem, base_address + i, (uint8_t )data[i]);
13486 }
13587 }
13688}
13789
13890Address 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 ; }
91+ uint64_t last = 0 ;
92+ for (const auto &seg : load_segments) {
93+ uint64_t end_addr = seg.get_hdr ().vaddr + seg.get_hdr ().filesz ;
94+ if (end_addr > last) {
95+ last = end_addr;
15096 }
15197 }
152- return Address (last + 0x10 ); // We add offset so we are sure that also
153- // pipeline is empty TODO propagate address
154- // deeper
98+ return Address (last + 0x10 );
15599}
156100
157101Address ProgramLoader::get_executable_entry () const {
@@ -160,42 +104,21 @@ Address ProgramLoader::get_executable_entry() const {
160104
161105SymbolTable *ProgramLoader::get_symbol_table () {
162106 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 ;
107+ for (const auto &sec : elf_file.sections ()) {
108+ if (sec.get_hdr ().type == elf::sht::symtab) {
109+ for (const auto &sym : sec.as_symtab ()) {
110+ const auto &d = sym.get_data ();
111+ p_st->add_symbol (sym.get_name ().c_str (), d.value , d.size , d.info , d.other );
112+ }
176113 }
177114 }
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-
191115 return p_st;
192116}
117+
193118Endian 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) {
119+ if (elf_file.get_hdr ().ei_data == elf::elfdata::lsb) {
197120 return LITTLE;
198- } else if (endian_id_byte == ELFDATA2MSB ) {
121+ } else if (elf_file. get_hdr (). ei_data == elf::elfdata::msb ) {
199122 return BIG;
200123 } else {
201124 throw SIMULATOR_EXCEPTION (
@@ -206,6 +129,7 @@ Endian ProgramLoader::get_endian() const {
206129 " " );
207130 }
208131}
132+
209133ArchitectureType ProgramLoader::get_architecture_type () const {
210134 return architecture_type;
211135}
0 commit comments