os/kernelhwsrv/kerneltest/f32test/loader/t_ldrtst.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // f32test\loader\t_ldrtst.cpp
    15 // 
    16 //
    17 
    18 #define __E32TEST_EXTENSION__
    19 
    20 #include "t_hash.h"
    21 #include "t_ldrtst.h"
    22 #include "../../../e32test/mmu/d_memorytest.h"
    23 
    24 #if defined(__WINS__)
    25 	#include <e32wins.h>
    26 	#include <emulator.h>
    27 #elif defined(__EPOC32__)
    28 	#include <f32image.h>
    29 #endif
    30 
    31 const TInt KNumberOfCorruptFiles = 2;
    32 
    33 RTest test(_L("T_LDRTST"));
    34 
    35 LoaderTest* TheLoaderTest;
    36 RFs Fs;
    37 #if defined (__X86__) || defined(__WINS__)
    38 TBool NoRemovable=ETrue;
    39 #else
    40 TBool NoRemovable=EFalse;
    41 #endif
    42 
    43 /** Error code of simulated RFs error */
    44 const TInt KRFsError = -99;
    45 
    46 /**
    47 	Number of drives which are identified by a numeric value,
    48 	which means, e.g., run from an internal pageable drive.
    49  */
    50 const TInt KSpecialDriveCount = 2;
    51 
    52 /** The real drive letters corresponding to each special drive. */
    53 static TFixedArray<TText, KSpecialDriveCount> SpecialDrives;
    54 
    55 /** Bitmask of paged and unpaged module flags. */
    56 const TUint32 KModulePagedCodeFlags = (KModuleFlagPagedCode | KModuleFlagUnpagedCode);
    57 
    58 _LIT(KSysHash,"?:\\Sys\\Hash\\");
    59 
    60 TInt GetModuleFlags(TInt aModule)
    61 	{
    62 	TInt f = ModuleFlags[aModule];
    63 #ifdef __WINS__
    64 	// paged and unpaged flags are not supported on the emulator
    65 	f &= ~KModulePagedCodeFlags;
    66 	// On emulator, treat all modules as XIP, all EXEs as fixed
    67 	f |= KModuleFlagXIP;
    68 	if (f & KModuleFlagExe)
    69 		f|=KModuleFlagFixed;
    70 #endif	// #ifdef __EPOC32__
    71 	return f;
    72 	}
    73 
    74 TModuleSet::TModuleSet()
    75 	{
    76 	Mem::FillZ(this,sizeof(TModuleSet));
    77 	}
    78 
    79 void TModuleSet::Add(TInt aModule)
    80 	{
    81 	TUint8 m=(TUint8)(1<<(aModule&7));
    82 	TInt i=aModule>>3;
    83 	if (!(iBitMap[i]&m))
    84 		{
    85 		iBitMap[i]|=m;
    86 		++iCount;
    87 		}
    88 	}
    89 
    90 void TModuleSet::Remove(TInt aModule)
    91 	{
    92 	TUint8 m=(TUint8)(1<<(aModule&7));
    93 	TInt i=aModule>>3;
    94 	if (iBitMap[i]&m)
    95 		{
    96 		iBitMap[i]&=~m;
    97 		--iCount;
    98 		}
    99 	}
   100 
   101 TModuleSet::TModuleSet(const TModuleList& aList, TInt aMask, TInt aVal)
   102 	{
   103 	Mem::FillZ(this,sizeof(TModuleSet));
   104 	TInt i;
   105 	for (i=0; i<aList.iCount; ++i)
   106 		{
   107 		TInt m=aList.iInfo[i].iDllNum;
   108 		if (((GetModuleFlags(m)&aMask)^aVal)==0)
   109 			Add(aList.iInfo[i].iDllNum);
   110 		}
   111 	}
   112 
   113 void TModuleSet::Remove(const TModuleList& aList)
   114 	{
   115 	TInt i;
   116 	for (i=0; i<aList.iCount; ++i)
   117 		Remove(aList.iInfo[i].iDllNum);
   118 	}
   119 
   120 void TModuleSet::Display(const TDesC& aTitle) const
   121 	{
   122 	TBuf<256> s=aTitle;
   123 	TInt i;
   124 	for (i=0; i<iCount; ++i)
   125 		{
   126 		if (Present(i))
   127 			s.AppendFormat(_L("%3d "),i);
   128 		}
   129 	test.Printf(_L("%S\n"),&s);
   130 	}
   131 
   132 TModuleList::TModuleList()
   133 	{
   134 	iCount=0;
   135 	Mem::Fill(iInfo, KNumModules*sizeof(SDllInfo), 0xff);
   136 	}
   137 
   138 void TModuleList::SetCount()
   139 	{
   140 	TInt i;
   141 	for (i=0; i<KNumModules && iInfo[i].iDllNum>=0; ++i) {}
   142 	iCount=i;
   143 	}
   144 
   145 void TModuleList::Display(const TDesC& aTitle) const
   146 	{
   147 	TBuf<256> s=aTitle;
   148 	TInt i;
   149 	for (i=0; i<iCount; ++i)
   150 		{
   151 		TInt modnum=iInfo[i].iDllNum;
   152 		s.AppendFormat(_L("%3d "),modnum);
   153 		}
   154 	test.Printf(_L("%S\n"),&s);
   155 	}
   156 
   157 TBool TModuleList::IsPresent(TInt aModNum) const
   158 	{
   159 	return Find(aModNum)>=0;
   160 	}
   161 
   162 TInt TModuleList::Find(TInt aModNum) const
   163 	{
   164 	TInt i;
   165 	for (i=iCount-1; i>=0 && iInfo[i].iDllNum!=aModNum; --i) {}
   166 	return i;
   167 	}
   168 
   169 void TModuleList::Add(const SDllInfo& a)
   170 	{
   171 	iInfo[iCount++]=a;
   172 	}
   173 
   174 
   175 RMemoryTestLdd TestLdd;
   176 
   177 TBool AddressReadable(TLinAddr a)
   178 	{
   179 	TUint32 value;
   180 	return TestLdd.ReadMemory((TAny*)a,value)==KErrNone;
   181 	}
   182 
   183 TInt LoaderTest::DetermineDllLoadResult(TInt aDllNum, TInt aExeNum)
   184 	{
   185 	TBool proc_sym=(iMemModelAtt & (EMemModelAttrSameVA|EMemModelAttrSupportFixed))==EMemModelAttrSameVA;
   186 	const TInt* exeinfo=ModuleExeInfo[aDllNum];
   187 	TInt attp=exeinfo[0];
   188 	TInt linkexe=exeinfo[1];
   189 	TInt dllflags=GetModuleFlags(aDllNum);
   190 	TInt exeflags=GetModuleFlags(aExeNum);
   191 
   192 #ifdef __EPOC32__
   193 	// if NP and DEFAULTPAGED or DEFAULTUNPAGED (not NOPAGING or ALWAYSPAGE) then
   194 	// executable identified as corrupt, unless previous conditions in S3.1.3.2 cause
   195 	// it to be paged or unpaged without examining the flags.
   196 
   197 	TUint32 policy = E32Loader::PagingPolicy();
   198 	test.Printf(_L("DetermineDllLoadResult,dll=%d,exe=%d,dllflags=0x%x,policy=0x%x\n"), aDllNum, aExeNum, dllflags, policy);
   199 
   200 	TBool flagsChecked =
   201 			policy != EKernelConfigCodePagingPolicyNoPaging					// 3.1.3.2.1, policy != no paging
   202 		&&	(dllflags & KModuleFlagIDrive) != 0							// 3.1.3.2.2-3, pageable drive
   203 		&&	(dllflags & (KModuleFlagUncompressed | KModuleFlagBytePair)) != 0	// 3.1.3.2.4 pageable format
   204 		&&	policy != EKernelConfigCodePagingPolicyAlwaysPage;				// 3.1.3.2.5, policy != ALWAYS
   205 	
   206 	if (flagsChecked && (dllflags & KModulePagedCodeFlags) == KModulePagedCodeFlags)
   207 		{
   208 		TBool codePolDefUnpaged = (policy == EKernelConfigCodePagingPolicyDefaultUnpaged);
   209 		TBool codePolDefPaged = (policy == EKernelConfigCodePagingPolicyDefaultPaged);
   210 		if (codePolDefPaged || codePolDefUnpaged)
   211 			return KErrCorrupt;
   212 		}
   213 #endif
   214 
   215 	if (linkexe>=0 && linkexe!=aExeNum)
   216 		return KErrNotSupported;	// if DLL links to a different EXE, no good
   217 	if (!(dllflags&KModuleFlagDataInTree))
   218 		return KErrNone;			// if no data in DLL tree, OK
   219 	if (proc_sym)
   220 		return KErrNone;			// if all user processes equivalent, OK
   221 	if (!(dllflags&KModuleFlagXIPDataInTree))
   222 		return KErrNone;			// if no XIP modules with data in DLL tree, OK
   223 
   224 #ifdef __EPOC32__
   225 	if (attp<0 || !(GetModuleFlags(attp)&KModuleFlagFixed))
   226 		{
   227 		// moving processes only
   228 		if (!(exeflags&KModuleFlagFixed))
   229 			return KErrNone;
   230 		return KErrNotSupported;
   231 		}
   232 	// fixed attach process only
   233 	if (aExeNum!=attp)
   234 		return KErrNotSupported;
   235 #else
   236 	(void)attp;
   237 	(void)exeflags;
   238 #endif
   239 	return KErrNone;
   240 	}
   241 
   242 TInt LoaderTest::DetermineDllLoadResult(TInt aDllNum, TInt aExeNum1, TInt aExeNum2)
   243 	{
   244 	// Determine result of loading aDllNum into aExeNum2 given that it's already loaded into aExeNum1
   245 	// return KErrNone if code segment can be shared, 1 if it must be duplicated
   246 	
   247 	TBool proc_sym=(iMemModelAtt & (EMemModelAttrSameVA|EMemModelAttrSupportFixed))==EMemModelAttrSameVA;
   248 	const TInt* exeinfo=ModuleExeInfo[aDllNum];
   249 //	TInt attp=exeinfo[0];
   250 	TInt linkexe=exeinfo[1];
   251 	TInt dllflags=GetModuleFlags(aDllNum);
   252 	TInt exe1flags=GetModuleFlags(aExeNum1);
   253 	TInt exe2flags=GetModuleFlags(aExeNum2);
   254 	if (linkexe>=0 && linkexe!=aExeNum2)
   255 		return KErrNotSupported;	// if DLL links to a different EXE, no good
   256 	if (!(dllflags&KModuleFlagDataInTree))
   257 		return KErrNone;			// if no data in DLL tree, OK
   258 	if (proc_sym)
   259 		return KErrNone;			// if all user processes equivalent, OK
   260 	if (!((exe1flags|exe2flags)&KModuleFlagFixed))
   261 		return KErrNone;			// if neither process fixed, OK
   262 	if (!(dllflags&KModuleFlagXIPDataInTree))
   263 		return 1;					// if no XIP modules with data in DLL tree, OK but can't share
   264 #ifdef __WINS__
   265 	return KErrNone;
   266 #else
   267 	return KErrNotSupported;
   268 #endif
   269 	}
   270 
   271 TBool LoaderTest::IsRomAddress(TLinAddr a)
   272 	{
   273 	const TRomHeader& rh=*(const TRomHeader*)UserSvr::RomHeaderAddress();
   274 	return (a>=rh.iRomBase && (a-rh.iRomBase)<rh.iRomSize);
   275 	}
   276 
   277 TBool LoaderTest::IsRamCodeAddress(TLinAddr a)
   278 	{
   279 	switch (iMemModelAtt & EMemModelTypeMask)
   280 		{
   281 		case EMemModelTypeDirect:
   282 			return ETrue;
   283 		case EMemModelTypeMoving:
   284 			return (a>=0xc0000000u);
   285 		case EMemModelTypeMultiple:
   286 			return (a<0x80000000u);
   287 		case EMemModelTypeFlexible:
   288 			return (a<0x80000000u);
   289 		case EMemModelTypeEmul:
   290 			return (a<0x80000000u);
   291 		default:
   292 			return EFalse;
   293 		}
   294 	}
   295 
   296 TBool LoaderTest::CheckDataAddress(TLinAddr a, TInt aDllNum, TInt aExeNum)
   297 	{
   298 	TInt xf=GetModuleFlags(aExeNum);
   299 	TInt df=GetModuleFlags(aDllNum);
   300 	switch (iMemModelAtt & EMemModelTypeMask)
   301 		{
   302 		case EMemModelTypeDirect:
   303 			return ETrue;
   304 		case EMemModelTypeMoving:
   305 			{
   306 			const TRomHeader& rh=*(const TRomHeader*)UserSvr::RomHeaderAddress();
   307 			if (!(xf&KModuleFlagFixed))
   308 				return (a<0x40000000u);
   309 			if ((xf&KModuleFlagXIP) && (df&KModuleFlagXIP))
   310 				return (a>=rh.iKernDataAddress && a<rh.iKernelLimit);
   311 			return (a>=rh.iKernelLimit && a<0xc0000000u);
   312 			}
   313 		case EMemModelTypeMultiple:
   314 			return (a<0x80000000u);
   315 		case EMemModelTypeFlexible:
   316 			return (a<0x80000000u);
   317 		case EMemModelTypeEmul:
   318 			return (a<0x80000000u);
   319 		default:
   320 			return EFalse;
   321 		}
   322 	}
   323 
   324 void LoaderTest::DumpModuleInfo(const SDllInfo& aInfo, TInt aExeNum)
   325 	{
   326 	TInt flags=GetModuleFlags(aInfo.iDllNum);
   327 	TUint32 mmtype=iMemModelAtt & EMemModelTypeMask;
   328 	TAny* h=iDev.ModuleCodeSeg(aInfo.iModuleHandle);
   329 	if (!h)
   330 		{
   331 #ifdef __EPOC32__
   332 		test(flags & KModuleFlagXIP);
   333 		test(IsRomAddress(aInfo.iEntryPointAddress));
   334 		test.Printf(_L("Module handle %08x ROM XIP\n"),aInfo.iModuleHandle);
   335 #endif
   336 		test(!(flags & KModuleFlagData));
   337 		return;
   338 		}
   339 	TCodeSegCreateInfo info;
   340 	TInt r=iDev.GetCodeSegInfo(h, info);
   341 	test(r==KErrNone);
   342 	TFileName fn;
   343 	fn.Copy(info.iFileName);
   344 	test.Printf(_L("DCodeSeg@%08x Data=%08x+%x,%x File %S,attr=0x%x\n"),h,info.iDataRunAddress,info.iDataSize,info.iBssSize,&fn,info.iAttr);
   345 	TInt total_data_size=info.iDataSize+info.iBssSize;
   346 #ifndef __WINS__
   347 	// Don't do check below for WINS because:
   348 	// a. It doesn't work on code warrior since it puts constants into .data
   349 	// b. On MSCV with c++ exceptions enabled we also get data
   350 	if (flags & KModuleFlagData)
   351 		test(total_data_size!=0);
   352 	else
   353 		test(total_data_size==0);
   354 
   355 	// ensure code paged iff expected.  This implements the logic from
   356 	// PREQ1110 Design Sketch SGL.TS0022.008 v1.0 S3.1.3.2
   357 
   358 	TUint policy = E32Loader::PagingPolicy();
   359 
   360 	TBool expected;
   361 	TBool isCodePaged = (info.iAttr & ECodeSegAttCodePaged)!=0;
   362 
   363 	// 1. If paging policy is NOPAGING then executable is Unpaged.
   364 	TUint32 memModelAttributes=UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL);
   365 	if (policy == EKernelConfigCodePagingPolicyNoPaging || !(memModelAttributes&EMemModelAttrCodePaging))
   366 		{
   367 		test.Printf(_L("sbcpexp,1\n"));
   368 		expected = false;
   369 		}
   370 	// 2. If ... media ... doesn't have Pageable Media Attribute then it is Unpaged.
   371 	// (this has been superseded by BlockMap check on filesystem / media.  During these
   372 	// tests, only the internal media supports paging.)
   373 	else if ((flags & KModuleFlagIDrive) == 0)
   374 		{
   375 		test.Printf(_L("sbcpexp,2\n"));
   376 		expected = false;
   377 		}
   378 	// 3. If ... removable media then it is Unpaged.
   379 	// Not tested here because removable media (drive 1) covered by above case.
   380 //	else if (MODULE_FILENAME(aInfo.iDllNum)[0] == '1')
   381 //		{
   382 //		test.Printf(_L("sbcpexp,2\n"));
   383 //		expected = false;
   384 //		}
   385 	// 4. [If not bytepair [or uncompressed]] then Unpaged
   386 	else if ((flags & (KModuleFlagBytePair | KModuleFlagUncompressed)) == 0)
   387 		{
   388 		test.Printf(_L("sbcpexp,3\n"));
   389 		expected = false;
   390 		}
   391 	// 5. If the Paging Policy is ALWAYSPAGE then the executable is Paged.
   392 	else if (policy == EKernelConfigCodePagingPolicyAlwaysPage)
   393 		{
   394 		test.Printf(_L("sbcpexp,4\n"));
   395 		expected = true;
   396 		}
   397 	// 6. if KImageCodePaged and KImageCodePaged both set, should not reach here
   398 	//	because load will have failed with KErrCorrupt.  If Paged on its own
   399 	//	then paged; if unpaged on its own then unpaged
   400 	else if ((flags & KModuleFlagPagedCode) != 0)
   401 		{
   402 		test.Printf(_L("sbcpexp,5\n"));
   403 		expected = true;
   404 		}
   405 	else if ((flags & KModuleFlagUnpagedCode) != 0)
   406 		{
   407 		test.Printf(_L("sbcpexp,6\n"));
   408 		expected = false;
   409 		}
   410 	// 7. Otherwise the PagingPolicy (DEFAULTPAGED or DEFAULTUNPAGED) determines
   411 	//	how the executable is treated
   412 	else
   413 		{
   414 		test.Printf(_L("sbcpexp,7\n"));
   415 		expected = (policy == EKernelConfigCodePagingPolicyDefaultPaged);
   416 		}
   417 
   418 	test(expected == isCodePaged);
   419 #endif
   420 	if ((flags & KModuleFlagXIP) && mmtype!=EMemModelTypeEmul)
   421 		test(IsRomAddress(aInfo.iEntryPointAddress));
   422 	else
   423 		{
   424 		test(IsRamCodeAddress(aInfo.iEntryPointAddress));
   425 		if(mmtype==EMemModelTypeFlexible)
   426 			{
   427 			// can't make assumtions about current processes address space
   428 			}
   429 		else if (mmtype==EMemModelTypeMultiple)
   430 			{
   431 			test(!AddressReadable(aInfo.iEntryPointAddress));
   432 			}
   433 		else
   434 			{
   435 			test(AddressReadable(aInfo.iEntryPointAddress));
   436 			}
   437 		}
   438 
   439 	if (total_data_size!=0)
   440 		test(CheckDataAddress(info.iDataRunAddress, aInfo.iDllNum, aExeNum));
   441 	}
   442 
   443 void LoaderTest::DumpModuleList(const TModuleList& aList, TInt aExeNum)
   444 	{
   445 	TInt i;
   446 	for (i=0; i<aList.iCount; ++i)
   447 		{
   448 		TInt modnum=aList.iInfo[i].iDllNum;
   449 		TInt entry=aList.iInfo[i].iEntryPointAddress;
   450 		test.Printf(_L("MODULE %3d: ENTRY %08x "),modnum,entry);
   451 		DumpModuleInfo(aList.iInfo[i],aExeNum);
   452 		}
   453 	}
   454 
   455 void LoaderTest::CheckModuleList(TInt aRoot, const TModuleList& aList)
   456 	{
   457 	const TInt* deps=ModuleDependencies[aRoot];
   458 	TInt ndeps=*deps++;
   459 	TInt f=0;
   460 	TInt i;
   461 	for (i=0; i<ndeps; ++i)
   462 		{
   463 		TInt m=deps[i];
   464 		f|=GetModuleFlags(m);
   465 		}
   466 	if (!(f&KModuleFlagDllInCycle))
   467 		{
   468 		i=0;		// indexes aList
   469 		TInt j=0;	// indexes deps
   470 		while(i<KNumModules)
   471 			{
   472 			if (j<ndeps)
   473 				{
   474 				if (!(GetModuleFlags(deps[j])&KModuleFlagExe))
   475 					{
   476 					test(aList.iInfo[i].iDllNum==deps[j]);
   477 					++i;
   478 					}
   479 				++j;
   480 				}
   481 			else if (j==ndeps)
   482 				{
   483 				test(aList.iInfo[i].iDllNum==aRoot);
   484 				++i;
   485 				++j;
   486 				}
   487 			else
   488 				{
   489 				test(aList.iInfo[i].iDllNum<0);
   490 				++i;
   491 				}
   492 			}
   493 		}
   494 	TModuleSet ml;
   495 	TInt nd=ndeps;
   496 	TBool root_included=EFalse;
   497 	for (i=0; i<ndeps; ++i)
   498 		{
   499 		if (deps[i]==aRoot)
   500 			root_included=ETrue;
   501 		if (!(GetModuleFlags(deps[i])&KModuleFlagExe))
   502 			ml.Add(deps[i]);
   503 		else
   504 			--nd;
   505 		}
   506 	test(ml.iCount==nd);
   507 	for (i=0; i<KNumModules; ++i)
   508 		{
   509 		if (i<nd)
   510 			{
   511 			test(aList.iInfo[i].iDllNum>=0);
   512 			ml.Remove(aList.iInfo[i].iDllNum);
   513 			}
   514 		else if (i==nd && !root_included)
   515 			test(aList.iInfo[i].iDllNum==aRoot);
   516 		else
   517 			test(aList.iInfo[i].iDllNum<0);
   518 		}
   519 	test(ml.iCount==0);
   520 	}
   521 
   522 LoaderTest::LoaderTest()
   523 	{
   524 	Mem::Fill(iCmdLine, sizeof(iCmdLine), 0xff);
   525 	iMemModelAtt=(TUint32)UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL);
   526 	test.Printf(_L("MemModelAttributes=%08x\n"),iMemModelAtt);
   527 	}
   528 
   529 LoaderTest::~LoaderTest()
   530 	{
   531 	iFs.Close();
   532 	iDev.Close();
   533 	}
   534 
   535 void LoaderTest::Init()
   536 	{
   537 	test.Next(_L("Load device driver"));
   538 	TInt r=User::LoadLogicalDevice(_L("D_LDRTST"));
   539 	test(r==KErrNone || r==KErrAlreadyExists);
   540 	r=iDev.Open();
   541 	test(r==KErrNone);
   542 	r=iFs.Connect();
   543 	test(r==KErrNone);
   544 
   545 	TBuf<256> cmdline;
   546 	User::CommandLine(cmdline);
   547 	TLex lex(cmdline);
   548 	TInt i;
   549 	for (i=0; i<8; ++i)
   550 		{
   551 		lex.SkipSpace();
   552 		if (lex.Eos())
   553 			break;
   554 		lex.Val(iCmdLine[i]);
   555 		}
   556 	}
   557 
   558 LoaderTest* LoaderTest::New()
   559 	{
   560 	LoaderTest* p=new LoaderTest;
   561 	test(p!=NULL);
   562 	p->Init();
   563 	return p;
   564 	}
   565 
   566 void LoaderTest::Close()
   567 	{
   568 	delete this;
   569 	}
   570 
   571 void LoaderTest::TraceOn()
   572 	{
   573 	iFs.SetDebugRegister(KFLDR);
   574 	User::SetDebugMask(0xefdfffff);
   575 	}
   576 
   577 void LoaderTest::TraceOff()
   578 	{
   579 	iFs.SetDebugRegister(0);
   580 	User::SetDebugMask(0x80000000);
   581 	}
   582 
   583 void LoaderTest::TestOneByOne()
   584 	{
   585 	test.Next(_L("Test all single EXE/DLL combinations"));
   586 	TInt i=0;
   587 	TInt r=0;
   588 	TInt x=0;
   589 	for (x=0; x<KNumModules; ++x)
   590 		{
   591 		if (!(GetModuleFlags(x)&KModuleFlagExe))
   592 			continue;
   593 #ifdef __WINS__
   594 		if (GetModuleFlags(x)&KModuleFlagTargetOnly)
   595 			continue;
   596 #endif
   597 		RProcess p;
   598 		TUint32 tt;
   599 		r=LoadExe(x, 0, p, tt);
   600 		test.Printf(_L("LoadExe(%d)->%d\n"),x,r);
   601 		test.Printf(_L("BENCHMARK: LoadExe(%d)->%dms\n"),x,tt);
   602 		test(r==KErrNone);
   603 		RLoaderTest lt;
   604 		r=lt.Connect(x);
   605 		test.Printf(_L("Connect(%d)->%d\n"),x,r);
   606 		test(r==KErrNone);
   607 		TModuleList exe_info;
   608 		r=lt.GetExeDepList(exe_info.iInfo);
   609 		test(r==KErrNone);
   610 		exe_info.SetCount();
   611 		DumpModuleList(exe_info, x);
   612 		CheckModuleList(x, exe_info);
   613 
   614 		TInt m;
   615 		for (m=0; m<KNumModules; ++m)
   616 			{
   617 			if (GetModuleFlags(m)&KModuleFlagExe)
   618 				continue;
   619 #ifdef __WINS__
   620 			if (GetModuleFlags(m)&KModuleFlagTargetOnly)
   621 				continue;
   622 #endif
   623 
   624 			if ((GetModuleFlags(m) & KModuleFlagVDrive) && NoRemovable)
   625 				{
   626 				test.Printf(_L("LoadDll: Not testing dll %d from removable media\n"),m);
   627 				continue;
   628 				}
   629 			TInt predicted=DetermineDllLoadResult(m,x);
   630 			if (x==iCmdLine[1] && m==iCmdLine[2])
   631 				TraceOn();
   632 			TModuleList dll_init_info;
   633 			TModuleList dll_c_info;
   634 			TModuleList dll_d_info;
   635 			TInt h=lt.LoadDll(m, dll_init_info.iInfo);
   636 			dll_init_info.SetCount();
   637 			test.Printf(_L("LoadDll(%d)->%d (%d)\n"),m,h,predicted);
   638 
   639 			test(Min(h,0)==predicted);
   640 			if (h>=0)
   641 				{
   642 				DumpModuleList(dll_init_info, x);
   643 				CheckModuleList(m, dll_init_info);
   644 				test(lt.GetCDList(dll_c_info.iInfo)==KErrNone);
   645 				dll_c_info.SetCount();
   646 				dll_c_info.Display(_L("Construct: "));
   647 				if (!(GetModuleFlags(m)&KModuleFlagDllInCycle))
   648 					{
   649 					TInt j=0;
   650 					for (i=0; i<dll_init_info.iCount; ++i)
   651 						{
   652 						TInt modnum=dll_init_info.iInfo[i].iDllNum;
   653 						if ((GetModuleFlags(modnum)&KModuleFlagData) && !exe_info.IsPresent(modnum))
   654 							{
   655 							test(modnum==dll_c_info.iInfo[j].iDllNum);
   656 							++j;
   657 							}
   658 						}
   659 					test(j==dll_c_info.iCount);
   660 					}
   661 				else
   662 					{
   663 					TModuleSet ms(dll_init_info, KModuleFlagData, KModuleFlagData);
   664 					ms.Remove(exe_info);
   665 					test(ms.iCount==dll_c_info.iCount);
   666 					ms.Remove(dll_c_info);
   667 					test(ms.iCount==0);
   668 					}
   669 				TInt y=(7*m+59);
   670 				r=lt.CallRBlkI(h,y);
   671 				r-=y;
   672 				r/=INC_BLOCK_SZ;
   673 				test.Printf(_L("DLL %d RBlkI->%d\n"),m,r);
   674 				y=ModuleRBlkIParams[m][1]+ModuleRBlkIParams[m][0]*DLLNUMOFFSET;
   675 				test(r==y);
   676 				r=lt.CloseDll(h);
   677 				test.Printf(_L("CloseDll(%d)->%d\n"),h,r);
   678 				test(r==KErrNone);
   679 				test(lt.GetCDList(dll_d_info.iInfo)==KErrNone);
   680 				dll_d_info.SetCount();
   681 				dll_d_info.Display(_L("Destruct:  "));
   682 				test(dll_d_info.iCount==dll_c_info.iCount);
   683 				for (i=0; i<dll_d_info.iCount; ++i)
   684 					test(dll_d_info.iInfo[i].iDllNum==dll_c_info.iInfo[dll_c_info.iCount-i-1].iDllNum);
   685 				}
   686 			if (x==iCmdLine[1] && m==iCmdLine[2])
   687 				TraceOff();
   688 			}
   689 		lt.Exit();
   690 		p.Close();
   691 		}
   692 	}
   693 
   694 // return KErrNone if shared code, 1 if not shared
   695 TInt LoaderTest::DetermineLoadExe2Result(TInt aExeNum)
   696 	{
   697 	if ( (iMemModelAtt&(EMemModelAttrSameVA|EMemModelAttrSupportFixed))==EMemModelAttrSameVA )
   698 		return KErrNone;	// multiple memory model always supports multiple instances
   699 	TUint32 f=GetModuleFlags(aExeNum);
   700 	if (!(f&KModuleFlagFixed))
   701 		return KErrNone;	// not fixed, so share code segment
   702 	if (!(f&KModuleFlagDataInTree))
   703 		{
   704 #ifdef __EPOC32__
   705 		return KErrNone;	// fixed but no data, so share code segment
   706 #else
   707 		return 1;			// on emulator, never share EXE code segments
   708 #endif
   709 		}
   710 #ifdef __EPOC32__
   711 	if (!(f&KModuleFlagXIP))
   712 		return 1;			// fixed but not XIP, data in tree - create second code segment
   713 	// fixed, XIP, data in tree
   714 	return KErrAlreadyExists;
   715 #else
   716 	if (f & KModuleFlagExports)
   717 		return KErrAlreadyExists;
   718 	if (!(f & KModuleFlagData))
   719 		return KErrNone;
   720 	return 1;
   721 #endif
   722 	}
   723 
   724 void LoaderTest::TestMultipleExeInstances()
   725 	{
   726 	test.Next(_L("Test multiple instantiation of EXEs"));
   727 	TInt i=0;
   728 	TInt r=0;
   729 	TInt x=0;
   730 	for (x=0; x<KNumModules; ++x)
   731 		{
   732 		TUint32 f=GetModuleFlags(x);
   733 		if (!(f&KModuleFlagExe))
   734 			continue;
   735 #ifdef __WINS__
   736 		if (f&KModuleFlagTargetOnly)
   737 			continue;
   738 #endif
   739 		RProcess p1, p2;
   740 		RLoaderTest lt1, lt2;
   741 		TModuleList exe_info1;
   742 		TModuleList exe_info2;
   743 		TUint32 tt;
   744 		r=LoadExe(x, 0, p1, tt);
   745 		test.Printf(_L("LoadExe1(%d)->%d\n"),x,r);
   746 		test.Printf(_L("BENCHMARK: LoadExe1(%d)->%dms\n"),x,tt);
   747 		test(r==KErrNone);
   748 		r=lt1.Connect(x, 0);
   749 		test.Printf(_L("Connect1(%d)->%d\n"),x,r);
   750 		test(r==KErrNone);
   751 		TInt s=DetermineLoadExe2Result(x);
   752 		r=LoadExe(x, 1, p2, tt);
   753 		test.Printf(_L("LoadExe2(%d)->%d (%d)\n"),x,r,s);
   754 		if (s==KErrNone)
   755 			test.Printf(_L("BENCHMARK: LoadExe2(%d)->%dms\n"),x,tt);
   756 		test(r==Min(s,0));
   757 
   758 		if (r==KErrNone)
   759 			{
   760 			r=lt2.Connect(x, 1);
   761 			test.Printf(_L("Connect2(%d)->%d\n"),x,r);
   762 			test(r==KErrNone);
   763 			r=lt1.GetExeDepList(exe_info1.iInfo);
   764 			test(r==KErrNone);
   765 			exe_info1.SetCount();
   766 			DumpModuleList(exe_info1, x);
   767 			r=lt2.GetExeDepList(exe_info2.iInfo);
   768 			test(r==KErrNone);
   769 			exe_info2.SetCount();
   770 			DumpModuleList(exe_info2, x);
   771 
   772 			test(exe_info1.iCount==exe_info2.iCount);
   773 			if (s==1)
   774 				{
   775 				TInt nm=exe_info1.iCount;
   776 				test(exe_info1.iInfo[nm-1].iModuleHandle!=exe_info2.iInfo[nm-1].iModuleHandle);
   777 				}
   778 #ifdef __WINS__
   779 			else if((GetModuleFlags(x) & KModuleFlagData))
   780 #else
   781 			else
   782 #endif
   783 				{
   784 				for (i=0; i<exe_info1.iCount; ++i)
   785 					test(exe_info1.iInfo[i].iModuleHandle==exe_info2.iInfo[i].iModuleHandle);
   786 				}
   787 
   788 			const TInt* tests=TC_ExeLoad;
   789 			TInt ntests=*tests++;
   790 			while(ntests--)
   791 				{
   792 				TInt m=*tests++;
   793 				TModuleList dll_init_info1;
   794 				TModuleList dll_c_info1;
   795 				TModuleList dll_d_info1;
   796 				TModuleList dll_init_info2;
   797 				TModuleList dll_c_info2;
   798 				TModuleList dll_d_info2;
   799 				TInt h1=lt1.LoadDll(m, dll_init_info1.iInfo);
   800 				dll_init_info1.SetCount();
   801 				test.Printf(_L("LoadDll1(%d)->%d\n"),m,h1);
   802 				if (h1>=0)
   803 					{
   804 					DumpModuleList(dll_init_info1, x);
   805 					CheckModuleList(m, dll_init_info1);
   806 					test(lt1.GetCDList(dll_c_info1.iInfo)==KErrNone);
   807 					dll_c_info1.SetCount();
   808 					dll_c_info1.Display(_L("Construct1: "));
   809 					TInt y=(41*m+487);
   810 					r=lt1.CallRBlkI(h1,y);
   811 					r-=y;
   812 					r/=INC_BLOCK_SZ;
   813 					test.Printf(_L("DLL1 %d RBlkI->%d\n"),m,r);
   814 					y=ModuleRBlkIParams[m][1]+ModuleRBlkIParams[m][0]*DLLNUMOFFSET;
   815 					test(r==y);
   816 
   817 					TInt s=DetermineDllLoadResult(m, x, x);
   818 					TInt h2=lt2.LoadDll(m, dll_init_info2.iInfo);
   819 					dll_init_info2.SetCount();
   820 					test.Printf(_L("LoadDll2(%d)->%d (%d)\n"),m,h2,s);
   821 					test(h2==Min(s,0));
   822 					if (h2>=0)
   823 						{
   824 						DumpModuleList(dll_init_info2, x);
   825 						CheckModuleList(m, dll_init_info2);
   826 						test(lt2.GetCDList(dll_c_info2.iInfo)==KErrNone);
   827 						dll_c_info2.SetCount();
   828 						dll_c_info2.Display(_L("Construct2: "));
   829 						y=(79*m+257);
   830 						r=lt2.CallRBlkI(h2,y);
   831 						r-=y;
   832 						r/=INC_BLOCK_SZ;
   833 						test.Printf(_L("DLL2 %d RBlkI->%d\n"),m,r);
   834 						y=ModuleRBlkIParams[m][1]+ModuleRBlkIParams[m][0]*DLLNUMOFFSET;
   835 						test(r==y);
   836 
   837 						test(dll_init_info1.iCount==dll_init_info2.iCount);
   838 #ifdef __WINS__
   839 						if (s==1 && !(ModuleFlags[m]&KModuleFlagDataInTree))
   840 #else
   841 						if (s==1)
   842 #endif
   843 							{
   844 							TInt nm=dll_init_info1.iCount;
   845 							test(dll_init_info1.iInfo[nm-1].iModuleHandle!=dll_init_info2.iInfo[nm-1].iModuleHandle);
   846 							}
   847 						else
   848 							{
   849 							for (i=0; i<dll_init_info1.iCount; ++i)
   850 								test(dll_init_info1.iInfo[i].iModuleHandle==dll_init_info2.iInfo[i].iModuleHandle);
   851 							}
   852 
   853 						r=lt2.CloseDll(h2);
   854 						test.Printf(_L("CloseDll2(%d)->%d\n"),h2,r);
   855 						test(r==KErrNone);
   856 						test(lt2.GetCDList(dll_d_info2.iInfo)==KErrNone);
   857 						dll_d_info2.SetCount();
   858 						dll_d_info2.Display(_L("Destruct2:  "));
   859 						test(dll_d_info2.iCount==dll_c_info2.iCount);
   860 						for (i=0; i<dll_d_info2.iCount; ++i)
   861 							test(dll_d_info2.iInfo[i].iDllNum==dll_c_info2.iInfo[dll_c_info2.iCount-i-1].iDllNum);
   862 						}
   863 
   864 					r=lt1.CloseDll(h1);
   865 					test.Printf(_L("CloseDll1(%d)->%d\n"),h1,r);
   866 					test(r==KErrNone);
   867 					test(lt1.GetCDList(dll_d_info1.iInfo)==KErrNone);
   868 					dll_d_info1.SetCount();
   869 					dll_d_info1.Display(_L("Destruct1:  "));
   870 					test(dll_d_info1.iCount==dll_c_info1.iCount);
   871 					for (i=0; i<dll_d_info1.iCount; ++i)
   872 						test(dll_d_info1.iInfo[i].iDllNum==dll_c_info1.iInfo[dll_c_info1.iCount-i-1].iDllNum);
   873 					}
   874 				}
   875 
   876 			lt2.Exit();
   877 			p2.Close();
   878 			}
   879 		lt1.Exit();
   880 		p1.Close();
   881 		}
   882 	}
   883 
   884 void SetLoaderFail(TInt aLdr, TInt aKern)
   885 	{
   886 	test.Printf(_L("ldr=%d, kern=%d\n"),aLdr,aKern);
   887 	RLoader l;
   888 	test(l.Connect()==KErrNone);
   889 	test(l.DebugFunction(ELoaderDebug_SetHeapFail, aLdr, aKern, 0)==KErrNone);
   890 	l.Close();
   891 	}
   892 
   893 void SetLoaderFailRFs(TInt aError, TInt aCount)
   894 	{
   895 	test.Printf(_L("SetLoaderFailRFs: error=%d, count=%d\n"),aError,aCount);
   896 	RLoader l;
   897 	test(l.Connect()==KErrNone);
   898 	test(l.DebugFunction(ELoaderDebug_SetRFsFail, aError, aCount, 0)==KErrNone);
   899 	l.Close();
   900 	}
   901 
   902 class TLoopOOM
   903 	{
   904 public:
   905 	enum OomState{EInit, EKernelHeap, EUserHeap, ERFsError};
   906 
   907 	TLoopOOM();
   908 	void Reset();
   909 	TBool Iterate(TInt aResult);
   910 public:
   911 	TInt iLdr;
   912 	TInt iKern;
   913 	TInt iRFsCount;
   914 	OomState iState;
   915 	};
   916 
   917 TLoopOOM::TLoopOOM()
   918 	{
   919 	Reset();
   920 	}
   921 
   922 void TLoopOOM::Reset()
   923 	{
   924 	iLdr = 0;
   925 	iKern = 0;
   926 	iRFsCount = 0;
   927 	iState = EInit;
   928 	}
   929 
   930 TBool TLoopOOM::Iterate(TInt aResult)
   931 	{
   932 	TBool noErrors = (aResult==KErrNone||aResult==KErrNotSupported);
   933 
   934 	test.Printf(_L("%d %d %d %d\n"), iKern,iLdr,iRFsCount,aResult);
   935 
   936 	switch(iState)
   937 		{
   938 
   939 	case EInit:
   940 		iState = EKernelHeap;
   941 		SetLoaderFail(iLdr,++iKern);
   942 		return ETrue;
   943 
   944 	case EKernelHeap:
   945 		if (noErrors)
   946 			{
   947 			iKern = 0;
   948 			iLdr = 1;
   949 			iState = EUserHeap;
   950 			}
   951 		else
   952 			++iKern;
   953 
   954 		SetLoaderFail(iLdr,iKern);
   955 		return ETrue;
   956 	
   957 	case EUserHeap:
   958 		if (noErrors)
   959 			{
   960 			iLdr = 0;
   961 			iState = ERFsError;
   962 			SetLoaderFail(0,0);
   963 			SetLoaderFailRFs(KRFsError, ++iRFsCount);
   964 			}
   965 		else
   966 			SetLoaderFail(++iLdr,iKern);
   967 		return ETrue;
   968 	
   969 	case ERFsError:
   970 		if (noErrors)
   971 			break;
   972 		else
   973 			{
   974 			SetLoaderFailRFs(KRFsError, ++iRFsCount);
   975 			return ETrue;
   976 			}
   977 		}
   978 
   979 	SetLoaderFailRFs(KErrNone, 0);
   980 	return EFalse;
   981 	}
   982 
   983 void LoaderTest::TestOOM()
   984 	{
   985 	test.Next(_L("Test OOM Handling"));
   986 #ifdef _DEBUG
   987 	TInt r=0;
   988 	TInt x=0;
   989 	TUint32 tt;
   990 	for (x=0; x<KNumModules; ++x)
   991 		{
   992 		if (!(GetModuleFlags(x)&KModuleFlagExe))
   993 			continue;
   994 #ifdef __WINS__
   995 		if (GetModuleFlags(x)&KModuleFlagTargetOnly)
   996 			continue;
   997 #endif
   998 
   999 		if ((GetModuleFlags(x) & KModuleFlagVDrive) && NoRemovable)
  1000 			{
  1001 			test.Printf(_L("LoaderTest::TestOOM Not testing dll %d from removable media\n"),x);
  1002 			continue;
  1003 			}
  1004 		if (x==iCmdLine[1])
  1005 			TraceOn();
  1006 		TLoopOOM loom;
  1007 		RProcess p;
  1008 		RLoaderTest lt;
  1009 		while(loom.Iterate(r))
  1010 			{
  1011 			r=LoadExe(x, 0, p, tt);
  1012 			test.Printf(_L("LoadExe(%d)->%d\n"),x,r);
  1013 			test(r==KErrNone || (loom.iState!=TLoopOOM::ERFsError && r==KErrNoMemory) || 
  1014 				(loom.iState==TLoopOOM::ERFsError && r==KRFsError));
  1015 			if (r==KErrNone)
  1016 				{
  1017 				TInt s=lt.Connect(x);
  1018 				test.Printf(_L("Connect(%d)->%d\n"),x,s);
  1019 				test(s==KErrNone);
  1020 				lt.Exit();
  1021 				p.Close();
  1022 				}
  1023 			}
  1024 		SetLoaderFail(0,0);
  1025 		r=LoadExe(x, 0, p, tt);
  1026 		test(r==KErrNone);
  1027 		r=lt.Connect(x);
  1028 		test(r==KErrNone);
  1029 		const TInt* tests=TC_DllOOM;
  1030 		TInt ntests=*tests++;
  1031 		TModuleList list;
  1032 		while(ntests--)
  1033 			{
  1034 			TInt m=*tests++;
  1035 			if ((GetModuleFlags(m) & KModuleFlagVDrive) && NoRemovable)
  1036 				{
  1037 				test.Printf(_L("LoaderTest::TestOOM Not testing dll %d from removable media\n"),m);
  1038 				continue;
  1039 				}
  1040 			loom.Reset();
  1041 			r=KErrNone;
  1042 			while(loom.Iterate(r))
  1043 				{
  1044 				TInt h=lt.LoadDll(m, list.iInfo);
  1045 				r=Min(h,0);
  1046 				test.Printf(_L("%d:LoadDll(%d)->%d\n"),x,m,h);
  1047 				
  1048 				test(r==KErrNone || r==KErrNotSupported || KErrNoMemory || 
  1049 					(loom.iState==TLoopOOM::ERFsError && r==KRFsError) );
  1050 					
  1051 				if (r==KErrNone)
  1052 					{
  1053 					TInt s=lt.CloseDll(h);
  1054 					test(s==KErrNone);
  1055 					}
  1056 				}
  1057 			}
  1058 		lt.Exit();
  1059 		p.Close();
  1060 		if (x==iCmdLine[1])
  1061 			TraceOff();
  1062 		}
  1063 #else
  1064 	test.Printf(_L("Only on DEBUG builds\n"));
  1065 #endif
  1066 	}
  1067 
  1068 class RLoaderTestHandle : public RSessionBase
  1069 	{
  1070 public:
  1071 	TInt Connect();
  1072 	void TryToGetPaniced();
  1073 	};
  1074 
  1075 TInt RLoaderTestHandle::Connect()
  1076 	{
  1077 	return CreateSession(_L("!Loader"),TVersion(KLoaderMajorVersionNumber,KLoaderMinorVersionNumber,KE32BuildVersionNumber));
  1078 	}
  1079 
  1080 void RLoaderTestHandle::TryToGetPaniced()
  1081 	{
  1082 	_LIT(KFoo,"foo");
  1083 	TLdrInfo info;
  1084 	TPckg<TLdrInfo> infoBuf(info);
  1085 	TIpcArgs args;
  1086 	args.Set(0,(TDes8*)&infoBuf);
  1087 	args.Set(1,&KFoo);
  1088 	args.Set(2,&KFoo);
  1089 	SendReceive(ELoadLibrary, args);
  1090 	}
  1091 
  1092 TInt PanicTestThread(TAny*)
  1093 	{
  1094 	RLoaderTestHandle t;
  1095 	TInt r = t.Connect();
  1096 	if (r==KErrNone) t.TryToGetPaniced();
  1097 	return r;
  1098 	}
  1099 
  1100 
  1101 void TestCorruptedFiles()
  1102 	{
  1103 	test.Next(_L("Test corrupted files"));
  1104 
  1105 	TInt numCorruptFiles=0;
  1106 	TInt r=0;
  1107 	for (TInt x=0; x<KNumModules; ++x)
  1108 		{
  1109 		if (!(GetModuleFlags(x)&KModuleFlagExe))
  1110 			continue;
  1111 
  1112 		const TPtrC fn = MODULE_FILENAME(x);
  1113 		if (fn[1] != ':')
  1114 			continue;
  1115 
  1116 		if (++numCorruptFiles > KNumberOfCorruptFiles)
  1117 			break;
  1118 
  1119 		RProcess p;
  1120 		TUint32 tt;
  1121 		r=LoadExe(x, 0, p, tt);
  1122 		test.Printf(_L("LoadCorruptExe(%d)->%d\n"),x,r);
  1123 		test(r==KErrCorrupt);
  1124 		}
  1125 	}
  1126 
  1127 // -------- copying files to non-ROM media --------
  1128 
  1129 static void GetSpecialDrives()
  1130 /**
  1131 	Work out which physical drive corresponds to each
  1132 	numeric drive in the list of filenames.  This populates
  1133 	SpecialDrives.
  1134 	
  1135 	@see SpecialDrives
  1136  */
  1137 	{
  1138 	test.Printf(_L("NoRemovable=%d\n"),NoRemovable);
  1139 
  1140 	// mark each special drive as not present
  1141 	for (TInt i = 0; i < KSpecialDriveCount; ++i)
  1142 		{
  1143 		SpecialDrives[i] = '!';
  1144 		}
  1145 	
  1146 	// cannot load binaries from emulated removable drives
  1147 #if defined (__WINS__)
  1148 	SpecialDrives[1] = 'c';			// "removable"
  1149 #endif
  1150 	
  1151 	TBuf<12> hashDir;
  1152 	hashDir = KSysHash;
  1153 	hashDir[0] = (TUint8) RFs::GetSystemDriveChar();
  1154 
  1155 	TInt r = Fs.MkDirAll(hashDir);
  1156 	test(r == KErrNone || r == KErrAlreadyExists);
  1157 
  1158 	for (TInt d = 0; d <= (TInt)sizeof(SpecialDriveList); ++d)
  1159 		{
  1160 		TInt dr = SpecialDriveList[d];
  1161 		TDriveInfo di;
  1162 		test.Printf(_L("Drive %d\n"), dr);
  1163 		test(Fs.Drive(di, dr) == KErrNone);
  1164 		if (di.iType == EMediaNotPresent)
  1165 			continue;
  1166 		
  1167 		TChar ch0;
  1168 		test(RFs::DriveToChar(dr, ch0) == KErrNone);
  1169 		
  1170 		TText ch = static_cast<TText>(TUint(ch0));
  1171 		
  1172 		// drive 0 == internal
  1173 		if ((di.iDriveAtt & KDriveAttInternal) && SpecialDrives[0] == '!')
  1174 			{
  1175 			SpecialDrives[0] = ch;
  1176 			if (NoRemovable)
  1177 				SpecialDrives[1] = ch;
  1178 			}
  1179 		// drive 1 == removable
  1180 		else if ((di.iDriveAtt & KDriveAttRemovable) && SpecialDrives[1] == '!' && !NoRemovable)
  1181 			SpecialDrives[1] = ch;
  1182 		else
  1183 			{
  1184 			// drive not useful so continue and don't create \sys\bin
  1185 			continue;
  1186 			}
  1187 
  1188 		TFileName fn;
  1189 		fn.Append(ch);
  1190 		fn.Append(_L(":\\sys\\bin\\"));
  1191 		r = Fs.MkDirAll(fn);
  1192 		test.Printf(_L("MkDirAll %S returns %d\n"), &fn, r);
  1193 		test(r == KErrNone || r == KErrAlreadyExists);
  1194 		}
  1195 	}
  1196 
  1197 void GetNonZFileName(const TDesC& aOrigName, TDes& aNonZName)
  1198 /**
  1199 	Resolve a special drive to the target drive using the mappings in
  1200 	SpecialDrives.  This is used to load non-XIP binaries from pageable media.
  1201 	
  1202 	@param	aOrigName		Fully-qualified filename with special drive number.
  1203 							E.g., "3:\\sys\\bin\\dllt45.dll".
  1204 	@param	aNonZName		Descriptor to populate with aOrigName and the transformed
  1205 							drive, e.g. "c:\\sys\\bin\\dllt45.dll".
  1206  */
  1207 	{
  1208 	test.Printf(_L(">GetNonZFileName,\"%S\"\n"), &aOrigName);
  1209 	test(aOrigName[1] == ':');
  1210 	aNonZName.Copy(aOrigName);
  1211 	TText replaceChar = SpecialDrives[aOrigName[0] - '0'];
  1212 	test(TChar(replaceChar).IsAlpha());
  1213 	aNonZName[0] = replaceChar;
  1214 	test.Printf(_L("<GetNonZFileName,\"%S\"\n"), &aNonZName);
  1215 	}
  1216 
  1217 static void GetHashFileName(const TDesC& aOrigName, TDes& aHashName)
  1218 /**
  1219 	Get name of the hash file used for an EXE or DLL which has been
  1220 	copied to writable media.
  1221 
  1222 	@param	aOrigName		Name of EXE or DLL which has been copied to
  1223 							writable media.  This does not have to be
  1224 							qualified because only the name and extension
  1225 							are used.
  1226 	@param	aHashName		On return this is set to the absolute filename
  1227 							which should contain the file's hash.  This
  1228 							function does not create the file, or its containing
  1229 							directory.
  1230  */
  1231 	{
  1232 	aHashName.Copy(KSysHash);
  1233 	aHashName[0] = (TUint8) RFs::GetSystemDriveChar();
  1234 	const TParsePtrC ppc(aOrigName);
  1235 	aHashName.Append(ppc.NameAndExt());
  1236 	}
  1237 
  1238 static void CopyExecutablesL(TBool aCorruptMode=EFalse)
  1239 /**
  1240 	Make a copy of each executable that should be copied
  1241 	to a writable drive.
  1242 	
  1243 	If aCorruptMode make KNumberOfCorruptFiles corrupted copies: truncated file and a file with corrupted header 
  1244 
  1245  */
  1246 	{
  1247 	TInt r;
  1248 	TInt numCorruptFiles = 0;
  1249 
  1250 	GetSpecialDrives();
  1251 	
  1252 	CFileMan* fm = CFileMan::NewL(Fs);
  1253 	
  1254 	for (TInt i = 0; i < KNumModules; ++i)
  1255 		{
  1256 		if (aCorruptMode && numCorruptFiles==KNumberOfCorruptFiles)
  1257 			break;
  1258 
  1259 		if (aCorruptMode && !(GetModuleFlags(i)&KModuleFlagExe))
  1260 			continue;
  1261 
  1262 		const TPtrC fn = MODULE_FILENAME(i);
  1263 		
  1264 		// if this is an absolute filename then copy it to
  1265 		// the appropriate drive.
  1266 		if (fn[1] != ':')
  1267 			continue;
  1268 		
  1269 		TFileName fnDest;
  1270 		GetNonZFileName(fn, fnDest);
  1271 
  1272 		
  1273 		TFileName fnSrc(fn);
  1274 		fnSrc[0] = 'z';
  1275 
  1276 		test.Printf(_L("CopyExecutables;%S,%S\n"), &fnSrc, &fnDest);
  1277 
  1278 #ifdef __WINS__
  1279 		const TParsePtrC sppc(fnSrc);
  1280 		TBuf<MAX_PATH> sName;
  1281 		r = MapEmulatedFileName(sName, sppc.NameAndExt());
  1282 		test(r == KErrNone);
  1283 
  1284 		TBuf<MAX_PATH> dName;
  1285 		r = MapEmulatedFileName(dName, fnDest);
  1286 		test(r == KErrNone);
  1287 
  1288 		BOOL b = Emulator::CopyFile((LPCTSTR)sName.PtrZ(),(LPCTSTR)dName.PtrZ(),FALSE);
  1289 		test(b);
  1290 #else
  1291 		r = fm->Copy(fnSrc, fnDest);
  1292 		test(r == KErrNone);
  1293 #endif
  1294 
  1295 		r = Fs.SetAtt(fnDest, 0, KEntryAttReadOnly);
  1296 		test.Printf(_L("CopyExecutables:setatt=%d\n"), r);
  1297 		User::LeaveIfError(r);
  1298 
  1299 #ifdef __EPOC32__
  1300 		TInt moduleFlags = GetModuleFlags(i);
  1301 
  1302 		// modify the new destination file by applying the required paging flags
  1303 		RFile fNp;
  1304 		r = fNp.Open(Fs, fnDest, EFileWrite | EFileStream);
  1305 		User::LeaveIfError(r);
  1306 		CleanupClosePushL(fNp);
  1307 
  1308 		// read the header and get the total number of bytes to checksum.
  1309 		// (This may be greater than sizeof(E32ImageHeader).
  1310 		TPckgBuf<E32ImageHeader> hdrBuf;
  1311 		r = fNp.Read(0, hdrBuf);
  1312 		User::LeaveIfError(r);
  1313 		TInt totalSize = hdrBuf().TotalSize();
  1314 		test.Printf(_L("np flags=0x%x,totalSize=%d\n"), hdrBuf().iFlags, totalSize);
  1315 		
  1316 		// read in the actual bytes to checksum
  1317 		TUint8* startBytes0 = (TUint8*) User::AllocLC(totalSize);
  1318 		TPtr8 startBytes(startBytes0, 0, totalSize);
  1319 		r = fNp.Read(0, startBytes);
  1320 		User::LeaveIfError(r);
  1321 		test(startBytes.Length() == totalSize);
  1322 
  1323 		// apply the required paging flags to the header
  1324 		E32ImageHeader* hdr2 = reinterpret_cast<E32ImageHeader*>(startBytes0);
  1325 		TUint& flags = hdr2->iFlags;
  1326 		flags &= ~(KImageCodePaged | KImageCodeUnpaged);
  1327 		if (moduleFlags & KModuleFlagPagedCode)
  1328 			flags |= KImageCodePaged;
  1329 		if (moduleFlags & KModuleFlagUnpagedCode)
  1330 			flags |= KImageCodeUnpaged;
  1331 		test.Printf(_L("setting new image flags 0x%x\n"), flags);
  1332 
  1333 		// corrupt header of the 2nd file
  1334 		if (aCorruptMode && numCorruptFiles==1 && (moduleFlags&KModuleFlagExe))
  1335 			{
  1336 			hdr2->iCodeBase += 3;
  1337 			hdr2->iDataBase += 1;
  1338 			hdr2->iImportOffset += 1;
  1339 			hdr2->iCodeRelocOffset += 3;
  1340 			hdr2->iDataRelocOffset += 3;
  1341 
  1342 			++numCorruptFiles;
  1343 			}
  1344 
  1345 		// recalculate the checksum
  1346 		hdr2->iHeaderCrc = KImageCrcInitialiser;
  1347 		TUint32 crc = 0;
  1348 		Mem::Crc32(crc, startBytes.Ptr(), totalSize);
  1349 		hdr2->iHeaderCrc = crc;
  1350 		r = fNp.Write(0, startBytes);
  1351 		User::LeaveIfError(r);
  1352 
  1353 		// truncate 1st corrupted file
  1354 		if (aCorruptMode && numCorruptFiles==0 && (moduleFlags&KModuleFlagExe))
  1355 			{
  1356 			TInt size;
  1357 			r = fNp.Size(size);
  1358 			User::LeaveIfError(r);
  1359 			// if trncate by 1 it managed to load. if trancate by 3 it failed to load with KErrCorrupt as expected
  1360 			r = fNp.SetSize(size-3); 
  1361 			User::LeaveIfError(r);
  1362 			++numCorruptFiles;
  1363 			}
  1364 
  1365 		CleanupStack::PopAndDestroy(2, &fNp);		// startBytes0, fNp
  1366 #endif
  1367 
  1368 		// if copied to removable media, then generate hash
  1369 		if (fn[0] == '0')
  1370 			continue;
  1371 
  1372 		CSHA1* sha1 = CSHA1::NewL();
  1373 		CleanupStack::PushL(sha1);
  1374 
  1375 		RFile fDest;
  1376 		r = fDest.Open(Fs, fnDest, EFileRead | EFileStream);
  1377 		User::LeaveIfError(r);
  1378 		CleanupClosePushL(fDest);
  1379 
  1380 		TBool done;
  1381 		TBuf8<512> content;
  1382 		do
  1383 			{
  1384 			r = fDest.Read(content);
  1385 			User::LeaveIfError(r);
  1386 			done = (content.Length() == 0);
  1387 			if (! done)
  1388 				sha1->Update(content);
  1389 			} while (! done);
  1390 		CleanupStack::PopAndDestroy(&fDest);
  1391 
  1392 		// write hash to \sys\hash
  1393 		TBuf8<SHA1_HASH> hashVal = sha1->Final();
  1394 
  1395 		// reuse fnSrc to save stack space
  1396 		GetHashFileName(fnDest, fnSrc);
  1397 		RFile fHash;
  1398 		r = fHash.Replace(Fs, fnSrc, EFileWrite | EFileStream);
  1399 		test.Printf(_L("hash file,%S,r=%d\n"), &fnSrc, r);
  1400 		User::LeaveIfError(r);
  1401 		CleanupClosePushL(fHash);
  1402 		r = fHash.Write(hashVal);
  1403 		User::LeaveIfError(r);
  1404 
  1405 		CleanupStack::PopAndDestroy(2, sha1);
  1406 		}
  1407 	
  1408 	delete fm;
  1409 	}
  1410 
  1411 static void DeleteExecutables(TBool aCorruptMode=EFalse)
  1412 /**
  1413 	Delete any executables which were created by CopyExecutables.
  1414 	This function is defined so the test cleans up when it has finished.
  1415  */
  1416 	{
  1417 	TInt numCorruptFiles = 0;
  1418 
  1419 	for (TInt i = 0; i < KNumModules; ++i)
  1420 		{
  1421 		if (aCorruptMode && numCorruptFiles==KNumberOfCorruptFiles)
  1422 			break;
  1423 
  1424 		if (aCorruptMode && !(GetModuleFlags(i)&KModuleFlagExe))
  1425 			continue;
  1426 
  1427 		const TPtrC fn = MODULE_FILENAME(i);
  1428 		
  1429 		// if this is an absolute filename then copy it to
  1430 		// the appropriate drive.
  1431 		if (fn[1] != ':')
  1432 			continue;
  1433 		
  1434 		test.Printf(_L("DeleteExecutables:fn=%S\n"), &fn);
  1435 		TFileName fnDest;
  1436 		GetNonZFileName(fn, fnDest);
  1437 		
  1438 		TInt r;
  1439 
  1440 		r = Fs.Delete(fnDest);
  1441 		test.Printf(_L("DeleteExecutables:fnDest=%S,del=%d\n"), &fnDest, r);
  1442 		test(r == KErrNone);
  1443 
  1444 		// only need to delete hash files for binaries copied to removable media,
  1445 		// but simpler to delete and test for KErrNotFound
  1446 		TFileName fnHash;
  1447 		GetHashFileName(fnDest, fnHash);
  1448 		r = Fs.Delete(fnHash);
  1449 		test.Printf(_L("DeleteExecutables,h=%S,hdel=%d\n"), &fnHash, r);
  1450 		test(r == KErrPathNotFound || r == KErrNotFound || r == KErrNone);
  1451 
  1452 		if (aCorruptMode)
  1453 			++numCorruptFiles;
  1454 		}
  1455 	}
  1456 
  1457 GLDEF_C TInt E32Main()
  1458 	{
  1459 	RThread().SetPriority(EPriorityLess);
  1460 
  1461 	test.Title();
  1462 	test.Start(_L("Setup"));
  1463 
  1464 	RLoader l;
  1465 	test(l.Connect()==KErrNone);
  1466 	test(l.CancelLazyDllUnload()==KErrNone);
  1467 	l.Close();
  1468 
  1469 	test(TestLdd.Open()==KErrNone);
  1470 	LoaderTest* pL=LoaderTest::New();
  1471 	TheLoaderTest=pL;
  1472 
  1473 	TInt tm=pL->iCmdLine[0];
  1474 	TInt nr = (tm>>4)&3;
  1475 	if (nr==1)
  1476 		NoRemovable = ETrue;
  1477 	else if (nr==2)
  1478 		NoRemovable = EFalse;
  1479 
  1480 	test(Fs.Connect() == KErrNone);
  1481 
  1482 	// allocate a cleanup stack so can call CFileMan::NewL in CopyExecutables
  1483 	test.Printf(_L("CopyExecutablesL()\n"));
  1484 	CTrapCleanup* cleanup=CTrapCleanup::New();
  1485 	TRAPD(r, CopyExecutablesL());
  1486 	test(r == KErrNone);
  1487 	delete cleanup;
  1488 
  1489 	if (tm&1)
  1490 		pL->TestOneByOne();
  1491 	if (tm&2)
  1492 		pL->TestMultipleExeInstances();
  1493 	if (tm&4)
  1494 		pL->TestOOM();
  1495 	if (tm&8)
  1496 		pL->TestMultipleLoads();
  1497 
  1498 	pL->Close();
  1499 
  1500 	// Test loader error handling - will panic the client thread
  1501 	test.Next(_L("Test loader error handling - will panic the client thread"));
  1502 	RThread t;
  1503 	t.Create(_L("Loader panic test"),PanicTestThread,KDefaultStackSize,0x1000,0x1000,NULL);
  1504 	TRequestStatus s;
  1505 	t.Logon(s);
  1506 	TBool justInTime=User::JustInTime(); 
  1507 	User::SetJustInTime(EFalse); 
  1508 	t.Resume();
  1509 	User::WaitForRequest(s);
  1510 	test(t.ExitType()==EExitPanic);
  1511 	test(t.ExitCategory().Compare(_L("LOADER"))==0);
  1512 	test(t.ExitReason()==0);
  1513 	t.Close();
  1514 	User::SetJustInTime(justInTime);
  1515 
  1516 	DeleteExecutables();
  1517 
  1518 #ifdef __EPOC32__
  1519 	// test corrupted files
  1520 	cleanup=CTrapCleanup::New();
  1521 	test.Next(_L("CopyExecutablesL(ETrue)"));
  1522 	TRAPD(rr, CopyExecutablesL(ETrue));
  1523 	test(rr == KErrNone);
  1524 	delete cleanup;
  1525 	test.Next(_L("TestCorruptedFiles()"));
  1526 	TestCorruptedFiles();
  1527 	test.Next(_L("DeleteExecutables()"));
  1528 	DeleteExecutables(ETrue);
  1529 #endif
  1530 
  1531 	Fs.Close();
  1532 
  1533 	test.End();
  1534 	return KErrNone;
  1535 	}
  1536