1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 23:58:11 +00:00
serenity/AK/ELF/ELFLoader.cpp
Robin Burchell 6917c42140 Kernel/AK: Move ELF loader to AK
This is in preparation for eventually using it in userspace.
LinearAddress.h has not been moved for the time being (as it seems to be
only used by a very small part of the code).
2019-05-23 16:57:34 +02:00

103 lines
3.1 KiB
C++

#include "ELFLoader.h"
#include <AK/kstdio.h>
#include <AK/QuickSort.h>
//#define ELFLOADER_DEBUG
ELFLoader::ELFLoader(const byte* buffer)
: m_image(buffer)
{
}
ELFLoader::~ELFLoader()
{
}
bool ELFLoader::load()
{
#ifdef ELFLOADER_DEBUG
m_image.dump();
#endif
if (!m_image.is_valid())
return false;
if (!layout())
return false;
return true;
}
bool ELFLoader::layout()
{
bool failed = false;
m_image.for_each_program_header([&] (const ELFImage::ProgramHeader& program_header) {
if (program_header.type() != PT_LOAD)
return;
#ifdef ELFLOADER_DEBUG
kprintf("PH: L%x %u r:%u w:%u\n", program_header.laddr().get(), program_header.size_in_memory(), program_header.is_readable(), program_header.is_writable());
#endif
if (program_header.is_writable()) {
alloc_section_hook(
program_header.laddr(),
program_header.size_in_memory(),
program_header.alignment(),
program_header.is_readable(),
program_header.is_writable(),
String::format("elf-alloc-%s%s", program_header.is_readable() ? "r" : "", program_header.is_writable() ? "w" : "")
);
memcpy(program_header.laddr().as_ptr(), program_header.raw_data(), program_header.size_in_image());
} else {
map_section_hook(
program_header.laddr(),
program_header.size_in_memory(),
program_header.alignment(),
program_header.offset(),
program_header.is_readable(),
program_header.is_writable(),
String::format("elf-map-%s%s", program_header.is_readable() ? "r" : "", program_header.is_writable() ? "w" : "")
);
}
});
return !failed;
}
char* ELFLoader::symbol_ptr(const char* name)
{
char* found_ptr = nullptr;
m_image.for_each_symbol([&] (const ELFImage::Symbol symbol) {
if (symbol.type() != STT_FUNC)
return IterationDecision::Continue;
if (strcmp(symbol.name(), name))
return IterationDecision::Continue;
if (m_image.is_executable())
found_ptr = (char*)symbol.value();
else
ASSERT_NOT_REACHED();
return IterationDecision::Abort;
});
return found_ptr;
}
String ELFLoader::symbolicate(dword address) const
{
if (m_sorted_symbols.is_empty()) {
m_sorted_symbols.ensure_capacity(m_image.symbol_count());
m_image.for_each_symbol([this] (auto& symbol) {
m_sorted_symbols.append({ symbol.value(), symbol.name() });
return IterationDecision::Continue;
});
quick_sort(m_sorted_symbols.begin(), m_sorted_symbols.end(), [] (auto& a, auto& b) {
return a.address < b.address;
});
}
for (int i = 0; i < m_sorted_symbols.size(); ++i) {
if (m_sorted_symbols[i].address > address) {
if (i == 0)
return "!!";
auto& symbol = m_sorted_symbols[i - 1];
return String::format("%s +%u", symbol.name, address - symbol.address);
}
}
return "??";
}