kernel/eka/memmodel/emul/win32/mcodeseg.cpp
changeset 0 a41df078684a
child 43 c1f20ce4abcf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/memmodel/emul/win32/mcodeseg.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,1145 @@
+// 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;
+	}
+
+