Skip to content

Commit 95b376f

Browse files
author
Derek Hower
committed
Add ElfReader
1 parent e23b48d commit 95b376f

File tree

6 files changed

+186
-1
lines changed

6 files changed

+186
-1
lines changed

.devcontainer/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ RUN apt-get install -y --no-install-recommends cmake
2323
RUN apt-get install -y --no-install-recommends g++
2424
RUN apt-get install -y --no-install-recommends clang-format
2525
RUN apt-get install -y --no-install-recommends clang-tidy
26+
RUN apt-get install -y --no-install-recommends libelf-dev
2627
RUN apt-get clean autoclean
2728
RUN apt-get autoremove -y
2829
RUN rm -rf /var/lib/{apt,dpkg,cache,log}/*

backends/cpp_hart_gen/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ endforeach()
7676
add_library(hart
7777
${CMAKE_SOURCE_DIR}/src/db_data.cxx
7878
${CMAKE_SOURCE_DIR}/src/version.cpp
79+
${CMAKE_SOURCE_DIR}/src/memory.cpp
7980
${GENERATED_SRCS}
8081
# ../gen/iss/oryon/src/types.cxx
8182
# ../gen/iss/oryon/src/csr_types.cxx
@@ -87,8 +88,9 @@ target_link_libraries(hart PUBLIC yaml-cpp::yaml-cpp nlohmann_json_schema_valida
8788

8889
add_executable(iss
8990
${CMAKE_SOURCE_DIR}/src/iss.cpp
91+
${CMAKE_SOURCE_DIR}/src/elf_reader.cpp
9092
)
91-
target_link_libraries(iss PRIVATE hart CLI11::CLI11)
93+
target_link_libraries(iss PRIVATE hart elf CLI11::CLI11)
9294

9395

9496
## TESTS
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#pragma once
2+
3+
#include <string>
4+
5+
class Elf;
6+
namespace udb {
7+
// Class to read data out of an ELF file
8+
class Memory;
9+
class ElfReader {
10+
// ElfException is thrown when something goes wrong when reading an ELF file
11+
class ElfException : public std::exception {
12+
public:
13+
ElfException() = default;
14+
ElfException(const std::string& what) : std::exception(), m_what(what) {}
15+
ElfException(std::string&& what)
16+
: std::exception(), m_what(std::move(what)) {}
17+
18+
const char* what() const noexcept override { return m_what.c_str(); }
19+
20+
private:
21+
const std::string m_what;
22+
};
23+
24+
public:
25+
ElfReader() = delete;
26+
ElfReader(const std::string& path);
27+
~ElfReader();
28+
29+
// get the address of a symbol named 'name', and put it in 'result'
30+
//
31+
// returns false if the symbol is not found, true otherwise
32+
bool getSym(const std::string& name, Elf64_Addr* result);
33+
34+
// Loads all LOADable sections from an ELF into 'm'
35+
//
36+
// returns the start address
37+
uint64_t loadLoadableSegments(Memory& m);
38+
39+
private:
40+
int m_fd;
41+
Elf* m_elf;
42+
};
43+
} // namespace udb
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
2+
#include <fcntl.h>
3+
#include <libelf.h>
4+
#include <sys/stat.h>
5+
#include <sys/types.h>
6+
7+
#include <udb/elf_reader.hpp>
8+
#include <udb/memory.hpp>
9+
10+
udb::ElfReader::ElfReader(const std::string& path) {
11+
if (elf_version(EV_CURRENT) == EV_NONE) {
12+
throw ElfException("Bad Elf version");
13+
}
14+
15+
m_fd = open(path.c_str(), O_RDONLY, 0);
16+
if (m_fd < 0) {
17+
throw ElfException("Could not open ELF file");
18+
}
19+
20+
m_elf = elf_begin(m_fd, ELF_C_READ, NULL);
21+
if (m_elf == nullptr) {
22+
throw ElfException("Could not begin reading ELF");
23+
}
24+
25+
if (elf_kind(m_elf) != ELF_K_ELF) {
26+
throw ElfException("Not an ELF file");
27+
}
28+
}
29+
30+
udb::ElfReader::~ElfReader() {
31+
if (m_elf != nullptr) {
32+
elf_end(m_elf);
33+
close(m_fd);
34+
}
35+
}
36+
37+
bool udb::ElfReader::getSym(const std::string& name, Elf64_Addr* result) {
38+
size_t num_sections;
39+
if (elf_getshdrnum(m_elf, &num_sections) != 0) {
40+
throw ElfException("Could not determine number of sections");
41+
}
42+
size_t shstrtab_index;
43+
if (elf_getshdrstrndx(m_elf, &shstrtab_index) != 0) {
44+
throw ElfException("Could not get Section Header String Table");
45+
}
46+
// first, find the strtab
47+
int strtab_index;
48+
for (size_t i = 0; i < num_sections; i++) {
49+
auto* strtab_section = elf_getscn(m_elf, i);
50+
Elf64_Shdr* header = elf64_getshdr(strtab_section);
51+
if (strcmp(elf_strptr(m_elf, shstrtab_index, header->sh_name), ".strtab") ==
52+
0) {
53+
strtab_index = i;
54+
break;
55+
}
56+
}
57+
// now, get the symtab
58+
for (size_t i = 0; i < num_sections; i++) {
59+
Elf_Scn* section;
60+
section = elf_getscn(m_elf, i);
61+
Elf64_Shdr* section_header = elf64_getshdr(section);
62+
if (strcmp(elf_strptr(m_elf, shstrtab_index, section_header->sh_name),
63+
".symtab") == 0) {
64+
unsigned num_syms = section_header->sh_size / section_header->sh_entsize;
65+
Elf64_Sym* symtab;
66+
Elf_Data* data;
67+
if ((data = elf_getdata(section, nullptr)) == nullptr) {
68+
throw ElfException(fmt::format("Could not get symtab data. {}",
69+
elf_errmsg(elf_errno()))
70+
.c_str());
71+
}
72+
symtab = (Elf64_Sym*)data->d_buf;
73+
for (unsigned j = 0; j < num_syms; j++) {
74+
if (strcmp(elf_strptr(m_elf, strtab_index, symtab[j].st_name),
75+
name.c_str()) == 0) {
76+
*result = symtab[j].st_value;
77+
return true;
78+
}
79+
}
80+
}
81+
}
82+
return false;
83+
}
84+
85+
// returns start address
86+
uint64_t udb::ElfReader::loadLoadableSegments(Memory& m) {
87+
Elf64_Phdr* phdr;
88+
size_t n;
89+
90+
if (elf_getphdrnum(m_elf, &n) != 0) {
91+
throw ElfException("Could not find number of Program Headers");
92+
}
93+
94+
phdr = elf64_getphdr(m_elf);
95+
for (size_t i = 0; i < n; i++) {
96+
if (phdr[i].p_type == PT_LOAD) {
97+
Elf_Data* d = elf_getdata_rawchunk(m_elf, phdr[i].p_offset,
98+
phdr[i].p_filesz, ELF_T_BYTE);
99+
m.memcpy_from_host(phdr[i].p_vaddr, d->d_buf, d->d_size);
100+
}
101+
}
102+
103+
return elf64_getehdr(m_elf)->e_entry;
104+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
2+
#include "udb/memory.hpp"
3+
4+
void udb::Memory::memcpy_from_host(uint64_t guest_paddr, const void* host_ptr,
5+
size_t size) {
6+
const size_t SZ_64 = sizeof(uint64_t);
7+
auto host_ptr64 = (const uint64_t*)host_ptr; // NOLINT
8+
while (size >= SZ_64) {
9+
write((guest_paddr += SZ_64) - SZ_64, *host_ptr64++);
10+
size -= SZ_64;
11+
}
12+
13+
auto host_ptr8 = (const uint8_t*)host_ptr64; // NOLINT
14+
while (size > 0) {
15+
write(guest_paddr++, *host_ptr8++);
16+
size--;
17+
}
18+
}
19+
20+
void udb::Memory::memcpy_to_host(void* host_ptr, uint64_t guest_paddr,
21+
size_t size) {
22+
const size_t SZ_64 = sizeof(uint64_t);
23+
auto host_ptr64 = (uint64_t*)host_ptr; // NOLINT
24+
while (size >= SZ_64) {
25+
*(host_ptr64++) = read<uint64_t>(guest_paddr += SZ_64);
26+
size -= SZ_64;
27+
}
28+
29+
auto host_ptr8 = (uint8_t*)host_ptr64; // NOLINT
30+
while (size > 0) {
31+
*(host_ptr8++) = read<uint8_t>(guest_paddr += SZ_64);
32+
size--;
33+
}
34+
}

container.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ From: ubuntu:24.04
3939
apt-get install -y --no-install-recommends libgmp-dev
4040
apt-get install -y --no-install-recommends clang-format
4141
apt-get install -y --no-install-recommends clang-tidy
42+
apt-get install -y --no-install-recommends libelf-dev
4243

4344
# cleanup
4445
apt-get clean autoclean

0 commit comments

Comments
 (0)