e32tools/elf2e32/source/pl_elfexecutable.cpp
author Mike Kinghan <mikek@symbian.org>
Thu, 25 Nov 2010 13:59:07 +0000
changeset 40 68f68128601f
parent 27 3a31ca4b29c4
permissions -rwxr-xr-x
1) Add the sbsv1 components from sftools/dev/build to make the linux_build package independent of the obsolete buildtools package. 2) Enhance romnibus.pl so that it generate the symbol file for the built rom when invoked by Raptor 3) Make the maksym.pl tool portable for Linux as well as Windows. 4) Remove the of armasm2as.pl from the e32tools component in favour of the copy now exported from sbsv1/e32util.

// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// Implementation of the Class ElfExecutable for the elf2e32 tool
// @internalComponent
// @released
// 
//


#include "pl_elfexecutable.h"
#include "errorhandler.h"
#include <stdio.h>
#include "parameterlistinterface.h"
#include "pl_elfimportrelocation.h"
#include "pl_dllsymbol.h"
#include "messagehandler.h"
#include "pl_elflocalrelocation.h"


/**
Constructor for class ElfExecutable
@param aParameterListInterface - Instance of class ParameterListInterface
@internalComponent
@released
*/
ElfExecutable::ElfExecutable(ParameterListInterface *aParameterListInterface) :\
	iElfHeader(NULL), \
	iEntryPoint(0),\
	iProgHeader(NULL), \
	iSONameOffset(0) ,\
	iSections (NULL) , \
	iVersionDef (NULL) , iVerDefCount(0), \
	iVersionNeed (NULL) , iVerNeedCount(0), \
	iVersionTbl (NULL) ,iRelSize(0),iRelEntSize(0), \
	iNRelocs(0),
	iRel (NULL) ,iRelaSize(0), iRelaEntSize(0), \
	iRela(NULL), 
	iStringTable (NULL) , \
	iSectionHdrStrTbl(NULL), \
	iVerInfo(NULL),	iElfDynSym (NULL), \
	iSymTab (NULL), \
	iStrTab (NULL), \
	iLim (NULL), \
	iNSymbols(0), \
	iHashTbl (NULL) , \
	iDynSegmentHdr (NULL) , \
	iDataSegmentHdr (NULL) ,iDataSegment(NULL), iDataSegmentSize(0), iDataSegmentIdx(0), \
	iCodeSegmentHdr (NULL) , iCodeSegment(NULL), iCodeSegmentSize(0), iCodeSegmentIdx(0), \
	iExports (NULL), \
	iParameterListInterface(aParameterListInterface),\
	iPltGotBase(0), iPltGotLimit(0), iStrTabSz(0), iSymEntSz(0), \
	iPltGot(NULL), iPltRel(NULL),iPltRelaSz(0), iPltRela(NULL), iPltRelSz(0)  \

{
}


/**
Destructor for class ElfExecutable
@internalComponent
@released
*/
ElfExecutable::~ElfExecutable()
{
	delete iExports;
	delete [] iVerInfo;
	/* 
	all of these were getting deleted, they are not allocated by 
	ElfExecutable, they simply refer to a linear array of images 
	in an ElfImage, hence they shouldn't be de-allocated 
	
	delete iRela;
	delete iPltRel;
	delete iPltRela; */ 

	iNeeded.clear();
	iSymbolTable.clear();
}


/**
Function to process Elf file
@param aElfHdr - pointer to Elf header
@return 0 if its valid ELF file
@internalComponent
@released
*/
PLUINT32  ElfExecutable::ProcessElfFile(Elf32_Ehdr *aElfHdr) {

	iElfHeader = aElfHdr;
	iEntryPoint = aElfHdr->e_entry;

	ValidateElfFile();

	/* A valid ELF file so far..*/

	/* Get the Section base..*/
	if(iElfHeader->e_shnum) {
		iSections = ELF_ENTRY_PTR(Elf32_Shdr, iElfHeader, iElfHeader->e_shoff); 
	}

	/* Get the program header..*/
	if(iElfHeader->e_phnum) {
		iProgHeader = ELF_ENTRY_PTR(Elf32_Phdr, iElfHeader, iElfHeader->e_phoff);
	}

	/* Get the section-header-string table..*/
	if(iElfHeader->e_shstrndx != SHN_UNDEF) {

		if(iElfHeader->e_shstrndx > iElfHeader->e_shnum ) {
			throw ELFFormatError(ELFSHSTRINDEXERROR,iParameterListInterface->ElfInput());
		}

		iSectionHdrStrTbl = ELF_ENTRY_PTR(char, iElfHeader, iSections[iElfHeader->e_shstrndx].sh_offset);
	}

	if( iProgHeader ) {
		PLUINT32 aIdx = 0;

		while( aIdx < iElfHeader->e_phnum) {
			switch( iProgHeader[aIdx].p_type ) {
			case PT_DYNAMIC:
				{
					iDynSegmentHdr = &iProgHeader[aIdx];
				}
				break;
			case PT_LOAD:
				{
					if( (iProgHeader[aIdx].p_flags) & (PF_X | PF_ARM_ENTRY) ) {
						iCodeSegmentHdr = &iProgHeader[aIdx];
						iCodeSegmentIdx = aIdx;
						iCodeSegment = ELF_ENTRY_PTR(char, iElfHeader, iCodeSegmentHdr->p_offset);
						iCodeSegmentSize = iCodeSegmentHdr->p_filesz;
					}
					else if( (iProgHeader[aIdx].p_flags) & (PF_W | PF_R) ) {
						iDataSegmentHdr = &iProgHeader[aIdx];
						iDataSegmentIdx = aIdx;
						iDataSegment = ELF_ENTRY_PTR(char, iElfHeader, iDataSegmentHdr->p_offset);
						iDataSegmentSize = iDataSegmentHdr->p_filesz;
					}
				}
				break;
			default:
				break;

			}
			aIdx++;
		}

		if( iDynSegmentHdr ) {
			ProcessDynamicEntries();
		}

		ProcessSymbols();
		ProcessRelocations();
	}

	return 0;
}

