2016-11-01 21:39:52 -04:00
|
|
|
#pragma once
|
2006-06-15 04:19:30 +00:00
|
|
|
|
2022-03-13 16:13:38 -04:00
|
|
|
#include <vector>
|
2022-07-25 11:19:56 -04:00
|
|
|
#include <stdexcept>
|
2022-10-07 13:37:39 -04:00
|
|
|
#include <cassert>
|
2023-07-31 18:21:18 -04:00
|
|
|
#include <functional>
|
2006-06-15 04:19:30 +00:00
|
|
|
#include "Types.h"
|
2022-07-22 17:01:59 -04:00
|
|
|
#include "ElfDefs.h"
|
|
|
|
#include "PtrStream.h"
|
2022-07-25 11:19:37 -04:00
|
|
|
#include "EndianUtils.h"
|
2023-05-02 08:56:25 -04:00
|
|
|
#include "maybe_unused.h"
|
2006-06-15 04:19:30 +00:00
|
|
|
|
2022-07-22 17:01:59 -04:00
|
|
|
struct ELFTRAITS32
|
2006-06-15 04:19:30 +00:00
|
|
|
{
|
2022-07-22 17:01:59 -04:00
|
|
|
typedef ELF::ELFHEADER32 ELFHEADER;
|
|
|
|
typedef ELF::ELFPROGRAMHEADER32 ELFPROGRAMHEADER;
|
|
|
|
typedef ELF::ELFSECTIONHEADER32 ELFSECTIONHEADER;
|
|
|
|
typedef ELF::ELFSYMBOL32 ELFSYMBOL;
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
HEADER_ID_CLASS = ELF::ELFCLASS32
|
|
|
|
};
|
2006-06-15 04:19:30 +00:00
|
|
|
};
|
|
|
|
|
2022-07-22 17:01:59 -04:00
|
|
|
struct ELFTRAITS64
|
2022-03-13 16:13:38 -04:00
|
|
|
{
|
2022-07-22 17:01:59 -04:00
|
|
|
typedef ELF::ELFHEADER64 ELFHEADER;
|
|
|
|
typedef ELF::ELFPROGRAMHEADER64 ELFPROGRAMHEADER;
|
|
|
|
typedef ELF::ELFSECTIONHEADER64 ELFSECTIONHEADER;
|
|
|
|
typedef ELF::ELFSYMBOL64 ELFSYMBOL;
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
HEADER_ID_CLASS = ELF::ELFCLASS64
|
|
|
|
};
|
2022-03-13 16:13:38 -04:00
|
|
|
};
|
|
|
|
|
2022-07-22 17:01:59 -04:00
|
|
|
template <typename ElfTraits>
|
2006-06-15 04:19:30 +00:00
|
|
|
class CELF
|
|
|
|
{
|
|
|
|
public:
|
2022-07-22 17:01:59 -04:00
|
|
|
typedef typename ElfTraits::ELFHEADER HEADER;
|
|
|
|
typedef typename ElfTraits::ELFPROGRAMHEADER PROGRAMHEADER;
|
|
|
|
typedef typename ElfTraits::ELFSECTIONHEADER SECTIONHEADER;
|
|
|
|
typedef typename ElfTraits::ELFSYMBOL SYMBOL;
|
2022-03-14 19:52:20 -04:00
|
|
|
|
2023-08-26 20:37:38 -04:00
|
|
|
CELF(uint8* content, uint64 contentSize = ~0ULL)
|
2022-07-22 17:01:59 -04:00
|
|
|
: m_content(content)
|
2022-03-12 10:49:17 -05:00
|
|
|
{
|
2023-08-26 20:37:38 -04:00
|
|
|
Framework::CPtrStream stream(m_content, contentSize);
|
2022-07-22 17:01:59 -04:00
|
|
|
|
|
|
|
stream.Read(&m_header, sizeof(m_header));
|
|
|
|
|
|
|
|
if(m_header.nId[0] != 0x7F || m_header.nId[1] != 'E' || m_header.nId[2] != 'L' || m_header.nId[3] != 'F')
|
|
|
|
{
|
|
|
|
throw std::runtime_error("This file isn't a valid ELF file.");
|
|
|
|
}
|
|
|
|
|
|
|
|
if(m_header.nId[ELF::EI_CLASS] != ElfTraits::HEADER_ID_CLASS)
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Failed to load ELF file: wrong bitness.");
|
|
|
|
}
|
|
|
|
|
2022-07-25 11:19:37 -04:00
|
|
|
if(m_header.nId[ELF::EI_DATA] == ELF::ELFDATA2MSB)
|
2022-07-22 17:01:59 -04:00
|
|
|
{
|
2022-07-25 11:19:37 -04:00
|
|
|
Framework::CEndian::FromMSBF(m_header.nType);
|
|
|
|
Framework::CEndian::FromMSBF(m_header.nCPU);
|
|
|
|
Framework::CEndian::FromMSBF(m_header.nVersion);
|
|
|
|
Framework::CEndian::FromMSBF(m_header.nEntryPoint);
|
|
|
|
Framework::CEndian::FromMSBF(m_header.nProgHeaderStart);
|
|
|
|
Framework::CEndian::FromMSBF(m_header.nSectHeaderStart);
|
|
|
|
Framework::CEndian::FromMSBF(m_header.nFlags);
|
|
|
|
Framework::CEndian::FromMSBF(m_header.nSize);
|
|
|
|
Framework::CEndian::FromMSBF(m_header.nProgHeaderEntrySize);
|
|
|
|
Framework::CEndian::FromMSBF(m_header.nProgHeaderCount);
|
|
|
|
Framework::CEndian::FromMSBF(m_header.nSectHeaderEntrySize);
|
|
|
|
Framework::CEndian::FromMSBF(m_header.nSectHeaderCount);
|
|
|
|
Framework::CEndian::FromMSBF(m_header.nSectHeaderStringTableIndex);
|
2022-07-22 17:01:59 -04:00
|
|
|
}
|
|
|
|
|
2022-09-28 08:36:18 -04:00
|
|
|
ReadProgramHeaders(stream);
|
|
|
|
ReadSectionHeaders(stream);
|
2022-07-22 17:01:59 -04:00
|
|
|
}
|
2022-03-12 10:49:17 -05:00
|
|
|
|
2022-07-22 17:01:59 -04:00
|
|
|
CELF(const CELF&) = delete;
|
|
|
|
virtual ~CELF() = default;
|
2022-03-10 17:33:28 -05:00
|
|
|
|
2022-07-22 17:01:59 -04:00
|
|
|
CELF& operator=(const CELF&) = delete;
|
2022-03-10 17:33:28 -05:00
|
|
|
|
2022-07-22 17:01:59 -04:00
|
|
|
uint8* GetContent() const
|
2012-01-29 22:31:57 +00:00
|
|
|
{
|
2022-07-22 17:01:59 -04:00
|
|
|
return m_content;
|
|
|
|
}
|
2012-01-29 22:31:57 +00:00
|
|
|
|
2022-07-22 17:01:59 -04:00
|
|
|
const HEADER& GetHeader() const
|
2012-01-29 22:31:57 +00:00
|
|
|
{
|
2022-07-22 17:01:59 -04:00
|
|
|
return m_header;
|
|
|
|
}
|
2012-01-29 22:31:57 +00:00
|
|
|
|
2022-09-28 08:36:18 -04:00
|
|
|
uint64 GetSectionHeaderCount() const
|
|
|
|
{
|
|
|
|
return m_sections.size();
|
|
|
|
}
|
|
|
|
|
2023-07-31 18:21:18 -04:00
|
|
|
const SECTIONHEADER* GetSection(unsigned int index) const
|
2012-01-29 22:31:57 +00:00
|
|
|
{
|
2022-09-28 08:36:18 -04:00
|
|
|
if(index >= m_sections.size())
|
2022-07-22 17:01:59 -04:00
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return &m_sections[index];
|
|
|
|
}
|
|
|
|
|
2023-07-31 18:21:18 -04:00
|
|
|
const void* GetSectionData(unsigned int index) const
|
2012-01-29 22:31:57 +00:00
|
|
|
{
|
2022-07-22 17:01:59 -04:00
|
|
|
auto section = GetSection(index);
|
|
|
|
if(section == nullptr) return nullptr;
|
|
|
|
return m_content + section->nOffset;
|
|
|
|
}
|
2012-01-29 22:31:57 +00:00
|
|
|
|
2022-07-22 17:01:59 -04:00
|
|
|
const char* GetSectionName(unsigned int sectionIndex)
|
2022-02-28 16:40:29 -05:00
|
|
|
{
|
2022-07-22 17:01:59 -04:00
|
|
|
auto stringTableData = reinterpret_cast<const char*>(GetSectionData(m_header.nSectHeaderStringTableIndex));
|
|
|
|
if(stringTableData == nullptr) return nullptr;
|
|
|
|
auto sectionHeader = GetSection(sectionIndex);
|
|
|
|
if(sectionHeader == nullptr) return nullptr;
|
|
|
|
return stringTableData + sectionHeader->nStringTableIndex;
|
|
|
|
}
|
|
|
|
|
2023-07-31 18:21:18 -04:00
|
|
|
const SECTIONHEADER* FindSection(const char* requestedSectionName) const
|
2012-01-29 22:31:57 +00:00
|
|
|
{
|
2022-07-22 17:01:59 -04:00
|
|
|
auto sectionIndex = FindSectionIndex(requestedSectionName);
|
|
|
|
if(sectionIndex == 0) return nullptr;
|
|
|
|
return GetSection(sectionIndex);
|
|
|
|
}
|
2012-01-29 22:31:57 +00:00
|
|
|
|
2023-07-31 18:21:18 -04:00
|
|
|
unsigned int FindSectionIndex(const char* requestedSectionName) const
|
2015-05-15 01:01:24 -04:00
|
|
|
{
|
2022-07-22 17:01:59 -04:00
|
|
|
auto stringTableData = reinterpret_cast<const char*>(GetSectionData(m_header.nSectHeaderStringTableIndex));
|
|
|
|
if(stringTableData == nullptr) return 0;
|
2022-09-28 08:36:18 -04:00
|
|
|
for(unsigned int i = 0; i < GetSectionHeaderCount(); i++)
|
2022-07-22 17:01:59 -04:00
|
|
|
{
|
|
|
|
auto sectionHeader = GetSection(i);
|
|
|
|
auto sectionName = stringTableData + sectionHeader->nStringTableIndex;
|
|
|
|
if(!strcmp(sectionName, requestedSectionName))
|
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-07-31 18:21:18 -04:00
|
|
|
const void* FindSectionData(const char* requestedSectionName) const
|
2012-01-29 22:31:57 +00:00
|
|
|
{
|
2022-07-22 17:01:59 -04:00
|
|
|
auto section = FindSection(requestedSectionName);
|
|
|
|
if(section == nullptr) return nullptr;
|
|
|
|
return m_content + section->nOffset;
|
|
|
|
}
|
2012-01-29 22:31:57 +00:00
|
|
|
|
2022-07-22 17:01:59 -04:00
|
|
|
PROGRAMHEADER* GetProgram(unsigned int index)
|
2012-01-29 22:31:57 +00:00
|
|
|
{
|
2022-07-22 17:01:59 -04:00
|
|
|
if(index >= m_header.nProgHeaderCount)
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return &m_programs[index];
|
|
|
|
}
|
2008-10-20 04:12:44 +00:00
|
|
|
|
2023-07-31 18:21:18 -04:00
|
|
|
uint64 GetSymbolCount() const
|
|
|
|
{
|
|
|
|
auto symbolTable = FindSection(".symtab");
|
|
|
|
if(!symbolTable) return 0;
|
|
|
|
return symbolTable->nSize / sizeof(SYMBOL);
|
|
|
|
}
|
|
|
|
|
2023-08-03 19:11:35 -04:00
|
|
|
typedef std::function<void(const SYMBOL&, uint8, uint8, const char*)> SymbolEnumerationCallback;
|
2023-07-31 18:21:18 -04:00
|
|
|
|
2023-08-03 19:11:35 -04:00
|
|
|
void EnumerateSymbols(const SymbolEnumerationCallback& callback) const
|
2023-07-31 18:21:18 -04:00
|
|
|
{
|
|
|
|
auto symbolTable = FindSection(".symtab");
|
|
|
|
if(!symbolTable) return;
|
|
|
|
|
|
|
|
auto stringTable = reinterpret_cast<const char*>(GetSectionData(symbolTable->nIndex));
|
|
|
|
if(!stringTable) return;
|
|
|
|
|
|
|
|
auto symbols = reinterpret_cast<const SYMBOL*>(FindSectionData(".symtab"));
|
|
|
|
unsigned int symbolCount = symbolTable->nSize / sizeof(SYMBOL);
|
|
|
|
|
|
|
|
for(unsigned int i = 0; i < symbolCount; i++)
|
|
|
|
{
|
|
|
|
auto symbol = symbols[i];
|
|
|
|
|
|
|
|
if(m_header.nId[ELF::EI_DATA] == ELF::ELFDATA2MSB)
|
|
|
|
{
|
|
|
|
Framework::CEndian::FromMSBF(symbol.nName);
|
|
|
|
Framework::CEndian::FromMSBF(symbol.nValue);
|
|
|
|
Framework::CEndian::FromMSBF(symbol.nSize);
|
|
|
|
Framework::CEndian::FromMSBF(symbol.nSectionIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8 symbolType = symbol.nInfo & 0x0F;
|
|
|
|
uint8 symbolBinding = (symbol.nInfo >> 4) & 0x0F;
|
|
|
|
auto symbolName = stringTable + symbol.nName;
|
|
|
|
callback(symbol, symbolType, symbolBinding, symbolName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-06-15 04:19:30 +00:00
|
|
|
private:
|
2022-09-28 08:36:18 -04:00
|
|
|
void ReadSectionHeaders(Framework::CStream& stream)
|
|
|
|
{
|
|
|
|
//Fetch extended section header count if needed
|
|
|
|
decltype(SECTIONHEADER::nSize) sectionHeaderCount = 0;
|
|
|
|
if((m_header.nSectHeaderCount == 0) && (m_header.nSectHeaderStart != 0))
|
|
|
|
{
|
|
|
|
SECTIONHEADER zeroSectionHeader = {};
|
|
|
|
stream.Seek(m_header.nSectHeaderStart, Framework::STREAM_SEEK_SET);
|
2023-08-26 20:37:38 -04:00
|
|
|
//Some ELF files have their section headers truncated (ex.: Psychonauts PS2)
|
|
|
|
//Make sure that we were able to read the zeroth section header
|
|
|
|
//properly before proceeding
|
|
|
|
auto amountRead = stream.Read(&zeroSectionHeader, sizeof(zeroSectionHeader));
|
|
|
|
if(amountRead == sizeof(zeroSectionHeader))
|
2022-09-28 08:36:18 -04:00
|
|
|
{
|
2023-08-26 20:37:38 -04:00
|
|
|
if(m_header.nId[ELF::EI_DATA] == ELF::ELFDATA2MSB)
|
|
|
|
{
|
|
|
|
Framework::CEndian::FromMSBF(zeroSectionHeader.nSize);
|
|
|
|
}
|
|
|
|
assert(zeroSectionHeader.nSize != 0);
|
|
|
|
sectionHeaderCount = zeroSectionHeader.nSize;
|
2022-09-28 08:36:18 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sectionHeaderCount = m_header.nSectHeaderCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_sections.resize(sectionHeaderCount);
|
|
|
|
stream.Seek(m_header.nSectHeaderStart, Framework::STREAM_SEEK_SET);
|
|
|
|
for(auto& section : m_sections)
|
|
|
|
{
|
2023-05-02 08:56:25 -04:00
|
|
|
FRAMEWORK_MAYBE_UNUSED auto readAmount = stream.Read(§ion, sizeof(section));
|
2022-09-28 08:36:18 -04:00
|
|
|
assert(readAmount == sizeof(section));
|
|
|
|
if(m_header.nId[ELF::EI_DATA] == ELF::ELFDATA2MSB)
|
|
|
|
{
|
|
|
|
Framework::CEndian::FromMSBF(section.nStringTableIndex);
|
|
|
|
Framework::CEndian::FromMSBF(section.nType);
|
|
|
|
Framework::CEndian::FromMSBF(section.nFlags);
|
|
|
|
Framework::CEndian::FromMSBF(section.nStart);
|
|
|
|
Framework::CEndian::FromMSBF(section.nOffset);
|
|
|
|
Framework::CEndian::FromMSBF(section.nSize);
|
|
|
|
Framework::CEndian::FromMSBF(section.nIndex);
|
|
|
|
Framework::CEndian::FromMSBF(section.nInfo);
|
|
|
|
Framework::CEndian::FromMSBF(section.nAlignment);
|
|
|
|
Framework::CEndian::FromMSBF(section.nOther);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ReadProgramHeaders(Framework::CStream& stream)
|
|
|
|
{
|
|
|
|
m_programs.resize(m_header.nProgHeaderCount);
|
|
|
|
stream.Seek(m_header.nProgHeaderStart, Framework::STREAM_SEEK_SET);
|
|
|
|
for(auto& program : m_programs)
|
|
|
|
{
|
|
|
|
stream.Read(&program, sizeof(program));
|
|
|
|
if(m_header.nId[ELF::EI_DATA] == ELF::ELFDATA2MSB)
|
|
|
|
{
|
|
|
|
Framework::CEndian::FromMSBF(program.nType);
|
|
|
|
Framework::CEndian::FromMSBF(program.nFlags);
|
|
|
|
Framework::CEndian::FromMSBF(program.nOffset);
|
|
|
|
Framework::CEndian::FromMSBF(program.nVAddress);
|
|
|
|
Framework::CEndian::FromMSBF(program.nPAddress);
|
|
|
|
Framework::CEndian::FromMSBF(program.nFileSize);
|
|
|
|
Framework::CEndian::FromMSBF(program.nMemorySize);
|
|
|
|
Framework::CEndian::FromMSBF(program.nAlignment);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-14 19:52:20 -04:00
|
|
|
HEADER m_header;
|
2018-04-30 21:01:23 +01:00
|
|
|
uint8* m_content = nullptr;
|
2008-10-20 04:12:44 +00:00
|
|
|
|
2022-03-14 19:52:20 -04:00
|
|
|
std::vector<SECTIONHEADER> m_sections;
|
|
|
|
std::vector<PROGRAMHEADER> m_programs;
|
2006-06-15 04:19:30 +00:00
|
|
|
};
|
2022-07-22 17:01:59 -04:00
|
|
|
|
|
|
|
typedef CELF<ELFTRAITS32> CELF32;
|
|
|
|
typedef CELF<ELFTRAITS64> CELF64;
|