// 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;
}