/**
Function to Find the Static Symbol Table
@internalComponent
@released
*/
void ElfExecutable::FindStaticSymbolTable()
{
	size_t nShdrs = iElfHeader->e_shnum;

	if (nShdrs)
	{
		// Find the static symbol table and string table
		for (PLUINT32 i = 0; i < nShdrs; i++)
		{
			if (iSections[i].sh_type == SHT_SYMTAB)
			{
				iSymTab = ELF_ENTRY_PTR(Elf32_Sym, iElfHeader, iSections[i].sh_offset);
				iLim = ELF_ENTRY_PTR(Elf32_Sym, iSymTab, iSections[i].sh_size);
				if (iStrTab) break;
			}
			else if (iSections[i].sh_type == SHT_STRTAB)
			{
				char * aSectionName = iSectionHdrStrTbl + iSections[i].sh_name;
				if (!strcmp(aSectionName, ".strtab"))
				{
					iStrTab = ELF_ENTRY_PTR(char, iElfHeader, iSections[i].sh_offset);
					if (iSymTab) break;
				}
			}
		}
	}
}

/**
Function to Find the Comment Section
@return aComment - Pointer to Comment Section
@internalComponent
@released
*/
char* ElfExecutable::FindCommentSection()
{
	size_t nShdrs = iElfHeader->e_shnum;
	char *aCommentSection = ".comment";
	char *aComment;

	if (nShdrs)
	{
		// find the comment section
		for (PLUINT32 i = 0; i < nShdrs; i++)
		{
			if (iSections[i].sh_type == SHT_PROGBITS)
			{
				char * aSectionName = iSectionHdrStrTbl + iSections[i].sh_name;
				int length = strlen(aCommentSection);
				if (!strncmp(aSectionName, aCommentSection, length))
				{
					aComment = ELF_ENTRY_PTR(char, iElfHeader, iSections[i].sh_offset);
					return aComment;
				}
			}
		}
	}
	return NULL;
}

/**
Function to process the ARM to Thumb veneers
@internalComponent
@released
*/
void ElfExecutable::ProcessVeneers()
{
	if (iSymTab && iStrTab)
	{	
		ElfRelocations::RelocationList & iLocalCodeRelocs = GetCodeRelocations();

		Elf32_Sym *aSymTab = iSymTab;
		int length = strlen("$Ven$AT$L$$");

		// Process the symbol table to find Long ARM to Thumb Veneers
		// i.e. symbols of the form '$Ven$AT$L$$'
		for(; aSymTab < iLim; aSymTab++)
		{
			if (!aSymTab->st_name) continue;
			char * aSymName = iStrTab + aSymTab->st_name;
			Elf32_Sym	*aSym;

			if (!strncmp(aSymName, "$Ven$AT$L$$", length))
			{
				aSym = aSymTab;
				Elf32_Addr r_offset = aSym->st_value;
				Elf32_Addr aOffset = r_offset + 4;
				Elf32_Word	aInstruction = FindValueAtLoc(r_offset);
				bool aRelocEntryFound = false;

				ElfRelocations::RelocationList::iterator r;
				for (r = iLocalCodeRelocs.begin(); r != iLocalCodeRelocs.end(); r++)
				{
					ElfLocalRelocation * aReloc = *r;
					// Check if there is a relocation entry for the veneer symbol
					if (aReloc->iAddr == aOffset)
					{
						aRelocEntryFound = true;
						break;
					}
				}

				Elf32_Word aPointer = FindValueAtLoc(aOffset);

				/* If the symbol addresses a Thumb instruction, its value is the
				 * address of the instruction with bit zero set (in a
				 * relocatable object, the section offset with bit zero set).
				 * This allows a linker to distinguish ARM and Thumb code symbols 
				 * without having to refer to the map. An ARM symbol will always have 
				 * an even value, while a Thumb symbol will always have an odd value.
				 * Reference: Section 4.5.3 in Elf for the ARM Architecture Doc
				 * aIsThumbSymbol will be 1 for a thumb symbol and 0 for ARM symbol
				 */
				int aIsThumbSymbol = aPointer & 0x1;

				/* The relocation entry should be generated for the veneer only if
				 * the following three conditions are satisfied:
				 * 1) Check if the instruction at the symbol is as expected 
				 *    i.e. has the bit pattern 0xe51ff004 == 'LDR pc,[pc,#-4]'
				 * 2) There is no relocation entry generated for the veneer symbol
				 * 3) The instruction in the location provided by the pointer is a thumb symbol
				 */
				if (aInstruction == 0xE51FF004 && !aRelocEntryFound && aIsThumbSymbol)
				{
					ElfLocalRelocation	*aRel;
					PLUCHAR	aType = R_ARM_NONE;

					aRel = new ElfLocalRelocation(this, aOffset, 0, 0, aType, NULL, ESegmentRO, aSym, false, true);
					if(aRel) 
					{
						aRel->Add();
					}
				}
			}
		}
	}
}

/**
Function to find the content of the address passed in
@param aOffset - Address
@return aLocVal - The content of the address, like instruction or a pointer
@internalComponent
@released
*/
Elf32_Word	ElfExecutable::FindValueAtLoc(Elf32_Addr aOffset)
{
	Elf32_Phdr  *aHdr = Segment(aOffset);
	PLUINT32 aLoc = aHdr->p_offset + aOffset - aHdr->p_vaddr;
	Elf32_Word	*aLocVal = ELF_ENTRY_PTR(Elf32_Word, iElfHeader, aLoc);
	return *aLocVal;
}

