kerneltest/f32test/loader/exet.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
child 43 c1f20ce4abcf
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// Copyright (c) 1999-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:
// f32test\loader\exet.cpp
// 
//

#define __INCLUDE_DEPENDENCY_GRAPH

#include <e32svr.h>
#include <f32file.h>
#include "dllt.h"
#include "exetifc.h"
#include "dlltree.h"
#include <d_ldrtst.h>
#include "../mmu/d_memorytest.h"

#ifdef __VC32__
#pragma warning(disable:4706)
#endif

const TInt KMaxHandlesPerDll=4;
const TInt KMaxHandles=KMaxHandlesPerDll*KNumModules;

extern "C" TInt _E32Startup();

extern "C" IMPORT_C void RegisterConstructorCall(TInt aDllNum);
extern "C" IMPORT_C void RegisterInitCall(TInt aDllNum);
extern "C" IMPORT_C void RegisterDestructorCall(TInt aDllNum);

#define PANIC()		ExeTPanic(__LINE__)
#define EXET_ASSERT(c)	((void)((c)||(PANIC(),0)))

static TText GetSpecialDrive(TInt aSpecialDriveNum);

void ExeTPanic(TInt aLine)
	{
	User::Panic(_L("EXET"),aLine);
	}

/******************************************************************************
 * Class Definitions
 ******************************************************************************/
class CDllInfo;
NONSHARABLE_CLASS(TDllList) : public MDllList
	{
public:
	TDllList();
	virtual TBool IsPresent(const SDllInfo& aInfo);
	virtual TInt Add(const SDllInfo& aInfo);
	virtual void MoveToEnd(TInt aPos);
public:
	TInt iCount;
	SDllInfo iInfo[KNumModules];
	};

NONSHARABLE_CLASS(CTestServer) : public CServer2
	{
public:
	CTestServer();
	virtual ~CTestServer();
	virtual CSession2* NewSessionL(const TVersion& aVersion, const RMessage2& aMessage) const;
	virtual TInt RunError(TInt aError);
public:
	CDllInfo* iInfo;
	};

NONSHARABLE_CLASS(CTestSession) : public CSession2
	{
public:
	virtual ~CTestSession();
	virtual void CreateL();
	virtual void ServiceL(const RMessage2& aMessage);
public:
	TInt GetExeDepList(const RMessage2& aMessage);
	TInt GetCDList(const RMessage2& aMessage);
	TInt LoadDll(const RMessage2& aMessage);
	TInt CloseDll(TInt aHandle);
	TInt CallBlkI(TInt aHandle, TInt aIn);
	TInt CallRBlkI(TInt aHandle, TInt aIn);
public:
	CDllInfo* iInfo;
	RMemoryTestLdd iTestLdd;
	};

NONSHARABLE_CLASS(CDllInfo) : public CBase
	{
public:
	CDllInfo();
	virtual ~CDllInfo();
	TInt Create();
	TInt StoreHandle(TInt aHandle);
	void RemoveHandle(TInt aIndex);
	void SetupCDList();
public:
	void RegisterConstructorCall(TInt aDllNum);
	void RegisterInitCall(TInt aDllNum);
	void RegisterDestructorCall(TInt aDllNum);
public:
	TInt iNextGen;
	TInt iHandleCount;
	TInt iNextHandle;
	TInt iHandles[KMaxHandles];
	TInt iModuleNum[KMaxHandles];
	TDllList iExeDepList;
	TDllList iDllConstructList;
	};

/******************************************************************************
 * Static data
 ******************************************************************************/
#ifdef __MODULE_HAS_DATA
class TExeData
	{
public:
	TExeData();
public:
	TTime iStartTime;
	TTime iInitTime;
	TInt iTest1;
	TFileName iFileName;
	};

TInt Bss[16];
TInt ExeNum=EXENUM;
TInt Generation=0;
TInt InitFlag=0;
TFullName StartThread=RThread().FullName();
TName StartProcess=RProcess().Name();
TExeData TheExeDataObject;

TExeData::TExeData()
	:	iFileName(RProcess().FileName())
	{
	TInt r;
	CHKDEPS(r);		// Check our dependencies are initialised
	if (r!=KErrNone)
		User::Panic(_L("CHKDEPS"),r);
	iStartTime.HomeTime();
	iTest1=299792458;
	RegisterConstructorCall(EXENUM);
	}
#endif

/******************************************************************************
 * Class TDllList
 ******************************************************************************/
TDllList::TDllList()
	{
	iCount=0;
	Mem::Fill(iInfo, KNumModules*sizeof(SDllInfo), 0xff);
	}

TBool TDllList::IsPresent(const SDllInfo& aInfo)
	{
	TInt i;
	for (i=0; i<iCount; ++i)
		{
		if (iInfo[i].iDllNum==aInfo.iDllNum)
			return ETrue;
		}
	return EFalse;
	}

