//! The name of the toolset option.
#define kToolsetOptionName "toolset"
#define kGHSToolsetName "GHS"
#define kGCCToolsetName "GCC"
#define kGNUToolsetName "GNU"
#define kADSToolsetName "ADS"
//! Name of the option to control .secinfo action.
#define kSecinfoClearOptionName "secinfoClear"
#define kSecinfoDefaultName "DEFAULT"
#define kSecinfoIgnoreName "IGNORE"
#define kSecinfoROMName "ROM"
#define kSecinfoCName "C"
// Read option and select default value
m_secinfoOption = readSecinfoClearOption();
if (m_secinfoOption == kSecinfoDefault)
{
m_secinfoOption = kSecinfoCStartupClear;
}
// Open the stream
SourceFile::open();
m_file = new StELFFile(*m_stream);
// m_file->dumpSections();
// Set toolset in elf file object
switch (m_toolset)
{
// default toolset is GHS
case kGHSToolset:
case kUnknownToolset:
m_file->setELFVariant(eGHSVariant);
break;
case kGCCToolset:
m_file->setELFVariant(eGCCVariant);
break;
case kADSToolset:
m_file->setELFVariant(eARMVariant);
break;
}
}
elf_toolset_t ELFSourceFile::readToolsetOption()
{
do {
const OptionContext * options = getOptions();
if (!options || !options->hasOption(kToolsetOptionName))
{
break;
}
const Value * value = options->getOption(kToolsetOptionName);
const StringValue * stringValue = dynamic_cast<const StringValue*>(value);
if (!stringValue)
{
// Not a string value, warn the user.
Log::log(Logger::WARNING, "invalid type for 'toolset' option\n");
break;
}
std::string toolsetName = *stringValue;
// convert option value to uppercase
std::transform<std::string::const_iterator, std::string::iterator, int (*)(int)>(toolsetName.begin(), toolsetName.end(), toolsetName.begin(), toupper);
if (toolsetName == kGHSToolsetName)
{
return kGHSToolset;
}
else if (toolsetName == kGCCToolsetName || toolsetName == kGNUToolsetName)
{
return kGCCToolset;
}
else if (toolsetName == kADSToolsetName)
{
return kADSToolset;
}
// Unrecognized option value, log a warning.
Log::log(Logger::WARNING, "unrecognized value for 'toolset' option\n");
} while (0);
return kUnknownToolset;
}
//! It is up to the caller to convert from kSecinfoDefault to the actual default
//! value.
secinfo_clear_t ELFSourceFile::readSecinfoClearOption()
{
do {
const OptionContext * options = getOptions();
if (!options || !options->hasOption(kSecinfoClearOptionName))
{
break;
}
const Value * value = options->getOption(kSecinfoClearOptionName);
const StringValue * stringValue = dynamic_cast<const StringValue*>(value);
if (!stringValue)
{
// Not a string value, warn the user.
Log::log(Logger::WARNING, "invalid type for 'secinfoClear' option\n");
break;
}
std::string secinfoOption = *stringValue;
// convert option value to uppercase
std::transform<std::string::const_iterator, std::string::iterator, int (*)(int)>(secinfoOption.begin(), secinfoOption.end(), secinfoOption.begin(), toupper);
if (secinfoOption == kSecinfoDefaultName)
{
return kSecinfoDefault;
}
else if (secinfoOption == kSecinfoIgnoreName)
{
return kSecinfoIgnore;
}
else if (secinfoOption == kSecinfoROMName)
{
return kSecinfoROMClear;
}
else if (secinfoOption == kSecinfoCName)
{
return kSecinfoCStartupClear;
}
// Unrecognized option value, log a warning.
Log::log(Logger::WARNING, "unrecognized value for 'secinfoClear' option\n");
} while (0);
return kSecinfoDefault;
}
//! To create a data source for all sections of the ELF file, a WildcardMatcher
//! is instantiated and passed to createDataSource(StringMatcher&).
DataSource * ELFSourceFile::createDataSource()
{
WildcardMatcher matcher;
return createDataSource(matcher);
}
Log::log(Logger::DEBUG2, "filtering sections of file: %s\n", getPath().c_str());
// We start at section 1 to skip the null section that is always first.
unsigned index = 1;
for (; index < m_file->getSectionCount(); ++index)
{
const Elf32_Shdr & header = m_file->getSectionAtIndex(index);
std::string name = m_file->getSectionNameAtIndex(header.sh_name);
// Ignore most section types
if (!(header.sh_type == SHT_PROGBITS || header.sh_type == SHT_NOBITS))
{
continue;
}
// Ignore sections that don't have the allocate flag set.
if ((header.sh_flags & SHF_ALLOC) == 0)
{
continue;
}
if (matcher.match(name))
{
Log::log(Logger::DEBUG2, "creating segment for section %s\n", name.c_str());
source->addSection(index);
}
else
{
Log::log(Logger::DEBUG2, "section %s did not match\n", name.c_str());
}
}
return source;
}
//! It is assumed that all ELF files have an entry point.
//!
bool ELFSourceFile::hasEntryPoint()
{
return true;
}
//! The StELFFile::getTypeOfSymbolAtIndex() method uses different methods of determining
//! ARM/Thumb mode depending on the toolset.
uint32_t ELFSourceFile::getEntryPointAddress()
{
uint32_t entryPoint = 0;
// get entry point address
const Elf32_Ehdr & header = m_file->getFileHeader();
// find symbol corresponding to entry point and determine if
// it is arm or thumb mode
unsigned symbolIndex = m_file->getIndexOfSymbolAtAddress(header.e_entry);
if (symbolIndex != 0)
{
ARMSymbolType_t symbolType = m_file->getTypeOfSymbolAtIndex(symbolIndex);
bool entryPointIsThumb = (symbolType == eThumbSymbol);
const Elf32_Sym & symbol = m_file->getSymbolAtIndex(symbolIndex);
std::string symbolName = m_file->getSymbolName(symbol);
Log::log(Logger::DEBUG2, "Entry point is %s@0x%08x (%s)\n", symbolName.c_str(), symbol.st_value, entryPointIsThumb ? "Thumb" : "ARM");
// set entry point, setting the low bit if it is thumb mode
entryPoint = header.e_entry + (entryPointIsThumb ? 1 : 0);
}
else
{
entryPoint = header.e_entry;
}
return entryPoint;
}
//! \return A DataTarget that describes the named section.
//! \retval NULL There was no section with the requested name.
DataTarget * ELFSourceFile::createDataTargetForSection(const std::string & section)
{
assert(m_file);
unsigned index = m_file->getIndexOfSectionWithName(section);
if (index == SHN_UNDEF)
{
return NULL;
}
//! \return A DataTarget instance pointing at the requested symbol.
//! \retval NULL No symbol matching the requested name was found.
DataTarget * ELFSourceFile::createDataTargetForSymbol(const std::string & symbol)
{
assert(m_file);
unsigned symbolCount = m_file->getSymbolCount();
unsigned i;
for (i=0; i < symbolCount; ++i)
{
const Elf32_Sym & symbolHeader = m_file->getSymbolAtIndex(i);
std::string symbolName = m_file->getSymbolName(symbolHeader);
if (symbolName == name)
{
// If the symbol is a function, then we check to see if it is Thumb code and set bit 0 if so.
if (ELF32_ST_TYPE(symbolHeader.st_info) == STT_FUNC)
{
ARMSymbolType_t symbolType = m_file->getTypeOfSymbolAtIndex(i);
bool symbolIsThumb = (symbolType == eThumbSymbol);
return symbolHeader.st_value + (symbolIsThumb ? 1 : 0);
}
else
{
return symbolHeader.st_value;
}
}
}
// Couldn't find the symbol, so return 0.
return 0;
}
//! \param name The name of the symbol on which info is wanted.
//! \param[out] info Upon succssful return this is filled in with the symbol's information.
//!
//! \retval true The symbol was found and \a info is valid.
//! \retval false No symbol with \a name was found in the file.
bool ELFSourceFile::lookupSymbol(const std::string & name, Elf32_Sym & info)
{
assert(m_file);
unsigned symbolCount = m_file->getSymbolCount();
unsigned i;
for (i=0; i < symbolCount; ++i)
{
const Elf32_Sym & symbol = m_file->getSymbolAtIndex(i);
std::string thisSymbolName = m_file->getSymbolName(symbol);
// Is this the symbol we're looking for?
if (thisSymbolName == name)
{
info = symbol;
return true;
}
}
// Didn't file the symbol.
return false;
}
ELFSourceFile::ELFDataSource::~ELFDataSource()
{
segment_vector_t::iterator it = m_segments.begin();
for (; it != m_segments.end(); ++it)
{
delete *it;
}
}
//! Not all sections will actually result in a new segment being created. Only
//! those sections whose type is #SHT_PROGBITS or #SHT_NOBITS will create
//! a new segment. Also, only sections whose size is non-zero will actually
//! create a segment.
//!
//! In addition to this, ELF files that have been marked as being created by
//! the Green Hills Software toolset have an extra step. #SHT_NOBITS sections
//! are looked up in the .secinfo section to determine if they really
//! should be filled. If not in the .secinfo table, no segment will be
//! created for the section.
void ELFSourceFile::ELFDataSource::addSection(unsigned sectionIndex)
{
// get section info
const Elf32_Shdr & section = m_elf->getSectionAtIndex(sectionIndex);
if (section.sh_size == 0)
{
// empty section, so ignore it
return;
}
// create the right segment subclass based on the section type
DataSource::Segment * segment = NULL;
if (section.sh_type == SHT_PROGBITS)
{
segment = new ProgBitsSegment(*this, m_elf, sectionIndex);
}
else if (section.sh_type == SHT_NOBITS)
{
// Always add NOBITS sections by default.
bool addNobits = true;
// For GHS ELF files, we use the secinfoClear option to figure out what to do.
// If set to ignore, treat like a normal ELF file and always add. If set to
// ROM, then only clear if the section is listed in .secinfo. Otherwise if set
// to C startup, then let the C startup do all clearing.
if (m_elf->ELFVariant() == eGHSVariant)
{
GHSSecInfo secinfo(m_elf);
// If there isn't a .secinfo section present then use the normal ELF rules
// and always add NOBITS sections.
if (secinfo.hasSecinfo() && m_secinfoOption != kSecinfoIgnore)
{
switch (m_secinfoOption)
{
case kSecinfoROMClear:
addNobits = secinfo.isSectionFilled(section);
break;
case kSecinfoCStartupClear:
addNobits = false;
break;
}
}
}
if (addNobits)
{
segment = new NoBitsSegment(*this, m_elf, sectionIndex);
}
else
{
std::string name = m_elf->getSectionNameAtIndex(section.sh_name);
Log::log(Logger::DEBUG2, "..section %s is not filled\n", name.c_str());
}
}
// add segment if one was created
if (segment)
{
m_segments.push_back(segment);
}
}