/**
Function to process Elf symbols
@internalComponent
@released
*/
PLUINT32  ElfExecutable::ProcessSymbols(){
	PLUINT32	aSymIdx = 0;
	DllSymbol	*aSymbol;
	char		*aDllName;
	char		*aSymName, *aNewSymName;
	SymbolType	aType;
	
	while( aSymIdx < iNSymbols ) {
		
		aSymName = ELF_ENTRY_PTR(char, iStringTable, iElfDynSym[aSymIdx].st_name );

		if( ExportedSymbol( &iElfDynSym[aSymIdx] ) ){

			if( FunctionSymbol( &iElfDynSym[aSymIdx] ))
				aType = SymbolTypeCode;
			else
				aType = SymbolTypeData;

			aSymName = ELF_ENTRY_PTR(char, iStringTable, iElfDynSym[aSymIdx].st_name );
			aDllName = iVerInfo[iVersionTbl[aSymIdx]].iLinkAs;
			aNewSymName = new char[strlen(aSymName)+1];
			strcpy(aNewSymName, aSymName);
			aSymbol = new DllSymbol( aNewSymName, aType, &iElfDynSym[aSymIdx], aSymIdx);
			aSymbol->SetSymbolSize(iElfDynSym[aSymIdx].st_size);
			
			//Putting the symbols into a hash table - Used later while processing relocations
			iSymbolTable[aSymIdx] = aSymbol ;
			if( !AddToExports( aDllName, aSymbol ))
			{
				//Not a valid export... delete it..
				delete aSymbol;
			}
		}
		else if( ImportedSymbol( &iElfDynSym[aSymIdx] ) ){

			if( FunctionSymbol( &iElfDynSym[aSymIdx] ))
				aType = SymbolTypeCode;
			else
				aType = SymbolTypeData;

			aSymName = ELF_ENTRY_PTR(char, iStringTable, iElfDynSym[aSymIdx].st_name );

			/*
			 * All imported symbols must be informed via the version needed information.
			 */
			if( iVerInfo[iVersionTbl[aSymIdx]].iVerCategory != VER_CAT_NEEDED ) {
				throw UndefinedSymbolError(UNDEFINEDSYMBOLERROR, iParameterListInterface->ElfInput(), aSymName);
			}
			aDllName = iVerInfo[iVersionTbl[aSymIdx]].iLinkAs;
			//aSymbol = new DllSymbol( aSymName, aType, &iElfDynSym[aSymIdx], aSymIdx);
			
			//Putting the symbols into a hash table
			//iSymbolTable[aSymIdx] = aSymbol ;
		}
		aSymIdx++;
	}

	return 0;
}

/**
This function Dump all the sections with their section details (i.e., the section name, type,
size and linked section if any)
@param aFile - ELF file name
@internalComponent
@released
*/
void ElfExecutable::DumpElfFile(char* aFile){
	aFile = aFile;
}


/**
This function adds exports into the export list
@param aDll - Dll name
@param aSymbol - Symbol
@return
@internalComponent
@released
*/
DllSymbol* ElfExecutable::AddToExports(char* aDll, DllSymbol* aSymbol){
	if( !iExports ) {
		iExports = new ElfExports();
	}
	return iExports->Add( aDll, this, aSymbol );
}


/**
This function adds imports into the map
@param aReloc - Instance of class ElfImportRelocation
@internalComponent
@released
*/
void  ElfExecutable::AddToImports(ElfImportRelocation* aReloc){
	SetVersionRecord(aReloc);
	//char *aDll = iVerInfo[iVersionTbl[aReloc->iSymNdx]].iLinkAs;
	char *aDll = aReloc->iVerRecord->iLinkAs;
	iImports.Add( (const char*)aDll, aReloc );
		
}

/**
This function adds local relocation into a list
@param aReloc - Instance of class ElfImportRelocation
@internalComponent
@released
*/
void ElfExecutable::AddToLocalRelocations(ElfRelocation* aReloc) {
	iLocalRelocations.Add((ElfLocalRelocation*)aReloc);
}

/**
This function records the version of an imported symbol
@param aReloc - Instance of class ElfImportRelocation
@internalComponent
@released
*/
void ElfExecutable::SetVersionRecord( ElfRelocation* aReloc ) {
	if( !aReloc )
		return;
	((ElfImportRelocation*)aReloc)->iVerRecord = &iVerInfo[ iVersionTbl[aReloc->iSymNdx]];
}

/**
This function validates the ELF file
@internalComponent
@released
*/
PLUINT32  ElfExecutable::ValidateElfFile() {

	/*Check if the ELF-Magic is correct*/
	if(!(iElfHeader->e_ident[EI_MAG0] == ELFMAG0) &&
		(iElfHeader->e_ident[EI_MAG1] == ELFMAG1) &&
		(iElfHeader->e_ident[EI_MAG2] == ELFMAG2) &&
		(iElfHeader->e_ident[EI_MAG3] == ELFMAG3) ) {
			throw ELFFormatError(ELFMAGICERROR, iParameterListInterface->ElfInput());
	}

	/*32-bit ELF file*/
	if(iElfHeader->e_ident[EI_CLASS] != ELFCLASS32) {
		throw ELFFormatError(ELFCLASSERROR, iParameterListInterface->ElfInput());
	}

	/* Check if the ELF file is in Little endian format*/
	if(iElfHeader->e_ident[EI_DATA] != ELFDATA2LSB) {
		throw ELFFormatError(ELFLEERROR, iParameterListInterface->ElfInput());
	}

	/* The ELF executable must be a DLL or an EXE*/
	if( iElfHeader->e_type != ET_EXEC && iElfHeader->e_type != ET_DYN) {
		throw ELFFormatError(ELFEXECUTABLEERROR, iParameterListInterface->ElfInput());
	}

	return 0;
}