TInt TDllList::Add(const SDllInfo& aInfo)
	{
	EXET_ASSERT(iCount<KNumModules);
	TInt pos=iCount;
	iInfo[iCount++]=aInfo;
	return pos;
	}

void TDllList::MoveToEnd(TInt aPos)
	{
	if (aPos<iCount-1)
		{
		SDllInfo x(iInfo[aPos]);
		Mem::Move(iInfo+aPos, iInfo+aPos+1, (iCount-aPos-1)*sizeof(SDllInfo));
		iInfo[iCount-1]=x;
		}
	}

/******************************************************************************
 * Class CTestSession/CTestServer
 ******************************************************************************/

CTestSession::~CTestSession()
	{
	}

void CTestSession::CreateL()
	{
	User::LeaveIfError(iTestLdd.Open());
	}

void CTestSession::ServiceL(const RMessage2& aMessage)
	{
	TInt r=KErrNotSupported;
	TInt mid=aMessage.Function();
	switch(mid)
		{
		case RLoaderTest::EMsgGetExeDepList:
			r=GetExeDepList(aMessage);
			break;
		case RLoaderTest::EMsgLoadDll:
			r=LoadDll(aMessage);
			break;
		case RLoaderTest::EMsgCallBlkI:
			r=CallBlkI(aMessage.Int0(), aMessage.Int1());
			break;
		case RLoaderTest::EMsgCallRBlkI:
			r=CallRBlkI(aMessage.Int0(), aMessage.Int1());
			break;
		case RLoaderTest::EMsgCloseDll:
			r=CloseDll(aMessage.Int0());
			break;
		case RLoaderTest::EMsgGetCDList:
			r=GetCDList(aMessage);
			break;
		case RLoaderTest::EMsgCheckReadable:
			{
			TUint32 value;
			r = iTestLdd.ReadMemory((TAny*)aMessage.Int0(),value);
			if(r)
				r = KErrGeneral;
			}
			break;
		case RLoaderTest::EMsgExit:
			r=KErrNone;
			CActiveScheduler::Stop();
			break;
		default:
			break;
		}
	aMessage.Complete(r);
	}

TInt CTestSession::GetExeDepList(const RMessage2& aMsg)
	{
	TPtrC8 dep_list_ptr((const TUint8*)&iInfo->iExeDepList.iInfo, KNumModules*sizeof(SDllInfo));
	aMsg.WriteL(0, dep_list_ptr, 0);
	return KErrNone;
	}

TInt CTestSession::GetCDList(const RMessage2& aMsg)
	{
	TPtrC8 list_ptr((const TUint8*)&iInfo->iDllConstructList.iInfo, KNumModules*sizeof(SDllInfo));
	aMsg.WriteL(0, list_ptr, 0);
	return KErrNone;
	}

static void GetDllFileName(const TDesC& aListName, TDes& aTargetName)
/**
	Helper function for CTestSession::LoadDll transforms the supplied
	filename to an absolutely qualified name if it has been copied to a drive.

	@param	aListName		The DLL name.  This will not have a path if it should
							be loaded from the Z drive.  Otherwise it will be fully
							qualified but with a digit for the drive letter.
	@param	aTargetName		Descriptor to populate with target filename.  If the
							DLL should be loaded from Z this is the same as aListName.
							Otherwise, it is the same as aListName but with the correct
							drive letter.
 */
	{
	aTargetName.Copy(aListName);
	if (aListName[1] != ':')
		return;

	TText& targetDrive = aTargetName[0];
	targetDrive = GetSpecialDrive(targetDrive - '0');
	}


TInt CTestSession::LoadDll(const RMessage2& aMsg)
	{
	TInt module=aMsg.Int0();
	TDllList dll_list;
	TPtrC8 dll_list_ptr((const TUint8*)dll_list.iInfo, KNumModules*sizeof(SDllInfo));
	TPtrC dllname0=MODULE_FILENAME(module);
	TFileName dllname;
	GetDllFileName(dllname0, dllname);
	iInfo->SetupCDList();
	RLibrary l;
	TInt r=l.Load(dllname, TUidType());
	if (r>0)
		{
		RDebug::Printf("RLibrary::Load returned 0x%x !",r);
		return -999; // return unexpected error type so test fails.
		}
	if (r!=KErrNone)
		return r;
	TInitFunction f=(TInitFunction)l.Lookup(INIT_ORDINAL);
	EXET_ASSERT(f);
	r=(*f)(dll_list);
	if (r!=KErrNone)
		return r;
	TBlkIFunction bf=(TBlkIFunction)l.Lookup(BLOCK_INC_ORDINAL);
	EXET_ASSERT(bf);
	TInt result=(*bf)(531441);
	EXET_ASSERT(result==BlkIValue(module, 531441));
	TInt h=iInfo->StoreHandle(l.Handle());
	EXET_ASSERT(h>=0);
	iInfo->iModuleNum[h]=module;
	aMsg.WriteL(1, dll_list_ptr, 0);
	return h;
	}

