[GCCE] We need a way for the HAL config extension to parameterise the HAL config file (.hcf) that will be used, depending upon
the toolchain we are building with. E.g. if we are building BeagleBoard with RVCT we can configure hardware floating point
because we have ARM's vfp math libraries; if we are building it with GCC, we lack this library support.
// 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 e32 image creation and dump for elf2e32 tool
// @internalComponent
// @released
//
//
#include "pl_elfexecutable.h"
// get E32ImageHeader class...
#define INCLUDE_E32IMAGEHEADER_IMPLEMENTATION
#define RETURN_FAILURE(_r) return (fprintf(stderr, "line %d\n", __LINE__),_r)
//#define E32IMAGEHEADER_TRACE(_t) printf _t
#include "e32imagefile.h"
#include "pl_elfimportrelocation.h"
#include "pl_elflocalrelocation.h"
#include "pl_elfimports.h"
#include "elffilesupplied.h"
#include "pl_dllsymbol.h"
#include "h_ver.h"
#include "checksum.h"
#include "errorhandler.h"
#include <string>
#include <vector>
#include <cassert>
#include <iostream>
#ifndef __LINUX__
#include <io.h>
#else
#include <time.h>
#endif
#include <time.h>
#include <stdio.h>
using namespace std;
template <class T> inline T Align(T v, size_t s)
{
unsigned int inc = s-1;
unsigned int mask = ~inc;
unsigned int val = (unsigned int)v;
unsigned int res = (val+inc) & mask;
return (T)res;
}
// Need a default constructor for TVersion, but don't want all the other stuff in h_utl.cpp
/**
Default constructor for TVersion class.
@internalComponent
@released
*/
TVersion::TVersion(){}
/**
Constructor for TVersion class.
@internalComponent
@released
*/
TVersion::TVersion(TInt aMajor, TInt aMinor, TInt aBuild):
iMajor((TInt8)aMajor), iMinor((TInt8)aMinor), iBuild((TInt16)aBuild)
{
}
/**
Constructor for E32ImageChunkDesc class.
@internalComponent
@released
*/
E32ImageChunkDesc::E32ImageChunkDesc(char * aData, size_t aSize, size_t aOffset, char * aDoc):
iData(aData), iSize(aSize), iOffset(aOffset), iDoc(aDoc)
{
}
/**
Destructor for E32ImageChunkDesc class.
@internalComponent
@released
*/
E32ImageChunkDesc::~E32ImageChunkDesc()
{
}
/**
This function writes its data in the buffer.
@param aPlace - a location in the buffer
@internalComponent
@released
*/
void E32ImageChunkDesc::Write(char * aPlace)
{
memcpy(aPlace+iOffset, iData, iSize);
}
/**
Constructor for E32ImageChunks class.
@internalComponent
@released
*/
E32ImageChunks::E32ImageChunks():
iOffset(0)
{
}
/**
Destructor for E32ImageChunks class.
@internalComponent
@released
*/
E32ImageChunks::~E32ImageChunks()
{
if(iChunks.size())
{
ChunkList::iterator aItr = iChunks.begin();
ChunkList::iterator last = iChunks.end();
E32ImageChunkDesc *temp;
while( aItr != last)
{
temp = *aItr;
aItr++;
delete temp;
}
}
}
/**
This function creates and adds a chunk into a list.
@param aData - input buffer
@param asize - size of the input buffer
@param aOffset - byte offset of this chunk from the 1 byte in e32 image file.
@param aDoc - name of the chunk
@internalComponent
@released
*/
void E32ImageChunks::AddChunk(char * aData, size_t aSize, size_t aOffset, char * aDoc)
{
E32ImageChunkDesc * aChunk = new E32ImageChunkDesc(aData, aSize, aOffset, aDoc);
iChunks.push_back(aChunk);
iOffset += Align(aSize, sizeof(TUint32));
}
/**
This function returns the list of chunks.
@internalComponent
@released
*/
E32ImageChunks::ChunkList & E32ImageChunks::GetChunks()
{
return iChunks;
}
/**
This function returns the current offset pointing to the last chunk that
was added into the list of chunks.
@internalComponent
@released
*/
size_t E32ImageChunks::GetOffset()
{
return iOffset;
}
/**
This function sets the current offset pointing to the last chunk that
was added into the list of chunks.
@internalComponent
@released
*/
void E32ImageChunks::SetOffset(size_t aOffset)
{
iOffset = aOffset;
}
/**
Constructor for E32ImageFile class.
@internalComponent
@released
*/
E32ImageFile::E32ImageFile(const char * aFileName, ElfExecutable * aExecutable, ElfFileSupplied *aUseCase) :
iFileName(aFileName),
iE32Image(0),
iExportBitMap(0),
iElfExecutable(aExecutable),
iData(0),
iUseCase(aUseCase),
iHdr(0),
iHdrSize(sizeof(E32ImageHeaderV)),
iImportSection(0),
iImportSectionSize(0),
iCodeRelocs(0),
iCodeRelocsSize(0),
iDataRelocs(0),
iDataRelocsSize(0),
iExportOffset(0),
iLayoutDone(false),
iMissingExports(0),
iSymNameOffset(0)
{
}
/**
This function generates the E32 image.
@internalComponent
@released
*/
void E32ImageFile::GenerateE32Image()
{
if( iUseCase->GetNamedSymLookup() ){
ProcessSymbolInfo();
}
ProcessImports();
ProcessRelocations();
ConstructImage();
}
/**
This function processes the import map by looking into the dso files
from which the symbols are imported. It also fetches the ordinal numbers
for the corresponding symbols.
@internalComponent
@released
*/
void E32ImageFile::ProcessImports()
{
string aStrTab;
vector<int> aStrTabOffsets;
int aNumDlls = 0;
int aNumImports = 0;
bool aNamedLookup = iUseCase->GetNamedSymLookup();
TUint aImportTabEntryPos = 0;
ElfImports::ImportMap aImportMap = iElfExecutable->GetImports();
ElfImports::ImportMap::iterator p;
// First set up the string table and record offsets into string table of each
// LinkAs name.
for (p = aImportMap.begin(); p != aImportMap.end(); p++)
{
ElfImports::RelocationList & aImports = (*p).second;
char* aLinkAs = aImports[0]->iVerRecord->iLinkAs;
aStrTabOffsets.push_back(aStrTab.size()); //
string s = aLinkAs;
aStrTab.insert(aStrTab.end(),s.begin(),s.end());
aStrTab.insert(aStrTab.end(),0);
aNumDlls++;
aNumImports += aImports.size();
}
iNumDlls = aNumDlls;
iNumImports = aNumImports;
// Now we can figure out the size of everything
size_t aImportSectionSize = sizeof(E32ImportSection) +
(sizeof(E32ImportBlock) * aNumDlls) +
(sizeof(unsigned int) * aNumImports);
vector<Elf32_Word> aImportSection;
// This is the 'E32ImportSection' header - fill with 0 for the moment
aImportSection.push_back(0);
if( aNamedLookup ) {
// These are the 0th ordinals imported into the import table, one
// entry for each DLL.
aImportSectionSize += (sizeof(unsigned int) * aNumDlls);
}
// Now fill in the E32ImportBlocks
int idx = 0;
char * aDsoName;
for (p = aImportMap.begin(); p != aImportMap.end(); p++, idx++)
{
ElfImports::RelocationList & aImports = (*p).second;
aDsoName = aImports[0]->iVerRecord->iSOName;
//const char * aDSO = FindDSO((*p).first);
const char * aDSO = FindDSO(aDsoName);
aImportSection.push_back(aStrTabOffsets[idx] + aImportSectionSize);
int nImports = aImports.size();
// Take the additional 0th ordinal import into account
if( aNamedLookup )
nImports++;
aImportSection.push_back(nImports);
size_t aSize;
Elf32_Ehdr * aElfFile = 0;
ReadInputELFFile(aDSO, aSize, aElfFile);
ElfExecutable aElfExecutable(NULL);//(aElfFile, aSize);
aElfExecutable.ProcessElfFile(aElfFile);
ElfImports::RelocationList::iterator q;
for (q = aImports.begin(); q != aImports.end(); q++)
{
ElfImportRelocation * aReloc = *q;
char * aSymName = iElfExecutable->GetSymbolName(aReloc->iSymNdx);
unsigned int aOrdinal = aElfExecutable.GetSymbolOrdinal(aSymName);
//check the reloc refers to Code Segment
try
{
if (iElfExecutable->SegmentType(aReloc->iAddr) != ESegmentRO)
{
throw ImportRelocationError(ILLEGALEXPORTFROMDATASEGMENT, aSymName, iElfExecutable->iParameterListInterface->ElfInput());
}
}
/**This catch block introduced here is to avoid deleting partially constructed object(s).
Otherwise global catch block will delete the partially constructed object(s) and the tool will crash.
*/
catch(ErrorHandler& aError)
{
aError.Report();
exit(EXIT_FAILURE);
}
Elf32_Word aRelocOffset = iElfExecutable->GetRelocationOffset(aReloc);
aImportSection.push_back(aRelocOffset);
Elf32_Word * aRelocPlace = iElfExecutable->GetRelocationPlace(aReloc);
if (aOrdinal > 0xFFFF)
{
}
if (aReloc->iAddend > 0xFFFF)
{
}
* aRelocPlace = (aReloc->iAddend<<16) | aOrdinal;
}
if( aNamedLookup ) {
aImportTabEntryPos = aImportSection.size();
// Keep track of the location of the entry
iImportTabLocations.push_back(aImportTabEntryPos);
// Put the entry as 0 now, which shall be updated
aImportSection.push_back(0);
}
delete [] ((char*)aElfFile);
}
assert(aImportSectionSize == aImportSection.size() * sizeof(Elf32_Word));
size_t aTotalSize = Align(aImportSectionSize + aStrTab.size(), sizeof(Elf32_Word));
// Fill in the section header now we have the correct value.
aImportSection[0] = aTotalSize;
// Now construct the unified section
iImportSectionSize = aTotalSize;
iImportSection = (uint32 *)new char[aTotalSize];
memset(iImportSection, 0, aTotalSize);
memcpy(iImportSection, aImportSection.begin(), aImportSectionSize);
char * strTab = ((char *)iImportSection) + aImportSectionSize;
memcpy(strTab, aStrTab.data(), aStrTab.size());
}
/**
This function checks if a DSO file exists.
@param aPath - DSO file name.
@internalComponent
@released
*/
static bool ProbePath(string & aPath)
{
ifstream aInput;
const char * p = aPath.c_str();
aInput.open(p);
if (aInput.is_open())
{
aInput.close();
return true;
}
else
{
return false;
}
}
/**
This function allocates space for a DSO file name.
@param aPath - DSO file name
@internalComponent
@released
*/
const char * AllocatePath(string & aPath)
{
const char * p = aPath.c_str();
size_t len = aPath.size();
char * result = new char[len+1];
strcpy(result, p);
return (const char *)result;
}
/**
This function searches for a DSO in the libpath specified.
@param aName - DSO file name
@internalComponent
@released
*/
const char * E32ImageFile::FindDSO(const char * aName)
{
string aDSOName(aName);
string aDSOPath(aName);
const char *aNewDsoName;
if (ProbePath(aDSOName))
{
aNewDsoName = AllocatePath(aDSOName);
cleanupStack.push_back((char*)aNewDsoName);
return aNewDsoName;
}
ParameterListInterface::LibSearchPaths & paths = iUseCase->GetLibSearchPaths();
ParameterListInterface::LibSearchPaths::iterator p = paths.begin();
for (; p != paths.end(); p++)
{
string path(*p);
char dir = iUseCase->GetDirectorySeparator();
aDSOPath.erase();
aDSOPath.insert(aDSOPath.end(), path.begin(), path.end());
aDSOPath.insert(aDSOPath.end(), dir);
aDSOPath.insert(aDSOPath.end(), aDSOName.begin(), aDSOName.end());
if (ProbePath(aDSOPath))
{
aNewDsoName = AllocatePath(aDSOPath);
cleanupStack.push_back((char*)aNewDsoName);
return aNewDsoName;
}
}
throw ELFFileError(DSONOTFOUNDERROR,(char*)aName);
}
void E32ImageFile::ReadInputELFFile(const char * aName, size_t & aFileSize, Elf32_Ehdr * & aELFFile )
{
ifstream aInput;
aInput.open(aName, ifstream::binary|ifstream::in);
if (aInput.is_open())
{
aInput.seekg(0,ios::end);
aFileSize = (unsigned int) aInput.tellg();
aInput.seekg(0,ios::beg);
aELFFile = (Elf32_Ehdr *)new char [aFileSize];
aInput.read((char *)aELFFile, aFileSize);
aInput.close();
}
else
{
throw FileError(FILEOPENERROR,(char*)aName);
}
}
/**
This function processes relocations.
@internalComponent
@released
*/
void E32ImageFile::ProcessRelocations()
{
ProcessCodeRelocations();
ProcessDataRelocations();
}
/**
This function processes Code relocations.
@internalComponent
@released
*/
void E32ImageFile::ProcessCodeRelocations()
{
CreateRelocations(iElfExecutable->GetCodeRelocations(), iCodeRelocs, iCodeRelocsSize);
}
/**
This function processes Data relocations.
@internalComponent
@released
*/
void E32ImageFile::ProcessDataRelocations()
{
CreateRelocations(iElfExecutable->GetDataRelocations(), iDataRelocs, iDataRelocsSize);
}
/**
This function creates Code and Data relocations from the corresponding
ELF form to E32 form.
@internalComponent
@released
*/
void E32ImageFile::CreateRelocations(ElfRelocations::RelocationList & aRelocList, char * & aRelocs, size_t & aRelocsSize)
{
size_t rsize = RelocationsSize(aRelocList);
if (rsize)
{
aRelocsSize = Align(rsize + sizeof(E32RelocSection), sizeof(uint32));
uint32 aBase = (*aRelocList.begin())->iSegment->p_vaddr;
//add for cleanup to be done later..
cleanupStack.push_back(aRelocs);
aRelocs = new char [aRelocsSize];
memset(aRelocs, 0, aRelocsSize);
E32RelocSection * aRelocSection = (E32RelocSection * )aRelocs;
uint16 * data = (uint16 *)(aRelocSection + 1);
E32RelocPageDesc * startofblock = (E32RelocPageDesc *)data;
int page = -1;
int pagesize = sizeof(E32RelocPageDesc);
ElfRelocations::RelocationList::iterator r;
for (r = aRelocList.begin(); r != aRelocList.end(); r++)
{
ElfLocalRelocation * aReloc = *r;
int p = aReloc->iAddr & 0xfffff000;
if (page != p)
{
if (pagesize%4 != 0)
{
*data++ = 0;
pagesize += sizeof(uint16);
}
if (page == -1) page = p;
startofblock->aOffset = page - aBase;
startofblock->aSize = pagesize;
pagesize = sizeof(E32RelocPageDesc);
page = p;
startofblock = (E32RelocPageDesc *)data;
data = (uint16 *)(startofblock + 1);
}
uint16 relocType = aReloc->Fixup();
*data++ = (uint16)((aReloc->iAddr & 0xfff) | relocType);
pagesize += sizeof(uint16);
}
if (pagesize%4 != 0)
{
*data++ = 0;
pagesize += sizeof(uint16);
}
startofblock->aOffset = page - aBase;
startofblock->aSize = pagesize;
((E32RelocSection *)aRelocs)->iNumberOfRelocs = aRelocList.size();
((E32RelocSection *)aRelocs)->iSize = rsize;
}
}
/**
This function calculates the relocation taking into consideration
the page boundaries if they are crossed. The relocations are
sorted.
@param aRelocList - relocations found in the Elf file.
@internalComponent
@released
*/
size_t E32ImageFile::RelocationsSize(ElfRelocations::RelocationList & aRelocList)
{
size_t bytecount = 0;
int page = -1;
ElfRelocations::RelocationList::iterator r;
for (r = aRelocList.begin(); r != aRelocList.end(); r++)
{
ElfLocalRelocation * aReloc = *r;
int p = aReloc->iAddr & 0xfffff000;
if (page != p)
{
if (bytecount%4 != 0)
bytecount += sizeof(uint16);
bytecount += sizeof(E32RelocPageDesc); // page, block size
page = p;
}
bytecount += sizeof(uint16);
}
if (bytecount%4 != 0)
bytecount += sizeof(uint16);
return bytecount;
}
/**
This function returns the E32 interpretation for an Elf relocation type.
@param aReloc - relocation entry.
@internalComponent
@released
*/
E32ImageFile::uint16 E32ImageFile::GetE32RelocType(ElfRelocation * aReloc)
{
ESegmentType aSegType = aReloc->iSegmentType; // iElfExecutable->SegmentType(aReloc->iSymbol->st_value);
switch (aSegType)
{
case ESegmentRO:
return KTextRelocType;
case ESegmentRW:
return KDataRelocType;
default:
break;
};
// maybe this should be an error
return KInferredRelocType;
}
/**
This function constructs the E32 image.
@internalComponent
@released
*/
void E32ImageFile::ConstructImage()
{
InitE32ImageHeader();
ComputeE32ImageLayout();
FinalizeE32Image();
AllocateE32Image();
}
/**
This function calculates the timestamp.
@param aTime
@internalComponent
@released
*/
Int64 timeToInt64(TInt aTime)
{
aTime-=(30*365*24*60*60+7*24*60*60); // seconds since midnight Jan 1st, 2000
Int64 daysTo2000AD=730497;
Int64 t=daysTo2000AD*24*3600+aTime; // seconds since 0000
t=t+3600; // BST (?)
return t*1000000; // milliseconds
}
/**
This function returns the E32 image header size.
@internalComponent
@released
*/
size_t E32ImageFile::GetE32ImageHeaderSize()
{
return sizeof(E32ImageHeaderV);
}
/**
This function returns the extended E32 image header size.
@internalComponent
@released
*/
size_t E32ImageFile::GetExtendedE32ImageHeaderSize()
{
return iHdrSize;
}
/**
This function sets the extended E32 image header size.
@internalComponent
@released
*/
void E32ImageFile::SetExtendedE32ImageHeaderSize(size_t aSize)
{
iHdrSize = aSize;
}
/**
This function initialises the E32 image header fields.
@internalComponent
@released
*/
void E32ImageFile::InitE32ImageHeader()
{
iHdr = iUseCase->AllocateE32ImageHeader();
iHdr->iUid1 = 0;
iHdr->iUid2 = 0;
iHdr->iUid3 = 0;
iHdr->iHeaderCrc = 0;
iHdr->iSignature = 0x434f5045u;
iHdr->iModuleVersion = 0x00010000u;
iHdr->iCompressionType = 0;
iHdr->iToolsVersion = TVersion(MajorVersion, MinorVersion, Build);
Int64 ltime(timeToInt64(time(0)));
iHdr->iTimeLo=(uint32)ltime;
iHdr->iTimeHi=(uint32)(ltime>>32);
iHdr->iFlags = KImageHdrFmt_V;
// Confusingly, CodeSize means everything except writable data
iHdr->iCodeSize = 0;
iHdr->iDataSize = iElfExecutable->GetRWSize();
iHdr->iHeapSizeMin = 0;
iHdr->iHeapSizeMax = 0;
iHdr->iStackSize = 0;
iHdr->iBssSize = iElfExecutable->GetBssSize();
iHdr->iEntryPoint = 0;
iHdr->iCodeBase = iElfExecutable->GetROBase();
iHdr->iDataBase = iElfExecutable->GetRWBase();
iHdr->iDllRefTableCount = iNumDlls;
iHdr->iExportDirOffset = 0;
iHdr->iExportDirCount = iUseCase->GetNumExports();
iHdr->iTextSize = iElfExecutable->GetROSize();
iHdr->iCodeOffset = 0;
iHdr->iDataOffset = 0;
iHdr->iImportOffset = 0;
iHdr->iCodeRelocOffset = 0;
iHdr->iDataRelocOffset = 0;
iHdr->iProcessPriority = (uint16)EPriorityForeground;
iHdr->iUncompressedSize = 0;
iHdr->iS.iSecureId = 0;
iHdr->iS.iVendorId = 0;
iHdr->iExceptionDescriptor = 0;
iHdr->iSpare2 = 0;
iHdr->iExportDescSize = iUseCase->GetExportDescSize();
iHdr->iExportDescType = iUseCase->GetExportDescType();
if (iHdr->iExportDescSize == 0) iHdr->iExportDesc[0] = 0;
}
/**
This function creates the E32 image layout.
@internalComponent
@released
*/
void E32ImageFile::ComputeE32ImageLayout()
{
// E32Image header
iChunks.AddChunk((char *)iHdr, Align(GetExtendedE32ImageHeaderSize(), sizeof(uint32)), 0, "Image Header");
uint32 endOfHeader = iChunks.GetOffset();
// Code section
iHdr->iCodeOffset = iChunks.GetOffset();
iChunks.AddChunk(iElfExecutable->GetRawROSegment(), iElfExecutable->GetROSize(), iHdr->iCodeOffset, "Code Section");
// Exports Next - then we can set up CodeSize
// Call out to the use case so it can decide how we do this
// record exporttable offset for default case
bool aSymLkupEnabled = iUseCase->GetNamedSymLookup();
// The export table is required either when:
// a. there are exported symbols
// b. symbol lookup is enabled - because this table also indicates the dependencies
bool aExportTableNeeded = (iHdr->iExportDirCount || aSymLkupEnabled) ? 1 : 0;
iExportOffset = iChunks.GetOffset() + 4;
iHdr->iExportDirOffset = aExportTableNeeded ? iUseCase->GetExportOffset() : 0;
if ( aExportTableNeeded && iUseCase->AllocateExportTableP())
iChunks.AddChunk(iUseCase->GetExportTable(), iUseCase->GetExportTableSize(), iChunks.GetOffset(), "Export Table");
// Symbol info next
if( aSymLkupEnabled ){
E32EpocExpSymInfoHdr* aSymHdrInfo = (E32EpocExpSymInfoHdr*)CreateSymbolInfo(iChunks.GetOffset());
if( aSymHdrInfo )
iChunks.AddChunk( (char*)aSymHdrInfo, aSymHdrInfo->iSize, iChunks.GetOffset(), "Symbol Info" );
}
// CodeSize is current offset - endof header offset
iHdr->iTextSize = iHdr->iCodeSize = iChunks.GetOffset() - endOfHeader;
// Data section
if (iElfExecutable->GetRWSize())
{
iHdr->iDataOffset = iChunks.GetOffset();
iChunks.AddChunk(iElfExecutable->GetRawRWSegment(), iElfExecutable->GetRWSize(), iHdr->iDataOffset, "Data Section");
}
// Import Section
if (iImportSectionSize)
{
iHdr->iImportOffset = iChunks.GetOffset();
iChunks.AddChunk((char *)iImportSection, iImportSectionSize, iHdr->iImportOffset, "Import Section");
}
// Code relocs
if (iCodeRelocsSize)
{
iHdr->iCodeRelocOffset = iChunks.GetOffset();
iChunks.AddChunk((char *)iCodeRelocs, iCodeRelocsSize, iHdr->iCodeRelocOffset, "Code Relocs");
}
// Data relocs
if (iDataRelocsSize)
{
iHdr->iDataRelocOffset = iChunks.GetOffset();
iChunks.AddChunk((char *)iDataRelocs, iDataRelocsSize, iHdr->iDataRelocOffset, "Data Relocs");
}
iLayoutDone = true;
}
/**
This function returns the byte offset in the E32 image from where the
export table starts.
@internalComponent
@released
*/
size_t E32ImageFile::GetExportOffset()
{
return iExportOffset;
}
/**
This function returns E32 image size.
@internalComponent
@released
*/
size_t E32ImageFile::GetE32ImageSize()
{
assert(iLayoutDone);
return iChunks.GetOffset();
}
/**
This function creates the export bitmap also replacing the absent symbols
with the entry point functions.
@internalComponent
@released
*/
void E32ImageFile::CreateExportBitMap()
{
int nexp = iUseCase->GetNumExports();
size_t memsz = (nexp + 7) >> 3;
iExportBitMap = new uint8[memsz];
memset(iExportBitMap, 0xff, memsz);
// skip header
uint32 * exports = ((uint32 *)iUseCase->GetExportTable()) + 1;
uint32 absentVal = EntryPointOffset() + iElfExecutable->GetROBase();
iMissingExports = 0;
for (int i=0; i<nexp; ++i)
{
if (exports[i] == absentVal)
{
iExportBitMap[i>>3] &= ~(1u << (i & 7));
++iMissingExports;
}
}
}
/**
This function creates export desription for the absent symbols.
@internalComponent
@released
*/
void E32ImageFile::AddExportDescription()
{
CreateExportBitMap();
if (iMissingExports == 0)
return; // nothing to do
int nexp = iUseCase->GetNumExports();
size_t memsz = (nexp + 7) >> 3; // size of complete bitmap
size_t mbs = (memsz + 7) >> 3; // size of meta-bitmap
size_t nbytes = 0;
unsigned int i;
for (i=0; i<memsz; ++i)
if (iExportBitMap[i] != 0xff)
++nbytes; // number of groups of 8
uint8 edt = KImageHdr_ExpD_FullBitmap;
uint32 extra_space = memsz - 1;
if (mbs + nbytes < memsz)
{
edt = KImageHdr_ExpD_SparseBitmap8;
extra_space = mbs + nbytes - 1;
}
extra_space = (extra_space + sizeof(uint32) - 1) &~ (sizeof(uint32) - 1);
iHdr->iExportDescType = edt;
if (edt == KImageHdr_ExpD_FullBitmap)
{
iHdr->iExportDescSize = (uint16)memsz;
iHdr->iExportDesc[0] = iExportBitMap[0];
uint8 * aDesc = new uint8[extra_space];
memset(aDesc, 0, extra_space);
memcpy(aDesc, &iExportBitMap[1], memsz-1);
iChunks.AddChunk((char *)aDesc,extra_space, iChunks.GetOffset(), "Export Description");
}
else
{
iHdr->iExportDescSize = (uint16)(mbs + nbytes);
uint8 * aBuf = new uint8[extra_space + 1];
memset(aBuf , 0, extra_space + 1);
TUint8* mptr = aBuf;
TUint8* gptr = mptr + mbs;
for (i=0; i<memsz; ++i)
{
if (iExportBitMap[i] != 0xff)
{
mptr[i>>3] |= (1u << (i&7));
*gptr++ = iExportBitMap[i];
}
}
iHdr->iExportDesc[0] = aBuf[0];
uint8 * aDesc = new uint8[extra_space];
memcpy(aDesc, aBuf+1, extra_space);
delete[] aBuf;
iChunks.AddChunk((char *)aDesc,extra_space, iChunks.GetOffset(), "Export Description");
}
}
/**
This function sets the fields of the E32 image.
@internalComponent
@released
*/
void E32ImageFile::FinalizeE32Image()
{
// Arrange a header for this E32 Image
iHdr->iCpuIdentifier = GetCpuIdentifier();
// Import format is ELF-derived
iHdr->iFlags |= KImageImpFmt_ELF;
// ABI is ARM EABI
iHdr->iFlags |= KImageABI_EABI;
iHdr->iFlags |= KImageEpt_Eka2;
bool isDllp = iUseCase->ImageIsDll();
if (isDllp)
{
iHdr->iFlags |= KImageDll;
if (iHdr->iDataSize && !iUseCase->AllowDllData())
throw ELFFileError(DLLHASINITIALISEDDATAERROR, (char*)iUseCase->InputElfFileName());
if (iHdr->iBssSize && !iUseCase->AllowDllData())
throw ELFFileError(DLLHASUNINITIALISEDDATAERROR, (char*)iUseCase->InputElfFileName());
}
iHdr->iHeapSizeMin = iUseCase->HeapCommittedSize();
iHdr->iHeapSizeMax = iUseCase->HeapReservedSize();
iHdr->iStackSize = iUseCase->StackCommittedSize();
iHdr->iEntryPoint = EntryPointOffset();
EEntryPointStatus r = ValidateEntryPoint();
if (r == EEntryPointCorrupt)
throw ELFFileError(ENTRYPOINTCORRUPTERROR, (char*)iUseCase->InputElfFileName());
else if (r == EEntryPointNotSupported)
throw ELFFileError(ENTRYPOINTNOTSUPPORTEDERROR, (char*)iUseCase->InputElfFileName());
SetUpExceptions();
SetUids();
SetSecureId();
SetVendorId();
SetCallEntryPoints();
SetCapability();
SetPriority(isDllp);
SetFixedAddress(isDllp);
SetVersion();
SetCompressionType();
SetFPU();
SetPaged();
SetSymbolLookup();
SetDebuggable();
SetSmpSafe();
UpdateHeaderCrc();
}
/**
This function returns the CPU identifier for the E32 image header.
@internalComponent
@released
*/
E32ImageFile::uint16 E32ImageFile::GetCpuIdentifier()
{
return (uint16)ECpuArmV5;
}
/**
This function returns the entry point of the E32 image .
@internalComponent
@released
*/
E32ImageFile::uint32 E32ImageFile::EntryPointOffset()
{
return iElfExecutable->EntryPointOffset();
}
/**
This function validates the entry point of the E32 image .
@internalComponent
@released
*/
E32ImageFile::EEntryPointStatus E32ImageFile::ValidateEntryPoint()
{
uint32 epOffset = iHdr->iEntryPoint;
if (epOffset & 3)
return EEntryPointOK; // if entry point not 4 byte aligned, must be old style
uint32 fileOffset = epOffset + iElfExecutable->iCodeSegmentHdr->p_offset;
if (fileOffset+4 > iChunks.GetOffset())
return EEntryPointCorrupt; // entry point is past the end of the file??
int ept = 0; // old style if first instruction not recognised
uint8 * p = ELF_ENTRY_PTR(uint8, iElfExecutable->iElfHeader, fileOffset + 4);
uint32 x = *--p;
x<<=8;
x|=*--p;
x<<=8;
x|=*--p;
x<<=8;
x|=*--p;
if ((x & 0xffffff00) == 0xe31f0000)
{
// starts with tst pc, #n - new entry point
ept = (x & 0xff) + 1;
}
if (ept>7)
return EEntryPointNotSupported;
iHdr->iFlags |= (ept<<KImageEptShift);
return EEntryPointOK;
}
/**
This function sets the exciption descriptor in the E32 image .
@internalComponent
@released
*/
void E32ImageFile::SetUpExceptions()
{
char * aExDescName = "Symbian$$CPP$$Exception$$Descriptor";
Elf32_Sym * aSym = iElfExecutable->LookupStaticSymbol(aExDescName);
if (aSym)
{
uint32 aSymVaddr = aSym->st_value;
uint32 aROBase = iElfExecutable->GetROBase();
uint32 aROSize = iElfExecutable->GetROSize();
//check its in RO segment
if (aSymVaddr < aROBase || aSymVaddr >= (aROBase + aROSize))
{
throw ELFFileError(EXCEPTIONDESCRIPTOROUTSIDEROERROR,(char*)iUseCase->InputElfFileName());
}
// Set bottom bit so 0 in header slot means an old binary.
// The decriptor is always aligned on a 4 byte boundary.
iHdr->iExceptionDescriptor = (aSymVaddr - aROBase) | 0x00000001;
}
}
/**
This function sets the UIDs of the E32 image .
@internalComponent
@released
*/
void E32ImageFile::SetUids()
{
iHdr->iUid1=iUseCase->GetUid1();
iHdr->iUid2=iUseCase->GetUid2();
iHdr->iUid3=iUseCase->GetUid3();
}
/**
This function sets the secure ID of the E32 image as passed in the command line.
@internalComponent
@released
*/
void E32ImageFile::SetSecureId()
{
if (iUseCase->GetSecureIdOption())
iHdr->iS.iSecureId = iUseCase->GetSecureId();
else
iHdr->iS.iSecureId = iUseCase->GetUid3();
}
/**
This function sets the vendor Id of the E32 image as passed in command line.
@internalComponent
@released
*/
void E32ImageFile::SetVendorId()
{
iHdr->iS.iVendorId = iUseCase->GetVendorId();
}
/**
This function sets the call entry point of the E32 image .
@internalComponent
@released
*/
void E32ImageFile::SetCallEntryPoints()
{
if (iUseCase->GetCallEntryPoints())
iHdr->iFlags|=KImageNoCallEntryPoint;
else
iHdr->iFlags&=~KImageNoCallEntryPoint;
}
/**
This function sets the capcbility of the E32 image as specified in the command line.
@internalComponent
@released
*/
void E32ImageFile::SetCapability()
{
iHdr->iS.iCaps = iUseCase->GetCapability();
}
/**
This function sets the priority of the E32 exe.
@internalComponent
@released
*/
void E32ImageFile::SetPriority(bool isDllp)
{
if (iUseCase->GetPriority())
{
if (isDllp)
{
cerr << "Warning: Cannot set priority of a DLL." << endl;
}
else
iHdr->iProcessPriority = (unsigned short)iUseCase->GetPriority();
}
}
/**
This function sets the fixed address flag of the E32 image .
@internalComponent
@released
*/
void E32ImageFile::SetFixedAddress(bool isDllp)
{
if (iUseCase->GetFixedAddress())
{
if (isDllp)
{
cerr << "Warning: Cannot set fixed address for DLL." << endl;
}
else
iHdr->iFlags|=KImageFixedAddressExe;
}
else
iHdr->iFlags&=~KImageFixedAddressExe;
}
/**
This function sets the version of the E32 image .
@internalComponent
@released
*/
void E32ImageFile::SetVersion()
{
iHdr->iModuleVersion = iUseCase->GetVersion();
}
/**
This function sets the compression type of the E32 image .
@internalComponent
@released
*/
void E32ImageFile::SetCompressionType()
{
if(iUseCase->GetCompress())
iHdr->iCompressionType = iUseCase->GetCompressionMethod();
else
iHdr->iCompressionType = KFormatNotCompressed;
}
/**
This function sets the FPU type that the E32 image targets .
@internalComponent
@released
*/
void E32ImageFile::SetFPU()
{
iHdr->iFlags &=~ KImageHWFloatMask;
if (iUseCase->GetFPU() == 1)
iHdr->iFlags |= KImageHWFloat_VFPv2;
}
/**
This function sets the paging attribute in the E32 image.
@internalComponent
@released
*/
void E32ImageFile::SetPaged()
{
// Code paging.
if ( iUseCase->IsCodePaged() )
{
iHdr->iFlags |= KImageCodePaged;
iHdr->iFlags &= ~KImageCodeUnpaged;
}
else if ( iUseCase->IsCodeUnpaged() )
{
iHdr->iFlags |= KImageCodeUnpaged;
iHdr->iFlags &= ~KImageCodePaged;
}
else if ( iUseCase->IsCodeDefaultPaged() )
{
iHdr->iFlags &= ~KImageCodePaged;
iHdr->iFlags &= ~KImageCodeUnpaged;
}
// Data paging.
if ( iUseCase->IsDataPaged() )
{
iHdr->iFlags |= KImageDataPaged;
iHdr->iFlags &= ~KImageDataUnpaged;
}
else if ( iUseCase->IsDataUnpaged() )
{
iHdr->iFlags |= KImageDataUnpaged;
iHdr->iFlags &= ~KImageDataPaged;
}
else if ( iUseCase->IsDataDefaultPaged() )
{
iHdr->iFlags &= ~KImageDataPaged;
iHdr->iFlags &= ~KImageDataUnpaged;
}
}
/**
This function sets the Debuggable attribute in the E32 image.
@internalComponent
@released
*/
void E32ImageFile::SetDebuggable()
{
if (iUseCase->IsDebuggable() == true)
{
iHdr->iFlags |= KImageDebuggable;
}
else
{
iHdr->iFlags &= ~KImageDebuggable;
}
}
void E32ImageFile::SetSmpSafe()
{
if ( iUseCase->IsSmpSafe() )
{
iHdr->iFlags |= KImageSMPSafe;
}
else
{
iHdr->iFlags &= ~KImageSMPSafe;
}
}
/**
This function sets the named symol-lookup attribute in the E32 image.
@internalComponent
@released
*/
void E32ImageFile::SetSymbolLookup()
{
if(iUseCase->GetNamedSymLookup())
{
iHdr->iFlags |= KImageNmdExpData;
}
else
{
iHdr->iFlags &= ~KImageNmdExpData;
}
}
/**
Class for Uids.
@internalComponent
@released
*/
class TE32ImageUids
{
public:
TE32ImageUids(TUint32 aUid1, TUint32 aUid2, TUint32 aUid3);
void Set(const TUidType& aUidType);
TUint Check() { return ((checkSum(((TUint8*)this)+1)<<16)|checkSum(this));}
private:
TUidType iType;
TUint iCheck;
};
/**
Constructor for TE32ImageUids.
@internalComponent
@released
*/
TE32ImageUids::TE32ImageUids(TUint32 aUid1, TUint32 aUid2, TUint32 aUid3)
{
Set(TUidType(TUid::Uid(aUid1), TUid::Uid(aUid2), TUid::Uid(aUid3)));
}
/**
This function sets the Uid.
@internalComponent
@released
*/
void TE32ImageUids::Set(const TUidType& aUidType)
{
iType=aUidType;
iCheck=Check();
}
/**
Default constructor for TUidType class.
@internalComponent
@released
*/
TUidType::TUidType()
{
memset(this, 0, sizeof(TUidType));
}
/**
Constructor for TUidType class.
@internalComponent
@released
*/
TUidType::TUidType(TUid aUid1,TUid aUid2,TUid aUid3)
{
iUid[0]=aUid1;
iUid[1]=aUid2;
iUid[2]=aUid3;
}
// needed by E32ImageHeaderV::ValidateHeader...
TCheckedUid::TCheckedUid(const TUidType& aUidType)
{
iType = aUidType;
iCheck = ((TE32ImageUids*)this)->Check();
}
// needed by E32ImageHeaderV::ValidateHeader...
void Mem::Crc32(TUint32& aCrc, const TAny* aPtr, TInt aLength)
{
::Crc32(aCrc, aPtr, aLength);
}
/**
This function updates the CRC of the E32 Image.
@internalComponent
@released
*/
void E32ImageFile::UpdateHeaderCrc()
{
TE32ImageUids u(iHdr->iUid1, iHdr->iUid2, iHdr->iUid3);
iHdr->iUidChecksum = u.Check();
TInt hdrsz = GetExtendedE32ImageHeaderSize();
iHdr->iUncompressedSize = iChunks.GetOffset() - Align(GetExtendedE32ImageHeaderSize(), sizeof(uint32));
iHdr->iHeaderCrc = KImageCrcInitialiser;
uint32 crc = 0;
Crc32(crc, iHdr, hdrsz);
iHdr->iHeaderCrc = crc;
}
/**
This function creates a buffer and writes all the data into the buffer.
@internalComponent
@released
*/
void E32ImageFile::AllocateE32Image()
{
size_t aImageSize = iChunks.GetOffset();
iE32Image = new char[aImageSize];
memset(iE32Image, 0, aImageSize);
E32ImageChunks::ChunkList aChunkList = iChunks.GetChunks();
E32ImageChunks::ChunkList::iterator p;
for(p = aChunkList.begin(); p != aChunkList.end(); p++)
{
(*p)->Write(iE32Image);
}
E32ImageHeaderV* header = (E32ImageHeaderV*)iE32Image;
TInt headerSize = header->TotalSize();
if(KErrNone!=header->ValidateWholeImage(iE32Image+headerSize,GetE32ImageSize()-headerSize))
throw InvalidE32ImageError(VALIDATIONERROR, (char*)iUseCase->OutputE32FileName());
}
/**
This function deflates the compressed data.
@param bytes
@param size
@param os
@internalComponent
@released
*/
void DeflateCompress(char* bytes, size_t size, ofstream & os);
/**
This function Paged Pack the compressed data.
@param bytes
@param size
@param os
@internalComponent
@released
*/
void CompressPages(TUint8 * bytes, TInt size, ofstream& os);
/**
This function writes into the final E32 image file.
@param aName - E32 image file name
@internalComponent
@released
*/
bool E32ImageFile::WriteImage(const char * aName)
{
ofstream *os = new ofstream();
os->open(aName, ofstream::binary|ofstream::out);
if (os->is_open())
{
uint32 compression = iHdr->CompressionType();
if (compression == KUidCompressionDeflate)
{
size_t aHeaderSize = GetExtendedE32ImageHeaderSize();
size_t aBodySize = GetE32ImageSize() - aHeaderSize;
os->write(iE32Image, aHeaderSize);
DeflateCompress(iE32Image + aHeaderSize, aBodySize, *os);
}
else if (compression == KUidCompressionBytePair)
{
size_t aHeaderSize = GetExtendedE32ImageHeaderSize();
os->write(iE32Image, aHeaderSize);
// Compress and write out code part
int srcStart = GetExtendedE32ImageHeaderSize();
CompressPages( (TUint8*)iE32Image + srcStart, iHdr->iCodeSize, *os);
// Compress and write out data part
srcStart += iHdr->iCodeSize;
int srcLen = GetE32ImageSize() - srcStart;
CompressPages((TUint8*)iE32Image + srcStart, srcLen, *os);
}
else if (compression == 0)
{
os->write(iE32Image, GetE32ImageSize()); // image not compressed
}
}
else
{
throw FileError(FILEOPENERROR,(char*)aName);
}
os->close();
if(os!=NULL)
{
delete os;
os = NULL;
}
return true;
}
/**
Constructor for E32ImageFile class.
@internalComponent
@released
*/
E32ImageFile::E32ImageFile(): iFileName(NULL), iE32Image(NULL),iExportBitMap(0),cleanupStack(0), iData(NULL),iHdr(NULL),iImportSection(0), iSize(0), iOrigHdr(NULL), iError(0), iSource(EE32Image), iOrigHdrOffsetAdj(0)
{
};
/**
Destructor for E32ImageFile class.
@internalComponent
@released
*/
E32ImageFile::~E32ImageFile()
{
delete[] iData;
if (iHdr && iHdr != iOrigHdr)
delete iHdr;
delete [] iExportBitMap;
delete [] iE32Image;
delete [] iImportSection;
std::vector<char*>::iterator aPos;
char *aPtr;
aPos = cleanupStack.begin();
while( aPos != cleanupStack.end() )
{
aPtr = *aPos;
delete [] aPtr;
aPos++;
}
}
/**
Adjust the size of allocated data and fix the member data
@internalComponent
@released
*/
void E32ImageFile::Adjust(TInt aSize, TBool aAllowShrink)
{
TInt asize = ((aSize+0x3)&0xfffffffc);
if (asize == iSize)
return;
if (iSize == 0)
{
iSize = asize;
iData = new char[iSize];
memset(iData, 0, iSize);
}
else if (aAllowShrink || asize > iSize)
{
TInt oldsize = iSize;
iSize = asize;
iData = (char*)realloc(iData, iSize);
if (iSize > oldsize)
memset(iData+oldsize, 0, iSize-oldsize);
}
if (!iData)
iSize = 0;
if (iHdr && iHdr == iOrigHdr)
iHdr = (E32ImageHeaderV*)iData;
iOrigHdr = (E32ImageHeader*)iData;
}
/**
Read the E32 image.
@param is - input stream
@internalComponent
@released
*/
TInt E32ImageFile::ReadHeader(ifstream& is)
{
Adjust(sizeof(E32ImageHeader), EFalse);
is.read(iData, sizeof(E32ImageHeader));
TInt hdrsz = iOrigHdr->TotalSize();
if (hdrsz > 0x10000)
return KErrCorrupt; // sanity check
if (hdrsz > (TInt)sizeof(E32ImageHeader))
{
Adjust(hdrsz, EFalse);
is.read(iData+sizeof(E32ImageHeader), hdrsz-sizeof(E32ImageHeader));
}
TUint32 uncompressedSize;
TInt r = iOrigHdr->ValidateHeader(iFileSize,uncompressedSize);
if (r != KErrNone)
{
fprintf(stderr, "Integrity check failed %d\n", r);
return r;
}
iHdr = (E32ImageHeaderV*)iOrigHdr;
return KErrNone;
}
/**
Return the offset of the text section
@internalComponent
@released
*/
TUint E32ImageFile::TextOffset()
{
return 0;
}
/**
Return the offset of the data section
@internalComponent
@released
*/
TUint E32ImageFile::DataOffset()
{
return iHdr->iCodeSize;
}
/**
Return the offset of the bss section
@internalComponent
@released
*/
TUint E32ImageFile::BssOffset()
{
return DataOffset()+iHdr->iDataSize;
}
/**
This function creates the bitmap after reading the E32 image file
@internalComponent
@released
*/
void E32ImageFile::E32ImageExportBitMap()
{
TInt nexp = iOrigHdr->iExportDirCount;
TInt memsz = (nexp + 7) >> 3;
iExportBitMap = new TUint8[memsz];
memset(iExportBitMap, 0xff, memsz);
TUint* exports = (TUint*)(iData + iOrigHdr->iExportDirOffset);
TUint absoluteEntryPoint = iOrigHdr->iEntryPoint + iOrigHdr->iCodeBase;
TUint impfmt = iOrigHdr->ImportFormat();
TUint hdrfmt = iOrigHdr->HeaderFormat();
TUint absentVal = (impfmt == KImageImpFmt_ELF) ? absoluteEntryPoint : iOrigHdr->iEntryPoint;
TInt i;
iMissingExports = 0;
for (i=0; i<nexp; ++i)
{
if (exports[i] == absentVal)
{
iExportBitMap[i>>3] &= ~(1u << (i & 7));
++iMissingExports;
}
}
if (hdrfmt < KImageHdrFmt_V && iMissingExports)
{
fprintf(stderr, "Bad exports\n");
exit(999);
}
}
/**
This function creates the export description after reading the E32 image file
@internalComponent
@released
*/
TInt E32ImageFile::CheckExportDescription()
{
TUint hdrfmt = iOrigHdr->HeaderFormat();
if (hdrfmt < KImageHdrFmt_V && iMissingExports)
return KErrCorrupt;
if (iHdr->iExportDescType == KImageHdr_ExpD_NoHoles)
{
return iMissingExports ? KErrCorrupt : KErrNone;
}
TInt nexp = iOrigHdr->iExportDirCount;
TInt memsz = (nexp + 7) >> 3; // size of complete bitmap
TInt mbs = (memsz + 7) >> 3; // size of meta-bitmap
TInt eds = iHdr->iExportDescSize;
if (iHdr->iExportDescType == KImageHdr_ExpD_FullBitmap)
{
if (eds != memsz)
return KErrCorrupt;
if (memcmp(iHdr->iExportDesc, iExportBitMap, eds) == 0)
return KErrNone;
return KErrCorrupt;
}
if (iHdr->iExportDescType != KImageHdr_ExpD_SparseBitmap8)
return KErrNotSupported;
TInt nbytes = 0;
TInt i;
for (i=0; i<memsz; ++i)
if (iExportBitMap[i] != 0xff)
++nbytes; // number of groups of 8
TInt exp_extra = mbs + nbytes;
if (eds != exp_extra)
return KErrCorrupt;
const TUint8* mptr = iHdr->iExportDesc;
const TUint8* gptr = mptr + mbs;
for (i=0; i<memsz; ++i)
{
TUint mbit = mptr[i>>3] & (1u << (i&7));
if (iExportBitMap[i] != 0xff)
{
if (!mbit || *gptr++ != iExportBitMap[i])
return KErrCorrupt;
}
else if (mbit)
return KErrCorrupt;
}
return KErrNone;
}
int DecompressPages(TUint8 * bytes, ifstream& is);
/**
This function creates the E32 image reading from the file
@param is
@param aImage
@internalComponent
@released
*/
ifstream& operator>>(ifstream& is, E32ImageFile& aImage)
{
aImage.iError = aImage.ReadHeader(is);
if (aImage.iError != KErrNone)
return is;
E32ImageHeader* oh = aImage.iOrigHdr;
TInt orighdrsz = oh->TotalSize();
int remainder = aImage.iSize - orighdrsz;
TUint compression = oh->CompressionType();
if (compression == 0)
{
is.read(aImage.iData + orighdrsz, remainder);
}
else if (compression == KUidCompressionDeflate)
{ //Uncompress
aImage.iError = KErrNoMemory;
unsigned int uncompsize = ((E32ImageHeaderComp*)aImage.iOrigHdr)->iUncompressedSize;
aImage.Adjust(uncompsize + orighdrsz);
if (aImage.iData==NULL)
return is;
oh = aImage.iOrigHdr;
unsigned char* compressedData = new unsigned char[remainder];
if (compressedData==NULL)
return is;
is.read(reinterpret_cast<char *>(compressedData), remainder);
unsigned int destsize = uncompsize;
InflateUnCompress( compressedData, remainder, (unsigned char*)(aImage.iData + orighdrsz), destsize);
if (destsize != uncompsize)
MessageHandler::GetInstance()->ReportMessage(WARNING, HUFFMANINCONSISTENTSIZEERROR);
delete [] compressedData;
if ((TUint)orighdrsz > oh->iCodeOffset)
{
// need to adjust code offsets in original
aImage.iOrigHdrOffsetAdj = (TUint)orighdrsz - oh->iCodeOffset;
aImage.OffsetAdjust(oh->iCodeOffset);
aImage.OffsetAdjust(oh->iDataOffset);
aImage.OffsetAdjust(oh->iCodeRelocOffset);
aImage.OffsetAdjust(oh->iDataRelocOffset);
aImage.OffsetAdjust(oh->iImportOffset);
aImage.OffsetAdjust(oh->iExportDirOffset);
}
aImage.iError = KErrNone;
}
else if(compression == KUidCompressionBytePair)
{ // Uncompress
aImage.iError = KErrNoMemory;
unsigned int uncompsize = ((E32ImageHeaderComp*)aImage.iOrigHdr)->iUncompressedSize;
aImage.Adjust(uncompsize + orighdrsz);
if (aImage.iData==NULL)
return is;
oh = aImage.iOrigHdr;
// Read and decompress code part of the image
unsigned int uncompressedCodeSize = DecompressPages((TUint8 *) (aImage.iData + orighdrsz), is);
// Read and decompress data part of the image
unsigned int uncompressedDataSize = DecompressPages((TUint8 *) (aImage.iData + orighdrsz + uncompressedCodeSize), is);
if (uncompressedCodeSize + uncompressedDataSize != uncompsize)
MessageHandler::GetInstance()->ReportMessage(WARNING, BYTEPAIRINCONSISTENTSIZEERROR);
if ((TUint)orighdrsz > oh->iCodeOffset)
{
// need to adjust code offsets in original
aImage.iOrigHdrOffsetAdj = (TUint)orighdrsz - oh->iCodeOffset;
aImage.OffsetAdjust(oh->iCodeOffset);
aImage.OffsetAdjust(oh->iDataOffset);
aImage.OffsetAdjust(oh->iCodeRelocOffset);
aImage.OffsetAdjust(oh->iDataRelocOffset);
aImage.OffsetAdjust(oh->iImportOffset);
aImage.OffsetAdjust(oh->iExportDirOffset);
}
aImage.iError = KErrNone;
}
aImage.E32ImageExportBitMap();
return is;
}
#ifdef __LINUX__
#include <sys/stat.h>
/**
Simple function uses stdlib fstat to obtain the size of the file.
@param aFileName - e32 image file name
@internalComponent
@released
*/
int GetFileSize(const char* aFileName) {
// Open the file the old-fashioned way :-)
struct stat fileInfo;
if(stat(aFileName,&fileInfo)!=0) {
throw FileError(FILEOPENERROR,(char *)aFileName);
}
off_t fileSize = fileInfo.st_size;
return fileSize;
}
#else
int GetFileSize(const char* aFileName) {
_finddata_t fileinfo;
int ret=_findfirst((char *)aFileName,&fileinfo);
if (ret==-1)
{
throw FileError(FILEOPENERROR,(char *)aFileName);
}
return fileinfo.size;
}
#endif
/**
This function opens the e32 image file.
@param aFileName - e32 image file name
@internalComponent
@released
*/
TInt E32ImageFile::Open(const char* aFileName)
{
iFileSize = GetFileSize(aFileName);
Adjust(iFileSize);
ifstream ifile((char *)aFileName, ios::in | ios::binary);
if(!ifile.is_open())
{
throw FileError(FILEOPENERROR,(char *)aFileName);
}
ifile >> *this;
ifile.close();
if (iError != KErrNone)
return iError;
return KErrNone;
}
void E32ImageFile::ProcessSymbolInfo() {
Elf32_Addr aPlace = iUseCase->GetExportTableAddress() - 4;// This location points to 0th ord.
// Create a relocation entry for the 0th ordinal.
ElfLocalRelocation *aRel = new ElfLocalRelocation(iElfExecutable, aPlace, 0, 0, R_ARM_ABS32, \
NULL, ESegmentRO, NULL, false);
aRel->Add();
aPlace += iUseCase->GetExportTableSize();// aPlace now points to the symInfo
uint32 *aZerothOrd = (uint32*)iUseCase->GetExportTable();
*aZerothOrd = aPlace;
aPlace += sizeof(E32EpocExpSymInfoHdr);// aPlace now points to the symbol address
// which is just after the syminfo header.
if(!iElfExecutable->iExports)
return;
// Donot disturb the internal list sorting.
ElfExports::ExportList aList = iElfExecutable->iExports->GetExports(false);
ElfExports::ExportList::iterator aIter = aList.begin();
DllSymbol *aSym;
TUint aAlign, aNameLen;
char aPad[] = {'\0', '\0', '\0', '\0'};
while ( aIter != aList.end() ) {
aSym = *aIter;
iSymAddrTab.push_back(aSym->iElfSym->st_value);
// The symbol names always start at a 4-byte aligned offset.
iSymNameOffset = iSymbolNames.size() >> 2;
iSymNameOffTab.push_back(iSymNameOffset);
iSymbolNames += aSym->SymbolName();
iSymbolNames += '\0';
aNameLen = iSymbolNames.size();
aAlign = Align(aNameLen, sizeof(int));
aAlign = aAlign - aNameLen;
if(aAlign % 4){
iSymbolNames.append(aPad, aAlign);
}
//Create a relocation entry...
aRel = new ElfLocalRelocation(iElfExecutable, aPlace, 0, 0, R_ARM_ABS32, NULL,\
ESegmentRO, aSym->iElfSym, false);
aPlace += sizeof(uint32);
aRel->Add();
aIter++;
}
}
char* E32ImageFile::CreateSymbolInfo(size_t aBaseOffset) {
E32EpocExpSymInfoHdr aSymInf;
uint32 aSizeofNames, aSize;
SetSymInfo(aSymInf);
if( aSymInf.iFlags & 1) {
aSizeofNames = sizeof(uint32);
}
else {
aSizeofNames = sizeof(uint16);
}
aSize = aSymInf.iSize;
char* aInfo = new char[aSize];
memset(aInfo, 0, aSize);
memcpy(aInfo, (void*)&aSymInf, sizeof(aSymInf));
TUint aPos = aSymInf.iSymbolTblOffset;
memcpy(aInfo+aPos, iSymAddrTab.begin(), iSymAddrTab.size()*sizeof(uint32));
aPos += iSymAddrTab.size()*aSizeofNames;
aPos += iSymNameOffTab.size()*aSizeofNames;
aPos = Align(aPos, sizeof(uint32));
std::vector<uint32>::iterator Iter = iSymNameOffTab.begin();
TInt aOffLen = 2;
if(aSymInf.iFlags & 1)
aOffLen=4;
while(Iter != iSymNameOffTab.end()){
memcpy( ((void*)(aInfo+aPos)), ((void*)Iter), aOffLen);
aPos += aOffLen;
Iter++;
}
aPos = aSymInf.iStringTableOffset;
memcpy(aInfo+aPos, iSymbolNames.begin(), iSymbolNames.size());
// At the end, the dependencies are listed. They remain zeroes and shall be fixed up
// while relocating.
// Update the import table to have offsets to ordinal zero entries
uint32 *aLocation, aOffset;
uint32 *aImportTab = iImportSection;
std::vector<int>::iterator aIter = iImportTabLocations.begin();
aOffset = aBaseOffset - iHdr->iCodeOffset;// This gives the offset of syminfo table base
// wrt the code section start
aOffset += aSymInf.iDepDllZeroOrdTableOffset; // This points to the ordinal zero offset table now
while( aIter != iImportTabLocations.end()) {
aLocation = (aImportTab + *aIter);
*aLocation = aOffset;
aOffset += sizeof(uint32);
aIter++;
}
return aInfo;
}
void E32ImageFile::SetSymInfo(E32EpocExpSymInfoHdr& aSymInfo)
{
uint32 aSize = sizeof(E32EpocExpSymInfoHdr);
memset(&aSymInfo, 0, aSize);
uint16 aNSymbols = (uint16) iSymAddrTab.size();
aSymInfo.iSymCount = aNSymbols;
aSymInfo.iSymbolTblOffset = aSize;
aSize += aNSymbols * sizeof(uint32); // Symbol addresses
TUint aNameTabSz = iSymbolNames.size();
TInt aSizeofNames;
if( iSymNameOffset < 0xffff) {
aSizeofNames = sizeof(uint16);
aSymInfo.iFlags &= ~1;//reset the 0th bit
}
else {
aSizeofNames = sizeof(uint32);
aSymInfo.iFlags |= 1;//set the 0th bit
}
aSize += Align((aNSymbols * aSizeofNames), sizeof(uint32)); // Symbol name offsets
aSymInfo.iStringTableOffset = aSize;
aSize += aNameTabSz; // Symbol names in string tab
aSymInfo.iStringTableSz = aNameTabSz;
aSymInfo.iDepDllZeroOrdTableOffset = aSize;
aSymInfo.iDllCount = iNumDlls ;
aSize += iNumDlls * sizeof(uint32); // Dependency list - ordinal zero placeholder
aSymInfo.iSize = aSize;
}