/**
This function processes the dynamic table.
@internalComponent
@released
*/
PLUINT32  ElfExecutable::ProcessDynamicEntries(){

	PLUINT32 aIdx = 0;
	bool aSONameFound = false;
	bool aPltRelTypeSeen = false, aJmpRelSeen = false;
	list<PLUINT32>	aNeeded;
	Elf32_Dyn *aDyn = ELF_ENTRY_PTR(Elf32_Dyn, iElfHeader, iDynSegmentHdr->p_offset);

	while( aDyn[aIdx].d_tag != DT_NULL ) {
		switch (aDyn[aIdx].d_tag) {
		case DT_NEEDED:
			aNeeded.push_back( aDyn[aIdx].d_val );
			break;
		case DT_HASH:
			iHashTbl = ELF_ENTRY_PTR(Elf32_HashTable, iElfHeader, aDyn[aIdx].d_val);
			break;
		case DT_STRTAB:
			iStringTable = ELF_ENTRY_PTR(char, iElfHeader, aDyn[aIdx].d_val);
			break;
		case DT_SYMTAB:
			iElfDynSym = ELF_ENTRY_PTR(Elf32_Sym, iElfHeader, aDyn[aIdx].d_val);
			break;
		case DT_RELA:
			iRela = ELF_ENTRY_PTR(Elf32_Rela, iElfHeader, aDyn[aIdx].d_val);
			break;
		case DT_RELASZ:
			iRelaSize = aDyn[aIdx].d_val;
			break;
		case DT_RELAENT:
			iRelaEntSize = aDyn[aIdx].d_val;
			break;
		case DT_SONAME:
			aSONameFound = true;
			iSONameOffset = aDyn[aIdx].d_val;
			break;
		case DT_REL:
			iRel = ELF_ENTRY_PTR(Elf32_Rel, iElfHeader, aDyn[aIdx].d_val);
			break;
		case DT_RELSZ:
			iRelSize = aDyn[aIdx].d_val;
			break;
		case DT_RELENT:
			iRelEntSize = aDyn[aIdx].d_val;
			break;
		case DT_VERSYM:
			iVersionTbl = ELF_ENTRY_PTR(Elf32_Half, iElfHeader, aDyn[aIdx].d_val);
			break;
		case DT_VERDEF:
			iVersionDef = ELF_ENTRY_PTR(Elf32_Verdef, iElfHeader, aDyn[aIdx].d_val);
			break;
		case DT_VERDEFNUM:
			iVerDefCount = aDyn[aIdx].d_val;
			break;
		case DT_VERNEED:
			iVersionNeed = ELF_ENTRY_PTR(Elf32_Verneed, iElfHeader, aDyn[aIdx].d_val);
			break;
		case DT_VERNEEDNUM:
			iVerNeedCount = aDyn[aIdx].d_val;
			break;
		case DT_STRSZ:
			iStrTabSz = aDyn[aIdx].d_val;
			break;
		case DT_SYMENT:
			iSymEntSz = aDyn[aIdx].d_val;
			break;
		case DT_PLTRELSZ:
			iPltRelSz = aDyn[aIdx].d_val;
			break;
		case DT_PLTGOT:
			iPltGot = ELF_ENTRY_PTR(Elf32_Word, iElfHeader, aDyn[aIdx].d_val);
			break;
		case DT_RPATH:
			break;
		case DT_SYMBOLIC:
			break;
		case DT_INIT:
			break;
		case DT_FINI:
			break;
		case DT_PLTREL:
			aPltRelTypeSeen = true;
			iPltRelType = aDyn[aIdx].d_val;
			break;
		case DT_DEBUG:
			break;
		case DT_TEXTREL:
			break;
		case DT_JMPREL:
			aJmpRelSeen = true;
			iJmpRelOffset = aDyn[aIdx].d_val;
			break;
		case DT_BIND_NOW:
			break;
		case DT_INIT_ARRAY:
			break;
		case DT_FINI_ARRAY:
			break;
		case DT_INIT_ARRAYSZ:
			break;
		case DT_FINI_ARRAYSZ:
			break;
		case DT_RELCOUNT:
			break;
		case DT_ARM_PLTGOTBASE:
			iPltGotBase = aDyn[aIdx].d_val;
			break;
		case DT_ARM_PLTGOTLIMIT:
			iPltGotLimit = aDyn[aIdx].d_val;
			break;
		case DT_ARM_SYMTABSZ:
			iNSymbols = aDyn[aIdx].d_val;
			break;
		default:
			//cout << "Unknown entry in dynamic table Tag=0x%x Value=0x%x",aDyn[aIdx].d_tag, aDyn[aIdx].d_val);
			break;
		}
		aIdx++;
	}

	//String table is found, so get the strings...
	if(aSONameFound) {
		iSOName = ELF_ENTRY_PTR(char, iStringTable, iSONameOffset);
	}

	std::list<PLUINT32>::iterator aItr = aNeeded.begin();
	char *aStr;
	for( ; aItr != aNeeded.end();aItr++ ) {
		aStr = ELF_ENTRY_PTR(char, iStringTable, *aItr);
		iNeeded.push_back( aStr );
	}

	if(iVerNeedCount || iVerDefCount) {
		ProcessVerInfo();
	}

	if(iHashTbl)
	{
		//The number of symbols should be same as the number of chains in hashtable
		if (iNSymbols && (iNSymbols != iHashTbl->nChains))
			throw ELFFormatError(SYMBOLCOUNTMISMATCHERROR,(char*)iParameterListInterface->ElfInput());
		else
		//The number of symbols is same as the number of chains in hashtable	
			iNSymbols = iHashTbl->nChains;
	}

	if( aPltRelTypeSeen  && aJmpRelSeen) {

		if (iPltRelType == DT_REL)
		{
			iPltRel = ELF_ENTRY_PTR(Elf32_Rel, iElfHeader, iJmpRelOffset);
			// check to see if PltRels are included in iRel. If they are
			// ignore them since we don't care about the distinction
			if (iRel <= iPltRel && iPltRel < ELF_ENTRY_PTR(Elf32_Rel, iRel, iRelSize))
				iPltRel = 0;
		}
		else
		{
			iPltRela = ELF_ENTRY_PTR(Elf32_Rela, iElfHeader, iJmpRelOffset);
			// check to see if PltRels are included in iRel.  If they are
			// ignore them since we don't care about the distinction
			if (iRela <= iPltRela && iPltRela < ELF_ENTRY_PTR(Elf32_Rela, iRela, iRelaSize))
				iPltRela = 0;
		}
	}

	return 0;
}

