Home | History | Annotate | Line # | Download | only in common
ELFSourceFile.cpp revision 1.1.4.2
      1 /*
      2  * File:	ELFSourceFile.cpp
      3  *
      4  * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
      5  * See included license file for license details.
      6  */
      7 
      8 #include "ELFSourceFile.h"
      9 #include "Logging.h"
     10 #include "GHSSecInfo.h"
     11 #include <ctype.h>
     12 #include <algorithm>
     13 #include "string.h"
     14 
     15 //! The name of the toolset option.
     16 #define kToolsetOptionName "toolset"
     17 #define kGHSToolsetName "GHS"
     18 #define kGCCToolsetName "GCC"
     19 #define kGNUToolsetName "GNU"
     20 #define kADSToolsetName "ADS"
     21 
     22 //! Name of the option to control .secinfo action.
     23 #define kSecinfoClearOptionName "secinfoClear"
     24 #define kSecinfoDefaultName "DEFAULT"
     25 #define kSecinfoIgnoreName "IGNORE"
     26 #define kSecinfoROMName "ROM"
     27 #define kSecinfoCName "C"
     28 
     29 using namespace elftosb;
     30 
     31 ELFSourceFile::ELFSourceFile(const std::string & path)
     32 :	SourceFile(path),
     33 	m_toolset(kUnknownToolset),
     34 	m_secinfoOption(kSecinfoDefault)
     35 {
     36 }
     37 
     38 ELFSourceFile::~ELFSourceFile()
     39 {
     40 }
     41 
     42 bool ELFSourceFile::isELFFile(std::istream & stream)
     43 {
     44 	try
     45 	{
     46 		StELFFile elf(stream);
     47 		return true;
     48 	}
     49 	catch (...)
     50 	{
     51 		return false;
     52 	}
     53 }
     54 
     55 void ELFSourceFile::open()
     56 {
     57 	// Read toolset option
     58 	m_toolset = readToolsetOption();
     59 
     60 	// Read option and select default value
     61 	m_secinfoOption = readSecinfoClearOption();
     62 	if (m_secinfoOption == kSecinfoDefault)
     63 	{
     64 		m_secinfoOption = kSecinfoCStartupClear;
     65 	}
     66 
     67 	// Open the stream
     68 	SourceFile::open();
     69 
     70 	m_file = new StELFFile(*m_stream);
     71 //	m_file->dumpSections();
     72 
     73 	// Set toolset in elf file object
     74 	switch (m_toolset)
     75 	{
     76         // default toolset is GHS
     77 		case kGHSToolset:
     78         case kUnknownToolset:
     79 			m_file->setELFVariant(eGHSVariant);
     80 			break;
     81 		case kGCCToolset:
     82 			m_file->setELFVariant(eGCCVariant);
     83 			break;
     84 		case kADSToolset:
     85 			m_file->setELFVariant(eARMVariant);
     86 			break;
     87 	}
     88 }
     89 
     90 void ELFSourceFile::close()
     91 {
     92 	SourceFile::close();
     93 
     94 	m_file.safe_delete();
     95 }
     96 
     97 elf_toolset_t ELFSourceFile::readToolsetOption()
     98 {
     99 	do {
    100 		const OptionContext * options = getOptions();
    101 		if (!options || !options->hasOption(kToolsetOptionName))
    102 		{
    103 			break;
    104 		}
    105 
    106 		const Value * value = options->getOption(kToolsetOptionName);
    107 		const StringValue * stringValue = dynamic_cast<const StringValue*>(value);
    108 		if (!stringValue)
    109 		{
    110 			// Not a string value, warn the user.
    111 			Log::log(Logger::WARNING, "invalid type for 'toolset' option\n");
    112 			break;
    113 		}
    114 
    115 		std::string toolsetName = *stringValue;
    116 
    117 		// convert option value to uppercase
    118 		std::transform<std::string::const_iterator, std::string::iterator, int (*)(int)>(toolsetName.begin(), toolsetName.end(), toolsetName.begin(), toupper);
    119 
    120 		if (toolsetName == kGHSToolsetName)
    121 		{
    122 			return kGHSToolset;
    123 		}
    124 		else if (toolsetName == kGCCToolsetName || toolsetName == kGNUToolsetName)
    125 		{
    126 			return kGCCToolset;
    127 		}
    128 		else if (toolsetName == kADSToolsetName)
    129 		{
    130 			return kADSToolset;
    131 		}
    132 
    133 		// Unrecognized option value, log a warning.
    134 		Log::log(Logger::WARNING, "unrecognized value for 'toolset' option\n");
    135 	} while (0);
    136 
    137 	return kUnknownToolset;
    138 }
    139 
    140 //! It is up to the caller to convert from kSecinfoDefault to the actual default
    141 //! value.
    142 secinfo_clear_t ELFSourceFile::readSecinfoClearOption()
    143 {
    144 	do {
    145 		const OptionContext * options = getOptions();
    146 		if (!options || !options->hasOption(kSecinfoClearOptionName))
    147 		{
    148 			break;
    149 		}
    150 
    151 		const Value * value = options->getOption(kSecinfoClearOptionName);
    152 		const StringValue * stringValue = dynamic_cast<const StringValue*>(value);
    153 		if (!stringValue)
    154 		{
    155 			// Not a string value, warn the user.
    156 			Log::log(Logger::WARNING, "invalid type for 'secinfoClear' option\n");
    157 			break;
    158 		}
    159 
    160 		std::string secinfoOption = *stringValue;
    161 
    162 		// convert option value to uppercase
    163 		std::transform<std::string::const_iterator, std::string::iterator, int (*)(int)>(secinfoOption.begin(), secinfoOption.end(), secinfoOption.begin(), toupper);
    164 
    165 		if (secinfoOption == kSecinfoDefaultName)
    166 		{
    167 			return kSecinfoDefault;
    168 		}
    169 		else if (secinfoOption == kSecinfoIgnoreName)
    170 		{
    171 			return kSecinfoIgnore;
    172 		}
    173 		else if (secinfoOption == kSecinfoROMName)
    174 		{
    175 			return kSecinfoROMClear;
    176 		}
    177 		else if (secinfoOption == kSecinfoCName)
    178 		{
    179 			return kSecinfoCStartupClear;
    180 		}
    181 
    182 		// Unrecognized option value, log a warning.
    183 		Log::log(Logger::WARNING, "unrecognized value for 'secinfoClear' option\n");
    184 	} while (0);
    185 
    186 	return kSecinfoDefault;
    187 }
    188 
    189 //! To create a data source for all sections of the ELF file, a WildcardMatcher
    190 //! is instantiated and passed to createDataSource(StringMatcher&).
    191 DataSource * ELFSourceFile::createDataSource()
    192 {
    193 	WildcardMatcher matcher;
    194 	return createDataSource(matcher);
    195 }
    196 
    197 DataSource * ELFSourceFile::createDataSource(StringMatcher & matcher)
    198 {
    199 	assert(m_file);
    200 	ELFDataSource * source = new ELFDataSource(m_file);
    201 	source->setSecinfoOption(m_secinfoOption);
    202 
    203 	Log::log(Logger::DEBUG2, "filtering sections of file: %s\n", getPath().c_str());
    204 
    205 	// We start at section 1 to skip the null section that is always first.
    206 	unsigned index = 1;
    207 	for (; index < m_file->getSectionCount(); ++index)
    208 	{
    209 		const Elf32_Shdr & header = m_file->getSectionAtIndex(index);
    210 		std::string name = m_file->getSectionNameAtIndex(header.sh_name);
    211 
    212 		// Ignore most section types
    213 		if (!(header.sh_type == SHT_PROGBITS || header.sh_type == SHT_NOBITS))
    214 		{
    215 			continue;
    216 		}
    217 
    218 		// Ignore sections that don't have the allocate flag set.
    219 		if ((header.sh_flags & SHF_ALLOC) == 0)
    220 		{
    221 			continue;
    222 		}
    223 
    224 		if (matcher.match(name))
    225 		{
    226 			Log::log(Logger::DEBUG2, "creating segment for section %s\n", name.c_str());
    227 			source->addSection(index);
    228 		}
    229 		else
    230 		{
    231 			Log::log(Logger::DEBUG2, "section %s did not match\n", name.c_str());
    232 		}
    233 	}
    234 
    235 	return source;
    236 }
    237 
    238 //! It is assumed that all ELF files have an entry point.
    239 //!
    240 bool ELFSourceFile::hasEntryPoint()
    241 {
    242 	return true;
    243 }
    244 
    245 //! The StELFFile::getTypeOfSymbolAtIndex() method uses different methods of determining
    246 //! ARM/Thumb mode depending on the toolset.
    247 uint32_t ELFSourceFile::getEntryPointAddress()
    248 {
    249 	uint32_t entryPoint = 0;
    250 
    251 	// get entry point address
    252 	const Elf32_Ehdr & header = m_file->getFileHeader();
    253 
    254 	// find symbol corresponding to entry point and determine if
    255 	// it is arm or thumb mode
    256 	unsigned symbolIndex = m_file->getIndexOfSymbolAtAddress(header.e_entry);
    257 	if (symbolIndex != 0)
    258 	{
    259 		ARMSymbolType_t symbolType = m_file->getTypeOfSymbolAtIndex(symbolIndex);
    260 		bool entryPointIsThumb = (symbolType == eThumbSymbol);
    261 		const Elf32_Sym & symbol = m_file->getSymbolAtIndex(symbolIndex);
    262 		std::string symbolName = m_file->getSymbolName(symbol);
    263 
    264 		Log::log(Logger::DEBUG2, "Entry point is %s@0x%08x (%s)\n", symbolName.c_str(), symbol.st_value, entryPointIsThumb ? "Thumb" : "ARM");
    265 
    266 		// set entry point, setting the low bit if it is thumb mode
    267 		entryPoint = header.e_entry + (entryPointIsThumb ? 1 : 0);
    268 	}
    269 	else
    270 	{
    271 		entryPoint = header.e_entry;
    272 	}
    273 
    274 	return entryPoint;
    275 }
    276 
    277 //! \return A DataTarget that describes the named section.
    278 //! \retval NULL There was no section with the requested name.
    279 DataTarget * ELFSourceFile::createDataTargetForSection(const std::string & section)
    280 {
    281 	assert(m_file);
    282 	unsigned index = m_file->getIndexOfSectionWithName(section);
    283 	if (index == SHN_UNDEF)
    284 	{
    285 		return NULL;
    286 	}
    287 
    288 	const Elf32_Shdr & sectionHeader = m_file->getSectionAtIndex(index);
    289 	uint32_t beginAddress = sectionHeader.sh_addr;
    290 	uint32_t endAddress = beginAddress + sectionHeader.sh_size;
    291 	ConstantDataTarget * target = new ConstantDataTarget(beginAddress, endAddress);
    292 	return target;
    293 }
    294 
    295 //! \return A DataTarget instance pointing at the requested symbol.
    296 //! \retval NULL No symbol matching the requested name was found.
    297 DataTarget * ELFSourceFile::createDataTargetForSymbol(const std::string & symbol)
    298 {
    299 	assert(m_file);
    300 	unsigned symbolCount = m_file->getSymbolCount();
    301 	unsigned i;
    302 
    303 	for (i=0; i < symbolCount; ++i)
    304 	{
    305 		const Elf32_Sym & symbolHeader = m_file->getSymbolAtIndex(i);
    306 		std::string symbolName = m_file->getSymbolName(symbolHeader);
    307 		if (symbolName == symbol)
    308 		{
    309             ARMSymbolType_t symbolType = m_file->getTypeOfSymbolAtIndex(i);
    310             bool symbolIsThumb = (symbolType == eThumbSymbol);
    311 
    312 			uint32_t beginAddress = symbolHeader.st_value + (symbolIsThumb ? 1 : 0);
    313 			uint32_t endAddress = beginAddress + symbolHeader.st_size;
    314 			ConstantDataTarget * target = new ConstantDataTarget(beginAddress, endAddress);
    315 			return target;
    316 		}
    317 	}
    318 
    319 	// didn't find a matching symbol
    320 	return NULL;
    321 }
    322 
    323 bool ELFSourceFile::hasSymbol(const std::string & name)
    324 {
    325 	Elf32_Sym symbol;
    326 	return lookupSymbol(name, symbol);
    327 }
    328 
    329 uint32_t ELFSourceFile::getSymbolValue(const std::string & name)
    330 {
    331 	unsigned symbolCount = m_file->getSymbolCount();
    332 	unsigned i;
    333 
    334 	for (i=0; i < symbolCount; ++i)
    335 	{
    336 		const Elf32_Sym & symbolHeader = m_file->getSymbolAtIndex(i);
    337 		std::string symbolName = m_file->getSymbolName(symbolHeader);
    338 		if (symbolName == name)
    339 		{
    340             // If the symbol is a function, then we check to see if it is Thumb code and set bit 0 if so.
    341             if (ELF32_ST_TYPE(symbolHeader.st_info) == STT_FUNC)
    342             {
    343                 ARMSymbolType_t symbolType = m_file->getTypeOfSymbolAtIndex(i);
    344                 bool symbolIsThumb = (symbolType == eThumbSymbol);
    345                 return symbolHeader.st_value + (symbolIsThumb ? 1 : 0);
    346             }
    347             else
    348             {
    349 			    return symbolHeader.st_value;
    350             }
    351 		}
    352 	}
    353 
    354     // Couldn't find the symbol, so return 0.
    355 	return 0;
    356 }
    357 
    358 unsigned ELFSourceFile::getSymbolSize(const std::string & name)
    359 {
    360 	Elf32_Sym symbol;
    361 	if (!lookupSymbol(name, symbol))
    362 	{
    363 		return 0;
    364 	}
    365 
    366 	return symbol.st_size;
    367 }
    368 
    369 //! \param name The name of the symbol on which info is wanted.
    370 //! \param[out] info Upon succssful return this is filled in with the symbol's information.
    371 //!
    372 //! \retval true The symbol was found and \a info is valid.
    373 //! \retval false No symbol with \a name was found in the file.
    374 bool ELFSourceFile::lookupSymbol(const std::string & name, Elf32_Sym & info)
    375 {
    376 	assert(m_file);
    377 	unsigned symbolCount = m_file->getSymbolCount();
    378 	unsigned i;
    379 
    380 	for (i=0; i < symbolCount; ++i)
    381 	{
    382 		const Elf32_Sym & symbol = m_file->getSymbolAtIndex(i);
    383 		std::string thisSymbolName = m_file->getSymbolName(symbol);
    384 
    385 		// Is this the symbol we're looking for?
    386 		if (thisSymbolName == name)
    387 		{
    388 			info = symbol;
    389 			return true;
    390 		}
    391 	}
    392 
    393 	// Didn't file the symbol.
    394 	return false;
    395 }
    396 
    397 ELFSourceFile::ELFDataSource::~ELFDataSource()
    398 {
    399 	segment_vector_t::iterator it = m_segments.begin();
    400 	for (; it != m_segments.end(); ++it)
    401 	{
    402 		delete *it;
    403 	}
    404 }
    405 
    406 //! Not all sections will actually result in a new segment being created. Only
    407 //! those sections whose type is #SHT_PROGBITS or #SHT_NOBITS will create
    408 //! a new segment. Also, only sections whose size is non-zero will actually
    409 //! create a segment.
    410 //!
    411 //! In addition to this, ELF files that have been marked as being created by
    412 //! the Green Hills Software toolset have an extra step. #SHT_NOBITS sections
    413 //! are looked up in the .secinfo section to determine if they really
    414 //! should be filled. If not in the .secinfo table, no segment will be
    415 //! created for the section.
    416 void ELFSourceFile::ELFDataSource::addSection(unsigned sectionIndex)
    417 {
    418 	// get section info
    419 	const Elf32_Shdr & section = m_elf->getSectionAtIndex(sectionIndex);
    420 	if (section.sh_size == 0)
    421 	{
    422 		// empty section, so ignore it
    423 		return;
    424 	}
    425 
    426 	// create the right segment subclass based on the section type
    427 	DataSource::Segment * segment = NULL;
    428 	if (section.sh_type == SHT_PROGBITS)
    429 	{
    430 		segment = new ProgBitsSegment(*this, m_elf, sectionIndex);
    431 	}
    432 	else if (section.sh_type == SHT_NOBITS)
    433 	{
    434 		// Always add NOBITS sections by default.
    435 		bool addNobits = true;
    436 
    437 		// For GHS ELF files, we use the secinfoClear option to figure out what to do.
    438 		// If set to ignore, treat like a normal ELF file and always add. If set to
    439 		// ROM, then only clear if the section is listed in .secinfo. Otherwise if set
    440 		// to C startup, then let the C startup do all clearing.
    441 		if (m_elf->ELFVariant() == eGHSVariant)
    442 		{
    443 			GHSSecInfo secinfo(m_elf);
    444 
    445 			// If there isn't a .secinfo section present then use the normal ELF rules
    446 			// and always add NOBITS sections.
    447 			if (secinfo.hasSecinfo() && m_secinfoOption != kSecinfoIgnore)
    448 			{
    449 				switch (m_secinfoOption)
    450 				{
    451 					case kSecinfoROMClear:
    452 						addNobits = secinfo.isSectionFilled(section);
    453 						break;
    454 
    455 					case kSecinfoCStartupClear:
    456 						addNobits = false;
    457 						break;
    458 				}
    459 			}
    460 		}
    461 
    462 		if (addNobits)
    463 		{
    464 			segment = new NoBitsSegment(*this, m_elf, sectionIndex);
    465 		}
    466 		else
    467 		{
    468 			std::string name = m_elf->getSectionNameAtIndex(section.sh_name);
    469 			Log::log(Logger::DEBUG2, "..section %s is not filled\n", name.c_str());
    470 		}
    471 	}
    472 
    473 	// add segment if one was created
    474 	if (segment)
    475 	{
    476 		m_segments.push_back(segment);
    477 	}
    478 }
    479 
    480 ELFSourceFile::ELFDataSource::ProgBitsSegment::ProgBitsSegment(ELFDataSource & source, StELFFile * elf, unsigned index)
    481 :	DataSource::Segment(source), m_elf(elf), m_sectionIndex(index)
    482 {
    483 }
    484 
    485 unsigned ELFSourceFile::ELFDataSource::ProgBitsSegment::getData(unsigned offset, unsigned maxBytes, uint8_t * buffer)
    486 {
    487 	const Elf32_Shdr & section = m_elf->getSectionAtIndex(m_sectionIndex);
    488 	uint8_t * data = m_elf->getSectionDataAtIndex(m_sectionIndex);
    489 
    490 	assert(offset < section.sh_size);
    491 
    492 	unsigned copyBytes = std::min<unsigned>(section.sh_size - offset, maxBytes);
    493 	if (copyBytes)
    494 	{
    495 		memcpy(buffer, &data[offset], copyBytes);
    496 	}
    497 
    498 	return copyBytes;
    499 }
    500 
    501 unsigned ELFSourceFile::ELFDataSource::ProgBitsSegment::getLength()
    502 {
    503 	const Elf32_Shdr & section = m_elf->getSectionAtIndex(m_sectionIndex);
    504 	return section.sh_size;
    505 }
    506 
    507 uint32_t ELFSourceFile::ELFDataSource::ProgBitsSegment::getBaseAddress()
    508 {
    509 	const Elf32_Shdr & section = m_elf->getSectionAtIndex(m_sectionIndex);
    510 	return section.sh_addr;
    511 }
    512 
    513 ELFSourceFile::ELFDataSource::NoBitsSegment::NoBitsSegment(ELFDataSource & source, StELFFile * elf, unsigned index)
    514 :	DataSource::PatternSegment(source), m_elf(elf), m_sectionIndex(index)
    515 {
    516 }
    517 
    518 unsigned ELFSourceFile::ELFDataSource::NoBitsSegment::getLength()
    519 {
    520 	const Elf32_Shdr & section = m_elf->getSectionAtIndex(m_sectionIndex);
    521 	return section.sh_size;
    522 }
    523 
    524 uint32_t ELFSourceFile::ELFDataSource::NoBitsSegment::getBaseAddress()
    525 {
    526 	const Elf32_Shdr & section = m_elf->getSectionAtIndex(m_sectionIndex);
    527 	return section.sh_addr;
    528 }
    529 
    530