/*
* Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "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:
*
*/
#define __REFERENCE_CAPABILITY_NAMES__
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <e32std.h>
#include <e32std_private.h>
#include <e32rom.h>
#include "u32std.h"
#include <e32uid.h>
#include <f32file.h>
#include "h_utl.h"
#define USE_IAT_FOR_IMPORTS (iOverrideFlags&KOverrideKeepIAT || (iHdr->iCpuIdentifier & 0x1000))
#if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
#include <iomanip>
#else //!__MSVCDOTNET__
#include <iomanip.h>
#endif
#if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
#include <iomanip>
#else //!__MSVCDOTNET__
#include <iomanip.h>
#endif
#include "r_obey.h"
#include "r_global.h"
#include "r_dir.h"
TInt NumRootDirs;
inline TLinAddr ActualToRomAddress(TAny* anAddr)
{ return TLinAddr(anAddr)-TheRomMem+TheRomLinearAddress; }
TBool THardwareVariant::MutuallyExclusive(THardwareVariant a) const
{
if (Layer()<=3 || a.Layer()<=3)
return EFalse;
if (Parent()==3 && a.Parent()==3)
return(Layer()!=a.Layer());
if (Parent()==3 && a.Parent()!=Layer())
return ETrue;
if (a.Parent()==3 && Parent()!=a.Layer())
return ETrue;
if (Layer()!=a.Layer())
return ETrue;
return((VMask()&a.VMask())==0);
}
TBool THardwareVariant::IsVariant() const
{
if (Layer()<=3 || Parent()==3)
return EFalse;
TUint v=VMask();
TInt i;
for (i=0; i<16; i++)
{
if (v==TUint(1<<i))
return ETrue;
}
return EFalse;
}
TInt THardwareVariant::Compare(THardwareVariant a) const
{
TUint l1=Layer();
TUint p1=Parent();
TUint v1=VMask();
TUint l2=a.Layer();
TUint p2=a.Parent();
TUint v2=a.VMask();
if (l1<=3)
{
if (l2<=3)
{
return EEqual;
}
return EGreater;
}
if (l2<=3)
return ELess;
if (p1==3)
{
if (p2==3)
{
if (l1==l2)
return EEqual;
return EUnordered;
}
if (p2==l1)
return EGreater;
return EUnordered;
}
if (p2==3)
{
if (p1==l2)
return ELess;
return EUnordered;
}
if (l1!=l2)
return EUnordered;
if ((v1&v2)==v1)
return ELess;
if ((v1&v2)==v2)
return EGreater;
return EUnordered;
}
//
TInt TRomNode::Count=0;
TRomNode::TRomNode(const TText* aName, TRomBuilderEntry* aEntry)
//
// Constructor from TRomBuilderEntry, i.e. for new file or directory
//
{
memset(this, 0, sizeof(TRomNode));
iAtt = (TUint8)KEntryAttReadOnly;
iName = (TText*)NormaliseFileName((const char*)aName);
iIdentifier=TRomNode::Count++;
iRomFile = new TRomFile;
if (aEntry)
{
iRomFile->iRbEntry = aEntry;
aEntry->SetRomNode(this);
iBareName = strdup(aEntry->iBareName);
iRomFile->iHwvd = aEntry->iHardwareVariant;
}
else
{
iRomFile->iDir = ETrue;
iAtt |= (TUint8)KEntryAttDir;
iBareName = strdup((const char*)iName);
iRomFile->iHwvd = KVariantIndependent;
}
TRACE(TROMNODE,Print(ELog, "TRomNode %d name %s bare %s att %02x romfile %08x\n", iIdentifier,
iName, iBareName, iAtt, iRomFile));
}
TRomNode::TRomNode(const TText* aName, TRomNode* aNode)
//
// Constructor from TRomNode, i.e. for aliased file
//
{
memset(this, 0, sizeof(TRomNode));
iAtt = aNode->iAtt;
iIdentifier=TRomNode::Count++;
iName = (TText*)NormaliseFileName((const char*)aName);
iHidden = aNode->iHidden;
iRomFile = aNode->iRomFile;
if (iRomFile)
{
iRomFile->Open();
}
TRACE(TROMNODE,Print(ELog, "TRomNode %d DUP name %s romfile %08x\n", iIdentifier, iName, iRomFile));
}
TRomNode::TRomNode(const TRomNode& aNode)
//
// Copy constructor - only used in deep copy function
//
{
memset(this, 0, sizeof(TRomNode));
iAtt = aNode.iAtt;
iIdentifier=TRomNode::Count++;
iName = (TText*)strdup((const char*)aNode.iName);
iBareName = strdup(aNode.iBareName);
iHidden = aNode.iHidden;
iRomFile = aNode.iRomFile;
if (iRomFile)
{
iRomFile->Open();
}
TRACE(TROMNODE,Print(ELog, "TRomNode %d COPY name %s bare %s att %02x romfile %08x\n", iIdentifier,
iName, iBareName, iAtt, iRomFile));
}
TRomNode::~TRomNode()
{
free(iName);
free(iBareName);
if (iRomFile)
iRomFile->Close();
}
TRomNode* TRomNode::FindInDirectory(const TText* aName)
//
// Check if the TRomNode for aName exists in aDir, and if so, return it.
//
{
TRomNode *entry=iChild; // first subdirectory or file
while (entry)
{
if (!entry->iHidden && (stricmp((const char *)aName, (const char *)entry->iName))==0)
return entry;
else
entry=entry->iSibling;
}
return 0;
}
TRomNode* TRomNode::FindInDirectory(const TText* aName, THardwareVariant aVariant, TBool aPatchDataFlag)
//
// Check for a file with same name and a compatible hardware variant
//
{
TRomNode *entry=iChild; // first subdirectory or file
while (entry)
{
if (((!entry->iHidden)||aPatchDataFlag) && entry->iRomFile && (stricmp((const char *)aName, (const char *)entry->iName))==0)
{
if (!aVariant.MutuallyExclusive(entry->HardwareVariant()))
return entry;
}
entry=entry->iSibling;
}
return 0;
}
void TRomNode::AddFile(TRomNode* aChild)
{
if (!(iAtt & KEntryAttDir))
{
Print(EError, "Adding subdirectory to a file!!!\n");
return;
}
Add(aChild);
}
TRomNode* TRomNode::NewSubDir(const TText* aName)
{
if (!(iAtt & KEntryAttDir))
{
Print(EError, "Adding subdirectory to a file!!!\n");
return 0;
}
TRomNode* node = new TRomNode(aName);
if (node==0)
{
Print(EError, "TRomNode::NewNode: Out of memory\n");
return 0;
}
Add(node);
return node;
}
void TRomNode::Add(TRomNode* aChild)
{
if (iChild) // this node is a non-empty directory
{
TRomNode* dir = iChild; // find where to link in the new node
while (dir->iSibling)
dir = dir->iSibling;
dir->iSibling = aChild;
}
else
iChild = aChild; // else just set it up as the child of the dir
aChild->iSibling = 0;
aChild->iParent = this;
}
void TRomNode::Remove(TRomNode* aChild)
{
if (iChild==0)
{
Print(EError, "Removing file from a file!!!\n");
return;
}
if (iChild==aChild) // first child in this directory
{
iChild = aChild->iSibling;
aChild->iSibling = 0;
aChild->iParent = 0;
return;
}
TRomNode* prev = iChild;
while (prev->iSibling && prev->iSibling != aChild)
prev = prev->iSibling;
if (prev==0)
{
Print(EError, "Attempting to remove file not in this directory!!!\n");
return;
}
prev->iSibling = aChild->iSibling;
aChild->iSibling = 0;
aChild->iParent = 0;
}
void TRomNode::CountDirectory(TInt& aFileCount, TInt& aDirCount)
{
TRomNode *current=iChild;
while(current)
{
if (current->iChild)
aDirCount++;
else if (!current->iHidden)
aFileCount++;
current=current->iSibling;
}
}
/**
* Walk the contents of the directory, accumulating the
* files as FileEntry objects in the specified RomFileStructure
* and recursively handling the sub-directories
*
* TRomNode::ProcessDirectory is a pair with
* RomFileStructure::ProcessDirectory
*/
int TRomNode::ProcessDirectory(RomFileStructure* aRFS)
{
TInt r=KErrNone;
TRomNode *current=iChild;
while(current)
{
if (current->iAtt & (TUint8)KEntryAttDir)
{
r=aRFS->ProcessDirectory(current);
if (r!=KErrNone)
return r;
}
else if (!current->iHidden)
{
FileEntry *pE=FileEntry::New(current);
if (!pE)
return KErrNoMemory;
r=aRFS->Add(*pE);
if (r==KErrOverflow)
return r;
}
current=current->iSibling;
}
return r;
}
void TRomNode::AddExecutableFile(TRomNode*& aLast, TRomNode* aNode)
{
aLast->iNextExecutable = aNode;
aLast = aNode;
aNode->iAtt |= KEntryAttXIP;
}
char* TRomNode::BareName() const
{
return iBareName;
}
TUint32 TRomNode::Uid3() const
{
return iRomFile->Uid3();
}
TUint32 TRomNode::ModuleVersion() const
{
return iRomFile->ModuleVersion();
}
THardwareVariant TRomNode::HardwareVariant() const
{
return iRomFile->HardwareVariant();
}
TUint32 TRomNode::ABI() const
{
return iRomFile->ABI();
}
TUint32 TRomFile::Uid3() const
{
assert(!iDir);
if (iRbEntry)
{
if(iRbEntry->iHdr)
return iRbEntry->iHdr->iUid3;
}
return RomImgHdr()->iUid3;
}
TUint32 TRomFile::ModuleVersion() const
{
assert(!iDir);
if (iRbEntry)
{
if(iRbEntry->iHdr)
return iRbEntry->iHdr->ModuleVersion();
}
return RomImgHdr()->iModuleVersion;
}
THardwareVariant TRomFile::HardwareVariant() const
{
return iHwvd;
}
TUint32 TRomFile::ABI() const
{
assert(!iDir);
if (iRbEntry)
{
if(iRbEntry->iHdr)
return iRbEntry->iHdr->ABI();
}
return RomImgHdr()->iFlags & KRomImageABIMask;
}
TInt TRomFile::ExportDirCount() const
{
assert(!iDir);
if (iRbEntry)
{
if(iRbEntry->iHdr)
return iRbEntry->iHdr->iExportDirCount;
}
return RomImgHdr()->iExportDirCount;
}
TUint32 TRomFile::RomImageFlags() const
{
assert(!iDir);
if (iRbEntry)
{
if(iRbEntry->iHdr)
{
const TUint KRomFlagMask = KImageDll | KImageNoCallEntryPoint | KImageFixedAddressExe | KImageNmdExpData;
TUint romflags = iRbEntry->iHdr->iFlags & KRomFlagMask;
return iRbEntry->iRomImageFlags | romflags;
}
}
return RomImgHdr()->iFlags;
}
TLinAddr TRomFile::DataBssLinearBase() const
{
assert(!iDir);
if (iRbEntry)
return iRbEntry->iDataBssLinearBase;
return RomImgHdr()->iDataBssLinearBase;
}
const SSecurityInfo& TRomFile::SecurityInfo() const
{
assert(!iDir);
if (iRbEntry)
return iRbEntry->iS;
return RomImgHdr()->iS;
}
TInt TRomNode::FullNameLength(TBool aIgnoreHiddenAttrib) const
{
TInt l = 0;
// aIgnoreHiddenAttrib is used to find the complete file name length as
// in ROM of a hidden file.
if (iParent && ( !iHidden || aIgnoreHiddenAttrib))
l = iParent->FullNameLength() + 1;
l += strlen((const char*)iName);
return l;
}
TInt TRomNode::GetFullName(char* aBuf, TBool aIgnoreHiddenAttrib) const
{
TInt l = 0;
TInt nl = strlen((const char*)iName);
// aIgnoreHiddenAttrib is used to find the complete file name as in ROM of a hidden file.
if (iParent && ( !iHidden || aIgnoreHiddenAttrib))
l = iParent->GetFullName(aBuf);
char* b = aBuf + l;
if (l)
*b++ = '\\', ++l;
memcpy(b, iName, nl);
b += nl;
*b = 0;
l += nl;
return l;
}
TInt CompareCapabilities(const SCapabilitySet& aSubCaps, const SCapabilitySet& aSuperCaps, const char* aSubName, const char* aSuperName)
//
// Check that a aSubCaps are a subset of aSuperCaps
//
{
if ((!gPlatSecEnforcement)&&(!gPlatSecDiagnostics))
return KErrNone;
TInt i;
TUint32 c = 0;
for (i=0; i<SCapabilitySet::ENCapW; ++i)
c |= (aSubCaps[i] &~ aSuperCaps[i]);
TInt r = c ? KErrPermissionDenied : KErrNone;
if (r && aSubName && aSuperName)
{
TPrintType printType;
if(gPlatSecEnforcement)
printType = EError;
else
{
printType = EWarning;
r = KErrNone;
}
char* buf = (char*)malloc(2);
if(!buf)
return KErrNoMemory;
TInt len = 0;
for(i=0; i<ECapability_Limit; i++)
{
if( (aSubCaps[i>>5] &~ aSuperCaps[i>>5]) & (1<<(i&31)) )
{
// append capability name to buf
const char* name = CapabilityNames[i];
if(!name)
continue;
if(len)
{
buf[len++] = ' ';
}
int nameLen=strlen(name);
buf = (char*)realloc(buf,len+nameLen+2);
if(!buf)
return KErrNoMemory;
memcpy(buf+len,CapabilityNames[i],nameLen);
len += nameLen;
}
}
buf[len]=0;
Print(printType, "*PlatSec* %s - Capability check failed. Can't load %s because it links to %s which has the following capabilities missing: %s\n",gPlatSecEnforcement?"ERROR":"WARNING",aSubName, aSuperName, buf);
free(buf);
}
return r;
}
TDllFindInfo::TDllFindInfo(const char* aImportName, const TRomBuilderEntry* aEntry)
{
TUint32 flags;
iBareName = SplitFileName(aImportName, iUid3, iModuleVersion, flags);
assert(iBareName != 0);
iHwVariant = aEntry->iHardwareVariant.ReturnVariant();
}
TDllFindInfo::~TDllFindInfo()
{
free((void*)iBareName);
}
// Generate name as follows:
// PC filename (UID3:xxxxxxxx HWVD:xxxxxxxx VER:M.m)
TModuleName::TModuleName(const TRomBuilderEntry* a)
{
TInt l = strlen(a->iFileName) + strlen(" (UID3:xxxxxxxx HWVD:xxxxxxxx VER:MMMMM.mmmmm)");
iName = (char*)malloc(l + 1);
assert(iName != 0);
sprintf(iName, "%s (UID3:%08lx HWVD:%08lx VER:%ld.%ld)", a->iFileName, a->iHdr->iUid3,
a->iHardwareVariant.ReturnVariant(), a->iHdr->ModuleVersion()>>16, a->iHdr->ModuleVersion()&0x0000ffffu);
}
// Generate name as follows:
// Bare name (UID3:xxxxxxxx HWVD:xxxxxxxx VER:M.m)
TModuleName::TModuleName(const TDllFindInfo& a)
{
TInt l = strlen(a.iBareName) + strlen(" (UID3:xxxxxxxx HWVD:xxxxxxxx VER:MMMMM.mmmmm)");
iName = (char*)malloc(l + 1);
assert(iName != 0);
sprintf(iName, "%s (UID3:%08lx HWVD:%08lx VER:%ld.%ld)", a.iBareName, a.iUid3,
a.iHwVariant, a.iModuleVersion>>16, a.iModuleVersion&0x0000ffffu);
}
// Generate name as follows:
// Name (UID3:xxxxxxxx HWVD:xxxxxxxx VER:M.m)
TModuleName::TModuleName(const TRomNode& a)
{
TBool xip = (a.iAtt & KEntryAttXIP);
TUint32 uid3 = xip ? a.Uid3() : 0;
TUint32 hwvd = (TUint)a.HardwareVariant();
TUint32 ver = xip ? a.ModuleVersion() : 0;
TInt l = a.FullNameLength() + strlen(" (UID3:xxxxxxxx HWVD:xxxxxxxx VER:MMMMM.mmmmm)");
iName = (char*)malloc(l + 1);
assert(iName != 0);
char* b = iName + a.GetFullName(iName);
sprintf(b, " (UID3:%08lx HWVD:%08lx VER:%ld.%ld)", uid3, hwvd, ver>>16, ver&0x0000ffffu);
}
TModuleName::TModuleName(const TRomFile& a, const TRomNode* aRootDir)
{
iName = 0;
if (a.iRbEntry)
{
new (this) TModuleName(a.iRbEntry);
return;
}
TRomNode* x = aRootDir->iNextExecutable;
for(; x; x=x->iNextExecutable)
{
if (x->iRomFile == &a)
{
new (this) TModuleName(*x);
return;
}
}
}
TModuleName::~TModuleName()
{
free(iName);
}
/**
* TRomNode::FindImageFileByName is always called on the root TRomNode, so
* it doesn't consider the current TRomNode, just the linked items in the
* iNextExecutable list.
*/
TRomNode* TRomNode::FindImageFileByName(const TDllFindInfo& aInfo, TBool aPrintDiag, TBool& aFallBack)
{
TUint r_major = aInfo.iModuleVersion >> 16;
TUint r_minor = aInfo.iModuleVersion & 0x0000ffffu;
TRomNode* fallback = NULL;
aFallBack = EFalse;
for (TRomNode* x=iNextExecutable; x!=0; x=x->iNextExecutable)
{
if (stricmp(x->BareName(), aInfo.iBareName))
continue; // name doesn't match
if (aPrintDiag)
Print(ELog, "Candidate: %s ", (const char*)TModuleName(*x) );
if ( !(THardwareVariant(aInfo.iHwVariant) <= x->HardwareVariant()) )
{
if (aPrintDiag)
Print(ELog, "HWVD mismatch - requested %08x\n", aInfo.iHwVariant);
continue;
}
if (aInfo.iUid3 && (aInfo.iUid3 != x->Uid3()))
{
if (aPrintDiag)
Print(ELog, "UID3 mismatch - requested %08x\n", aInfo.iUid3);
continue;
}
TUint x_major = x->ModuleVersion() >> 16;
TUint x_minor = x->ModuleVersion() & 0x0000ffffu;
if ( x->ModuleVersion() == 0x00010000 && aInfo.iModuleVersion == 0 )
{
// allow requested version 0.0 to link to 1.0 with a warning
fallback = x;
}
if ( x_major != r_major )
{
if (aPrintDiag)
Print(ELog, "Major version mismatch - requested %d\n", r_major);
continue;
}
if ( x_minor < r_minor )
{
if (aPrintDiag)
Print(ELog, "??? Minor version mismatch - requested %d\n", r_minor);
continue;
}
if (aPrintDiag)
Print(ELog, "OK\n");
return x;
}
if (fallback)
{
aFallBack = ETrue;
return fallback;
}
return 0;
}
TInt TRomNode::CheckForVersionConflicts(const TRomBuilderEntry* a)
{
TUint r_major = a->iHdr->ModuleVersion() >> 16;
TUint r_minor = a->iHdr->ModuleVersion() & 0x0000ffffu;
TInt errors = 0;
for (TRomNode* x=iNextExecutable; x!=0; x=x->iNextExecutable)
{
if (x->iRomFile->iRbEntry == a)
continue; // don't compare a with itself
if (stricmp(x->BareName(), a->iBareName))
continue; // name doesn't match
if ( a->iHardwareVariant.MutuallyExclusive(x->HardwareVariant()) )
continue; // HWVDs are mutually exclusive
if ( a->iHdr->iUid3 && x->Uid3() && (a->iHdr->iUid3 != x->Uid3()) )
continue; // UID3's don't match
TUint x_major = x->ModuleVersion() >> 16;
TUint x_minor = x->ModuleVersion() & 0x0000ffffu;
if (x_major == r_major && x_minor != r_minor) // allow two copies of same file
{
Print(EError, "Version Conflict %s with %s\n", (const char*)TModuleName(a), (const char*)TModuleName(*x) );
++errors;
}
}
return errors;
}
TInt E32Rom::WriteHeadersToRom(char *anAddr)
//
// Follow the TRomBuilderEntry tree, writing TRomEntry headers to the rom.
//
{
TRACE(TTIMING,Print(EAlways,"0\n"));
TRACE(TDIR,Print(EAlways,"WriteHeadersToRom()\n"));
char* start=anAddr;
TRomRootDirectoryList* dirPointers=(TRomRootDirectoryList*)anAddr;
anAddr+=NumberOfVariants*sizeof(TRootDirInfo)+sizeof(TInt);
RomFileStructure* pS=RomFileStructure::New(NumberOfVariants);
if (!pS)
Print(EError,"Error creating RomFileStructure\n");
TInt r=pS->ProcessDirectory(iObey->iRootDirectory);
if (r!=KErrNone)
Print(EError,"Error %d processing directory tree\n",r);
TInt c=pS->Count();
NumRootDirs=c;
if (c!=NumberOfVariants)
Print(EError,"Error processing directory tree NR=%d NV=%d\n",c,NumberOfVariants);
dirPointers->iNumRootDirs=c;
TInt i;
TRACE(TDIR,Print(EAlways,"Count=%d\n",c));
TRACE(TDIR,pS->DebugPrint());
for(i=0; i<c; i++)
{
DirEntry* pD=(DirEntry*)&(*pS)[i];
TRomDir* pR=pD->CreateRomEntries(anAddr);
dirPointers->iRootDir[i].iHardwareVariant=TUint(pD->Variants().Lookup());
dirPointers->iRootDir[i].iAddressLin=ActualToRomAddress(pR);
}
TRACE(TDIR,Print(EAlways,"Beginning final cleanup\n"));
delete pS;
TRACE(TTIMING,Print(EAlways,"1\n"));
return anAddr-start;
}
void TRomNode::Destroy()
//
// Follow the TRomNode tree, destroying it
//
{
TRomNode *current = this; // root has no siblings
while (current)
{
if (current->iChild)
current->iChild->Destroy();
TRomNode* prev=current;
current=current->iSibling;
delete prev;
}
}
TInt TRomNode::SetAtt(TText *anAttWord)
//
// Set the file attribute byte from the letters passed
//
{
iAtt=0;
if (anAttWord==0 || anAttWord[0]=='\0')
return Print(EError, "Missing argument for keyword 'attrib'.\n");
for (TText *letter=anAttWord;*letter!=0;letter++)
{
switch (*letter)
{
case 'R':
case 'w':
iAtt |= KEntryAttReadOnly;
break;
case 'r':
case 'W':
iAtt &= ~KEntryAttReadOnly;
break;
case 'H':
iAtt |= KEntryAttHidden;
break;
case 'h':
iAtt &= ~KEntryAttHidden;
break;
case 'S':
iAtt |= KEntryAttSystem;
break;
case 's':
iAtt &= ~KEntryAttSystem;
break;
default:
return Print(EError, "Unrecognised attrib - '%c'.\n", *letter);
break;
}
}
return KErrNone;
}
TRomBuilderEntry::TRomBuilderEntry(const char *aFileName,TText *aName)
//
// Constructor
//
:
E32ImageFile(),
iName(0),
iResource(EFalse), iNonXIP(EFalse), iPreferred(EFalse), iCompression(0), iPatched(EFalse),iArea(0),
iOverrideFlags(0),iCodeAlignment(0),iDataAlignment(0),iUid1(0), iUid2(0), iUid3(0),iBareName(0),
iHardwareVariant(KVariantIndependent),iDataBssOffset(0xffffffff),
iStackReserve(0),iIATRefs(0), iNext(0), iNextInArea(0),
iRomImageFlags(0),iProcessName(0), iRomNode(NULL)
{
if (aFileName)
iFileName = NormaliseFileName((const char*)aFileName);
if (aName)
iName = (TText*)NormaliseFileName((const char*)aName);
}
TRomBuilderEntry::~TRomBuilderEntry()
//
// Destructor
//
{
free(iFileName);
iFileName = 0;
free(iName);
iName = 0;
delete[] iProcessName;
free(iBareName);
iBareName = 0;
delete[] iIATRefs;
}
TInt isNumber(TText *aString)
{
if (aString==NULL)
return 0;
if (strlen((char *)aString)==0)
return 0;
return isdigit(aString[0]);
}
TInt getNumber(TText *aStr)
{
TUint a;
#ifdef __TOOLS2__
istringstream val((char *)aStr);
#else
istrstream val((char *)aStr,strlen((char *)aStr));
#endif
#if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
val >> setbase(0);
#endif //__MSVCDOTNET__
val >> a;
return a;
}
TInt TRomBuilderEntry::SetCodeAlignment(TText* aStr)
{
if (!aStr || (aStr && isNumber(aStr)==0))
return Print(EError, "Number required as argument for keyword 'code-align'.\n");
iCodeAlignment=getNumber(aStr);
return KErrNone;
}
TInt TRomBuilderEntry::SetDataAlignment(TText* aStr)
{
if (!isNumber(aStr))
return Print(EError, "Number required as argument for keyword 'data-align'.\n");
TInt align=getNumber(aStr);
if (align<0 || (align&0x0F) != 0)
return Print(EError, "Positive multiple of 16 required for 'data-align'.\n");
iDataAlignment=align;
return KErrNone;
}
TInt TRomBuilderEntry::SetRelocationAddress(TText *aStr)
{
if (aStr && isNumber(aStr)==0)
return Print(EError, "Number required as argument for keyword 'reloc'.\n");
iOverrideFlags |= KOverrideAddress;
iRelocationAddress=aStr ? getNumber(aStr) : 0xFFFFFFFF;
return KErrNone;
}
TInt TRomBuilderEntry::SetStackReserve(TText *aStr)
{
if (isNumber(aStr)==0)
return Print(EError, "Number required as argument for keyword 'stackreserve'.\n");
iOverrideFlags |= KOverrideStackReserve;
iStackReserve=getNumber(aStr);
return KErrNone;
}
TInt TRomBuilderEntry::SetStackSize(TText *aStr)
{
if (isNumber(aStr)==0)
return Print(EError, "Number required as argument for keyword 'stack'.\n");
iOverrideFlags |= KOverrideStack;
iStackSize=getNumber(aStr);
return KErrNone;
}
TInt TRomBuilderEntry::SetHeapSizeMin(TText *aStr)
{
if (isNumber(aStr)==0)
return Print(EError, "Number required as argument for keyword 'heapmin'.\n");
iOverrideFlags |= KOverrideHeapMin;
iHeapSizeMin=getNumber(aStr);
return KErrNone;
}
TInt TRomBuilderEntry::SetHeapSizeMax(TText *aStr)
{
if (isNumber(aStr)==0)
return Print(EError, "Number required as argument for keyword 'heapmax'.\n");
iOverrideFlags |= KOverrideHeapMax;
iHeapSizeMax=getNumber(aStr);
return KErrNone;
}
TInt TRomBuilderEntry::SetCapability(TText *aStr)
{
iOverrideFlags |= KOverrideCapability;
if (isNumber(aStr))
{
Print(EDiagnostic,"Old style numeric CAPABILTY specification ignored.\n");
return KErrNone;
}
return ParseCapabilitiesArg(iS.iCaps, (char*)aStr);
}
TInt TRomBuilderEntry::SetPriority(TText *aStr)
{
if (isNumber(aStr))
iPriority=(TProcessPriority)getNumber(aStr);
else
{
char *str=(char *)aStr;
if (stricmp(str, "low")==0)
iPriority=EPriorityLow;
else if (strnicmp(str, "background", 4)==0)
iPriority=EPriorityBackground;
else if (strnicmp(str, "foreground", 4)==0)
iPriority=EPriorityForeground;
else if (stricmp(str, "high")==0)
iPriority=EPriorityHigh;
else if (strnicmp(str, "windowserver",3)==0)
iPriority=EPriorityWindowServer;
else if (strnicmp(str, "fileserver",4)==0)
iPriority=EPriorityFileServer;
else if (strnicmp(str, "realtimeserver",4)==0)
iPriority=EPriorityRealTimeServer;
else if (strnicmp(str, "supervisor",3)==0)
iPriority=EPrioritySupervisor;
else
return Print(EError, "Unrecognised priority keyword.\n");
}
if (iPriority<EPriorityLow || iPriority>EPrioritySupervisor)
return Print(EError, "Priority out of range.\n");
iOverrideFlags |= KOverridePriority;
return KErrNone;
}
TInt TRomBuilderEntry::SetUid1(TText *aStr)
{
if (isNumber(aStr)==0)
return Print(EError, "Number required as argument for keyword 'uid1'.\n");
iOverrideFlags |= KOverrideUid1;
iUid1=getNumber(aStr);
return KErrNone;
}
TInt TRomBuilderEntry::SetUid2(TText *aStr)
{
if (isNumber(aStr)==0)
return Print(EError, "Number required as argument for keyword 'uid2'.\n");
iOverrideFlags |= KOverrideUid2;
iUid2=getNumber(aStr);
return KErrNone;
}
TInt TRomBuilderEntry::SetUid3(TText *aStr)
{
if (isNumber(aStr)==0)
return Print(EError, "Number required as argument for keyword 'uid3'.\n");
iOverrideFlags |= KOverrideUid3;
iUid3=getNumber(aStr);
return KErrNone;
}
TInt TRomBuilderEntry::SetCallEntryPoint(TBool aState)
{
if (aState)
iOverrideFlags|=KOverrideCallEntryPoint;
else
iOverrideFlags|=KOverrideNoCallEntryPoint;
return KErrNone;
}
TInt TRomBuilderEntry::SetAttachProcess(TText *aStr)
{
const char* s=(const char*)aStr;
TInt nd=0;
if (*s=='\\')
{
++s;
++nd;
}
TInt l=strlen(s);
if (l==0)
return KErrGeneral;
const char* ss=s;
while(*ss!=0 && *ss!='.') ++ss;
int ext=*ss; // 0 if no extension
iProcessName=new TText[l+2+(ext?0:4)];
char* d=(char *)iProcessName;
strcpy(d+1, s);
if (!ext)
{
char* t=d+1+l;
*t++='.';
*t++='e';
*t++='x';
*t++='e';
*t++=0;
}
char* dd=d;
int ind=nd;
while(*dd)
{
while(*dd && *dd!='\\') ++dd;
if (*dd=='\\')
{
*dd++=0; // change \ to NUL
++nd; // count path elements
}
}
if (!ind && nd)
++nd; // add initial \ if not present
*d=(char)nd;
return 0;
}
TInt TRomBuilderEntry::OpenImageFile()
{
Print(ELog,"Loading E32Image file %s \n", iFileName);
TInt err = Open(iFileName);
if (err != KErrNone)
{
Print(EError,"File %s is not a valid E32Image file (error %d)\n", iFileName, err);
return err;
}
TUint hdrfmt = iHdr->HeaderFormat();
if (hdrfmt != KImageHdrFmt_V)
{
Print(EError,"%s: Can't load old format binary\n", iFileName);
return KErrNotSupported;
}
E32ImageHeaderV* h = iHdr;
// Overide any settings in the image file with those in the obey file
if (iOverrideFlags & (KOverrideUid1|KOverrideUid2|KOverrideUid3))
{
TUint uid1 = h->iUid1;
TUint uid2 = h->iUid2;
TUint uid3 = h->iUid3;
if (iOverrideFlags & KOverrideUid1)
uid1 = iUid1;
if (iOverrideFlags & KOverrideUid2)
uid2 = iUid2;
if (iOverrideFlags & KOverrideUid3)
uid3 = iUid3;
SetUids(TUid::Uid(uid1), TUid::Uid(uid2), TUid::Uid(uid3));
}
if (iOverrideFlags & KOverrideStack)
h->iStackSize = iStackSize;
if (iOverrideFlags & KOverrideHeapMax)
h->iHeapSizeMax = iHeapSizeMax;
if (iOverrideFlags & KOverrideHeapMin)
h->iHeapSizeMin = iHeapSizeMin;
if (iOverrideFlags & KOverridePriority)
h->iProcessPriority = (TUint16)iPriority;
if (iOverrideFlags & KOverrideCapability)
h->iS.iCaps = iS.iCaps;
for (TInt i=0; i<SCapabilitySet::ENCapW; ++i)
{
h->iS.iCaps[i] |= gPlatSecDisabledCaps[i];
h->iS.iCaps[i] &= gPlatSecAllCaps[i];
}
if (iOverrideFlags & KOverrideCodePaged)
{
h->iFlags &= ~KImageCodeUnpaged;
h->iFlags |= KImageCodePaged;
}
if (iOverrideFlags & KOverrideCodeUnpaged)
{
h->iFlags |= KImageCodeUnpaged;
h->iFlags &= ~KImageCodePaged;
}
if ((TInt)h->iUid1 == KExecutableImageUidValue)
{
if (iOverrideFlags & KOverrideDataPaged)
{
h->iFlags &= ~KImageDataUnpaged;
h->iFlags |= KImageDataPaged;
}
if (iOverrideFlags & KOverrideDataUnpaged)
{
h->iFlags |= KImageDataUnpaged;
h->iFlags &= ~KImageDataPaged;
}
}
switch(gCodePagingOverride)
{
case EKernelConfigPagingPolicyNoPaging:
h->iFlags |= KImageCodeUnpaged;
h->iFlags &= ~KImageCodePaged;
break;
case EKernelConfigPagingPolicyAlwaysPage:
h->iFlags |= KImageCodePaged;
h->iFlags &= ~KImageCodeUnpaged;
break;
case EKernelConfigPagingPolicyDefaultUnpaged:
if(!(h->iFlags&(KImageCodeUnpaged|KImageCodePaged)))
h->iFlags |= KImageCodeUnpaged;
break;
case EKernelConfigPagingPolicyDefaultPaged:
if(!(h->iFlags&(KImageCodeUnpaged|KImageCodePaged)))
h->iFlags |= KImageCodePaged;
break;
}
switch(gDataPagingOverride)
{
case EKernelConfigPagingPolicyNoPaging:
h->iFlags |= KImageDataUnpaged;
h->iFlags &= ~KImageDataPaged;
break;
case EKernelConfigPagingPolicyAlwaysPage:
h->iFlags |= KImageDataPaged;
h->iFlags &= ~KImageDataUnpaged;
break;
case EKernelConfigPagingPolicyDefaultUnpaged:
if(!(h->iFlags&(KImageDataUnpaged|KImageDataPaged)))
h->iFlags |= KImageDataUnpaged;
break;
case EKernelConfigPagingPolicyDefaultPaged:
if(!(h->iFlags&(KImageDataUnpaged|KImageDataPaged)))
h->iFlags |= KImageDataPaged;
break;
}
h->iCompressionType=KUidCompressionDeflate; // XIP images are always uncompressed
Print(ELog,"\t\tcompression format:0x%08x \n", h->iCompressionType);
if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO)
Print(ELog,"\t\tgCompress:%d, gCompressionMethod: 0x%08x \n", gEnableCompress , gCompressionMethod);
// Check the uids
if ((TInt)h->iUid1 != KExecutableImageUidValue && (TInt)h->iUid1 != KDynamicLibraryUidValue)
return Print(EError, "First Uid for %s is not KExecutableImageUid or KDynamicLibraryUid\n", iFileName);
// Set up the sizes and location of the distinct areas
iHeaderRange.iSize = sizeof(TRomImageHeader);
iCodeSection.iSize = h->iTextSize;
iCodeSection.iFilePtr = iData + iOrigHdr->iCodeOffset;
TUint impfmt = h->ImportFormat();
if (impfmt==KImageImpFmt_PE || impfmt==KImageImpFmt_PE2)
{
TInt nimports = NumberOfImports();
if (nimports)
{
iImportAddressTableSection.iSize = (nimports+1)*4;
iImportAddressTableSection.iFilePtr = iData + iOrigHdr->iCodeOffset + iOrigHdr->iTextSize;
iIATRefs = new TLinAddr*[nimports+1];
memcpy(iIATRefs, iImportAddressTableSection.iFilePtr, (nimports+1)*sizeof(TLinAddr*));
}
if (h->iExportDirCount)
{
iExportDirSection.iSize = h->iExportDirCount*4;
iExportDirSection.iFilePtr = iData + iOrigHdr->iExportDirOffset;
}
// assertion - there's no rdata between IAT and Export Directory
TInt rdatasize = h->iCodeSize; // overall "readonly" size
rdatasize -= iCodeSection.iSize; // text
rdatasize -= iImportAddressTableSection.iSize; // IAT plus trailing 0
rdatasize -= iExportDirSection.iSize; // export data
if (rdatasize != 0)
{
Print(EWarning, "Unexpected code in %s: %d bytes unexplained\n", iFileName, rdatasize);
// expand the code to cover text+IAT+rdata
iCodeSection.iSize = h->iCodeSize - iExportDirSection.iSize;
}
else
{
if (USE_IAT_FOR_IMPORTS)
iCodeSection.iSize += iImportAddressTableSection.iSize; // include IAT
}
}
else
{
// ELF-derived images have no IAT and the export directory is included in the code section
iImportAddressTableSection.iSize = 0;
iImportAddressTableSection.iFilePtr = NULL;
iExportDirSection.iSize = 0;
iExportDirSection.iFilePtr = NULL;
}
if (h->iDataSize)
{
iDataSection.iSize = h->iDataSize;
iDataSection.iFilePtr = iData + iOrigHdr->iDataOffset;
}
iRomNode->iRomFile->iTotalDataBss = h->iDataSize + h->iBssSize;
iS = h->iS;
if (iVersionPresentInName && iVersionInName != h->ModuleVersion())
{
Print(EError,"%s: Version in name (%d.%d) does not match version in header (%d.%d)\n", iFileName,
iVersionInName>>16, iVersionInName&0x0000ffffu, h->ModuleVersion()>>16, h->ModuleVersion()&0x0000ffffu);
return KErrGeneral;
}
return KErrNone;
}
TInt TRomNode::NameCpy(char* aDest)
//
// Safely copy a file name in the rom entry
//
{
if ((aDest==NULL) || (iName==NULL))
return 0;
if (Unicode)
{
const unsigned char* pSourceByte=iName;
unsigned char* pTargetByte=(unsigned char*)aDest;
for (;;)
{
const TUint sourceByte=*pSourceByte;
if (sourceByte==0)
{
*pTargetByte=0;
*(pTargetByte+1)=0;
break;
}
if ((sourceByte&0x80)==0)
{
*pTargetByte=(unsigned char)sourceByte;
++pTargetByte;
*pTargetByte=0;
++pTargetByte;
++pSourceByte;
}
else if ((sourceByte&0xe0)==0xc0)
{
++pSourceByte;
const TUint secondSourceByte=*pSourceByte;
if ((secondSourceByte&0xc0)!=0x80)
{
Print(EError, "Bad UTF-8 '%s'", iName);
exit(671);
}
*pTargetByte=(unsigned char)((secondSourceByte&0x3f)|((sourceByte&0x03)<<6));
++pTargetByte;
*pTargetByte=(unsigned char)((sourceByte>>2)&0x07);
++pTargetByte;
++pSourceByte;
}
else if ((sourceByte&0xf0)==0xe0)
{
++pSourceByte;
const TUint secondSourceByte=*pSourceByte;
if ((secondSourceByte&0xc0)!=0x80)
{
Print(EError, "Bad UTF-8 '%s'", iName);
exit(672);
}
++pSourceByte;
const TUint thirdSourceByte=*pSourceByte;
if ((thirdSourceByte&0xc0)!=0x80)
{
Print(EError, "Bad UTF-8 '%s'", iName);
exit(673);
}
*pTargetByte=(unsigned char)((thirdSourceByte&0x3f)|((secondSourceByte&0x03)<<6));
++pTargetByte;
*pTargetByte=(unsigned char)(((secondSourceByte>>2)&0x0f)|((sourceByte&0x0f)<<4));
++pTargetByte;
++pSourceByte;
}
else
{
Print(EError, "Bad UTF-8 '%s'", iName);
exit(674);
}
}
const TInt numberOfBytesInTarget=(pTargetByte-(unsigned char*)aDest); // this number excludes the trailing null-terminator
if (numberOfBytesInTarget%2!=0)
{
Print(EError, "Internal error");
exit(675);
}
return numberOfBytesInTarget/2; // returns the length of aDest (in UTF-16 characters for Unicode, not bytes)
}
strcpy(aDest,(const char*)iName);
return strlen((const char*)iName);
}
TInt TRomBuilderEntry::SizeInRom()
//
// Approximate the required size of the file when rommed
//
{
TInt size1, size2;
SizeInSections(size1,size2);
return size1+size2;
}
void TRomBuilderEntry::LoadToRom()
//
//
//
{
// Copy fixed stuff into iRomImageHeader
E32ImageHeaderV* h = iHdr;
const TUint KRomFlagMask = KImageDll | KImageNoCallEntryPoint | KImageFixedAddressExe | KImageNmdExpData | KImageDataPagingMask;
TUint romflags = h->iFlags & KRomFlagMask;
TUint abi = h->ABI();
TUint ept = h->EntryPointFormat();
TUint impfmt = h->ImportFormat();
romflags |= (abi | ept);
iRomImageHeader = (TRomImageHeader*)iHeaderRange.iImagePtr;
iRomImageHeader->iUid1 = h->iUid1;
iRomImageHeader->iUid2 = h->iUid2;
iRomImageHeader->iUid3 = h->iUid3;
iRomImageHeader->iUidChecksum = h->iUidChecksum;
iRomImageHeader->iEntryPoint = iCodeSection.iRunAddr + h->iEntryPoint;
iRomImageHeader->iCodeAddress = iCodeSection.iRunAddr;
iRomImageHeader->iDataAddress = iDataSection.iRunAddr;
iRomImageHeader->iCodeSize = iCodeSection.iSize+iExportDirSection.iSize;
iRomImageHeader->iTextSize = iCodeSection.iSize;
iRomImageHeader->iDataSize = iDataSection.iSize;
iRomImageHeader->iBssSize = h->iBssSize;
iRomImageHeader->iTotalDataSize = iRomNode->iRomFile->iTotalDataBss;
iRomImageHeader->iHeapSizeMin = h->iHeapSizeMin;
iRomImageHeader->iHeapSizeMax = h->iHeapSizeMax;
iRomImageHeader->iStackSize = h->iStackSize;
iRomImageHeader->iDllRefTable = (TDllRefTable*)(iDllRefTableRange.iImageAddr);
iRomImageHeader->iExportDirCount = h->iExportDirCount;
iRomImageHeader->iExportDir = (impfmt==KImageImpFmt_ELF) ?
iCodeSection.iRunAddr + (h->iExportDirOffset - h->iCodeOffset)
: iExportDirSection.iRunAddr;
iRomImageHeader->iS = h->iS;
iRomImageHeader->iToolsVersion = h->iToolsVersion;
iRomImageHeader->iModuleVersion = h->ModuleVersion();
iRomImageHeader->iFlags = romflags | iRomImageFlags;
iRomImageHeader->iPriority = h->ProcessPriority();
iRomImageHeader->iDataBssLinearBase = iDataBssLinearBase;
iRomImageHeader->iNextExtension = 0;
iRomImageHeader->iHardwareVariant = iHardwareVariant;
iRomImageHeader->iExceptionDescriptor = 0;
TUint32 xd = h->iExceptionDescriptor;
if ((xd & 1) && (xd != 0xffffffffu))
iRomImageHeader->iExceptionDescriptor = (xd & ~1) + iRomImageHeader->iCodeAddress;
if (iPreferred)
{
iRomImageHeader->iModuleVersion &= ~0xffffu;
iRomImageHeader->iModuleVersion |= 0x8000u;
}
// Relocate the file to reflect the new addresses
Relocate();
// Copy the sections
iCodeSection.Load();
iExportDirSection.Load();
iDataSection.Load();
}
void TRomBuilderEntry::Relocate()
//
// Relocates the iData to new Code and Data addresses
//
{
TUint codeDelta=iRomImageHeader->iCodeAddress - iHdr->iCodeBase;
TUint dataDelta=iRomImageHeader->iDataBssLinearBase - iHdr->iDataBase;
// code section (text, IAT, export directory)
if (iOrigHdr->iCodeRelocOffset)
RelocateSection(iData + iOrigHdr->iCodeOffset, iData + iOrigHdr->iCodeRelocOffset,
codeDelta, dataDelta, (char*)iCodeSection.iImagePtr, iIATRefs);
// data section
if (iOrigHdr->iDataRelocOffset)
RelocateSection(iData + iOrigHdr->iDataOffset, iData + iOrigHdr->iDataRelocOffset,
codeDelta, dataDelta, (char*)iDataSection.iImagePtr, iIATRefs);
// export directory (only for PE-derived files)
if (iExportDirSection.iSize)
{
TLinAddr* ptr=(TLinAddr*)(iData + iOrigHdr->iExportDirOffset);
TLinAddr textStart = iHdr->iCodeBase;
TLinAddr textFinish = textStart + iHdr->iTextSize;
TLinAddr dataStart = textStart + iHdr->iCodeSize;
TLinAddr dataFinish = dataStart + iHdr->iDataSize + iHdr->iBssSize;
TInt i;
for (i=0; i<iHdr->iExportDirCount; i++, ptr++)
{
TLinAddr data=*ptr+textStart;
if ((data>=textStart) && (data<textFinish))
*ptr=data+codeDelta; // export something from the text/rdata section
else if ((data>=dataStart) && (data<dataFinish))
*ptr=data+dataDelta; // export some data or bss item
else
{
Print(EWarning, "Export directory in %s: item %d -> %08x, which is not text or data!\n", iFileName, i, data);
*ptr=0x13; // unlucky for some
}
}
}
// Replace absent exports with 0
TLinAddr* ptr = (TLinAddr*)(iData + iOrigHdr->iExportDirOffset);
TInt i;
for (i=0; i<iHdr->iExportDirCount; i++, ptr++)
{
if ( !( iExportBitMap[i>>3] & (1u << (i&7)) ) )
*ptr = 0;
}
// Update E32ImageHeader, in case we want to do this process again later
iHdr->iCodeBase += codeDelta;
iHdr->iDataBase += dataDelta;
}
TInt TRomBuilderEntry::FixupImports(E32Rom& aRom)
//
// Modify the import stubs to point directly into the export directory of the corresponding DLLs
// using the back pointers captured by detecting relocations referring to the Import Address Table
// The old-style Import Address Table behaviour can be retained by specifying the "keepIAT" attribute.
//
{
if (iHdr->iImportOffset == 0)
return KErrNone; // nothing to do
TUint impfmt = iHdr->ImportFormat();
TUint my_abi = iHdr->ABI();
TRACE(TIMPORT,Print(ELog,"%40s[%08x] flags %08x\n",iFileName,(TUint)iHardwareVariant,iHdr->iFlags));
const E32ImportSection* importsection = (const E32ImportSection*)(iData + iOrigHdr->iImportOffset);
TLinAddr **iatRef=iIATRefs;
TAddressRange iatRange = iCodeSection;
iatRange.Move(iHdr->iTextSize);
if (USE_IAT_FOR_IMPORTS)
{
if (impfmt == KImageImpFmt_ELF)
return Print(EError, "Can't retain IAT for %s since it never existed\n", iFileName);
if (iRomSectionNumber==0 && aRom.iObey->iSectionPosition!=-1)
return Print(EError, "Can't retain IAT for %s in first section - not yet implemented\n", iFileName);
Print(ELog, "%s has IAT at %08x\n", iFileName, iatRange.iRunAddr);
}
const E32ImportBlock* b = (const E32ImportBlock*)(importsection + 1);
TInt i = iHdr->iDllRefTableCount;
TInt numberOfImports=0;
TUint *impOrdinalP = (TUint*)iImportAddressTableSection.iFilePtr; // points to original IAT in file
while (i-->0)
{
char* dllname = (char*)importsection + b->iOffsetOfDllName;
TDllFindInfo find_info(dllname, this);
TBool fallback;
TRomNode* romnode = aRom.FindImageFileByName(find_info, EFalse, fallback);
if (!romnode)
{
Print(EError, "Can't fixup imports for\n\t%s\nbecause\n\t%s\nis not in rom.\n",
(const char*)TModuleName(this), (const char*)TModuleName(find_info));
aRom.FindImageFileByName(find_info, ETrue, fallback);
return KErrGeneral;
}
TRomFile* dll=romnode->iRomFile;
TRACE(TIMPORT,Print(ELog,"%s importing from %s\n", (const char*)TModuleName(this), (const char*)TModuleName(find_info)));
if (romnode->ABI() != my_abi)
{
Print(EWarning, "File %s links to %s with different ABI\n", (const char*)TModuleName(this), (const char*)TModuleName(find_info));
}
TInt j;
numberOfImports += b->iNumberOfImports;
if (impfmt==KImageImpFmt_ELF)
impOrdinalP = (TUint*)(b->Imports()); // for ELF must look in import block
char* codeBase = (char*)iCodeSection.iImagePtr;
for (j=0; j<b->iNumberOfImports; j++)
{
TLinAddr exportAddr = 0xdeadbeef;
TLinAddr exporter = 0xdeadbeef;
TUint impOrdinal = *impOrdinalP;
TUint impOffset = 0;
if (impfmt==KImageImpFmt_ELF)
{
TUint impd = *(TUint*)(codeBase + impOrdinal);
impOrdinal = impd & 0xffff;
impOffset = impd >> 16;
}
TRACE(TIMPORT,Print(ELog,"Ordinal %d\n", impOrdinal));
TInt ret=dll->AddressFromOrdinal(exporter, exportAddr, impOrdinal);
TRACE(TIMPORT,Print(ELog,"export %08x exporter %08x\n",exportAddr,exporter));
if (ret!=KErrNone)
{
Print(EError, "%s wants ordinal %d from %s which only exports %d functions\n",
iFileName, impOrdinal, (const char*)TModuleName(find_info), dll->ExportDirCount());
exporter=0x13; // unlucky for some...
exportAddr=0x13;
}
else if (exportAddr == 0 && impOrdinal != 0)
{
Print(EError, "%s wants ordinal %d from %s which is absent\n",
iFileName, impOrdinal, (const char*)TModuleName(find_info));
exporter=0x13; // unlucky for some...
exportAddr=0x13;
}
if (USE_IAT_FOR_IMPORTS)
{
// must be PE-derived
*iatRef=(unsigned long*)exportAddr; //iatRange.iRunAddr; // point into IAT ...
*(TLinAddr*)(iatRange.iImagePtr)=exportAddr; // ... which has a copy of the export
iatRange.Move(sizeof(TLinAddr));
iatRef++;
}
else if (impfmt==KImageImpFmt_PE || impfmt==KImageImpFmt_PE2)
{
**iatRef=exporter; // point directly into export directory
iatRef++;
}
else
{
// ELF-derived
*(TUint*)(codeBase + *impOrdinalP) = exportAddr + impOffset;
}
impOrdinalP++;
}
b = b->NextBlock(impfmt);
}
iImportCount=numberOfImports;
return KErrNone;
}
const char* KF32ProcessName="efile.exe";
const char* KWservProcessName="ewsrv.exe";
const char* KFbservProcessName="fbserv.exe";
const char* KMdaSvrProcessName="mediaserverstub.exe";
const char* KC32ProcessName="c32exe.exe";
const char* TRomBuilderEntry::GetDefaultAttachProcess()
//
// Work out the attach process from the file extension
//
// Only need to handle DLLs which run in F32, WSERV, FBSERV, MEDIASVR, C32
// F32: FSY FXT
// WSERV: ANI
// FBSERV:
// MDASVR: MDA
// C32: CSY, PRT, TSY, AGT, AGX
//
{
const char* s=(const char*)iName;
TInt l=strlen(s);
if (l<4 || s[l-4]!='.')
return NULL;
s+=(l-3);
if (stricmp(s,"fsy")==0)
return KF32ProcessName;
if (stricmp(s,"fxt")==0)
return KF32ProcessName;
if (stricmp(s,"ani")==0)
return KWservProcessName;
if (stricmp(s,"mda")==0)
return KMdaSvrProcessName;
if (stricmp(s,"csy")==0)
return KC32ProcessName;
if (stricmp(s,"prt")==0)
return KC32ProcessName;
if (stricmp(s,"tsy")==0)
return KC32ProcessName;
if (stricmp(s,"agt")==0)
return KC32ProcessName;
if (stricmp(s,"agx")==0)
return KC32ProcessName;
return NULL;
}
TInt TRomBuilderEntry::FindAttachProcess(E32Rom& aRom)
{
if (iRomImageFlags & (KRomImageFlagVariant|KRomImageFlagExtension|KRomImageFlagDevice))
return KErrNone;
const char* attp_name=(const char*)iProcessName;
int nd=0;
if (attp_name)
nd=*attp_name++;
else
attp_name=GetDefaultAttachProcess();
if (!attp_name)
return KErrNone;
TInt i;
TUint my_abi = iHdr->ABI();
TUint abi = 0;
if (nd)
{
// path search
TRomNode* rn=aRom.iObey->iRootDirectory;
for (; nd; --nd)
{
rn=rn->FindInDirectory((TText*)attp_name);
if (!rn)
{
Print(EError, "Invalid attach process name element %s\n", attp_name);
return KErrGeneral;
}
attp_name+=(strlen(attp_name)+1);
}
iRomNode->iRomFile->iAttachProcess=rn->iRomFile;
abi = iRomNode->iRomFile->iAttachProcess->ABI();
}
else
{
// filename only search
for (i=0; i<aRom.iObey->iNumberOfPeFiles; i++)
{
TRomBuilderEntry* e=aRom.iPeFiles[i];
abi = e->iHdr->ABI();
if (stricmp((const char*)e->iName, attp_name)==0)
{
if (iRomNode->iRomFile->iAttachProcess)
{
Print(EError, "Ambiguous attach process name %s\n", attp_name);
return KErrGeneral;
}
iRomNode->iRomFile->iAttachProcess=e->iRomNode->iRomFile;
}
}
}
if (abi != my_abi)
{
Print(EWarning, "File %s: Attach process has different ABI\n", (const char*)TModuleName(this));
}
return KErrNone;
}
TInt TRomBuilderEntry::BuildDependenceGraph(E32Rom& aRom)
//
// Fill in the iDeps
//
{
TBool is_kernel = ((iRomImageFlags & KRomImageFlagsKernelMask) != 0);
TRomNode* rn = iRomNode;
TRomFile* rf = rn->iRomFile;
TUint my_abi = iHdr->ABI();
TUint impfmt = iHdr->ImportFormat();
rf->iNumDeps = iHdr->iDllRefTableCount;
if (IsDll() && aRom.iObey->iMemModel!=E_MM_Flexible && aRom.iObey->iMemModel!=E_MM_Multiple && (iHdr->iDataSize!=0 || iHdr->iBssSize!=0))
{
TInt r=FindAttachProcess(aRom);
if (r!=KErrNone)
return r;
if (aRom.iObey->iMemModel==E_MM_Moving)
{
if (rf->iAttachProcess && !(rf->iAttachProcess->RomImageFlags() & KRomImageFlagFixedAddressExe))
rf->iAttachProcess=NULL; // ignore attach process if not fixed
}
}
TRomFile* attp=rf->iAttachProcess;
if (attp)
++rf->iNumDeps; // extra implicit dependence on process
if (rf->iNumDeps)
{
rf->iDeps=new TRomFile* [rf->iNumDeps];
memset(rf->iDeps, 0, rf->iNumDeps*sizeof(TRomFile*));
}
TInt err = KErrNone;
const E32ImportSection* importSection = (const E32ImportSection*)(iData + iOrigHdr->iImportOffset);
const E32ImportBlock* block = (const E32ImportBlock*)(importSection + 1);
TInt i;
for (i=0; i<iHdr->iDllRefTableCount; i++, block = block->NextBlock(impfmt), TRACE(TIMPORT,Print(ELog,"DllRef/dll done\n")) )
{
char* dllname = (char*)importSection + block->iOffsetOfDllName;
TDllFindInfo find_info(dllname, this);
TBool fallback;
TRomNode* romnode = aRom.FindImageFileByName(find_info, EFalse, fallback);
if (!romnode)
{
Print(EError, "Can't build dependence graph for\n\t%s\nbecause\n\t%s\nis not in rom.\n",
(const char*)TModuleName(this), (const char*)TModuleName(find_info));
aRom.FindImageFileByName(find_info, ETrue, fallback);
err = KErrNotFound;
continue;
}
if (fallback)
{
Print(EWarning, "File %s links to %s\n\twhich is not in ROM. Version 1.0 of latter used instead.\n",
(const char*)TModuleName(this), (const char*)TModuleName(find_info));
}
TRACE(TIMPORT,Print(ELog,"%s links to %s\n", (const char*)TModuleName(this), (const char*)TModuleName(find_info)));
TRACE(TIMPORT,Print(ELog,"Resolves to %s\n", (const char*)TModuleName(*romnode)));
TBool dep_is_kernel = ((romnode->iRomFile->RomImageFlags() & KRomImageFlagsKernelMask) != 0);
if (dep_is_kernel != is_kernel)
{
if (is_kernel)
{
Print(EError, "Kernel side executable\n\t%s\nlinks to user side executable\n\t%s\n",
(const char*)TModuleName(this), (const char*)TModuleName(find_info));
}
else
{
Print(EError, "User side executable\n\t%s\nlinks to kernel side executable\n\t%s\n",
(const char*)TModuleName(this), (const char*)TModuleName(find_info));
}
err = KErrGeneral;
continue;
}
// prevent the situiation which importer is primary, variant or extension, exporter is device
if (is_kernel && !Device() && romnode->iRomFile->iRbEntry->Device())
{
Print(EWarning, "Kernel/variant/extension\n\t%s\nlinks to non-extension LDD/PDD\n\t%s\n",
(const char*)TModuleName(this), (const char*)TModuleName(find_info));
}
if (romnode->ABI() != my_abi)
{
Print(EWarning, "File %s links to %s with different ABI\n", (const char*)TModuleName(this), (const char*)TModuleName(find_info));
}
rf->iDeps[i]=romnode->iRomFile;
const SSecurityInfo& s1 = iHdr->iS;
const SSecurityInfo& s2 = romnode->iRomFile->SecurityInfo();
TInt r = CompareCapabilities(s1.iCaps, s2.iCaps, iFileName, dllname);
if (r != KErrNone)
err = r;
if (romnode->iRomFile==attp)
attp=NULL;
}
if (attp)
rf->iDeps[rf->iNumDeps-1]=attp;
TRACE(TIMPORT,Print(ELog,"BuildDep done all\n"));
return err;
}
TInt TRomBuilderEntry::ResolveDllRefTable(E32Rom& aRom)
//
// Fill in the DLLRefTable
//
{
TRomNode* rn = iRomNode;
TRomFile* rf = rn->iRomFile;
(void)aRom;
if (rf->iNumPDeps==0)
return KErrNone; // nothing to do
TDllRefTable* dllRefTable=(TDllRefTable*)(iDllRefTableRange.iImagePtr);
TUint16 flags=0;
dllRefTable->iFlags=flags;
dllRefTable->iNumberOfEntries=(TUint16)rf->iNumPDeps;
TInt err = KErrNone;
TInt i;
for (i=0; i<rf->iNumPDeps; i++)
{
dllRefTable->iEntry[i]=(TRomImageHeader*)rf->iPDeps[i]->iAddresses.iRunAddr;
}
TRACE(TIMPORT,Print(ELog,"DllRef done all\n"));
return err;
}
void TRomBuilderEntry::DisplaySize(TPrintType aWhere)
{
if(gLogLevel > DEFAULT_LOG_LEVEL){
if(gLogLevel & LOG_LEVEL_FILE_DETAILS)
{
// More detailed information about file name in .
TBool aIgnoreHiddenAttrib = ETrue;
TInt aLen = iRomNode->FullNameLength(aIgnoreHiddenAttrib);
char * aBuf = new char[aLen+1];
iRomNode->GetFullName(aBuf, aIgnoreHiddenAttrib);
if (iPatched|iRomNode->iHidden)
Print(aWhere, "%s\t%d\t%s\t%s\n", iFileName, SizeInRom(), iPatched?"patched":"hidden", aBuf);
else
Print(aWhere, "%s\t%d\t%s\n", iFileName, SizeInRom(), aBuf);
delete[] aBuf;
}
}
else{
if (iPatched|iRomNode->iHidden)
Print(aWhere, "%s\t%d\t%s\n", iFileName, SizeInRom(), iPatched?"patched":"hidden");
else
Print(aWhere, "%s\t%d\n", iFileName, SizeInRom());
}
}
/**
* TRomFile iRomEntry is a linked list through the various
* distinct TRomEntry objects which may exist for the associated file
* due to variant processing / aliasing
*/
void TRomFile::SetRomEntry(TRomEntry* aEntry)
{
// Need to add to the tail of the list, for backwards compatibility
// Adding to the front of the list changes the iPrimary and iSecondary
// values in the TRomHeader when multiple variants are present
if (iFinal)
return; // address already established so no fixup required
if (iRomEntry==0)
{
iRomEntry = aEntry;
return;
}
TRomEntry* entry = iRomEntry;
while (entry->iAddressLin != 0)
entry = (TRomEntry*)entry->iAddressLin;
entry->iAddressLin = (TLinAddr)aEntry;
}
void TRomBuilderEntry::FixupRomEntries(TInt aSize)
{
if (iPatched)
return; // patched files don't appear in the ROM file system
iRomNode->Finalise(aSize);
}
/**
* TRomNode::Finalise updates the associated TRomEntry objects with the final size and
* linear address information supplied by the TRomBuilderEntry. It also stores the
* summary information for resolving static linkages to this executable (if appropriate)
* and adjusts the TRomNodes so that they are identical to the ones which would be
* obtained by walking the directory structure in an existing ROM.
*/
void TRomNode::Finalise(TInt aSize)
{
TRACE(TIMPORT,Print(ELog,"TRomNode %s Finalise %08x %d\n", (const char*)TModuleName(*this), iRomFile->iFinal));
iRomFile->Finalise(aSize);
}
/**
* TRomFile::Finalise updates the associated TRomEntry objects with the final size and
* linear address information supplied by the TRomBuilderEntry. It also stores the
* summary information for resolving static linkages to this executable (if appropriate)
* and adjusts the TRomFiles so that they are identical to the ones which would be
* obtained by walking the directory structure in an existing ROM.
*/
void TRomFile::Finalise(TInt aSize)
{
if (iFinal)
return;
TLinAddr ra = iRbEntry->iHeaderRange.iImageAddr;
TRomEntry* entry = iRomEntry;
while (entry)
{
TRomEntry* next = (TRomEntry*)entry->iAddressLin;
entry->iSize = aSize;
entry->iAddressLin = ra;
entry = next;
}
iAddresses = iRbEntry->iHeaderRange;
iAddresses.iSize = aSize;
if ((!iRbEntry->iResource) && (!iRbEntry->HCRDataFile()))
{
iExportDir = iAddresses;
iExportDir.iSize = iRbEntry->iHdr->iExportDirCount * sizeof(TLinAddr);
iExportDir.Move(RomImgHdr()->iExportDir - iAddresses.iRunAddr);
}
iRbEntry = 0;
iFinal = ETrue;
}
void TRomBuilderEntry::SetRomNode(TRomNode* aNode)
{
iRomNode = aNode;
}
void TImageSection::Load() const
{
if (iSize && iImagePtr && iFilePtr)
memcpy(iImagePtr,iFilePtr,iSize);
}
/**
* TDllExportInfo is the information about a DLL which is necessary to
* resolve a static link to that DLL. It all comes from the TRomImageHeader,
* as it would with a static linkage resolved at runtime.
*/
TRomFile::TRomFile()
{
memset(this, 0, sizeof(TRomFile));
iRefCount = 1;
iHwvd = KVariantIndependent;
iDataBssOffsetInExe = -1;
}
TRomFile::~TRomFile()
{
delete[] iDeps;
delete[] iPDeps;
}
TInt TRomFile::AddressFromOrdinal(TLinAddr& aEDataAddr, TLinAddr& aExport, TUint aOrdinal)
//
// Get the export address of symbol aOrdinal
//
{
if(aOrdinal == 0)
{
aEDataAddr = iExportDir.iRunAddr -1 ;
aExport = *(TLinAddr*)((TLinAddr*)iExportDir.iImagePtr - 1);
if((TInt)aExport == ExportDirCount()) {
aEDataAddr = 0;
aExport = 0;
}
return KErrNone;
}
TUint index = aOrdinal - KOrdinalBase;
if (index >= (TUint)ExportDirCount())
return KErrNotFound;
aEDataAddr = iExportDir.iRunAddr + index * sizeof(TLinAddr);
aExport = ((TLinAddr*)iExportDir.iImagePtr)[index];
return KErrNone;
}
bool TRomFile::ComputeSmpSafe(const TRomBuilderEntry* aRbEntry)
{
// A component is SMP safe if:
//
// 1. It's E32 image file is marked as SMP safe (MMP keyword SMPSAFE).
// 2. All components it links to are SMP safe.
//
// This implies a recursive dependency structure.
if (iSmpInfo.isInit)
{
// We have already visited this node.
return iSmpInfo.isSafe;
}
// Mark this node as "active," meaning that we are currently evaluating it. We
// use this to detect cycles in the dependency graph.
iSmpInfo.isActive = 1;
iSmpInfo.isSafe = 1;
// Have we found any cycle in the graph?
bool is_cycle = 0;
if ( aRbEntry->iOrigHdr->iFlags & KImageSMPSafe )
{
// OK, the E32 file for this node is marked as SMPSAFE. Now we need to check
// that all nodes we depend on are SMP safe.
for (int i = 0; i < iNumDeps; i++)
{
TRomFile* e = iDeps[i];
assert(this != e);
if (e->iSmpInfo.isActive)
{
is_cycle = 1;
}
else if ( ! e->ComputeSmpSafe(e->iRbEntry) )
{
if (gLogLevel & LOG_LEVEL_SMP_INFO)
{
Print(ELog,"SMP-unsafe: %s: links to unsafe component %s.\n",
aRbEntry->iBareName , e->iRbEntry->iBareName);
}
iSmpInfo.isSafe = 0;
break;
}
}
}
else
{
if (gLogLevel & LOG_LEVEL_SMP_INFO)
{
Print(ELog,"SMP-unsafe: %s: MMP keyword SMPSAFE not used.\n", aRbEntry->iBareName);
}
iSmpInfo.isSafe = 0;
}
iSmpInfo.isActive = 0;
if (!iSmpInfo.isSafe || !is_cycle)
{
iSmpInfo.isInit = 1;
}
return iSmpInfo.isSafe;
}
/**
* TRomNode::CopyDirectory performs a deep copy of the TRomNode structure
*/
TRomNode* TRomNode::CopyDirectory(TRomNode*& aLastExecutable, TRomNode* aParent)
{
if (iHidden && iChild==0)
{
// Hidden file - do not copy (as it wouldn't be visible in the ROM filestructure)
if (iSibling)
return iSibling->CopyDirectory(aLastExecutable, aParent);
else
return 0;
}
TRomNode* copy = new TRomNode(*this);
copy->iParent = aParent;
if(aLastExecutable==0)
aLastExecutable = copy; // this must be the root of the structure
// recursively copy the sub-structures
if (iChild)
copy->iChild = iChild->CopyDirectory(aLastExecutable, copy);
if (iSibling)
copy->iSibling = iSibling->CopyDirectory(aLastExecutable, aParent);
if (copy->iAtt & KEntryAttXIP)
AddExecutableFile(aLastExecutable,copy);
return copy;
}
TInt TRomNode::Alias(TRomNode* aNode, TRomNode*& aLastExecutable)
{
if (aNode->iAtt & KEntryAttXIP)
AddExecutableFile(aLastExecutable,this);
return SetBareName();
}
TInt TRomNode::Rename(TRomNode *aOldParent, TRomNode* aNewParent, TText* aNewName)
{
aOldParent->Remove(this);
aNewParent->Add(this);
free(iName);
iName = (TText*)NormaliseFileName((const char*)aNewName);
return SetBareName();
}
TInt TRomNode::SetBareName()
{
free(iBareName);
TUint32 uid;
TUint32 vin;
TUint32 flg;
iBareName = SplitFileName((const char*)iName, uid, vin, flg);
if (uid || (flg & EUidPresent))
return KErrBadName;
if (strchr(iBareName, '{') || strchr(iBareName, '}'))
return KErrBadName;
if ((iAtt & KEntryAttXIP) && (flg & EVerPresent))
{
TUint32 ver = iRomFile->ModuleVersion();
if (ver != vin)
return KErrArgument;
}
return KErrNone;
}