/**
This function processes version information
@internalComponent
@released
*/
void ElfExecutable::ProcessVerInfo() {
	PLUINT32 aSz = iVerNeedCount + iVerDefCount + 1;
	iVerInfo = new VersionInfo[aSz];

	Elf32_Verdef	*aDef;
	Elf32_Verdaux	*aDaux;
	Elf32_Verneed	*aNeed;
	Elf32_Vernaux	*aNaux;
	char			*aSoName;
	char			*aLinkAs;
	
	aDef = iVersionDef;
	
	while( aDef ) {
		aDaux = ELF_ENTRY_PTR( Elf32_Verdaux, aDef, aDef->vd_aux);
		aLinkAs = ELF_ENTRY_PTR(char, iStringTable, aDaux->vda_name );
		aSoName = iSOName;
		iVerInfo[aDef->vd_ndx].iLinkAs = aLinkAs;
		iVerInfo[aDef->vd_ndx].iSOName = aSoName;
		iVerInfo[aDef->vd_ndx].iVerCategory = VER_CAT_DEFINED;

		if( !aDef->vd_next ) {
			break;
		}
		aDef = ELF_ENTRY_PTR(Elf32_Verdef, aDef, aDef->vd_next);
	}

	aNeed = iVersionNeed;

	while( aNeed ) {
		aNaux = ELF_ENTRY_PTR(Elf32_Vernaux, aNeed, aNeed->vn_aux);
		aLinkAs = ELF_ENTRY_PTR(char, iStringTable, aNaux->vna_name);
		aSoName = ELF_ENTRY_PTR(char, iStringTable, aNeed->vn_file);

		iVerInfo[aNaux->vna_other].iLinkAs = aLinkAs;
		iVerInfo[aNaux->vna_other].iSOName = aSoName;
		iVerInfo[aNaux->vna_other].iVerCategory = VER_CAT_NEEDED;

		if( !aNeed->vn_next ) {
			break;
		}
		aNeed = ELF_ENTRY_PTR(Elf32_Verneed, aNeed, aNeed->vn_next);
	}
}

/**
This function processes Elf relocations
@internalComponent
@released
*/
void ElfExecutable::ProcessRelocations(){
	ProcessRelocations(iRel, iRelSize);
	ProcessRelocations(iRela, iRelaSize);
	ProcessRelocations(iPltRel, iPltRelSz);
	ProcessRelocations(iPltRela, iPltRelaSz);
}

/**
Template Function to process relocations
@param aElfRel - relocation table
@param aSize - relocation table size
@internalComponent
@released
*/
template <class T> 
void ElfExecutable::ProcessRelocations(T *aElfRel, size_t aSize){
	if( !aElfRel ) 
		return;

	T * aElfRelLimit = ELF_ENTRY_PTR(T, aElfRel, aSize);

	PLUINT32		aSymIdx;
	PLUCHAR			aType;
	ElfRelocation	*aRel;
	bool			aImported;
	Elf32_Word		aAddend;

	while( aElfRel < aElfRelLimit) {
		
		aType = ELF32_R_TYPE(aElfRel->r_info );
		
		if(ElfRelocation::ValidRelocEntry(aType)) {

			aSymIdx = ELF32_R_SYM(aElfRel->r_info);
			aImported = ImportedSymbol( &iElfDynSym[aSymIdx] );
			aAddend = Addend(aElfRel);
			aRel = ElfRelocation::NewRelocEntry(this, aElfRel->r_offset, aAddend, \
				aSymIdx, aType, aElfRel, aImported);

			if(aRel) {
				aRel->Add();
			}
		}
		aElfRel++;
	}
}

/**
This function finds the addend associated with a relocation entry.
@param aRel - relocation entry
@return location in the elf image
@internalComponent
@released
*/
Elf32_Word ElfExecutable::Addend(Elf32_Rel* aRel) {
	PLUINT32 aOffset;
	Elf32_Word	*aAddendPlace;
	Elf32_Phdr  *aHdr = Segment(aRel->r_offset);
	aOffset = aHdr->p_offset + aRel->r_offset - aHdr->p_vaddr;
	aAddendPlace = ELF_ENTRY_PTR(Elf32_Word, iElfHeader, aOffset);
	return *aAddendPlace;
}

/**
This function returns the addend for a relocation entry
@param aRel - relocation entry
@return location in the elf image
@internalComponent
@released
*/
Elf32_Word ElfExecutable::Addend(Elf32_Rela* aRel) {
	return aRel->r_addend;
}

/**
This function gets the version info at an index
@param aIndex - index into the version table
@return version record
@internalComponent
@released
*/
VersionInfo* ElfExecutable::GetVersionInfo(PLUINT32  aIndex){
	return &iVerInfo[ iVersionTbl[aIndex]];
}


/**
This function returns the Dll name in which an imported symbol is 
defined by looking in the version required section.
@param aSymbolIndex - Index of symbol
@return Dll name
@internalComponent
@released
*/
char* ElfExecutable::SymbolDefinedInDll(PLUINT32  aSymbolIndex){

	VersionInfo *aVInfo = GetVersionInfo(aSymbolIndex);
	return aVInfo ? aVInfo->iLinkAs : NULL;
}

/**
This function returns the DSO(import library) name where the Symbol information can be found.
This DSO is then looked up for the ordinal number of this symbol.
@param aSymbolIndex - Index of symbol
@return DSO name
@internalComponent
@released
*/
char* ElfExecutable::SymbolFromDSO(PLUINT32  aSymbolIndex){

	VersionInfo *aVInfo = GetVersionInfo(aSymbolIndex);
	return aVInfo ? aVInfo->iSOName : NULL;
}

/**
This function returns the segment type
@param aAddr - Address
@return Segment type
@internalComponent
@released
*/
ESegmentType ElfExecutable::SegmentType(Elf32_Addr aAddr) {
	
	try {
		Elf32_Phdr *aHdr = Segment(aAddr);
		if( !aHdr )
			return ESegmentUndefined;

		if( aHdr == iCodeSegmentHdr)
			return ESegmentRO;
		else if(aHdr == iDataSegmentHdr)
			return ESegmentRW;
		else
			return ESegmentUndefined;
	}
	catch(...)
	{
	}

	return ESegmentUndefined;
}

/**
This function returns the segment type
@param aType
@return Segment header
@internalComponent
@released
*/
Elf32_Phdr* ElfExecutable::Segment(ESegmentType aType) {
	
	switch(aType)
	{
	case ESegmentRO:
		return iCodeSegmentHdr;
	case ESegmentRW:
		return iDataSegmentHdr;
	default:
		return NULL;
	}
}