TInt CTestSession::CallBlkI(TInt aHandle, TInt aIn)
	{
	TInt h=iInfo->iHandles[aHandle];
	EXET_ASSERT(h!=0);
	RLibrary l;
	l.SetHandle(h);
	TBlkIFunction bf=(TBlkIFunction)l.Lookup(BLOCK_INC_ORDINAL);
	EXET_ASSERT(bf);
	return (*bf)(aIn);
	}

TInt CTestSession::CallRBlkI(TInt aHandle, TInt aIn)
	{
	TInt h=iInfo->iHandles[aHandle];
	EXET_ASSERT(h!=0);
	RLibrary l;
	l.SetHandle(h);
	TRBlkIFunction rbf=(TRBlkIFunction)l.Lookup(REC_BLOCK_INC_ORDINAL);
	EXET_ASSERT(rbf);
	++iInfo->iNextGen;
	return (*rbf)(aIn,iInfo->iNextGen);
	}

TInt CTestSession::CloseDll(TInt aHandle)
	{
	TInt h=iInfo->iHandles[aHandle];
	TInt m=iInfo->iModuleNum[aHandle];
	EXET_ASSERT(h!=0);
	EXET_ASSERT(m>=0);
	iInfo->iHandles[aHandle]=0;
	iInfo->iModuleNum[aHandle]=-1;
	iInfo->SetupCDList();
	RLibrary l;
	l.SetHandle(h);
	l.Close();
	return KErrNone;
	}

CTestServer::CTestServer()
	: CServer2(0,ESharableSessions)
	{
	}

CTestServer::~CTestServer()
	{
	}

CSession2* CTestServer::NewSessionL(const TVersion& aVersion, const RMessage2& /*aMessage*/) const
	{
	(void)aVersion;
	CTestSession* s = new (ELeave) CTestSession;
	s->iInfo=iInfo;
	return s;
	}

_LIT(KExetErr,"EXETERR");
TInt CTestServer::RunError(TInt aError)
	{
	User::Panic(KExetErr,aError);
	return 0;
	}

/******************************************************************************
 * Class CDllInfo
 ******************************************************************************/
TInt ChkC()
	{
#ifdef __MODULE_HAS_DATA
	TInt init_mark=~((EXENUM+DLLNUMOFFSET)*(EXENUM+DLLNUMOFFSET));
	if (InitFlag==init_mark)
		return KErrNone;
	if (InitFlag!=0)
		return 0x494e4946;
	TInt i;
	TInt x=0;
	for (i=0; i<16; ++i) x|=Bss[i];
	if (x)
		return 0x425353;
	if (ExeNum!=EXENUM)
		return 0x44415441;
	if (Generation!=0)
		return 0x47454e;
	if (StartProcess!=RProcess().Name())
		return 0x535450;
	if (TheExeDataObject.iTest1!=299792458)
		return 0x54455354;
	if (TheExeDataObject.iFileName != RProcess().FileName())
		return 0x464e414d;
	InitFlag=init_mark;
	RDebug::Print(_L("ChkC %S OK"),&TheExeDataObject.iFileName);
#endif
	return KErrNone;
	}

TInt Init(MDllList& aList)
	{
	TInt r=KErrNone;
	SDllInfo info;
	info.iDllNum=DLLNUM;
	info.iEntryPointAddress=((TInt)&_E32Startup);
	RLdrTest ldd;
	ldd.Open();
	info.iModuleHandle=ldd.ModuleHandleFromAddr((TInt)&_E32Startup);
	ldd.Close();
	if (!aList.IsPresent(info))
		{
		TInt pos=aList.Add(info);
		INITDEPS(r,aList);		// Call Init on our dependencies
		aList.MoveToEnd(pos);
#ifdef __MODULE_HAS_DATA
		if (r==KErrNone)
			r=ChkC();		// Check initial values for .data/.bss and check constructors have been called
#endif
		RegisterInitCall(DLLNUM);
		}
	return r;
	}

CDllInfo::CDllInfo()
	{
	Mem::Fill(iModuleNum, sizeof(iModuleNum), 0xff);
	}

CDllInfo::~CDllInfo()
	{
	}

TInt CDllInfo::Create()
	{
	TInt r;
	r=UserSvr::DllSetTls(0, this);
	if (r==KErrNone)
		r=UserSvr::DllSetTls(TLS_INDEX, NULL);
	if (r==KErrNone)
		{
		r=Init(iExeDepList);
		}
	return r;
	}

