diff --git a/src/emucore/CartELF.cxx b/src/emucore/CartELF.cxx index 81091a378..61dab4eae 100644 --- a/src/emucore/CartELF.cxx +++ b/src/emucore/CartELF.cxx @@ -22,6 +22,8 @@ #include "CartELF.hxx" +#define DUMP_ELF + namespace { constexpr size_t TRANSACTION_QUEUE_CAPACITY = 16384; @@ -78,6 +80,22 @@ CartridgeELF::CartridgeELF(const ByteBuffer& image, size_t size, string_view md5 std::fill_n(myLastPeekResult.get(), 0x1000, 0); createRomAccessArrays(0x1000); + + #ifdef DUMP_ELF + cout << "ELF sections:" << std::endl << std::endl; + + size_t i = 0; + for (auto& section: elfParser.getSections()) + if (section.type != 0x00) cout << (i++) << " " << section << std::endl; + + auto symbols = elfParser.getSymbols(); + cout << std::endl << "ELF symbols:" << std::endl << std::endl; + if (symbols.size() > 0) { + i = 0; + for (auto& symbol: symbols) + cout << (i++) << " " << symbol << std::endl; + } + #endif } diff --git a/src/emucore/elf/ElfParser.cxx b/src/emucore/elf/ElfParser.cxx index bc5e37683..5a6e551ad 100644 --- a/src/emucore/elf/ElfParser.cxx +++ b/src/emucore/elf/ElfParser.cxx @@ -6,9 +6,11 @@ namespace { constexpr uInt32 ELF_MAGIC = 0x7f454c46; constexpr uInt8 ELF_CLASS_32 = 1; constexpr uInt8 ELF_VERSION = 1; + constexpr uInt32 SYMBOL_ENTRY_SIZE = 16; } // namespace -void ElfParser::parse(const uInt8 *elfData, size_t size) { +void ElfParser::parse(const uInt8 *elfData, size_t size) +{ data = elfData; this->size = size; @@ -36,7 +38,7 @@ void ElfParser::parse(const uInt8 *elfData, size_t size) { sections.reserve(header.shNum); - for (uInt32 i = 0; i < header.shNum; i++) + for (size_t i = 0; i < header.shNum; i++) sections.push_back( readSection(header.shOffset + i * header.shSize)); @@ -44,10 +46,19 @@ void ElfParser::parse(const uInt8 *elfData, size_t size) { if (shrstrtab.type != SHT_STRTAB) EInvalidElf::raise(".shstrtab has wrong type"); - for (Section §ion : sections) section.name = getName(shrstrtab, section.nameOffset); + const Section* symtab = getSymtab(); + if (symtab) { + const Section* strtab = getStrtab(); + if (!strtab) EInvalidElf::raise("no string table to resolve symbol names"); + + symbols.reserve(symtab->size / SYMBOL_ENTRY_SIZE); + + for (size_t i = 0; i < symtab->size / SYMBOL_ENTRY_SIZE; i++) + symbols.push_back(readSymbol(i, *symtab, *strtab)); + } } catch (const EInvalidElf &e) { EInvalidElf::raise("failed to parse ELF: " + string(e.what())); } @@ -57,10 +68,16 @@ const uInt8 *ElfParser::getData() const { return data; } size_t ElfParser::getSize() const { return size; } -const vector &ElfParser::getSections() const { +const vector &ElfParser::getSections() const +{ return sections; } +const vector& ElfParser::getSymbols() const +{ + return symbols; +} + const optional ElfParser::getSection(const string &name) const { for (const Section §ion : sections) @@ -70,26 +87,29 @@ ElfParser::getSection(const string &name) const { return optional
(); } -uInt8 ElfParser::read8(uInt32 offset) { +uInt8 ElfParser::read8(uInt32 offset) const +{ if (offset >= size) EInvalidElf::raise("reference beyond bounds"); return data[offset]; } -uInt16 ElfParser::read16(uInt32 offset) { +uInt16 ElfParser::read16(uInt32 offset) const +{ return bigEndian ? ((read8(offset) << 8) | read8(offset + 1)) : ((read8(offset + 1) << 8) | read8(offset)); } -uInt32 ElfParser::read32(uInt32 offset) { +uInt32 ElfParser::read32(uInt32 offset) const +{ return bigEndian ? ((read8(offset) << 24) | (read8(offset + 1) << 16) | (read8(offset + 2) << 8) | read8(offset + 3)) : ((read8(offset + 3) << 24) | (read8(offset + 2) << 16) | (read8(offset + 1) << 8) | read8(offset)); } -ElfParser::Section ElfParser::readSection(uInt32 offset) { +ElfParser::Section ElfParser::readSection(uInt32 offset) const { Section section; try { @@ -110,7 +130,29 @@ ElfParser::Section ElfParser::readSection(uInt32 offset) { return section; } -const char* ElfParser::getName(const Section& section, uInt32 offset) +ElfParser::Symbol ElfParser::readSymbol(uInt32 index, const Section& symSec, const Section& strSec) const +{ + Symbol sym; + + uInt32 offset = index * SYMBOL_ENTRY_SIZE; + if (offset + SYMBOL_ENTRY_SIZE > symSec.size) EInvalidElf::raise("symbol is beyond section"); + offset += symSec.offset; + + sym.nameOffset = read32(offset); + sym.value = read32(offset + 0x04); + sym.size = read32(offset + 0x08); + sym.info = read8(offset + 0x0c); + sym.visibility = read8(offset + 0x0d); + sym.section = read16(offset + 0x0e); + + sym.name = getName(strSec, sym.nameOffset); + sym.bind = sym.info >> 4; + sym.type = sym.info & 0x0f; + + return sym; +} + +const char* ElfParser::getName(const Section& section, uInt32 offset) const { if (offset >= section.size) EInvalidElf::raise("name out of bounds"); const uInt32 imageOffset = offset + section.offset; @@ -122,3 +164,62 @@ const char* ElfParser::getName(const Section& section, uInt32 offset) return name; } + +const ElfParser::Section* ElfParser::getSymtab() const +{ + for (auto& section: sections) + if (section.type == SHT_SYMTAB) return §ion; + + return nullptr; +} + +const ElfParser::Section* ElfParser::getStrtab() const +{ + for (size_t i = 0; i < sections.size(); i++) + if (sections[i].type == SHT_STRTAB && i != header.shstrIndex) return §ions[i]; + + return nullptr; +} + +ostream& operator<<(ostream& os, const ElfParser::Section& section) +{ + std::ios reset(nullptr); + reset.copyfmt(os); + + os + << std::hex << std::setw(4) << std::setfill('0') + << section.name + << " type=0x" << section.type + << " flags=0x" << section.flags + << " vaddr=0x" << section.virtualAddress + << " offset=0x" << section.offset; + + os.copyfmt(reset); + + os + << " size=" << section.size + << " align=" << section.align; + + return os; +} + +ostream& operator<<(ostream& os, const ElfParser::Symbol symbol) +{ + std::ios reset(nullptr); + reset.copyfmt(os); + + os + << symbol.name + << std::hex << std::setw(4) << std::setfill('0') + << " value=0x" << symbol.value + << " size=0x" << symbol.size + << std::setw(1) + << " bind=0x" << (int)symbol.bind + << " type=0x" << (int)symbol.type; + + os.copyfmt(reset); + + os << " section=" << symbol.section; + + return os; +} diff --git a/src/emucore/elf/ElfParser.hxx b/src/emucore/elf/ElfParser.hxx index 93db02fdf..3b93fa3d7 100644 --- a/src/emucore/elf/ElfParser.hxx +++ b/src/emucore/elf/ElfParser.hxx @@ -64,6 +64,19 @@ class ElfParser { uInt32 align; }; + struct Symbol { + uInt32 nameOffset; + uInt32 value; + uInt32 size; + uInt8 info; + uInt8 visibility; + uInt16 section; + + string name; + uInt8 bind; + uInt8 type; + }; + public: static constexpr uInt8 ENDIAN_LITTLE_ENDIAN = 0x01; static constexpr uInt8 ENDIAN_BIG_ENDIAN = 0x02; @@ -72,6 +85,7 @@ class ElfParser { static constexpr uInt16 ARCH_ARM32 = 0x28; + static constexpr uInt32 SHT_NULL = 0x00; static constexpr uInt32 SHT_PROGBITS = 0x01; static constexpr uInt32 SHT_SYMTAB = 0x02; static constexpr uInt32 SHT_STRTAB = 0x03; @@ -81,6 +95,9 @@ class ElfParser { static constexpr uInt32 SHT_INIT_ARRAY = 0x0e; static constexpr uInt32 SHT_PREINIT_ARRAY = 0x10; + static constexpr uInt32 SHN_ABS = 0xfff1; + static constexpr uInt32 SHN_UND = 0x00; + public: ElfParser() = default; @@ -91,15 +108,20 @@ class ElfParser { const Header& getHeader() const; const vector
& getSections() const; + const vector& getSymbols() const; const optional
getSection(const std::string &name) const; private: - uInt8 read8(uInt32 offset); - uInt16 read16(uInt32 offset); - uInt32 read32(uInt32 offset); + uInt8 read8(uInt32 offset) const; + uInt16 read16(uInt32 offset) const; + uInt32 read32(uInt32 offset) const; - Section readSection(uInt32 offset); - const char* getName(const Section& section, uInt32 offset); + Section readSection(uInt32 offset) const; + Symbol readSymbol(uInt32 index, const Section& symSec, const Section& strSec) const; + const char* getName(const Section& section, uInt32 offset) const; + + const Section* getSymtab() const; + const Section* getStrtab() const; private: const uInt8 *data{nullptr}; @@ -109,6 +131,11 @@ class ElfParser { Header header; vector
sections; + vector symbols; }; +ostream& operator<<(ostream& os, const ElfParser::Section& section); + +ostream& operator<<(ostream& os, const ElfParser::Symbol symbol); + #endif // ELF_PARSER