/**
Function to get segment header
@param aAddr - Address
@return Segment header
@internalComponent
@released
*/
Elf32_Phdr* ElfExecutable::Segment(Elf32_Addr aAddr) {
	
	if(iCodeSegmentHdr) {
		PLUINT32 aBase = iCodeSegmentHdr->p_vaddr;
		if( aBase <= aAddr && aAddr < (aBase + iCodeSegmentHdr->p_memsz) ) {
			return iCodeSegmentHdr;
		}
	}
	if(iDataSegmentHdr) {
		PLUINT32 aBase = iDataSegmentHdr->p_vaddr;
		if( aBase <= aAddr && aAddr < (aBase + iDataSegmentHdr->p_memsz) ) {
			return iDataSegmentHdr;
		}
	}

	throw int(0);
}

/**
Thsi function returns the segment header to which the address refers.
@param aAddr - location
@return Segment header.
@internalComponent
@released
*/
Elf32_Phdr* ElfExecutable::SegmentFromAbs(Elf32_Addr aAddr) {

	if(iCodeSegmentHdr) {
		PLUINT32 aBase = iCodeSegmentHdr->p_vaddr;
		if( aBase <= aAddr && aAddr <= (aBase + iCodeSegmentHdr->p_memsz) ) {
			return iCodeSegmentHdr;
		}
	}
	if(iDataSegmentHdr) {
		PLUINT32 aBase = iDataSegmentHdr->p_vaddr;
		if( aBase <= aAddr && aAddr <= (aBase + iDataSegmentHdr->p_memsz) ) {
			return iDataSegmentHdr;
		}
	}
	return NULL;
}

/**
This function says if the symbol is global.
@param aSym - Symbol
@return True if symbol is global, otherwise false
@internalComponent
@released
*/
bool ElfExecutable::GlobalSymbol(Elf32_Sym* aSym)
{
	return (ELF32_ST_BIND(aSym->st_info) == STB_GLOBAL);
}

/**
This function says if the symbol is exported.
@param aSym - Symbol
@return True if symbol is exported, otherwise false
@internalComponent
@released
*/
bool ElfExecutable::ExportedSymbol(Elf32_Sym* aSym)
{
	PLUINT32 aIdx = aSym->st_shndx;

	if(GlobalSymbol(aSym) && VisibleSymbol(aSym) && DefinedSymbol(aSym) && \
		(aIdx != SHN_UNDEF) && (FunctionSymbol(aSym) || DataSymbol(aSym) ) && aIdx < SHN_ABS )
		return true;
	return false;
}

/**
This function says if the symbol is imported.
@param aSym - Symbol
@return True if symbol is imported, otherwise false
@internalComponent
@released
*/
bool ElfExecutable::ImportedSymbol(Elf32_Sym* aSym)
{
	PLUINT32 aIdx = aSym->st_shndx;

	if( (aIdx == SHN_UNDEF) && GlobalSymbol(aSym) && VisibleSymbol(aSym) && (!DefinedSymbol(aSym)) )
		return true;
	return false;
}

/**
This function says if the symbol refers to code or data.
@param aSym - Symbol
@return True if symbol refers to code, otherwise false
@internalComponent
@released
*/
bool ElfExecutable::FunctionSymbol(Elf32_Sym* aSym)
{
	return (STT_FUNC == ELF32_ST_TYPE(aSym->st_info));
}

/**
This function says if the symbol refers to code or data.
@param aSym - Symbol
@return True if symbol refers to data, otherwise false
@internalComponent
@released
*/
bool ElfExecutable::DataSymbol(Elf32_Sym* aSym)
{
	return (STT_OBJECT == ELF32_ST_TYPE(aSym->st_info));
}

/**
This function says if the symbol is defined in the Elf executable.
@param aSym - Symbol
@return True if symbol is defined, otherwise false
@internalComponent
@released
*/
bool ElfExecutable::DefinedSymbol(Elf32_Sym* aSym)
{
	if( aSym->st_shndx == SHN_UNDEF )
		return false;
	ESegmentType aType = SegmentType(aSym->st_value);
	return ((aType == ESegmentRO) || (aType == ESegmentRW));
}

/**
This function says if the visibility of the symbol is default.
@param aSym - Symbol
@return True if symbol has default visibility, otherwise false
@internalComponent
@released
*/
bool ElfExecutable::VisibleSymbol(Elf32_Sym* aSym)
{
	return (STV_DEFAULT == ELF32_ST_VISIBILITY(aSym->st_other) || STV_PROTECTED == ELF32_ST_VISIBILITY(aSym->st_other));
}

/**
This function finds symbol using the hash table
@param aName - Symbol name
@return elf symbol.
@internalComponent
@released
*/
Elf32_Sym* ElfExecutable::FindSymbol(char* aName) {
	if(!aName )
		return NULL;

	PLULONG aHashVal = Util::elf_hash((const PLUCHAR*) aName );
	
	Elf32_Sword* aBuckets = ELF_ENTRY_PTR(Elf32_Sword, iHashTbl, sizeof(Elf32_HashTable) );
	Elf32_Sword* aChains = ELF_ENTRY_PTR(Elf32_Sword, aBuckets, sizeof(Elf32_Sword)*(iHashTbl->nBuckets) );

	Elf32_Sword aIdx = aHashVal % iHashTbl->nBuckets;
	aIdx = aBuckets[aIdx];
	
	char	*aSymName;
	do {
		aSymName = ELF_ENTRY_PTR(char, iStringTable, iElfDynSym[aIdx].st_name);
		if( !strcmp(aSymName, aName) ) {
			return &iElfDynSym[aIdx];
		}
		aIdx = aChains[aIdx];
	}while( aIdx > 0 );

	return NULL;
}

/**
Function to get symbol name
@param aSymIdx - Index of symbol
@return Symbol name
@internalComponent
@released
*/
char* ElfExecutable::GetSymbolName( PLUINT32 aSymIdx) {
	return ELF_ENTRY_PTR(char, iStringTable, iElfDynSym[aSymIdx].st_name);
}