void CDllInfo::RegisterConstructorCall(TInt aDllNum)
	{
	(void)aDllNum;
	}

void CDllInfo::RegisterInitCall(TInt aDllNum)
	{
	(void)aDllNum;
	}

void CDllInfo::RegisterDestructorCall(TInt aDllNum)
	{
	(void)aDllNum;
	}

TInt CDllInfo::StoreHandle(TInt aHandle)
	{
	if (iHandleCount==KMaxHandles)
		return KErrOverflow;
	TInt i=iNextHandle;
	for (; i<KMaxHandles && iHandles[i]!=0; ++i) {}
	if (i==KMaxHandles)
		{
		for (i=0; i<iNextHandle && iHandles[i]!=0; ++i) {}
		EXET_ASSERT(i!=iNextHandle);
		}
	iNextHandle=i;
	iHandles[i]=aHandle;
	++iHandleCount;
	return i;
	}

void CDllInfo::RemoveHandle(TInt aIndex)
	{
	iHandles[aIndex]=0;
	--iHandleCount;
	}

void CDllInfo::SetupCDList()
	{
	new (&iDllConstructList) TDllList;
	EXET_ASSERT(UserSvr::DllSetTls(TLS_INDEX, &iDllConstructList)==KErrNone);
	}

/******************************************************************************
 * Exports
 ******************************************************************************/
extern "C" __MODULE_EXPORT void RegisterConstructorCall(TInt aDllNum)
	{
	CDllInfo* p=(CDllInfo*)UserSvr::DllTls(0);
	if (p)
		p->RegisterConstructorCall(aDllNum);
	}

extern "C" __MODULE_EXPORT void RegisterInitCall(TInt aDllNum)
	{
	CDllInfo* p=(CDllInfo*)UserSvr::DllTls(0);
	if (p)
		p->RegisterInitCall(aDllNum);
	}

extern "C" __MODULE_EXPORT void RegisterDestructorCall(TInt aDllNum)
	{
	CDllInfo* p=(CDllInfo*)UserSvr::DllTls(0);
	if (p)
		p->RegisterDestructorCall(aDllNum);
	}

static TText GetSpecialDrive(TInt aSpecialDriveNum)
/**
	Work out which physical drive corresponds to the supplied
	logical drive.
	
	@param	aSpecialDriveNum	Number which identifies which drive to find.
							Zero means internal drive.
	@return					Drive letter.
 */
	{
	RFs fs;
	TInt r = fs.Connect();
	EXET_ASSERT(r == KErrNone);

	// cannot load binaries from emulated removable drives
#ifdef __WINS__
	if (aSpecialDriveNum == 1)
		return 'c';
#endif

	TInt dr = 0;
	for (TInt d = 0; d <= (TInt)sizeof(SpecialDriveList); ++d)
		{
		dr = SpecialDriveList[d];
		TDriveInfo di;
		r = fs.Drive(di, dr);
		EXET_ASSERT(r == KErrNone);
		if (di.iType == EMediaNotPresent)
			continue;
		
		// drive 0 == internal
		if (aSpecialDriveNum == 0 && (di.iDriveAtt & KDriveAttInternal) != 0)
			break;
		// drive 1 == removable
		if (aSpecialDriveNum == 1 && (di.iDriveAtt & KDriveAttRemovable) != 0)
			break;
		}	

	TChar ch0;
	r = RFs::DriveToChar(dr, ch0);
	EXET_ASSERT(r == KErrNone);
	fs.Close();
	return static_cast<TText>(TUint(ch0));
	}

GLDEF_C TInt E32Main()
	{
	CTrapCleanup* cleanup=CTrapCleanup::New();
	EXET_ASSERT(cleanup);
	CActiveScheduler* sched=new CActiveScheduler;
	EXET_ASSERT(sched);
	CActiveScheduler::Install(sched);
	CTestServer* svr=new CTestServer;
	EXET_ASSERT(svr);
	TBuf<16> suffix;
	User::CommandLine(suffix);
	TName svr_name=KServerName();
	if (suffix.Length())
		{
		svr_name.Append('.');
		svr_name+=suffix;
		}
	EXET_ASSERT(svr->Start(svr_name)==KErrNone);
	CDllInfo* dllinfo=new CDllInfo;
	EXET_ASSERT(dllinfo);
	EXET_ASSERT(dllinfo->Create()==KErrNone);
	svr->iInfo=dllinfo;

	CActiveScheduler::Start();

	UserSvr::DllFreeTls(0);
	UserSvr::DllFreeTls(TLS_INDEX);
	delete dllinfo;
	delete svr;
	delete sched;
	delete cleanup;

	return 0;
	}