More cleanup.

This commit is contained in:
Christian Speckner 2024-07-07 13:20:10 +02:00
parent c581fd7be3
commit 4c44735f40
1 changed files with 74 additions and 30 deletions

View File

@ -1,3 +1,20 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include "ElfParser.hxx" #include "ElfParser.hxx"
#include <cstring> #include <cstring>
@ -11,6 +28,7 @@ namespace {
constexpr uInt32 RELA_ENTRY_SIZE = 12; constexpr uInt32 RELA_ENTRY_SIZE = 12;
} // namespace } // namespace
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ElfParser::parse(const uInt8 *elfData, size_t size) void ElfParser::parse(const uInt8 *elfData, size_t size)
{ {
data = elfData; data = elfData;
@ -22,14 +40,14 @@ void ElfParser::parse(const uInt8 *elfData, size_t size)
bigEndian = true; bigEndian = true;
try { try {
if (read32(0x00) != ELF_MAGIC) EInvalidElf::raise("bad magic"); if (read32(0x00) != ELF_MAGIC) ElfParseError::raise("bad magic");
if (read8(0x04) != ELF_CLASS_32) EInvalidElf::raise("not 32bit ELF"); if (read8(0x04) != ELF_CLASS_32) ElfParseError::raise("not 32bit ELF");
if (read8(0x06) != ELF_VERSION) EInvalidElf::raise("invalid ELF version"); if (read8(0x06) != ELF_VERSION) ElfParseError::raise("invalid ELF version");
header.endianess = read8(0x05); header.endianess = read8(0x05);
bigEndian = header.endianess == ENDIAN_BIG_ENDIAN; bigEndian = header.endianess == ENDIAN_BIG_ENDIAN;
if (read32(0x14) != ELF_VERSION) EInvalidElf::raise("inconsistent ELF version"); if (read32(0x14) != ELF_VERSION) ElfParseError::raise("inconsistent ELF version");
header.type = read16(0x10); header.type = read16(0x10);
header.arch = read16(0x12); header.arch = read16(0x12);
@ -39,7 +57,7 @@ void ElfParser::parse(const uInt8 *elfData, size_t size)
header.shNum = read16(0x30); header.shNum = read16(0x30);
header.shstrIndex = read16(0x32); header.shstrIndex = read16(0x32);
if (header.shstrIndex >= header.shNum) EInvalidElf::raise(".shstrtab out of range"); if (header.shstrIndex >= header.shNum) ElfParseError::raise(".shstrtab out of range");
sections.reserve(header.shNum); sections.reserve(header.shNum);
@ -49,7 +67,7 @@ void ElfParser::parse(const uInt8 *elfData, size_t size)
const Section &shrstrtab(sections[header.shstrIndex]); const Section &shrstrtab(sections[header.shstrIndex]);
if (shrstrtab.type != SHT_STRTAB) EInvalidElf::raise(".shstrtab has wrong type"); if (shrstrtab.type != SHT_STRTAB) ElfParseError::raise(".shstrtab has wrong type");
for (Section &section : sections) for (Section &section : sections)
section.name = getName(shrstrtab, section.nameOffset); section.name = getName(shrstrtab, section.nameOffset);
@ -58,7 +76,7 @@ void ElfParser::parse(const uInt8 *elfData, size_t size)
if (symtab) { if (symtab) {
const Section* strtab = getStrtab(); const Section* strtab = getStrtab();
if (!strtab) EInvalidElf::raise("no string table to resolve symbol names"); if (!strtab) ElfParseError::raise("no string table to resolve symbol names");
symbols.reserve(symtab->size / SYMBOL_ENTRY_SIZE); symbols.reserve(symtab->size / SYMBOL_ENTRY_SIZE);
@ -68,7 +86,7 @@ void ElfParser::parse(const uInt8 *elfData, size_t size)
for (auto& section: sections) { for (auto& section: sections) {
if (section.type != SHT_REL && section.type != SHT_RELA) continue; if (section.type != SHT_REL && section.type != SHT_RELA) continue;
if (section.info >= sections.size()) EInvalidElf::raise("relocation table for invalid section"); if (section.info >= sections.size()) ElfParseError::raise("relocation table for invalid section");
vector<Relocation> rels; vector<Relocation> rels;
const size_t relocationCount = section.size / (section.type == SHT_REL ? REL_ENTRY_SIZE : RELA_ENTRY_SIZE); const size_t relocationCount = section.size / (section.type == SHT_REL ? REL_ENTRY_SIZE : RELA_ENTRY_SIZE);
@ -77,7 +95,7 @@ void ElfParser::parse(const uInt8 *elfData, size_t size)
for (size_t i = 0; i < relocationCount; i++) { for (size_t i = 0; i < relocationCount; i++) {
Relocation rel = readRelocation(i, section); Relocation rel = readRelocation(i, section);
if (rel.symbol >= symbols.size()) EInvalidElf::raise("invalid relocation symbol"); if (rel.symbol >= symbols.size()) ElfParseError::raise("invalid relocation symbol");
rel.symbolName = symbols[rel.symbol].name; rel.symbolName = symbols[rel.symbol].name;
rels.push_back(rel); rels.push_back(rel);
@ -85,25 +103,30 @@ void ElfParser::parse(const uInt8 *elfData, size_t size)
relocations[section.info] = rels; relocations[section.info] = rels;
} }
} catch (const EInvalidElf &e) { } catch (const ElfParseError &e) {
EInvalidElf::raise("failed to parse ELF: " + string(e.what())); ElfParseError::raise("failed to parse ELF: " + string(e.what()));
} }
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8 *ElfParser::getData() const { return data; } const uInt8 *ElfParser::getData() const { return data; }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
size_t ElfParser::getSize() const { return size; } size_t ElfParser::getSize() const { return size; }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const vector<ElfParser::Section> &ElfParser::getSections() const const vector<ElfParser::Section> &ElfParser::getSections() const
{ {
return sections; return sections;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const vector<ElfParser::Symbol>& ElfParser::getSymbols() const const vector<ElfParser::Symbol>& ElfParser::getSymbols() const
{ {
return symbols; return symbols;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const optional<ElfParser::Section> const optional<ElfParser::Section>
ElfParser::getSection(const string &name) const { ElfParser::getSection(const string &name) const {
for (const Section &section : sections) for (const Section &section : sections)
@ -113,25 +136,29 @@ ElfParser::getSection(const string &name) const {
return optional<Section>(); return optional<Section>();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const optional<vector<ElfParser::Relocation>> ElfParser::getRelocations(size_t section) const const optional<vector<ElfParser::Relocation>> ElfParser::getRelocations(size_t section) const
{ {
return relocations.contains(section) ? relocations.at(section) : optional<vector<ElfParser::Relocation>>(); return relocations.contains(section) ? relocations.at(section) : optional<vector<ElfParser::Relocation>>();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 ElfParser::read8(uInt32 offset) const uInt8 ElfParser::read8(uInt32 offset) const
{ {
if (offset >= size) if (offset >= size)
EInvalidElf::raise("reference beyond bounds"); ElfParseError::raise("reference beyond bounds");
return data[offset]; return data[offset];
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 ElfParser::read16(uInt32 offset) const uInt16 ElfParser::read16(uInt32 offset) const
{ {
return bigEndian ? ((read8(offset) << 8) | read8(offset + 1)) return bigEndian ? ((read8(offset) << 8) | read8(offset + 1))
: ((read8(offset + 1) << 8) | read8(offset)); : ((read8(offset + 1) << 8) | read8(offset));
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 ElfParser::read32(uInt32 offset) const uInt32 ElfParser::read32(uInt32 offset) const
{ {
return bigEndian ? ((read8(offset) << 24) | (read8(offset + 1) << 16) | return bigEndian ? ((read8(offset) << 24) | (read8(offset + 1) << 16) |
@ -140,6 +167,7 @@ uInt32 ElfParser::read32(uInt32 offset) const
(read8(offset + 1) << 8) | read8(offset)); (read8(offset + 1) << 8) | read8(offset));
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ElfParser::Section ElfParser::readSection(uInt32 offset) const { ElfParser::Section ElfParser::readSection(uInt32 offset) const {
Section section; Section section;
@ -154,34 +182,39 @@ ElfParser::Section ElfParser::readSection(uInt32 offset) const {
section.align = read32(offset + 0x20); section.align = read32(offset + 0x20);
if (section.offset + section.size >= size) if (section.offset + section.size >= size)
EInvalidElf::raise("section exceeds bounds"); ElfParseError::raise("section exceeds bounds");
} catch (const EInvalidElf &e) { } catch (const ElfParseError &e) {
EInvalidElf::raise("failed to parse section: " + string(e.what())); ElfParseError::raise("failed to read section: " + string(e.what()));
} }
return section; return section;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ElfParser::Symbol ElfParser::readSymbol(uInt32 index, const Section& symSec, const Section& strSec) const ElfParser::Symbol ElfParser::readSymbol(uInt32 index, const Section& symSec, const Section& strSec) const
{ {
uInt32 offset = index * SYMBOL_ENTRY_SIZE; uInt32 offset = index * SYMBOL_ENTRY_SIZE;
if (offset + SYMBOL_ENTRY_SIZE > symSec.size) EInvalidElf::raise("symbol is beyond section"); if (offset + SYMBOL_ENTRY_SIZE > symSec.size) ElfParseError::raise("symbol is beyond section");
offset += symSec.offset; offset += symSec.offset;
Symbol sym; Symbol sym;
try {
sym.nameOffset = read32(offset); sym.nameOffset = read32(offset);
sym.value = read32(offset + 0x04); sym.value = read32(offset + 0x04);
sym.size = read32(offset + 0x08); sym.size = read32(offset + 0x08);
sym.info = read8(offset + 0x0c); sym.info = read8(offset + 0x0c);
sym.visibility = read8(offset + 0x0d); sym.visibility = read8(offset + 0x0d);
sym.section = read16(offset + 0x0e); sym.section = read16(offset + 0x0e);
} catch (const ElfParseError& e) {
ElfParseError::raise("failed to read section: " + string(e.what()));
}
if ( if (
((sym.section != SHN_ABS && sym.section != SHN_UND) || sym.type == STT_SECTION) && ((sym.section != SHN_ABS && sym.section != SHN_UND) || sym.type == STT_SECTION) &&
sym.section >= sections.size() sym.section >= sections.size()
) )
EInvalidElf::raise("symbol: section index out of range"); ElfParseError::raise("symbol: section index out of range");
sym.bind = sym.info >> 4; sym.bind = sym.info >> 4;
sym.type = sym.info & 0x0f; sym.type = sym.info & 0x0f;
@ -191,6 +224,7 @@ ElfParser::Symbol ElfParser::readSymbol(uInt32 index, const Section& symSec, con
return sym; return sym;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ElfParser::Relocation ElfParser::readRelocation(uInt32 index, const Section& sec) const ElfParser::Relocation ElfParser::readRelocation(uInt32 index, const Section& sec) const
{ {
if (sec.type != SHT_REL && sec.type != SHT_RELA) if (sec.type != SHT_REL && sec.type != SHT_RELA)
@ -199,14 +233,18 @@ ElfParser::Relocation ElfParser::readRelocation(uInt32 index, const Section& sec
const size_t size = sec.type == SHT_REL ? REL_ENTRY_SIZE : RELA_ENTRY_SIZE; const size_t size = sec.type == SHT_REL ? REL_ENTRY_SIZE : RELA_ENTRY_SIZE;
uInt32 offset = index * size; uInt32 offset = index * size;
if (offset + size > sec.size) EInvalidElf::raise("relocation is beyond bounds"); if (offset + size > sec.size) ElfParseError::raise("relocation is beyond bounds");
offset += sec.offset; offset += sec.offset;
Relocation rel; Relocation rel;
try {
rel.address = read32(offset); rel.address = read32(offset);
rel.info = read32(offset + 0x04); rel.info = read32(offset + 0x04);
rel.addend = sec.type == SHT_RELA ? read32(offset + 0x08) : 0; rel.addend = sec.type == SHT_RELA ? read32(offset + 0x08) : 0;
} catch (const ElfParseError& e) {
ElfParseError::raise("failed to read relocation: " + string(e.what()));
}
rel.symbol = rel.info >> 8; rel.symbol = rel.info >> 8;
rel.type = rel.info & 0x0f; rel.type = rel.info & 0x0f;
@ -214,19 +252,21 @@ ElfParser::Relocation ElfParser::readRelocation(uInt32 index, const Section& sec
return rel; return rel;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* ElfParser::getName(const Section& section, uInt32 offset) const const char* ElfParser::getName(const Section& section, uInt32 offset) const
{ {
if (offset >= section.size) EInvalidElf::raise("name out of bounds"); if (offset >= section.size) ElfParseError::raise("name out of bounds");
const uInt32 imageOffset = offset + section.offset; const uInt32 imageOffset = offset + section.offset;
const char *name = reinterpret_cast<const char *>(data + imageOffset); const char *name = reinterpret_cast<const char *>(data + imageOffset);
if (data[imageOffset + strnlen(name, section.size - offset)] != '\0') if (data[imageOffset + strnlen(name, section.size - offset)] != '\0')
EInvalidElf::raise("unterminated section name"); ElfParseError::raise("unterminated section name");
return name; return name;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const ElfParser::Section* ElfParser::getSymtab() const const ElfParser::Section* ElfParser::getSymtab() const
{ {
for (auto& section: sections) for (auto& section: sections)
@ -235,6 +275,7 @@ const ElfParser::Section* ElfParser::getSymtab() const
return nullptr; return nullptr;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const ElfParser::Section* ElfParser::getStrtab() const const ElfParser::Section* ElfParser::getStrtab() const
{ {
const Section* strtab = nullptr; const Section* strtab = nullptr;
@ -247,11 +288,12 @@ const ElfParser::Section* ElfParser::getStrtab() const
count++; count++;
} }
if (count > 1) EInvalidElf::raise("more than one symbol table"); if (count > 1) ElfParseError::raise("more than one symbol table");
return strtab; return strtab;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ostream& operator<<(ostream& os, const ElfParser::Section& section) ostream& operator<<(ostream& os, const ElfParser::Section& section)
{ {
std::ios reset(nullptr); std::ios reset(nullptr);
@ -275,6 +317,7 @@ ostream& operator<<(ostream& os, const ElfParser::Section& section)
return os; return os;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ostream& operator<<(ostream& os, const ElfParser::Symbol symbol) ostream& operator<<(ostream& os, const ElfParser::Symbol symbol)
{ {
std::ios reset(nullptr); std::ios reset(nullptr);
@ -297,6 +340,7 @@ ostream& operator<<(ostream& os, const ElfParser::Symbol symbol)
return os; return os;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ostream& operator<<(ostream& os, const ElfParser::Relocation rel) ostream& operator<<(ostream& os, const ElfParser::Relocation rel)
{ {
std::ios reset(nullptr); std::ios reset(nullptr);