// 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 = %S", a.iFileName);
	Kern::Printf("iRootName = %S", &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 %S", &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 -> %S", &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;
	}


