//! \exception StELFFileException is thrown if there is a problem with the file format.
//!
StELFFile::StELFFile(std::istream & inStream)
: m_stream(inStream)
{
readFileHeaders();
}
//! Disposes of the string table data.
StELFFile::~StELFFile()
{
SectionDataMap::iterator it = m_sectionDataCache.begin();
for (; it != m_sectionDataCache.end(); ++it)
{
SectionDataInfo & info = it->second;
if (info.m_data != NULL)
{
delete [] info.m_data;
}
}
}
//! \exception StELFFileException is thrown if the file is not an ELF file.
//!
void StELFFile::readFileHeaders()
{
// move read head to beginning of stream
m_stream.seekg(0, std::ios_base::beg);
// read ELF header
m_stream.read(reinterpret_cast<char *>(&m_header), sizeof(m_header));
if (m_stream.bad())
{
throw StELFFileException("could not read file header");
}
//! If there is not a matching section, then #SHN_UNDEF is returned instead.
//!
unsigned StELFFile::getIndexOfSectionWithName(const std::string & inName)
{
unsigned sectionIndex = 0;
const_section_iterator it = getSectionBegin();
for (; it != getSectionEnd(); ++it, ++sectionIndex)
{
const Elf32_Shdr & header = *it;
if (header.sh_name != 0)
{
std::string sectionName = getSectionNameAtIndex(header.sh_name);
if (inName == sectionName)
return sectionIndex;
}
}
// no matching section
return SHN_UNDEF;
}
//! The pointer returned from this method must be freed with the delete array operator (i.e., delete []).
//! If either the section data offset (sh_offset) or the section size (sh_size) are 0, then NULL will
//! be returned instead.
//!
//! The data is read directly from the input stream passed into the constructor. The stream must
//! still be open, or an exception will be thrown.
//!
//! \exception StELFFileException is thrown if an error occurs while reading the file.
//! \exception std::bad_alloc is thrown if memory for the data cannot be allocated.
uint8_t * StELFFile::getSectionDataAtIndex(unsigned inIndex)
{
return readSectionData(m_sectionHeaders[inIndex]);
}
//! The pointer returned from this method must be freed with the delete array operator (i.e., delete []).
//! If either the section data offset (sh_offset) or the section size (sh_size) are 0, then NULL will
//! be returned instead.
//!
//! The data is read directly from the input stream passed into the constructor. The stream must
//! still be open, or an exception will be thrown.
//!
//! \exception StELFFileException is thrown if an error occurs while reading the file.
//! \exception std::bad_alloc is thrown if memory for the data cannot be allocated.
uint8_t * StELFFile::getSectionData(const_section_iterator inSection)
{
return readSectionData(*inSection);
}
//! \exception StELFFileException is thrown if an error occurs while reading the file.
//! \exception std::bad_alloc is thrown if memory for the data cannot be allocated.
uint8_t * StELFFile::readSectionData(const Elf32_Shdr & inHeader)
{
// check for empty data
if (inHeader.sh_offset == 0 || inHeader.sh_size == 0)
return NULL;
uint8_t * sectionData = new uint8_t[inHeader.sh_size];
//! The pointer returned from this method must be freed with the delete array operator (i.e., delete []).
//! If either the segment offset (p_offset) or the segment file size (p_filesz) are 0, then NULL will
//! be returned instead.
//!
//! The data is read directly from the input stream passed into the constructor. The stream must
//! still be open, or an exception will be thrown.
//!
//! \exception StELFFileException is thrown if an error occurs while reading the file.
//! \exception std::bad_alloc is thrown if memory for the data cannot be allocated.
uint8_t * StELFFile::getSegmentDataAtIndex(unsigned inIndex)
{
return readSegmentData(m_programHeaders[inIndex]);
}
//! The pointer returned from this method must be freed with the delete array operator (i.e., delete []).
//! If either the segment offset (p_offset) or the segment file size (p_filesz) are 0, then NULL will
//! be returned instead.
//!
//! The data is read directly from the input stream passed into the constructor. The stream must
//! still be open, or an exception will be thrown.
//!
//! \exception StELFFileException is thrown if an error occurs while reading the file.
//! \exception std::bad_alloc is thrown if memory for the data cannot be allocated.
uint8_t * StELFFile::getSegmentData(const_segment_iterator inSegment)
{
return readSegmentData(*inSegment);
}
//! \exception StELFFileException is thrown if an error occurs while reading the file.
//! \exception std::bad_alloc is thrown if memory for the data cannot be allocated.
uint8_t * StELFFile::readSegmentData(const Elf32_Phdr & inHeader)
{
// check for empty data
if (inHeader.p_offset == 0 || inHeader.p_filesz== 0)
return NULL;
uint8_t * segmentData = new uint8_t[inHeader.p_filesz];
//! If the index is out of range, or if there is no string table in the file, then
//! an empty string will be returned instead. This will also happen when the index
//! is either 0 or the last byte in the table, since the table begins and ends with
//! zero bytes.
std::string StELFFile::getSectionNameAtIndex(unsigned inIndex)
{
// make sure there's a section name string table
if (m_header.e_shstrndx == SHN_UNDEF)
return std::string("");
//! \exception std::invalid_argument is thrown if the section identified by \a
//! inStringTableSectionIndex is not actually a string table, or if \a
//! inStringIndex is out of range for the string table.
std::string StELFFile::getStringAtIndex(unsigned inStringTableSectionIndex, unsigned inStringIndex)
{
// check section type
const Elf32_Shdr & header = getSectionAtIndex(inStringTableSectionIndex);
if (header.sh_type != SHT_STRTAB)
throw std::invalid_argument("inStringTableSectionIndex");
if (inStringIndex >= header.sh_size)
throw std::invalid_argument("inStringTableSectionIndex");
//! The number of entries in the symbol table is the symbol table section size
//! divided by the size of each symbol entry (the #Elf32_Shdr::sh_entsize field of the
//! symbol table section header).
unsigned StELFFile::getSymbolCount()
{
if (m_symbolTableIndex == SHN_UNDEF)
return 0;
//! \exception std::invalid_argument is thrown if \a inIndex is out of range.]
//!
const Elf32_Sym & StELFFile::getSymbolAtIndex(unsigned inIndex)
{
// get section data
const Elf32_Shdr & header = getSectionAtIndex(m_symbolTableIndex);
SectionDataInfo & info = getCachedSectionData(m_symbolTableIndex);
// has the symbol table been byte swapped yet?
if (!info.m_swapped)
{
byteSwapSymbolTable(header, info);
}
//! Returns STN_UNDEF if it cannot find a symbol at the given \a symbolAddress.
unsigned StELFFile::getIndexOfSymbolAtAddress(uint32_t symbolAddress, bool strict)
{
unsigned symbolCount = getSymbolCount();
unsigned symbolIndex = 0;
for (; symbolIndex < symbolCount; ++symbolIndex)
{
const Elf32_Sym & symbol = getSymbolAtIndex(symbolIndex);
// the GHS toolchain puts in STT_FUNC symbols marking the beginning and ending of each
// file. if the entry point happens to be at the beginning of the file, the beginning-
// of-file symbol will have the same value and type. fortunately, the size of these
// symbols is 0 (or seems to be). we also ignore symbols that start with two dots just
// in case.
if (symbol.st_value == symbolAddress && (strict && ELF32_ST_TYPE(symbol.st_info) == STT_FUNC && symbol.st_size != 0))
{
std::string symbolName = getSymbolName(symbol);
// ignore symbols that start with two dots
if (symbolName[0] == '.' && symbolName[1] == '.')
continue;