// 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:
// e32\memmodel\emul\win32\mcodeseg.cpp
//
//
#define __INCLUDE_ALL_SUPPORTED_CAPABILITIES__
#include "memmodel.h"
#include <property.h>
#include <emulator.h>
#include <wchar.h>
#define __CHECKHEAP() ((RHeapK*)K::Allocator)->Check()
static TBool BootComplete; // flag set when boot EXE is loaded as an EPOC process
static DWin32CodeSeg* KernelCodeSeg;
static HMODULE KernelModuleHandle;
GLREF_C TInt CompareCodeSegsByName(const DCodeSeg& aA, const DCodeSeg& aB);
void TruncToNarrow(TUint8* aDes, const TUint16* aSrc, int aLen)
{
//converts to narrow by dumping the high order byte
if(aDes && aSrc)
{
if(aLen==-1)
{
for(int index=0;*aSrc;index++)
*aDes++ = (TUint8)*aSrc++;
*aDes = '\0';
}
else
for(int index=0;index<aLen;index++)
*aDes++ = (TUint8)*aSrc++;
}
}
void ExpandToWide(TUint16* aDes, const TUint8* aSrc, int aLen)
{
if(aDes && aSrc)
{
for(int index=0;index<aLen;index++)
*aDes++ = (TUint16)*aSrc++;
}
}
#ifdef KDLL
void DumpWin32CodeSeg(DWin32CodeSeg& a)
{
const TUint32* uid=(const TUint32*)&a.iUids;
Kern::Printf("DWin32CodeSeg@%08x:",&a);
Kern::Printf("iLink = %08x %08x", a.iLink.iNext, a.iLink.iPrev);
Kern::Printf("iTempLink = %08x %08x", a.iTempLink.iNext, a.iTempLink.iPrev);
Kern::Printf("iGbgLink = %08x %08x", a.iGbgLink.iNext, a.iGbgLink.iPrev);
Kern::Printf("iAccessCount = %d", a.iAccessCount);
Kern::Printf("iEntryPtVeneer = %08x", a.iEntryPtVeneer);
Kern::Printf("iFileEntryPoint = %08x", a.iFileEntryPoint);
Kern::Printf("iFileName = %lS", a.iFileName);
Kern::Printf("iRootName = %lS", &a.iRootName);
Kern::Printf("iExtOffset = %d", a.iExtOffset);
Kern::Printf("iModuleVersion = %08x", a.iModuleVersion);
Kern::Printf("iUids = %08x %08x %08x", uid[0], uid[1], uid[2]);
Kern::Printf("iDepCount=%d iDeps=%08x", a.iDepCount, a.iDeps);
Kern::Printf("iNextDep=%d, iMark=%08x, iAttr=%08x", a.iNextDep, a.iMark, a.iAttr);
Kern::Printf("iExeCodeSeg=%08x, iAttachProcess=%O", a.iExeCodeSeg, a.iAttachProcess);
Kern::Printf("iWinInstance = %08x", a.iWinInstance);
Kern::Printf("iModuleHandle = %08x", a.iModuleHandle);
Kern::Printf("iModuleFile = %08x", a.iModuleFile);
Kern::Printf("iAlwaysLoaded = %08x", a.iAlwaysLoaded);
Kern::Printf("iModuleList = %08x", a.iModuleList);
}
#endif
void ExecInEntryPoint()
{
// This function will be called if an Exec:: call is attempted in the entry
// point of a DLL which didn't specify 'epocallowdlldata'
Kern::Fault("BAD DLL STATIC",0);
}
static const SFastExecTable DummyFastExecTable={0,{0}};
static const SSlowExecTable DummySlowExecTable={0,(TLinAddr)ExecInEntryPoint,0,{{0,0}}};
// Force a call to a DLL entry point to initialise any gratuitous writeable data
// generated by the compiler.
// Change exec table to prevent any executive calls in case someone forgot to
// use the 'epocallowdlldata' option.
void ForceEntryPointCall(TLinAddr aEntryPoint)
{
__KTRACE_OPT(KDLL,Kern::Printf("ForceEntryPoint %08x", aEntryPoint));
NKern::Lock();
NThread* nthrd = NKern::CurrentThread();
const SFastExecTable* fast = nthrd->iFastExecTable;
const SSlowExecEntry* slow = nthrd->iSlowExecTable;
nthrd->iFastExecTable = (SFastExecTable*)&DummyFastExecTable;
nthrd->iSlowExecTable = DummySlowExecTable.iEntries;
TLibraryEntry ep = (TLibraryEntry)aEntryPoint;
(*ep)(KModuleEntryReasonProcessAttach);
nthrd->iFastExecTable = fast;
nthrd->iSlowExecTable = slow;
NKern::Unlock();
}
class TWin32Filename
{
public:
inline TWin32Filename()
{iBuf[0] = '\0';}
inline TWin32Filename(const TDesC& aFilename)
{Set(aFilename);}
inline TWin32Filename& operator=(const TDesC& aFilename)
{Set(aFilename);return *this;}
inline operator LPCWSTR() const
{return iBuf;}
private:
void Set(const TDesC& aFilename);
private:
WCHAR iBuf[KMaxFileName + 1];
};
void TWin32Filename::Set(const TDesC& aFilename)
{
TUint16 fileName[KMaxFileName];
ExpandToWide(fileName, aFilename.Ptr(), aFilename.Length());
TPtr p((TUint8*)iBuf,KMaxFileName<<1);
Property::MapFilename(p, TPtrC((TUint8*)fileName,aFilename.Length()<<1));
iBuf[p.Length()>>1] = '\0';
}
class DModuleList : public DBase
{
public:
enum TFlags
{
EFlagData=0x01,
EFlagDataPresent=0x02,
EFlagAlreadyLoaded=0x04,
EFlagMark=0x08,
EFlagExe=0x10,
EFlagAlwaysLoaded=0x20,
EFlagExeInTree=0x40,
};
struct SModule
{
TLinAddr iModuleHandle;
DWin32CodeSeg* iCodeSeg;
TUint32 iFlags;
SSecurityInfo iS;
TUint32 iModuleVersion;
TInt iDepCount;
TInt* iDepList;
};
public:
DModuleList(DWin32CodeSeg* aMainSeg, DProcess* aProcess);
virtual ~DModuleList();
TInt Find(TInt aModule);
TInt GatherDependencies(HMODULE aModule);
TInt CompileDepLists();
void SetFlags();
TUint32 Flags(SModule* aM);
TInt LoadDependencies();
void LinkDependencies();
TInt Loaded();
public:
DWin32CodeSeg* iMain;
DProcess* iAttachProcess;
RArray<SModule> iModules;
};
DModuleList::DModuleList(DWin32CodeSeg* aMainSeg, DProcess* aProcess)
: iMain(aMainSeg), iAttachProcess(aProcess),
iModules(8, _FOFF(SModule,iModuleHandle), 2*256)
{
}
DModuleList::~DModuleList()
{
TInt c = iModules.Count();
if (c)
{
SModule* pM = (SModule*)&iModules[0];
SModule* pE = pM + c;
for (; pM<pE; ++pM)
{
Kern::Free(pM->iDepList);
}
}
iModules.Close();
}
TInt DModuleList::Find(TInt aModule)
{
SModule mod;
mod.iModuleHandle=(TLinAddr)aModule;
return iModules.FindInUnsignedKeyOrder(mod);
}
/**
Populate iModules with SModule entries corresponding to supplied HModule and all of its dependencies,
direct and indirect.
@param aModule A Windows module handle
@return KErrNone if successful
*/
TInt DModuleList::GatherDependencies(HMODULE aModule)
{
__KTRACE_OPT(KDLL, Kern::Printf(">DModuleList::GatherDependencies %08x %08x %C", aModule, iMain, iMain));
Emulator::TModule etm(aModule);
SModule mod;
mod.iModuleHandle=(TLinAddr)aModule;
mod.iCodeSeg=NULL;
mod.iDepList=NULL;
TUint32 uid[3];
TUidType& uidref=*(TUidType*)uid;
const TEmulatorImageHeader* hdr = (const TEmulatorImageHeader*)etm.Section(KWin32SectionName_Symbian);
if (!hdr)
return KErrNotSupported;
__KTRACE_OPT(KDLL,Kern::Printf("Module flags %08x, cap %08x %08x, sid %08x", hdr->iFlags, hdr->iS.iCaps[1], hdr->iS.iCaps[0], hdr->iS.iSecureId));
mod.iS = hdr->iS;
// Overide capabilities in image
const SCapabilitySet& disabledCaps = *(SCapabilitySet*)&TheSuperPage().iDisabledCapabilities;
for(TInt i=0; i<SCapabilitySet::ENCapW; i++)
{
mod.iS.iCaps[i] |= disabledCaps[i];
mod.iS.iCaps[i] &= AllSupportedCapabilities[i];
}
mod.iModuleVersion = hdr->iModuleVersion;
mod.iFlags = (hdr->iFlags & KEmulatorImageFlagAllowDllData) ? EFlagData|EFlagDataPresent : 0;
uidref = *(const TUidType*)&hdr->iUids[0];
TBool isExe = (uid[0]==KExecutableImageUidValue);
TBool data_section_present = (etm.Section(KWin32SectionName_EpocData) != NULL);
if (data_section_present && isExe)
mod.iFlags = EFlagData|EFlagDataPresent;
__KTRACE_OPT(KDLL,Kern::Printf("DataSectionPresent = %x", data_section_present));
// Can't do this for CodeWarrior since it sticks everything in .data, even constants
// On VC6 this check works for Base code, but not for some other code.
// if (data_section_present && !isExe && !(hdr->iFlags & KEmulatorImageFlagAllowDllData))
// return KErrNotSupported;
if (!data_section_present)
mod.iFlags = 0;
if (isExe)
mod.iFlags |= EFlagExe|EFlagExeInTree;
SWin32Module w32m;
w32m.iWin32ModuleHandle=(TLinAddr)aModule;
w32m.iCodeSeg=NULL;
TInt ix=MM::Win32Modules.FindInUnsignedKeyOrder(w32m);
__KTRACE_OPT(KDLL, Kern::Printf("GlobalIx=%d", ix));
if ((ix>=0 && !MM::Win32Modules[ix].iCodeSeg) || aModule==KernelModuleHandle)
mod.iFlags|=EFlagAlwaysLoaded;
TInt r=iModules.InsertInUnsignedKeyOrder(mod);
__KTRACE_OPT(KDLL, Kern::Printf("Flags=%08x, InsertRes=%d", mod.iFlags, r));
if (r==KErrAlreadyExists)
return KErrNone;
if (r!=KErrNone)
return r;
if (mod.iFlags & EFlagAlwaysLoaded)
return KErrNone; // stop if we reach an extension or variant
if (data_section_present && (mod.iFlags & EFlagData)==0)
{
// DLL, .data present but 'epocallowdlldata' not specified
// - either the compiler forgetting that something's constant or
// developer forgetting to specify 'epocallowdlldata'.
// call entry point from here to keep the compiler happy
const char* entry_name = "_E32Dll" ;
TLinAddr ep = (TLinAddr)Emulator::GetProcAddress(aModule, entry_name);
__NK_ASSERT_ALWAYS(ep!=0);
ForceEntryPointCall(ep);
}
const IMAGE_IMPORT_DESCRIPTOR* imports = etm.Imports();
if (imports)
{
for (; imports->Characteristics; ++imports )
{
__KTRACE_OPT(KDLL, { TPtrC8 n((const TText8*)etm.Translate(imports->Name)); Kern::Printf("Importing from %S", &n);} );
Emulator::TModule imp_etm((PCSTR)etm.Translate(imports->Name));
if (!imp_etm.IsValid())
{
__KTRACE_OPT(KDLL, Kern::Printf("Spurious import"));
continue;
}
if (imp_etm.Section(KWin32SectionName_Symbian) == 0)
{
__KTRACE_OPT(KDLL, Kern::Printf("Not EPOC Module"));
continue; // not an epoc DLL
}
r=GatherDependencies(imp_etm.iModule);
if (r!=KErrNone)
return r;
}
}
__KTRACE_OPT(KDLL, Kern::Printf("<DModuleList::GatherDependencies %08x %08x %C", aModule, iMain, iMain));
return KErrNone;
}
#ifdef __VC32__
#pragma warning( disable : 4701 ) // disable warning C4701: local variable 'missingCaps' may be used without having been initialized
#endif
/**
Iterate through imports (if any) of each SModule in list. Populate iDepList with the indicies (in iModules)
of directly required modules. Checks that dependencies are legal under platsec.
@return KErrNone on success.
*/
TInt DModuleList::CompileDepLists()
{
__KTRACE_OPT(KDLL, Kern::Printf(">DModuleList::CompileDepLists"));
TInt result=KErrNone;
TInt c=iModules.Count();
SModule* pM=(SModule*)&iModules[0];
SModule* pE=pM+c;
for (; pM<pE; ++pM)
{
pM->iDepList=(TInt*)Kern::Alloc(c*sizeof(TInt));
if (!pM->iDepList)
return KErrNoMemory;
memset(pM->iDepList, 0xff, c*sizeof(TInt));
Emulator::TModule etm((HINSTANCE)pM->iModuleHandle);
const IMAGE_IMPORT_DESCRIPTOR* imports = etm.Imports();
__KTRACE_OPT(KDLL, Kern::Printf("Module %08x, imports=%08x flags=%08x", pM->iModuleHandle, imports, pM->iFlags));
if (!imports || (pM->iFlags&EFlagAlwaysLoaded))
continue;
const SCapabilitySet& cap = pM->iS.iCaps;
const SCapabilitySet& disabledCaps=*(SCapabilitySet*)&TheSuperPage().iDisabledCapabilities;
TInt* pI=pM->iDepList;
for (; imports->Characteristics; ++imports )
{
Emulator::TModule imp_etm((PCSTR)etm.Translate(imports->Name));
if (!imp_etm.IsValid())
continue; // spurious import
if (imp_etm.Section(KWin32SectionName_Symbian) == 0)
continue; // not an epoc DLL
TInt ix=Find((TInt)imp_etm.iModule);
__ASSERT_ALWAYS(ix>=0, MM::Panic(MM::ECompileDepLists));
*pI++=ix;
__KTRACE_OPT(KDLL, Kern::Printf("Depends on %08x, ix=%d", imp_etm.iModule, ix));
const SModule& dep = iModules[ix];
SCapabilitySet missingCaps;
SCapabilitySet depCaps = dep.iS.iCaps;
TUint32 checkFail = 0;
for (TInt i=0; i<SCapabilitySet::ENCapW; ++i)
{
depCaps[i] = dep.iS.iCaps[i]|disabledCaps[i];
TUint32 missing = cap[i] & ~depCaps[i];
missingCaps[i] = missing;
checkFail |= missing;
}
__KTRACE_OPT(KDLL, Kern::Printf("Cap=%08x %08x, DepCap=%08x %08x", cap[1], cap[0], depCaps[1], depCaps[0]));
if (checkFail)
{
TUint8 mainBuf8[MAX_PATH];
TInt mainlen;
{
TUint16 mainBuf[MAX_PATH];
mainlen=Emulator::GetModuleFileName(reinterpret_cast<HMODULE>(pM->iModuleHandle),mainBuf);
TruncToNarrow(mainBuf8, mainBuf, mainlen);
}
TPtrC mainp(mainBuf8,mainlen);
TInt ix=mainp.LocateReverse('\\');
if (ix>=0)
mainp.Set(mainp.Mid(ix+1));
if (mainp.Length() && mainp[mainp.Length()-1]==')' && (ix=mainp.LocateReverse('('))>=0)
mainp.Set(mainp.Left(ix));
TUint8 depBuf8[MAX_PATH];
TInt deplen;
{
TUint16 depBuf[MAX_PATH];
deplen=Emulator::GetModuleFileName(reinterpret_cast<HMODULE>(dep.iModuleHandle),depBuf);
TruncToNarrow(depBuf8, depBuf, deplen);
}
TPtrC depp(depBuf8,deplen);
if ((ix=depp.LocateReverse('\\'))>=0)
depp.Set(depp.Mid(ix+1));
#ifndef __REMOVE_PLATSEC_DIAGNOSTICS__
TInt r = PlatSec::LoaderCapabilityViolation(mainp, depp, missingCaps);
#else //__REMOVE_PLATSEC_DIAGNOSTICS__
TInt r = PlatSec::EmitDiagnostic();
#endif // !__REMOVE_PLATSEC_DIAGNOSTICS__
if(r!=KErrNone)
result=r;
}
}
}
return result;
}
#ifdef __VC32__
#pragma warning( default : 4701 ) // enable warning C4701: local variable 'missingCaps' may be used without having been initialized
#endif
void DModuleList::SetFlags()
{
__KTRACE_OPT(KDLL, Kern::Printf("DModuleList::SetFlags"));
TInt c=iModules.Count();
SModule* pM=(SModule*)&iModules[0];
SModule* pE=pM+c;
for (; pM<pE; ++pM)
{
SModule* pM2=(SModule*)&iModules[0];
for (; pM2<pE; ++pM2)
pM2->iFlags &= ~EFlagMark;
TUint32 flags=Flags(pM);
if (flags & EFlagData)
pM->iFlags|=EFlagDataPresent;
if (flags & EFlagExe)
pM->iFlags|=EFlagExeInTree;
__KTRACE_OPT(KDLL, Kern::Printf("Module %08x Flags=%08x", pM->iModuleHandle, pM->iFlags));
}
pM=(SModule*)&iModules[0];
for (; pM<pE; ++pM)
{
TInt dc=0;
const TInt* pI=pM->iDepList;
const TInt* pIE=pI+c;
while (pI<pIE)
{
TInt ix=*pI++;
if (ix<0)
break;
TUint32 mflags=iModules[ix].iFlags;
if ( (mflags&(EFlagDataPresent|EFlagExeInTree)) && !(mflags&EFlagAlwaysLoaded))
++dc;
}
pM->iDepCount=dc;
__KTRACE_OPT(KDLL, Kern::Printf("Module %08x DepCount=%d", pM->iModuleHandle, pM->iDepCount));
}
}
TUint32 DModuleList::Flags(SModule* aM)
{
TUint32 flags=aM->iFlags;
__KTRACE_OPT(KDLL, Kern::Printf(">DModuleList::Flags %08x", aM->iModuleHandle));
if ((aM->iFlags & EFlagMark)==0)
{
aM->iFlags |= EFlagMark;
const TInt* pI=aM->iDepList;
const TInt* pE=pI+iModules.Count();
while (pI<pE)
{
TInt ix=*pI++;
if (ix<0)
break;
TUint32 mflags=Flags(&iModules[ix]);
if (mflags&EFlagExe)
mflags&=~EFlagData;
flags |= mflags;
}
}
__KTRACE_OPT(KDLL, Kern::Printf("<DModuleList::Flags %08x = %08x", aM->iModuleHandle, flags));
return flags;
}
TInt DModuleList::LoadDependencies()
{
__KTRACE_OPT(KDLL, Kern::Printf("DModuleList::LoadDependencies"));
TInt c=iModules.Count();
SModule* pM=(SModule*)&iModules[0];
SModule* pE=pM+c;
for (; pM<pE; ++pM)
{
DWin32CodeSeg* pS;
TUint32 flags=pM->iFlags;
__KTRACE_OPT(KDLL, Kern::Printf("ModuleHandle %08x flags %08x", pM->iModuleHandle, flags));
if (!(flags & (EFlagDataPresent|EFlagExeInTree)) || (flags&EFlagAlwaysLoaded))
continue;
SWin32Module w32m;
w32m.iWin32ModuleHandle=(TLinAddr)pM->iModuleHandle;
w32m.iCodeSeg=NULL;
TInt ix=MM::Win32Modules.FindInUnsignedKeyOrder(w32m);
__KTRACE_OPT(KDLL, Kern::Printf("GlobalIndex=%d", ix));
if (ix<0 && (flags & EFlagExe))
return KErrNotSupported; // we never implicitly load an EXE
if (ix>=0)
{
pS=MM::Win32Modules[ix].iCodeSeg;
__KTRACE_OPT(KDLL, Kern::Printf("Already loaded; CSEG=%08x %C", pS, pS));
if (pS==iMain)
{
pS->iDepCount=pM->iDepCount;
if (pS->iDepCount)
{
pS->iDeps=(DCodeSeg**)Kern::AllocZ(pS->iDepCount*sizeof(DCodeSeg*));
if (!pS->iDeps)
return KErrNoMemory;
}
}
else
{
if (!(pS->iMark & DCodeSeg::EMarkLdr))
{
pS->iMark |= DCodeSeg::EMarkLdr;
pS->CheckedOpen();
}
pM->iFlags|=EFlagAlreadyLoaded;
}
pM->iCodeSeg=pS;
continue;
}
__KTRACE_OPT(KDLL, Kern::Printf("Create new, depcount=%d", pM->iDepCount));
pS=new DWin32CodeSeg;
if (!pS)
return KErrNoMemory;
TInt r=pS->CreateAlreadyLoaded((HMODULE)pM->iModuleHandle, pM->iDepCount);
if (r!=KErrNone)
{
delete pS;
return r;
}
pM->iCodeSeg=pS;
pS->iS = pM->iS;
pS->iModuleVersion = pM->iModuleVersion;
if (iMain->iAttr & ECodeSegAttKernel)
pS->iAttr |= ECodeSegAttKernel;
if (flags & EFlagData)
{
pS->iMark |= DCodeSeg::EMarkData|DCodeSeg::EMarkDataPresent;
if (!(flags&EFlagExe))
pS->iMark |= DCodeSeg::EMarkDataInit;
}
if ( (flags & EFlagData) || ((flags&(EFlagExe|EFlagExeInTree))==EFlagExeInTree) )
{
if (iAttachProcess)
{
pS->iExeCodeSeg = iAttachProcess->CodeSeg();
pS->SetAttachProcess(iAttachProcess);
}
}
}
return KErrNone;
}
void DModuleList::LinkDependencies()
{
__KTRACE_OPT(KDLL, Kern::Printf("DModuleList::LinkDependencies"));
TInt c=iModules.Count();
SModule* pM=(SModule*)&iModules[0];
SModule* pE=pM+c;
for (; pM<pE; ++pM)
{
DWin32CodeSeg* pS=pM->iCodeSeg;
if (!pS || (pM->iFlags&EFlagAlreadyLoaded))
continue;
const TInt* pI=pM->iDepList;
const TInt* pIE=pI+c;
while (pI<pIE)
{
TInt ix=*pI++;
if (ix<0)
break;
DWin32CodeSeg* pD=iModules[ix].iCodeSeg;
if (pD)
pS->iDeps[pS->iNextDep++]=pD;
}
}
pM=(SModule*)&iModules[0];
}
TInt DModuleList::Loaded()
{
__KTRACE_OPT(KDLL, Kern::Printf("DModuleList::Loaded()"));
TInt c=iModules.Count();
SModule* pM=(SModule*)&iModules[0];
SModule* pE=pM+c;
TInt r=KErrNone;
for (; pM<pE && r==KErrNone; ++pM)
{
DWin32CodeSeg* pS=pM->iCodeSeg;
if (pS && pS!=iMain)
{
pS->FinaliseRecursiveFlags();
pS->iMark |= DCodeSeg::EMarkLoaded;
}
}
if (r==KErrNone)
{
pM=(SModule*)&iModules[0];
for (; pM<pE; ++pM)
pM->iCodeSeg=NULL; // cleanup will occur by EMarkLdr if needed
}
return r;
}
TInt MakeDll(HANDLE aFile)
{
IMAGE_DOS_HEADER dosh;
DWORD bytes;
ReadFile(aFile, &dosh, sizeof(dosh), &bytes, NULL);
if ( IMAGE_DOS_SIGNATURE != dosh.e_magic )
return KErrArgument;
if (dosh.e_lfarlc < sizeof(dosh))
return KErrArgument;
SetFilePointer(aFile,dosh.e_lfanew,NULL,FILE_BEGIN);
IMAGE_NT_HEADERS32 peh;
ReadFile(aFile, &peh, sizeof(peh), &bytes, NULL);
if ( peh.Signature != IMAGE_NT_SIGNATURE )
return KErrArgument;
peh.FileHeader.Characteristics |= IMAGE_FILE_DLL;
peh.OptionalHeader.AddressOfEntryPoint = 0;
SetFilePointer(aFile,dosh.e_lfanew,NULL,FILE_BEGIN);
WriteFile(aFile, &peh, sizeof(peh), &bytes, NULL);
return KErrNone;
}
wchar_t* TempModuleName(const wchar_t* aExe)
{
static TInt ModuleGeneration = 0;
static TInt Time = 0;
WCHAR ex_[KMaxFileName + 1];
if (!Time)
{
SYSTEMTIME st;
GetSystemTime(&st);
Time = st.wSecond + st.wMinute*60 + st.wHour*3600;
}
const char* imagePath = Property::GetString("EmulatorImagePath");
WCHAR* p = ex_;
while ((*p++ = *imagePath++) != 0)
;
wcscpy(p-1, wcsrchr(aExe, '\\') + 1);
p = ex_ + wcslen(ex_);
*p++ = '(';
_itow(Time, p, 36);
p += wcslen(p);
*p++ = '-';
_itow(ModuleGeneration++, p, 10);
p += wcslen(p);
*p++ = ')';
*p++ = '\0';
wchar_t* file = (wchar_t*)Kern::Alloc((p-ex_)*sizeof(WCHAR));
if (file)
wcscpy(file, ex_);
return file;
}
DCodeSeg* M::NewCodeSeg(TCodeSegCreateInfo&)
//
// Create a new instance of this class.
//
{
__KTRACE_OPT(KDLL,Kern::Printf("M::NewCodeSeg"));
return new DWin32CodeSeg;
}
DWin32CodeSeg::DWin32CodeSeg()
//
// Constructor
//
{
}
DWin32CodeSeg::~DWin32CodeSeg()
//
// Destructor
//
{
__KTRACE_OPT(KDLL,Kern::Printf("DWin32CodeSeg::Destruct %C", this));
DBase::Delete(iModuleList);
if (iWinInstance)
{
DCodeSeg::Wait();
SWin32Module w32m;
w32m.iWin32ModuleHandle=(TLinAddr)iModuleHandle;
w32m.iCodeSeg=NULL;
TInt ix=MM::Win32Modules.FindInUnsignedKeyOrder(w32m);
if (ix>=0)
{
if (iAlwaysLoaded)
MM::Win32Modules[ix].iCodeSeg=NULL;
else
MM::Win32Modules.Remove(ix);
}
// Kernel process has to be told to unmap code seg to work round
// a problem where failed driver code seg is not unmapped before delete
K::TheKernelProcess->UnmapCodeSeg(this);
Emulator::FreeLibrary(iWinInstance);
DCodeSeg::Signal();
}
if (iModuleFile)
{
Emulator::DeleteFile(iModuleFile);
Kern::Free(iModuleFile);
}
Kern::Free(iDataCopy);
DCodeSeg::Destruct();
}
TInt DWin32CodeSeg::DoCreate(TCodeSegCreateInfo& aInfo, DProcess* aProcess)
{
__KTRACE_OPT(KDLL,Kern::Printf("DWin32CodeSeg::DoCreate %C proc %O", this, aProcess));
TBool exe=(iExeCodeSeg==this);
if (exe && (iAttr&ECodeSegAttKernel))
{
// loading EKERN.EXE
__KTRACE_OPT(KDLL,Kern::Printf("W32CodeSeg : EKERN"));
TUint16 fileNameW[KMaxFileName];
ExpandToWide(fileNameW, iFileName->Ptr(), iFileName->Length());
fileNameW[iFileName->Length()] = '\0';
iWinInstance = Emulator::LoadLibrary(fileNameW);
__KTRACE_OPT(KDLL,Kern::Printf("W32CodeSeg : EKERN %08x", iWinInstance));
if (!iWinInstance)
return KErrGeneral;
if (aInfo.iTotalDataSize)
iMark|=EMarkData|EMarkDataPresent;
KernelCodeSeg=this;
KernelModuleHandle=Emulator::GetModuleHandle(fileNameW);
return RegisterCodeSeg(KernelModuleHandle);
}
TWin32Filename w32fn(*iFileName);
__KTRACE_OPT(KDLL,Kern::Printf("W32CodeSeg : w32fn=%S",iFileName))
DWin32Process* p=(DWin32Process*)aProcess;
TInt r=KErrNone;
DCodeSeg::Wait();
HMODULE h = Emulator::GetModuleHandle(w32fn);
__KTRACE_OPT(KDLL,Kern::Printf("W32CodeSeg : h=%08x exe=%08x",h,exe));
if (h && exe)
{
if (h == GetModuleHandleA(NULL))
{
// This was the executable that was used to run the emulator
// so all relocations will be valid and we can use it
__KTRACE_OPT(KDLL,Kern::Printf("W32CodeSeg : initial exe"));
if (BootComplete)
goto makecopy; // we can only do this once however
iWinInstance = Emulator::LoadLibrary(w32fn);
BootComplete = ETrue;
}
else
r=KErrAlreadyExists; // can't load same EXEXP twice
}
else if (h)
{
// Already loaded DLL
// Code segment doesn't exist so create it
__KTRACE_OPT(KDLL,Kern::Printf("Already loaded, module %08x",h));
iWinInstance = Emulator::LoadLibrary(w32fn);
}
else if (iAttr & ECodeSegAttHDll)
{
// EXE with exports (EXEXP target) - can only have one instance
// or DLL not already loaded
__KTRACE_OPT(KDLL,Kern::Printf("W32CodeSeg : EXEXP or new DLL"));
iWinInstance = Emulator::LoadLibrary(w32fn);
if (iWinInstance)
h=Emulator::GetModuleHandle(w32fn);
}
else
{
// EXE with no exports. In order that multiple instances of the EXE may be run,
// we make a copy of the EXE file to a name which is unique across instances,
// set the DLL flag and load it as a DLL.
makecopy:
__KTRACE_OPT(KDLL,Kern::Printf("W32CodeSeg : MakeCopy"));
h=0;
iModuleFile = TempModuleName(w32fn);
if (!iModuleFile)
r=KErrNoMemory;
else if (Emulator::CopyFile(w32fn,iModuleFile,FALSE))
{
DWORD fattr = Emulator::GetFileAttributes(iModuleFile);
if (fattr != 0xffffffff && Emulator::SetFileAttributes(iModuleFile, fattr & ~FILE_ATTRIBUTE_READONLY))
{
HANDLE f = Emulator::CreateFile(iModuleFile,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_FLAG_RANDOM_ACCESS,NULL);
if (INVALID_HANDLE_VALUE != f)
{
r = MakeDll(f);
CloseHandle(f);
if (r==KErrNone)
{
iWinInstance = Emulator::LoadLibrary(iModuleFile);
if (iWinInstance)
h=Emulator::GetModuleHandle(iModuleFile);
}
}
}
}
}
__KTRACE_OPT(KDLL,Kern::Printf("W32CodeSeg : line %d r=%d iWinInstance=%08x",__LINE__,r,iWinInstance));
if (r==KErrNone && !iWinInstance)
r=Emulator::LastError();
__KTRACE_OPT(KDLL,Kern::Printf("W32CodeSeg : line %d r=%d",__LINE__,r));
if (r==KErrNone)
{
const char* entry_name = exe ? "_E32Startup" : "_E32Dll" ;
aInfo.iFileEntryPoint = (TLinAddr)Emulator::GetProcAddress(iWinInstance, entry_name);
if (!aInfo.iFileEntryPoint)
r=KErrNotSupported;
else
r=RegisterCodeSeg(h);
if (r == KErrNone)
r = CopyDataBss();
}
if (r==KErrNone && aInfo.iTotalDataSize && !iAlwaysLoaded)
{
iMark|=EMarkData|EMarkDataPresent;
if (!exe)
iMark|=EMarkDataInit;
}
if (r==KErrNone)
r=ProcessImports(p);
__KTRACE_OPT(KDLL, DumpWin32CodeSeg(*this));
DCodeSeg::Signal();
return r;
}
TInt DWin32CodeSeg::RegisterCodeSeg(HMODULE aModule)
{
__KTRACE_OPT(KDLL, Kern::Printf("DWin32CodeSeg %C RegisterCodeSeg(%08x)", this, aModule));
Emulator::TModule etm(aModule);
const IMAGE_NT_HEADERS32* nth=etm.NtHeader();
iRunAddress = (TLinAddr)aModule;
iSize = nth->OptionalHeader.SizeOfImage;
SWin32Module w32m;
w32m.iWin32ModuleHandle=(TLinAddr)aModule;
w32m.iCodeSeg=this;
TInt r=KErrNone;
TInt ix=MM::Win32Modules.FindInUnsignedKeyOrder(w32m);
if (ix>=0)
{
SWin32Module& wmr=MM::Win32Modules[ix];
__ASSERT_ALWAYS(!wmr.iCodeSeg, MM::Panic(MM::EInvalidSharedModule));
wmr.iCodeSeg=this;
iAlwaysLoaded=ETrue;
}
else
r=MM::Win32Modules.InsertInUnsignedKeyOrder(w32m);
if (r==KErrNone)
{
iModuleHandle=aModule;
iCodeSegId=++MM::NextCodeSegId;
}
return r;
}
TInt DWin32CodeSeg::CreateAlreadyLoaded(HMODULE aModule, TInt aDepCount)
{
__KTRACE_OPT(KDLL, Kern::Printf("DWin32CodeSeg %08x CreateAlreadyLoaded(%08x,%d)", this, aModule, aDepCount));
Emulator::TModule etm(aModule);
etm.GetUids(iUids);
TInt32 uid1=iUids.iUid[0].iUid;
if (uid1!=KDynamicLibraryUidValue) // only implicitly load DLLs
return KErrNotSupported;
WCHAR name[MAX_PATH+1];
TInt r=Emulator::GetModuleFileName(aModule, name);
if (!r)
return Emulator::LastError();
TUint8 name8[MAX_PATH+1];
TruncToNarrow(name8,name,-1);
TPtrC fpptr((const TText*)name8);
TInt slash=fpptr.LocateReverse('\\');
TPtrC nptr=fpptr.Mid(slash+1);
iFileName=HBuf::New(nptr);
if (!iFileName)
return KErrNoMemory;
iRootName.Set(*iFileName);
iExtOffset = iFileName->LocateReverse('.');
if (iExtOffset==KErrNotFound)
iExtOffset = iFileName->Length();
iModuleVersion = 0x00010000u;
iDepCount=aDepCount;
if (iDepCount)
{
iDeps=(DCodeSeg**)Kern::AllocZ(iDepCount*sizeof(DCodeSeg*));
if (!iDeps)
return KErrNoMemory;
}
iWinInstance = Emulator::LoadLibrary(name);
if (!iWinInstance)
return Emulator::LastError();
iFileEntryPoint = (TLinAddr)Emulator::GetProcAddress(iWinInstance, "_E32Dll");
if (!iFileEntryPoint)
return KErrNotSupported;
iEntryPtVeneer = iFileEntryPoint;
r=RegisterCodeSeg(aModule);
if (r == KErrNone)
r = CopyDataBss();
if (r == KErrNone)
r = CodeSegsByName.InsertInOrderAllowRepeats(this, &CompareCodeSegsByName);
if (r == KErrNone)
r = CodeSegsByAddress.Add(this);
if (r==KErrNone)
{
GlobalList.Add(&iLink);
iAsyncDeleteNext=this;
}
__KTRACE_OPT(KDLL, DumpWin32CodeSeg(*this));
return r;
}
TInt DWin32CodeSeg::CopyDataBss()
{
__KTRACE_OPT(KDLL, Kern::Printf("DWin32CodeSeg::CopyDataBss()"));
Emulator::TModule etm(iModuleHandle);
const TEmulatorImageHeader* hdr = (const TEmulatorImageHeader*)etm.Section(KWin32SectionName_Symbian);
if (!(hdr->iFlags & KEmulatorImageFlagAllowDllData))
return KErrNone;
const IMAGE_SECTION_HEADER* data=etm.SectionHeader(KWin32SectionName_EpocData);
const IMAGE_SECTION_HEADER* bss=etm.SectionHeader(KWin32SectionName_EpocBss);
if (data)
{
iRealDataSize = data->Misc.VirtualSize;
iDataDest = (TLinAddr)etm.Translate(data->VirtualAddress);
iDataCopy = Kern::Alloc(iRealDataSize);
if (!iDataCopy)
return KErrNoMemory;
memcpy(iDataCopy, (const TAny*)iDataDest, iRealDataSize);
}
if (bss)
{
iRealBssSize = bss->Misc.VirtualSize;
iBssDest = (TLinAddr)etm.Translate(bss->VirtualAddress);
}
return KErrNone;
}
TInt DWin32CodeSeg::ProcessImports(DProcess* aProcess)
{
__KTRACE_OPT(KDLL, Kern::Printf("DWin32CodeSeg::ProcessImports(%O)", aProcess));
iModuleList=new DModuleList(this, aProcess);
if (!iModuleList)
return KErrNoMemory;
TInt r=iModuleList->GatherDependencies(iModuleHandle);
if (r!=KErrNone)
return r;
TInt ix=iModuleList->Find((TInt)iModuleHandle);
DModuleList::SModule& mm=iModuleList->iModules[ix];
r=iModuleList->CompileDepLists();
if (r==KErrNone)
{
iModuleList->SetFlags();
r=iModuleList->LoadDependencies();
if (r==KErrNone)
{
if ((mm.iFlags&(DModuleList::EFlagDataPresent|DModuleList::EFlagExeInTree)) && !(mm.iFlags&DModuleList::EFlagAlwaysLoaded))
{
if (aProcess)
{
iExeCodeSeg=aProcess->CodeSeg();
SetAttachProcess(aProcess);
}
}
iModuleList->LinkDependencies();
}
}
return r;
}
TInt DWin32CodeSeg::Loaded(TCodeSegCreateInfo& aInfo)
{
__KTRACE_OPT(KDLL, Kern::Printf("DWin32CodeSeg::Loaded()"));
TInt r=KErrNone;
if (iModuleList)
{
r=iModuleList->Loaded();
if (r==KErrNone)
{
DBase::Delete(iModuleList);
iModuleList=NULL;
}
}
if (r==KErrNone)
r=DCodeSeg::Loaded(aInfo);
__KTRACE_OPT(KDLL, Kern::Printf("DWin32CodeSeg::Loaded() - %d", r));
return r;
}
void DWin32CodeSeg::ReadExportDir(TUint32*)
{
// not needed
}
TBool DWin32CodeSeg::FindCheck(DProcess* /*aProcess*/)
{
// We never create multiple copies of the same code segment,
// so if code segment exists, allow it to be found.
// CodeSegOpen will fail if it is incompatible.
return ETrue;
}
TBool DWin32CodeSeg::OpenCheck(DProcess* aProcess)
{
__KTRACE_OPT(KDLL,Kern::Printf("CSEG:%08x Compat? proc=%O",this,aProcess));
if (!aProcess)
return EFalse; // never reuse EXE code segments
return ETrue;
}
TLibraryFunction DWin32CodeSeg::Lookup(TInt aOrdinal)
//
// Find an exported function by ordinal
//
{
TLibraryFunction f = NULL;
if (aOrdinal != 0)
{
f = (TLibraryFunction)Emulator::GetProcAddress(iWinInstance, (const char *)aOrdinal);
if ((TLinAddr)f == iFileEntryPoint)
f = NULL;
}
else
{
// Find 0th Ordinal, which should be named symbol export data, from named data segment
Emulator::TModule etm(iModuleHandle);
f = (TLibraryFunction)etm.Section(KWin32SectionName_NmdExpData);
}
__KTRACE_OPT(KDLL,Kern::Printf("DWin32CodeSeg::Lookup(%d)->%08x",aOrdinal,f));
return f;
}
DCodeSeg* DCodeSeg::FindRomCode(const TAny*)
{
// never used
return NULL;
}
void DWin32CodeSeg::InitData()
{
}
TInt DWin32CodeSeg::GetMemoryInfo(TModuleMemoryInfo&, DProcess*)
{
return KErrNotSupported;
}
void DWin32CodeSeg::Info(TCodeSegCreateInfo& aInfo)
{
Emulator::TModule etm(iModuleHandle);
const IMAGE_NT_HEADERS32* nth=etm.NtHeader();
const IMAGE_EXPORT_DIRECTORY* exd=
(const IMAGE_EXPORT_DIRECTORY*)etm.Translate(nth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
const TEmulatorImageHeader* hdr = (const TEmulatorImageHeader*)etm.Section(KWin32SectionName_Symbian);
TBool isExe = hdr && hdr->iUids[0].iUid==KExecutableImageUidValue;
const IMAGE_SECTION_HEADER* text=etm.SectionHeader(KWin32SectionName_Text);
const IMAGE_SECTION_HEADER* rdata=etm.SectionHeader(KWin32SectionName_RData);
const IMAGE_SECTION_HEADER* data=etm.SectionHeader(KWin32SectionName_EpocData);
if (!isExe && !(hdr->iFlags & KEmulatorImageFlagAllowDllData))
data = NULL;
aInfo.iTextSize=text->Misc.VirtualSize;
aInfo.iCodeSize=text->Misc.VirtualSize;
if (rdata)
aInfo.iCodeSize+=rdata->Misc.VirtualSize;
aInfo.iDataSize=data ? (data->SizeOfRawData) : 0;
aInfo.iBssSize=data ? (data->Misc.VirtualSize-data->SizeOfRawData) : 0;
aInfo.iTotalDataSize=aInfo.iDataSize+aInfo.iBssSize;
aInfo.iExportDir=(TLinAddr)exd;
aInfo.iExportDirCount=exd ? exd->NumberOfFunctions : 0;
aInfo.iCodeLoadAddress=(TLinAddr)etm.Translate(text->VirtualAddress);
aInfo.iCodeRunAddress=aInfo.iCodeLoadAddress;
aInfo.iDataLoadAddress=data ? (TLinAddr)etm.Translate(data->VirtualAddress) : 0;
aInfo.iDataRunAddress=aInfo.iDataLoadAddress;
DCodeSeg::Info(aInfo);
}
TLinAddr DCodeSeg::ExceptionDescriptor()
{
return 0; // not used on emulator
}
TInt MM::RegisterModule(HMODULE aModule)
{
__KTRACE_OPT(KBOOT, Kern::Printf("MM::RegisterModule %08x",aModule));
SWin32Module w32m;
w32m.iWin32ModuleHandle=(TLinAddr)aModule;
w32m.iCodeSeg=NULL;
TInt r=MM::Win32Modules.InsertInUnsignedKeyOrder(w32m);
__KTRACE_OPT(KBOOT, Kern::Printf("MM::RegisterModule ret %d",r));
return r;
}
_LIT(KRomSysBin, "Z:\\sys\\bin");
// Massage file names returned for stuff in EPOCROOT\epoc32\release\wins\xxxx\
// in order to make them appear to be in z:\system\libs
void P::NormalizeExecutableFileName(TDes& a)
{
__KTRACE_OPT(KDLL, Kern::Printf("NormalizeExecutableFileName %lS", &a));
if (a.Length()<3 || a[1]!=':' || a[2]!='\\')
{
// don't have a drive so assume in 'ROM'
TFileName initial(a);
a=KRomSysBin();
if (initial.Length()==0 || initial[0]!='\\')
a.Append('\\');
a+=initial;
__KTRACE_OPT(KDLL, Kern::Printf("NormalizeExecutableFileName -> %lS", &a));
}
}
TInt LookupDllUid(TInt aModule)
{
TInt r = KDllUid_Default;
Kern::AccessCode();
SWin32Module w32m;
w32m.iWin32ModuleHandle=(TLinAddr)aModule;
TInt ix;
MM::Win32Modules.SpecificFindInUnsignedKeyOrder(w32m, ix, EArrayFindMode_Last);
if (ix>0)
{
DWin32CodeSeg* pS = MM::Win32Modules[ix-1].iCodeSeg;
if (pS && pS->iFileEntryPoint==(TLinAddr)aModule)
r = pS->iCodeSegId;
}
Kern::EndAccessCode();
return r;
}