/**
Function to get symbol ordinal
@param aSymName - Symbol name
@return Symbol ordinal
@internalComponent
@released
*/
PLUINT32 ElfExecutable::GetSymbolOrdinal( char* aSymName) {
	Elf32_Sym	*aSym = FindSymbol(aSymName);
	if( !aSym )
		return (PLUINT32)-1;
	return GetSymbolOrdinal( aSym );
	
}

/**
Function to get symbol ordinal
@param aSym - Symbol
@return Symbol ordinal
@internalComponent
@released
*/
PLUINT32 ElfExecutable::GetSymbolOrdinal( Elf32_Sym* aSym) {
	PLUINT32 aOrd = (PLUINT32)-1;
	if( aSym->st_shndx == ESegmentRO) {
		Elf32_Word *aLocation, aOffset;

		aOffset = iCodeSegmentHdr->p_offset + aSym->st_value - iCodeSegmentHdr->p_vaddr;
		aLocation = ELF_ENTRY_PTR(Elf32_Word, iElfHeader, aOffset);
		aOrd = *aLocation;
	}
	return aOrd;
}

/**
Function to get relocation offset
@param aReloc - Instance of class ElfRelocation
@return offset
@internalComponent
@released
*/
Elf32_Word ElfExecutable::GetRelocationOffset(ElfRelocation * aReloc)
{
	Elf32_Phdr * aHdr = Segment(aReloc->iAddr);
	unsigned int aOffset = aReloc->iAddr - aHdr->p_vaddr;
	return aOffset;
}

/**
Function to get relocation place address
@param aReloc - Instance of class ElfRelocation
@return address to place relocation
@internalComponent
@released
*/
Elf32_Word * ElfExecutable::GetRelocationPlace(ElfRelocation * aReloc)
{
	Elf32_Phdr * aHdr = Segment(aReloc->iAddr);
	unsigned int aOffset = aHdr->p_offset + aReloc->iAddr - aHdr->p_vaddr;
	Elf32_Word * aPlace = ELF_ENTRY_PTR(Elf32_Word, iElfHeader, aOffset);
	return aPlace;
}

/**
Function to get local relocation
@return local relocation
@internalComponent
@released
*/
ElfRelocations& ElfExecutable::GetLocalRelocations()
{
	return iLocalRelocations;
}

/**
Function to get code relocation
@return code relocation list
@internalComponent
@released
*/
ElfRelocations::RelocationList & ElfExecutable::GetCodeRelocations()
{
	return GetLocalRelocations().GetCodeRelocations();
}

/**
Function to get data relocation
@return data relocation list
@internalComponent
@released
*/
ElfRelocations::RelocationList & ElfExecutable::GetDataRelocations()
{
	return GetLocalRelocations().GetDataRelocations();
}

/**
Function to get RO base address
@return RO base virtual address
@internalComponent
@released
*/
Elf32_Word ElfExecutable::GetROBase()
{
	if (iCodeSegmentHdr) return iCodeSegmentHdr->p_vaddr;
	return 0;
}

/**
Function to get RO segment
@return code segment
@internalComponent
@released
*/
MemAddr ElfExecutable::GetRawROSegment()
{
	return iCodeSegment;
}

/**
Function to get RW segment virtual address
@return RW base address
@internalComponent
@released
*/
Elf32_Word ElfExecutable::GetRWBase()
{
	if (iDataSegmentHdr) return iDataSegmentHdr->p_vaddr;
	return 0;
}

/**
Function to get Raw RW segment
@return data segment address
@internalComponent
@released
*/
MemAddr ElfExecutable::GetRawRWSegment()
{
	return iDataSegment;
}

/**
Function to get RO segment size
@return code segment size
@internalComponent
@released
*/
size_t ElfExecutable::GetROSize()
{
	return iCodeSegmentHdr->p_filesz;
}

/**
Function to get RW segment size
@return data segment size
@internalComponent
@released
*/
size_t ElfExecutable::GetRWSize()
{
	if (iDataSegmentHdr)
		return iDataSegmentHdr->p_filesz;;
	return 0;
}

/**
Function to get Bss segment size
@return Bss segment size, if data segment, otherwise 0
@internalComponent
@released
*/
size_t ElfExecutable::GetBssSize()
{
	if (iDataSegmentHdr)
		return iDataSegmentHdr->p_memsz - iDataSegmentHdr->p_filesz;
	return 0;
}

/**
Function returns entry point location in Elf image.
@return entry point offset if valid, warning if undefined, otherwise throw error
@internalComponent
@released
*/
Elf32_Word ElfExecutable::EntryPointOffset()
{
	if (!(iElfHeader->e_entry) && !(iCodeSegmentHdr->p_vaddr))
	{
		MessageHandler::GetInstance()->ReportMessage(WARNING, UNDEFINEDENTRYPOINTERROR,(char*)iParameterListInterface->ElfInput());
		return 0;
	}
	else if (!(iElfHeader->e_entry))
		throw ELFFormatError(ENTRYPOINTNOTSETERROR, (char*)iParameterListInterface->ElfInput());
	else 
		return iElfHeader->e_entry - iCodeSegmentHdr->p_vaddr;
}

/**
Function to check exception is present in the Elf image.
@return True if exception present, otherwise false
@internalComponent
@released
*/
bool ElfExecutable::ExeceptionsPresentP()
{	
	size_t nShdrs = iElfHeader->e_shnum;
	if (nShdrs)
	{
		// Find the exception index table section
		Elf32_Shdr * aShdr = ELF_ENTRY_PTR(Elf32_Shdr, iElfHeader, iElfHeader->e_shoff);
		char * aShStrTab = ELF_ENTRY_PTR(char, iElfHeader, aShdr[iElfHeader->e_shstrndx].sh_offset);

		for (PLUINT32 i = 0; i < nShdrs; i++)
		{
			if (aShdr[i].sh_type == SHT_ARM_EXIDX)
			{
				char * aSectionName = aShStrTab + aShdr[i].sh_name;
				if (!strcmp(aSectionName, ".ARM.exidx"))
				{
					return true;
				}
			}
		}

	}
	else
		throw ELFFileError(NEEDSECTIONVIEWERROR, (char*)iParameterListInterface->ElfInput());
	
	return false;
}

