diff -r 000000000000 -r 83f4b4db085c toolsandutils/e32tools/elf2e32/source/pl_elfexecutable.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolsandutils/e32tools/elf2e32/source/pl_elfexecutable.cpp Tue Feb 02 01:39:43 2010 +0200 @@ -0,0 +1,1484 @@ +// 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 +#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 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::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 +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 limitSymbolFound = 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 + { + if( (iCodeSegmentHdr && aSym->st_value == (iCodeSegmentHdr->p_vaddr + iCodeSegmentHdr->p_memsz)) || + (iDataSegmentHdr && aSym->st_value == (iDataSegmentHdr->p_vaddr + iDataSegmentHdr->p_memsz)) ) + { + //If Symbol is a $$Limit symbol, then consider the open boundary. + String limitstr = iStringTable + aSym->st_name; + if (limitstr.rfind("$$Limit",limitstr.length()) != String::npos) + { + aHdr = SegmentFromAbs(aSym->st_value); + limitSymbolFound = true; + } + } + + if(!limitSymbolFound ) + { + aHdr = Segment(aSym->st_value); + } + + } + + if (aHdr == iCodeSegmentHdr) + { + return ESegmentRO; + } + else if (aHdr == iDataSegmentHdr) + { + return ESegmentRW; + } + } + catch(...) + { + } + return ESegmentUndefined; +} +