/**
Function to get the exports in ordinal number order.
@return ordered exports
@internalComponent
@released
*/
ElfExports::ExportList &ElfExecutable::GetExportsInOrdinalOrder() {
	return iExports->GetExportsInOrdinalOrder();
}

/**
This function looks up for a symbol in the static symbol table.
@return Elf symbol.
@internalComponent
@released
*/
Elf32_Sym * ElfExecutable::LookupStaticSymbol(char * aName) {
	size_t nShdrs = iElfHeader->e_shnum;
	if (nShdrs)
	{
		// find the static symbol table and string table
		Elf32_Shdr * aShdr = ELF_ENTRY_PTR(Elf32_Shdr, iElfHeader, iElfHeader->e_shoff);
		char * aShStrTab = ELF_ENTRY_PTR(char, iElfHeader, aShdr[iElfHeader->e_shstrndx].sh_offset);
		Elf32_Sym * aSymTab = 0;
		Elf32_Sym * aLim = 0;
		char * aStrTab = 0;
		for (PLUINT32 i = 0; i < nShdrs; i++)
		{
			if (aShdr[i].sh_type == SHT_SYMTAB)
			{
				aSymTab = ELF_ENTRY_PTR(Elf32_Sym, iElfHeader, aShdr[i].sh_offset);
				aLim = ELF_ENTRY_PTR(Elf32_Sym, aSymTab, aShdr[i].sh_size);
				if (aStrTab) break;
			}
			else if (aShdr[i].sh_type == SHT_STRTAB)
			{
				char * aSectionName = aShStrTab + aShdr[i].sh_name;
				if (!strcmp(aSectionName, ".strtab"))
				{
					aStrTab = ELF_ENTRY_PTR(char, iElfHeader, aShdr[i].sh_offset);
					if (aSymTab) break;
				}
			}
		}

		/*if(aHashTbl && aSymTab && aStrTab)
		{
			PLULONG aHashVal = Util::elf_hash((const PLUCHAR*)aName);
			Elf32_Sword* aBuckets = ELF_ENTRY_PTR(Elf32_Sword, aHashTbl, sizeof(Elf32_HashTable) );
			Elf32_Sword* aChains = ELF_ENTRY_PTR(Elf32_Sword, aBuckets, sizeof(Elf32_Sword)*(aHashTbl->nBuckets) );

			PLUINT32 aIdx = aHashVal % aHashTbl->nBuckets;
			aIdx = aBuckets[aIdx];
			
			char	*aSymName;
			do {
				aSymName = ELF_ENTRY_PTR(char, aStrTab, aSymTab[aIdx].st_name);
				if( !strcmp(aSymName, aName) ) {
					return &aSymTab[aIdx];
				}
				aIdx = aChains[aIdx];
			}while( aIdx > 0 );

			return NULL;
		}
		else */ 

		if (aSymTab && aStrTab)
		{	
			for(; aSymTab < aLim; aSymTab++)
			{
				if (!aSymTab->st_name) continue;
				char * aSymName = aStrTab + aSymTab->st_name;
				if (!strcmp(aSymName, aName))
					return aSymTab;
			}
			return 0;
		}
		else
		{
			throw ELFFileError(NOSTATICSYMBOLSERROR, (char*)iParameterListInterface->ElfInput());
		}
	}
	else
	{
			throw ELFFileError(NOSTATICSYMBOLSERROR, (char*)iParameterListInterface->ElfInput());
	}
}

/**
Function to get imports
@return imports
@internalComponent
@released
*/
ElfImports::ImportMap ElfExecutable::GetImports() {
	return iImports.GetImports();
}

/**
Function to get exports
@return exports
@internalComponent
@released
*/
ElfExports* ElfExecutable::GetExports() {
	return iExports;
}

/**
Function to get fixup location
@param aReloc - Instance of class ElfLocalRelocation
@param aPlace -
@return addres of position for relocation
@internalComponent
@released
*/
Elf32_Word* ElfExecutable::GetFixupLocation(ElfLocalRelocation* aReloc, Elf32_Addr aPlace)
{
	Elf32_Phdr * aPhdr = aReloc->ExportTableReloc() ? 
		iCodeSegmentHdr :
		Segment(aPlace);
	Elf32_Word offset = aPhdr->p_offset + aPlace - aPhdr->p_vaddr;
	return ELF_ENTRY_PTR(Elf32_Word, iElfHeader, offset);
}

/**
Function to get the segment type
@param aSym - Symbol
@return Segment type
@internalComponent
@released
*/
ESegmentType ElfExecutable::Segment(Elf32_Sym *aSym)
{
	Elf32_Phdr * aHdr;

	try {

		bool specialSymbolFound = false;

		// If Symbol is absolute then assume it came from linker and is a
		// limit symbol.
		if (aSym->st_shndx == SHN_ABS)
		{
			aHdr = SegmentFromAbs(aSym->st_value);
		}
		else
		{
			// does the symbol point to the address after the end of the code or data segments?
			if( (iCodeSegmentHdr && aSym->st_value == (iCodeSegmentHdr->p_vaddr + iCodeSegmentHdr->p_memsz)) ||
				(iDataSegmentHdr && aSym->st_value == (iDataSegmentHdr->p_vaddr + iDataSegmentHdr->p_memsz)) )
			{
				//If Symbol contains $$, it is linker generated so consider the open boundary.
				//e.g. SHT$$INIT_ARRAY$$Limit and sometimes SHT$$INIT_ARRAY$$Base 
				String aSymstr = iStringTable + aSym->st_name;
				if (aSymstr.rfind("$$",aSymstr.length()) != String::npos)
 				{
 					aHdr = SegmentFromAbs(aSym->st_value);
					specialSymbolFound = true;
 				}

			}

			if(!specialSymbolFound )
			{
				aHdr = Segment(aSym->st_value);
			}

		}
		
		if (aHdr == iCodeSegmentHdr)
		{
			return ESegmentRO;
		} 
		else if (aHdr == iDataSegmentHdr)
		{
			return ESegmentRW;
		}
	}
	catch(...)
	{
	}
	return ESegmentUndefined;
}