--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/f32test/loader/t_ldrtst.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,1536 @@
+// 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\t_ldrtst.cpp
+//
+//
+
+#define __E32TEST_EXTENSION__
+
+#include "t_hash.h"
+#include "t_ldrtst.h"
+#include "../../../e32test/mmu/d_memorytest.h"
+
+#if defined(__WINS__)
+ #include <e32wins.h>
+ #include <emulator.h>
+#elif defined(__EPOC32__)
+ #include <f32image.h>
+#endif
+
+const TInt KNumberOfCorruptFiles = 2;
+
+RTest test(_L("T_LDRTST"));
+
+LoaderTest* TheLoaderTest;
+RFs Fs;
+#if defined (__X86__) || defined(__WINS__)
+TBool NoRemovable=ETrue;
+#else
+TBool NoRemovable=EFalse;
+#endif
+
+/** Error code of simulated RFs error */
+const TInt KRFsError = -99;
+
+/**
+ Number of drives which are identified by a numeric value,
+ which means, e.g., run from an internal pageable drive.
+ */
+const TInt KSpecialDriveCount = 2;
+
+/** The real drive letters corresponding to each special drive. */
+static TFixedArray<TText, KSpecialDriveCount> SpecialDrives;
+
+/** Bitmask of paged and unpaged module flags. */
+const TUint32 KModulePagedCodeFlags = (KModuleFlagPagedCode | KModuleFlagUnpagedCode);
+
+_LIT(KSysHash,"?:\\Sys\\Hash\\");
+
+TInt GetModuleFlags(TInt aModule)
+ {
+ TInt f = ModuleFlags[aModule];
+#ifdef __WINS__
+ // paged and unpaged flags are not supported on the emulator
+ f &= ~KModulePagedCodeFlags;
+ // On emulator, treat all modules as XIP, all EXEs as fixed
+ f |= KModuleFlagXIP;
+ if (f & KModuleFlagExe)
+ f|=KModuleFlagFixed;
+#endif // #ifdef __EPOC32__
+ return f;
+ }
+
+TModuleSet::TModuleSet()
+ {
+ Mem::FillZ(this,sizeof(TModuleSet));
+ }
+
+void TModuleSet::Add(TInt aModule)
+ {
+ TUint8 m=(TUint8)(1<<(aModule&7));
+ TInt i=aModule>>3;
+ if (!(iBitMap[i]&m))
+ {
+ iBitMap[i]|=m;
+ ++iCount;
+ }
+ }
+
+void TModuleSet::Remove(TInt aModule)
+ {
+ TUint8 m=(TUint8)(1<<(aModule&7));
+ TInt i=aModule>>3;
+ if (iBitMap[i]&m)
+ {
+ iBitMap[i]&=~m;
+ --iCount;
+ }
+ }
+
+TModuleSet::TModuleSet(const TModuleList& aList, TInt aMask, TInt aVal)
+ {
+ Mem::FillZ(this,sizeof(TModuleSet));
+ TInt i;
+ for (i=0; i<aList.iCount; ++i)
+ {
+ TInt m=aList.iInfo[i].iDllNum;
+ if (((GetModuleFlags(m)&aMask)^aVal)==0)
+ Add(aList.iInfo[i].iDllNum);
+ }
+ }
+
+void TModuleSet::Remove(const TModuleList& aList)
+ {
+ TInt i;
+ for (i=0; i<aList.iCount; ++i)
+ Remove(aList.iInfo[i].iDllNum);
+ }
+
+void TModuleSet::Display(const TDesC& aTitle) const
+ {
+ TBuf<256> s=aTitle;
+ TInt i;
+ for (i=0; i<iCount; ++i)
+ {
+ if (Present(i))
+ s.AppendFormat(_L("%3d "),i);
+ }
+ test.Printf(_L("%S\n"),&s);
+ }
+
+TModuleList::TModuleList()
+ {
+ iCount=0;
+ Mem::Fill(iInfo, KNumModules*sizeof(SDllInfo), 0xff);
+ }
+
+void TModuleList::SetCount()
+ {
+ TInt i;
+ for (i=0; i<KNumModules && iInfo[i].iDllNum>=0; ++i) {}
+ iCount=i;
+ }
+
+void TModuleList::Display(const TDesC& aTitle) const
+ {
+ TBuf<256> s=aTitle;
+ TInt i;
+ for (i=0; i<iCount; ++i)
+ {
+ TInt modnum=iInfo[i].iDllNum;
+ s.AppendFormat(_L("%3d "),modnum);
+ }
+ test.Printf(_L("%S\n"),&s);
+ }
+
+TBool TModuleList::IsPresent(TInt aModNum) const
+ {
+ return Find(aModNum)>=0;
+ }
+
+TInt TModuleList::Find(TInt aModNum) const
+ {
+ TInt i;
+ for (i=iCount-1; i>=0 && iInfo[i].iDllNum!=aModNum; --i) {}
+ return i;
+ }
+
+void TModuleList::Add(const SDllInfo& a)
+ {
+ iInfo[iCount++]=a;
+ }
+
+
+RMemoryTestLdd TestLdd;
+
+TBool AddressReadable(TLinAddr a)
+ {
+ TUint32 value;
+ return TestLdd.ReadMemory((TAny*)a,value)==KErrNone;
+ }
+
+TInt LoaderTest::DetermineDllLoadResult(TInt aDllNum, TInt aExeNum)
+ {
+ TBool proc_sym=(iMemModelAtt & (EMemModelAttrSameVA|EMemModelAttrSupportFixed))==EMemModelAttrSameVA;
+ const TInt* exeinfo=ModuleExeInfo[aDllNum];
+ TInt attp=exeinfo[0];
+ TInt linkexe=exeinfo[1];
+ TInt dllflags=GetModuleFlags(aDllNum);
+ TInt exeflags=GetModuleFlags(aExeNum);
+
+#ifdef __EPOC32__
+ // if NP and DEFAULTPAGED or DEFAULTUNPAGED (not NOPAGING or ALWAYSPAGE) then
+ // executable identified as corrupt, unless previous conditions in S3.1.3.2 cause
+ // it to be paged or unpaged without examining the flags.
+
+ TUint32 policy = E32Loader::PagingPolicy();
+ test.Printf(_L("DetermineDllLoadResult,dll=%d,exe=%d,dllflags=0x%x,policy=0x%x\n"), aDllNum, aExeNum, dllflags, policy);
+
+ TBool flagsChecked =
+ policy != EKernelConfigCodePagingPolicyNoPaging // 3.1.3.2.1, policy != no paging
+ && (dllflags & KModuleFlagIDrive) != 0 // 3.1.3.2.2-3, pageable drive
+ && (dllflags & (KModuleFlagUncompressed | KModuleFlagBytePair)) != 0 // 3.1.3.2.4 pageable format
+ && policy != EKernelConfigCodePagingPolicyAlwaysPage; // 3.1.3.2.5, policy != ALWAYS
+
+ if (flagsChecked && (dllflags & KModulePagedCodeFlags) == KModulePagedCodeFlags)
+ {
+ TBool codePolDefUnpaged = (policy == EKernelConfigCodePagingPolicyDefaultUnpaged);
+ TBool codePolDefPaged = (policy == EKernelConfigCodePagingPolicyDefaultPaged);
+ if (codePolDefPaged || codePolDefUnpaged)
+ return KErrCorrupt;
+ }
+#endif
+
+ if (linkexe>=0 && linkexe!=aExeNum)
+ return KErrNotSupported; // if DLL links to a different EXE, no good
+ if (!(dllflags&KModuleFlagDataInTree))
+ return KErrNone; // if no data in DLL tree, OK
+ if (proc_sym)
+ return KErrNone; // if all user processes equivalent, OK
+ if (!(dllflags&KModuleFlagXIPDataInTree))
+ return KErrNone; // if no XIP modules with data in DLL tree, OK
+
+#ifdef __EPOC32__
+ if (attp<0 || !(GetModuleFlags(attp)&KModuleFlagFixed))
+ {
+ // moving processes only
+ if (!(exeflags&KModuleFlagFixed))
+ return KErrNone;
+ return KErrNotSupported;
+ }
+ // fixed attach process only
+ if (aExeNum!=attp)
+ return KErrNotSupported;
+#else
+ (void)attp;
+ (void)exeflags;
+#endif
+ return KErrNone;
+ }
+
+TInt LoaderTest::DetermineDllLoadResult(TInt aDllNum, TInt aExeNum1, TInt aExeNum2)
+ {
+ // Determine result of loading aDllNum into aExeNum2 given that it's already loaded into aExeNum1
+ // return KErrNone if code segment can be shared, 1 if it must be duplicated
+
+ TBool proc_sym=(iMemModelAtt & (EMemModelAttrSameVA|EMemModelAttrSupportFixed))==EMemModelAttrSameVA;
+ const TInt* exeinfo=ModuleExeInfo[aDllNum];
+// TInt attp=exeinfo[0];
+ TInt linkexe=exeinfo[1];
+ TInt dllflags=GetModuleFlags(aDllNum);
+ TInt exe1flags=GetModuleFlags(aExeNum1);
+ TInt exe2flags=GetModuleFlags(aExeNum2);
+ if (linkexe>=0 && linkexe!=aExeNum2)
+ return KErrNotSupported; // if DLL links to a different EXE, no good
+ if (!(dllflags&KModuleFlagDataInTree))
+ return KErrNone; // if no data in DLL tree, OK
+ if (proc_sym)
+ return KErrNone; // if all user processes equivalent, OK
+ if (!((exe1flags|exe2flags)&KModuleFlagFixed))
+ return KErrNone; // if neither process fixed, OK
+ if (!(dllflags&KModuleFlagXIPDataInTree))
+ return 1; // if no XIP modules with data in DLL tree, OK but can't share
+#ifdef __WINS__
+ return KErrNone;
+#else
+ return KErrNotSupported;
+#endif
+ }
+
+TBool LoaderTest::IsRomAddress(TLinAddr a)
+ {
+ const TRomHeader& rh=*(const TRomHeader*)UserSvr::RomHeaderAddress();
+ return (a>=rh.iRomBase && (a-rh.iRomBase)<rh.iRomSize);
+ }
+
+TBool LoaderTest::IsRamCodeAddress(TLinAddr a)
+ {
+ switch (iMemModelAtt & EMemModelTypeMask)
+ {
+ case EMemModelTypeDirect:
+ return ETrue;
+ case EMemModelTypeMoving:
+ return (a>=0xc0000000u);
+ case EMemModelTypeMultiple:
+ return (a<0x80000000u);
+ case EMemModelTypeFlexible:
+ return (a<0x80000000u);
+ case EMemModelTypeEmul:
+ return (a<0x80000000u);
+ default:
+ return EFalse;
+ }
+ }
+
+TBool LoaderTest::CheckDataAddress(TLinAddr a, TInt aDllNum, TInt aExeNum)
+ {
+ TInt xf=GetModuleFlags(aExeNum);
+ TInt df=GetModuleFlags(aDllNum);
+ switch (iMemModelAtt & EMemModelTypeMask)
+ {
+ case EMemModelTypeDirect:
+ return ETrue;
+ case EMemModelTypeMoving:
+ {
+ const TRomHeader& rh=*(const TRomHeader*)UserSvr::RomHeaderAddress();
+ if (!(xf&KModuleFlagFixed))
+ return (a<0x40000000u);
+ if ((xf&KModuleFlagXIP) && (df&KModuleFlagXIP))
+ return (a>=rh.iKernDataAddress && a<rh.iKernelLimit);
+ return (a>=rh.iKernelLimit && a<0xc0000000u);
+ }
+ case EMemModelTypeMultiple:
+ return (a<0x80000000u);
+ case EMemModelTypeFlexible:
+ return (a<0x80000000u);
+ case EMemModelTypeEmul:
+ return (a<0x80000000u);
+ default:
+ return EFalse;
+ }
+ }
+
+void LoaderTest::DumpModuleInfo(const SDllInfo& aInfo, TInt aExeNum)
+ {
+ TInt flags=GetModuleFlags(aInfo.iDllNum);
+ TUint32 mmtype=iMemModelAtt & EMemModelTypeMask;
+ TAny* h=iDev.ModuleCodeSeg(aInfo.iModuleHandle);
+ if (!h)
+ {
+#ifdef __EPOC32__
+ test(flags & KModuleFlagXIP);
+ test(IsRomAddress(aInfo.iEntryPointAddress));
+ test.Printf(_L("Module handle %08x ROM XIP\n"),aInfo.iModuleHandle);
+#endif
+ test(!(flags & KModuleFlagData));
+ return;
+ }
+ TCodeSegCreateInfo info;
+ TInt r=iDev.GetCodeSegInfo(h, info);
+ test(r==KErrNone);
+ TFileName fn;
+ fn.Copy(info.iFileName);
+ 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);
+ TInt total_data_size=info.iDataSize+info.iBssSize;
+#ifndef __WINS__
+ // Don't do check below for WINS because:
+ // a. It doesn't work on code warrior since it puts constants into .data
+ // b. On MSCV with c++ exceptions enabled we also get data
+ if (flags & KModuleFlagData)
+ test(total_data_size!=0);
+ else
+ test(total_data_size==0);
+
+ // ensure code paged iff expected. This implements the logic from
+ // PREQ1110 Design Sketch SGL.TS0022.008 v1.0 S3.1.3.2
+
+ TUint policy = E32Loader::PagingPolicy();
+
+ TBool expected;
+ TBool isCodePaged = (info.iAttr & ECodeSegAttCodePaged)!=0;
+
+ // 1. If paging policy is NOPAGING then executable is Unpaged.
+ TUint32 memModelAttributes=UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL);
+ if (policy == EKernelConfigCodePagingPolicyNoPaging || !(memModelAttributes&EMemModelAttrCodePaging))
+ {
+ test.Printf(_L("sbcpexp,1\n"));
+ expected = false;
+ }
+ // 2. If ... media ... doesn't have Pageable Media Attribute then it is Unpaged.
+ // (this has been superseded by BlockMap check on filesystem / media. During these
+ // tests, only the internal media supports paging.)
+ else if ((flags & KModuleFlagIDrive) == 0)
+ {
+ test.Printf(_L("sbcpexp,2\n"));
+ expected = false;
+ }
+ // 3. If ... removable media then it is Unpaged.
+ // Not tested here because removable media (drive 1) covered by above case.
+// else if (MODULE_FILENAME(aInfo.iDllNum)[0] == '1')
+// {
+// test.Printf(_L("sbcpexp,2\n"));
+// expected = false;
+// }
+ // 4. [If not bytepair [or uncompressed]] then Unpaged
+ else if ((flags & (KModuleFlagBytePair | KModuleFlagUncompressed)) == 0)
+ {
+ test.Printf(_L("sbcpexp,3\n"));
+ expected = false;
+ }
+ // 5. If the Paging Policy is ALWAYSPAGE then the executable is Paged.
+ else if (policy == EKernelConfigCodePagingPolicyAlwaysPage)
+ {
+ test.Printf(_L("sbcpexp,4\n"));
+ expected = true;
+ }
+ // 6. if KImageCodePaged and KImageCodePaged both set, should not reach here
+ // because load will have failed with KErrCorrupt. If Paged on its own
+ // then paged; if unpaged on its own then unpaged
+ else if ((flags & KModuleFlagPagedCode) != 0)
+ {
+ test.Printf(_L("sbcpexp,5\n"));
+ expected = true;
+ }
+ else if ((flags & KModuleFlagUnpagedCode) != 0)
+ {
+ test.Printf(_L("sbcpexp,6\n"));
+ expected = false;
+ }
+ // 7. Otherwise the PagingPolicy (DEFAULTPAGED or DEFAULTUNPAGED) determines
+ // how the executable is treated
+ else
+ {
+ test.Printf(_L("sbcpexp,7\n"));
+ expected = (policy == EKernelConfigCodePagingPolicyDefaultPaged);
+ }
+
+ test(expected == isCodePaged);
+#endif
+ if ((flags & KModuleFlagXIP) && mmtype!=EMemModelTypeEmul)
+ test(IsRomAddress(aInfo.iEntryPointAddress));
+ else
+ {
+ test(IsRamCodeAddress(aInfo.iEntryPointAddress));
+ if(mmtype==EMemModelTypeFlexible)
+ {
+ // can't make assumtions about current processes address space
+ }
+ else if (mmtype==EMemModelTypeMultiple)
+ {
+ test(!AddressReadable(aInfo.iEntryPointAddress));
+ }
+ else
+ {
+ test(AddressReadable(aInfo.iEntryPointAddress));
+ }
+ }
+
+ if (total_data_size!=0)
+ test(CheckDataAddress(info.iDataRunAddress, aInfo.iDllNum, aExeNum));
+ }
+
+void LoaderTest::DumpModuleList(const TModuleList& aList, TInt aExeNum)
+ {
+ TInt i;
+ for (i=0; i<aList.iCount; ++i)
+ {
+ TInt modnum=aList.iInfo[i].iDllNum;
+ TInt entry=aList.iInfo[i].iEntryPointAddress;
+ test.Printf(_L("MODULE %3d: ENTRY %08x "),modnum,entry);
+ DumpModuleInfo(aList.iInfo[i],aExeNum);
+ }
+ }
+
+void LoaderTest::CheckModuleList(TInt aRoot, const TModuleList& aList)
+ {
+ const TInt* deps=ModuleDependencies[aRoot];
+ TInt ndeps=*deps++;
+ TInt f=0;
+ TInt i;
+ for (i=0; i<ndeps; ++i)
+ {
+ TInt m=deps[i];
+ f|=GetModuleFlags(m);
+ }
+ if (!(f&KModuleFlagDllInCycle))
+ {
+ i=0; // indexes aList
+ TInt j=0; // indexes deps
+ while(i<KNumModules)
+ {
+ if (j<ndeps)
+ {
+ if (!(GetModuleFlags(deps[j])&KModuleFlagExe))
+ {
+ test(aList.iInfo[i].iDllNum==deps[j]);
+ ++i;
+ }
+ ++j;
+ }
+ else if (j==ndeps)
+ {
+ test(aList.iInfo[i].iDllNum==aRoot);
+ ++i;
+ ++j;
+ }
+ else
+ {
+ test(aList.iInfo[i].iDllNum<0);
+ ++i;
+ }
+ }
+ }
+ TModuleSet ml;
+ TInt nd=ndeps;
+ TBool root_included=EFalse;
+ for (i=0; i<ndeps; ++i)
+ {
+ if (deps[i]==aRoot)
+ root_included=ETrue;
+ if (!(GetModuleFlags(deps[i])&KModuleFlagExe))
+ ml.Add(deps[i]);
+ else
+ --nd;
+ }
+ test(ml.iCount==nd);
+ for (i=0; i<KNumModules; ++i)
+ {
+ if (i<nd)
+ {
+ test(aList.iInfo[i].iDllNum>=0);
+ ml.Remove(aList.iInfo[i].iDllNum);
+ }
+ else if (i==nd && !root_included)
+ test(aList.iInfo[i].iDllNum==aRoot);
+ else
+ test(aList.iInfo[i].iDllNum<0);
+ }
+ test(ml.iCount==0);
+ }
+
+LoaderTest::LoaderTest()
+ {
+ Mem::Fill(iCmdLine, sizeof(iCmdLine), 0xff);
+ iMemModelAtt=(TUint32)UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL);
+ test.Printf(_L("MemModelAttributes=%08x\n"),iMemModelAtt);
+ }
+
+LoaderTest::~LoaderTest()
+ {
+ iFs.Close();
+ iDev.Close();
+ }
+
+void LoaderTest::Init()
+ {
+ test.Next(_L("Load device driver"));
+ TInt r=User::LoadLogicalDevice(_L("D_LDRTST"));
+ test(r==KErrNone || r==KErrAlreadyExists);
+ r=iDev.Open();
+ test(r==KErrNone);
+ r=iFs.Connect();
+ test(r==KErrNone);
+
+ TBuf<256> cmdline;
+ User::CommandLine(cmdline);
+ TLex lex(cmdline);
+ TInt i;
+ for (i=0; i<8; ++i)
+ {
+ lex.SkipSpace();
+ if (lex.Eos())
+ break;
+ lex.Val(iCmdLine[i]);
+ }
+ }
+
+LoaderTest* LoaderTest::New()
+ {
+ LoaderTest* p=new LoaderTest;
+ test(p!=NULL);
+ p->Init();
+ return p;
+ }
+
+void LoaderTest::Close()
+ {
+ delete this;
+ }
+
+void LoaderTest::TraceOn()
+ {
+ iFs.SetDebugRegister(KFLDR);
+ User::SetDebugMask(0xefdfffff);
+ }
+
+void LoaderTest::TraceOff()
+ {
+ iFs.SetDebugRegister(0);
+ User::SetDebugMask(0x80000000);
+ }
+
+void LoaderTest::TestOneByOne()
+ {
+ test.Next(_L("Test all single EXE/DLL combinations"));
+ TInt i=0;
+ TInt r=0;
+ TInt x=0;
+ for (x=0; x<KNumModules; ++x)
+ {
+ if (!(GetModuleFlags(x)&KModuleFlagExe))
+ continue;
+#ifdef __WINS__
+ if (GetModuleFlags(x)&KModuleFlagTargetOnly)
+ continue;
+#endif
+ RProcess p;
+ TUint32 tt;
+ r=LoadExe(x, 0, p, tt);
+ test.Printf(_L("LoadExe(%d)->%d\n"),x,r);
+ test.Printf(_L("BENCHMARK: LoadExe(%d)->%dms\n"),x,tt);
+ test(r==KErrNone);
+ RLoaderTest lt;
+ r=lt.Connect(x);
+ test.Printf(_L("Connect(%d)->%d\n"),x,r);
+ test(r==KErrNone);
+ TModuleList exe_info;
+ r=lt.GetExeDepList(exe_info.iInfo);
+ test(r==KErrNone);
+ exe_info.SetCount();
+ DumpModuleList(exe_info, x);
+ CheckModuleList(x, exe_info);
+
+ TInt m;
+ for (m=0; m<KNumModules; ++m)
+ {
+ if (GetModuleFlags(m)&KModuleFlagExe)
+ continue;
+#ifdef __WINS__
+ if (GetModuleFlags(m)&KModuleFlagTargetOnly)
+ continue;
+#endif
+
+ if ((GetModuleFlags(m) & KModuleFlagVDrive) && NoRemovable)
+ {
+ test.Printf(_L("LoadDll: Not testing dll %d from removable media\n"),m);
+ continue;
+ }
+ TInt predicted=DetermineDllLoadResult(m,x);
+ if (x==iCmdLine[1] && m==iCmdLine[2])
+ TraceOn();
+ TModuleList dll_init_info;
+ TModuleList dll_c_info;
+ TModuleList dll_d_info;
+ TInt h=lt.LoadDll(m, dll_init_info.iInfo);
+ dll_init_info.SetCount();
+ test.Printf(_L("LoadDll(%d)->%d (%d)\n"),m,h,predicted);
+
+ test(Min(h,0)==predicted);
+ if (h>=0)
+ {
+ DumpModuleList(dll_init_info, x);
+ CheckModuleList(m, dll_init_info);
+ test(lt.GetCDList(dll_c_info.iInfo)==KErrNone);
+ dll_c_info.SetCount();
+ dll_c_info.Display(_L("Construct: "));
+ if (!(GetModuleFlags(m)&KModuleFlagDllInCycle))
+ {
+ TInt j=0;
+ for (i=0; i<dll_init_info.iCount; ++i)
+ {
+ TInt modnum=dll_init_info.iInfo[i].iDllNum;
+ if ((GetModuleFlags(modnum)&KModuleFlagData) && !exe_info.IsPresent(modnum))
+ {
+ test(modnum==dll_c_info.iInfo[j].iDllNum);
+ ++j;
+ }
+ }
+ test(j==dll_c_info.iCount);
+ }
+ else
+ {
+ TModuleSet ms(dll_init_info, KModuleFlagData, KModuleFlagData);
+ ms.Remove(exe_info);
+ test(ms.iCount==dll_c_info.iCount);
+ ms.Remove(dll_c_info);
+ test(ms.iCount==0);
+ }
+ TInt y=(7*m+59);
+ r=lt.CallRBlkI(h,y);
+ r-=y;
+ r/=INC_BLOCK_SZ;
+ test.Printf(_L("DLL %d RBlkI->%d\n"),m,r);
+ y=ModuleRBlkIParams[m][1]+ModuleRBlkIParams[m][0]*DLLNUMOFFSET;
+ test(r==y);
+ r=lt.CloseDll(h);
+ test.Printf(_L("CloseDll(%d)->%d\n"),h,r);
+ test(r==KErrNone);
+ test(lt.GetCDList(dll_d_info.iInfo)==KErrNone);
+ dll_d_info.SetCount();
+ dll_d_info.Display(_L("Destruct: "));
+ test(dll_d_info.iCount==dll_c_info.iCount);
+ for (i=0; i<dll_d_info.iCount; ++i)
+ test(dll_d_info.iInfo[i].iDllNum==dll_c_info.iInfo[dll_c_info.iCount-i-1].iDllNum);
+ }
+ if (x==iCmdLine[1] && m==iCmdLine[2])
+ TraceOff();
+ }
+ lt.Exit();
+ p.Close();
+ }
+ }
+
+// return KErrNone if shared code, 1 if not shared
+TInt LoaderTest::DetermineLoadExe2Result(TInt aExeNum)
+ {
+ if ( (iMemModelAtt&(EMemModelAttrSameVA|EMemModelAttrSupportFixed))==EMemModelAttrSameVA )
+ return KErrNone; // multiple memory model always supports multiple instances
+ TUint32 f=GetModuleFlags(aExeNum);
+ if (!(f&KModuleFlagFixed))
+ return KErrNone; // not fixed, so share code segment
+ if (!(f&KModuleFlagDataInTree))
+ {
+#ifdef __EPOC32__
+ return KErrNone; // fixed but no data, so share code segment
+#else
+ return 1; // on emulator, never share EXE code segments
+#endif
+ }
+#ifdef __EPOC32__
+ if (!(f&KModuleFlagXIP))
+ return 1; // fixed but not XIP, data in tree - create second code segment
+ // fixed, XIP, data in tree
+ return KErrAlreadyExists;
+#else
+ if (f & KModuleFlagExports)
+ return KErrAlreadyExists;
+ if (!(f & KModuleFlagData))
+ return KErrNone;
+ return 1;
+#endif
+ }
+
+void LoaderTest::TestMultipleExeInstances()
+ {
+ test.Next(_L("Test multiple instantiation of EXEs"));
+ TInt i=0;
+ TInt r=0;
+ TInt x=0;
+ for (x=0; x<KNumModules; ++x)
+ {
+ TUint32 f=GetModuleFlags(x);
+ if (!(f&KModuleFlagExe))
+ continue;
+#ifdef __WINS__
+ if (f&KModuleFlagTargetOnly)
+ continue;
+#endif
+ RProcess p1, p2;
+ RLoaderTest lt1, lt2;
+ TModuleList exe_info1;
+ TModuleList exe_info2;
+ TUint32 tt;
+ r=LoadExe(x, 0, p1, tt);
+ test.Printf(_L("LoadExe1(%d)->%d\n"),x,r);
+ test.Printf(_L("BENCHMARK: LoadExe1(%d)->%dms\n"),x,tt);
+ test(r==KErrNone);
+ r=lt1.Connect(x, 0);
+ test.Printf(_L("Connect1(%d)->%d\n"),x,r);
+ test(r==KErrNone);
+ TInt s=DetermineLoadExe2Result(x);
+ r=LoadExe(x, 1, p2, tt);
+ test.Printf(_L("LoadExe2(%d)->%d (%d)\n"),x,r,s);
+ if (s==KErrNone)
+ test.Printf(_L("BENCHMARK: LoadExe2(%d)->%dms\n"),x,tt);
+ test(r==Min(s,0));
+
+ if (r==KErrNone)
+ {
+ r=lt2.Connect(x, 1);
+ test.Printf(_L("Connect2(%d)->%d\n"),x,r);
+ test(r==KErrNone);
+ r=lt1.GetExeDepList(exe_info1.iInfo);
+ test(r==KErrNone);
+ exe_info1.SetCount();
+ DumpModuleList(exe_info1, x);
+ r=lt2.GetExeDepList(exe_info2.iInfo);
+ test(r==KErrNone);
+ exe_info2.SetCount();
+ DumpModuleList(exe_info2, x);
+
+ test(exe_info1.iCount==exe_info2.iCount);
+ if (s==1)
+ {
+ TInt nm=exe_info1.iCount;
+ test(exe_info1.iInfo[nm-1].iModuleHandle!=exe_info2.iInfo[nm-1].iModuleHandle);
+ }
+#ifdef __WINS__
+ else if((GetModuleFlags(x) & KModuleFlagData))
+#else
+ else
+#endif
+ {
+ for (i=0; i<exe_info1.iCount; ++i)
+ test(exe_info1.iInfo[i].iModuleHandle==exe_info2.iInfo[i].iModuleHandle);
+ }
+
+ const TInt* tests=TC_ExeLoad;
+ TInt ntests=*tests++;
+ while(ntests--)
+ {
+ TInt m=*tests++;
+ TModuleList dll_init_info1;
+ TModuleList dll_c_info1;
+ TModuleList dll_d_info1;
+ TModuleList dll_init_info2;
+ TModuleList dll_c_info2;
+ TModuleList dll_d_info2;
+ TInt h1=lt1.LoadDll(m, dll_init_info1.iInfo);
+ dll_init_info1.SetCount();
+ test.Printf(_L("LoadDll1(%d)->%d\n"),m,h1);
+ if (h1>=0)
+ {
+ DumpModuleList(dll_init_info1, x);
+ CheckModuleList(m, dll_init_info1);
+ test(lt1.GetCDList(dll_c_info1.iInfo)==KErrNone);
+ dll_c_info1.SetCount();
+ dll_c_info1.Display(_L("Construct1: "));
+ TInt y=(41*m+487);
+ r=lt1.CallRBlkI(h1,y);
+ r-=y;
+ r/=INC_BLOCK_SZ;
+ test.Printf(_L("DLL1 %d RBlkI->%d\n"),m,r);
+ y=ModuleRBlkIParams[m][1]+ModuleRBlkIParams[m][0]*DLLNUMOFFSET;
+ test(r==y);
+
+ TInt s=DetermineDllLoadResult(m, x, x);
+ TInt h2=lt2.LoadDll(m, dll_init_info2.iInfo);
+ dll_init_info2.SetCount();
+ test.Printf(_L("LoadDll2(%d)->%d (%d)\n"),m,h2,s);
+ test(h2==Min(s,0));
+ if (h2>=0)
+ {
+ DumpModuleList(dll_init_info2, x);
+ CheckModuleList(m, dll_init_info2);
+ test(lt2.GetCDList(dll_c_info2.iInfo)==KErrNone);
+ dll_c_info2.SetCount();
+ dll_c_info2.Display(_L("Construct2: "));
+ y=(79*m+257);
+ r=lt2.CallRBlkI(h2,y);
+ r-=y;
+ r/=INC_BLOCK_SZ;
+ test.Printf(_L("DLL2 %d RBlkI->%d\n"),m,r);
+ y=ModuleRBlkIParams[m][1]+ModuleRBlkIParams[m][0]*DLLNUMOFFSET;
+ test(r==y);
+
+ test(dll_init_info1.iCount==dll_init_info2.iCount);
+#ifdef __WINS__
+ if (s==1 && !(ModuleFlags[m]&KModuleFlagDataInTree))
+#else
+ if (s==1)
+#endif
+ {
+ TInt nm=dll_init_info1.iCount;
+ test(dll_init_info1.iInfo[nm-1].iModuleHandle!=dll_init_info2.iInfo[nm-1].iModuleHandle);
+ }
+ else
+ {
+ for (i=0; i<dll_init_info1.iCount; ++i)
+ test(dll_init_info1.iInfo[i].iModuleHandle==dll_init_info2.iInfo[i].iModuleHandle);
+ }
+
+ r=lt2.CloseDll(h2);
+ test.Printf(_L("CloseDll2(%d)->%d\n"),h2,r);
+ test(r==KErrNone);
+ test(lt2.GetCDList(dll_d_info2.iInfo)==KErrNone);
+ dll_d_info2.SetCount();
+ dll_d_info2.Display(_L("Destruct2: "));
+ test(dll_d_info2.iCount==dll_c_info2.iCount);
+ for (i=0; i<dll_d_info2.iCount; ++i)
+ test(dll_d_info2.iInfo[i].iDllNum==dll_c_info2.iInfo[dll_c_info2.iCount-i-1].iDllNum);
+ }
+
+ r=lt1.CloseDll(h1);
+ test.Printf(_L("CloseDll1(%d)->%d\n"),h1,r);
+ test(r==KErrNone);
+ test(lt1.GetCDList(dll_d_info1.iInfo)==KErrNone);
+ dll_d_info1.SetCount();
+ dll_d_info1.Display(_L("Destruct1: "));
+ test(dll_d_info1.iCount==dll_c_info1.iCount);
+ for (i=0; i<dll_d_info1.iCount; ++i)
+ test(dll_d_info1.iInfo[i].iDllNum==dll_c_info1.iInfo[dll_c_info1.iCount-i-1].iDllNum);
+ }
+ }
+
+ lt2.Exit();
+ p2.Close();
+ }
+ lt1.Exit();
+ p1.Close();
+ }
+ }
+
+void SetLoaderFail(TInt aLdr, TInt aKern)
+ {
+ test.Printf(_L("ldr=%d, kern=%d\n"),aLdr,aKern);
+ RLoader l;
+ test(l.Connect()==KErrNone);
+ test(l.DebugFunction(ELoaderDebug_SetHeapFail, aLdr, aKern, 0)==KErrNone);
+ l.Close();
+ }
+
+void SetLoaderFailRFs(TInt aError, TInt aCount)
+ {
+ test.Printf(_L("SetLoaderFailRFs: error=%d, count=%d\n"),aError,aCount);
+ RLoader l;
+ test(l.Connect()==KErrNone);
+ test(l.DebugFunction(ELoaderDebug_SetRFsFail, aError, aCount, 0)==KErrNone);
+ l.Close();
+ }
+
+class TLoopOOM
+ {
+public:
+ enum OomState{EInit, EKernelHeap, EUserHeap, ERFsError};
+
+ TLoopOOM();
+ void Reset();
+ TBool Iterate(TInt aResult);
+public:
+ TInt iLdr;
+ TInt iKern;
+ TInt iRFsCount;
+ OomState iState;
+ };
+
+TLoopOOM::TLoopOOM()
+ {
+ Reset();
+ }
+
+void TLoopOOM::Reset()
+ {
+ iLdr = 0;
+ iKern = 0;
+ iRFsCount = 0;
+ iState = EInit;
+ }
+
+TBool TLoopOOM::Iterate(TInt aResult)
+ {
+ TBool noErrors = (aResult==KErrNone||aResult==KErrNotSupported);
+
+ test.Printf(_L("%d %d %d %d\n"), iKern,iLdr,iRFsCount,aResult);
+
+ switch(iState)
+ {
+
+ case EInit:
+ iState = EKernelHeap;
+ SetLoaderFail(iLdr,++iKern);
+ return ETrue;
+
+ case EKernelHeap:
+ if (noErrors)
+ {
+ iKern = 0;
+ iLdr = 1;
+ iState = EUserHeap;
+ }
+ else
+ ++iKern;
+
+ SetLoaderFail(iLdr,iKern);
+ return ETrue;
+
+ case EUserHeap:
+ if (noErrors)
+ {
+ iLdr = 0;
+ iState = ERFsError;
+ SetLoaderFail(0,0);
+ SetLoaderFailRFs(KRFsError, ++iRFsCount);
+ }
+ else
+ SetLoaderFail(++iLdr,iKern);
+ return ETrue;
+
+ case ERFsError:
+ if (noErrors)
+ break;
+ else
+ {
+ SetLoaderFailRFs(KRFsError, ++iRFsCount);
+ return ETrue;
+ }
+ }
+
+ SetLoaderFailRFs(KErrNone, 0);
+ return EFalse;
+ }
+
+void LoaderTest::TestOOM()
+ {
+ test.Next(_L("Test OOM Handling"));
+#ifdef _DEBUG
+ TInt r=0;
+ TInt x=0;
+ TUint32 tt;
+ for (x=0; x<KNumModules; ++x)
+ {
+ if (!(GetModuleFlags(x)&KModuleFlagExe))
+ continue;
+#ifdef __WINS__
+ if (GetModuleFlags(x)&KModuleFlagTargetOnly)
+ continue;
+#endif
+
+ if ((GetModuleFlags(x) & KModuleFlagVDrive) && NoRemovable)
+ {
+ test.Printf(_L("LoaderTest::TestOOM Not testing dll %d from removable media\n"),x);
+ continue;
+ }
+ if (x==iCmdLine[1])
+ TraceOn();
+ TLoopOOM loom;
+ RProcess p;
+ RLoaderTest lt;
+ while(loom.Iterate(r))
+ {
+ r=LoadExe(x, 0, p, tt);
+ test.Printf(_L("LoadExe(%d)->%d\n"),x,r);
+ test(r==KErrNone || (loom.iState!=TLoopOOM::ERFsError && r==KErrNoMemory) ||
+ (loom.iState==TLoopOOM::ERFsError && r==KRFsError));
+ if (r==KErrNone)
+ {
+ TInt s=lt.Connect(x);
+ test.Printf(_L("Connect(%d)->%d\n"),x,s);
+ test(s==KErrNone);
+ lt.Exit();
+ p.Close();
+ }
+ }
+ SetLoaderFail(0,0);
+ r=LoadExe(x, 0, p, tt);
+ test(r==KErrNone);
+ r=lt.Connect(x);
+ test(r==KErrNone);
+ const TInt* tests=TC_DllOOM;
+ TInt ntests=*tests++;
+ TModuleList list;
+ while(ntests--)
+ {
+ TInt m=*tests++;
+ if ((GetModuleFlags(m) & KModuleFlagVDrive) && NoRemovable)
+ {
+ test.Printf(_L("LoaderTest::TestOOM Not testing dll %d from removable media\n"),m);
+ continue;
+ }
+ loom.Reset();
+ r=KErrNone;
+ while(loom.Iterate(r))
+ {
+ TInt h=lt.LoadDll(m, list.iInfo);
+ r=Min(h,0);
+ test.Printf(_L("%d:LoadDll(%d)->%d\n"),x,m,h);
+
+ test(r==KErrNone || r==KErrNotSupported || KErrNoMemory ||
+ (loom.iState==TLoopOOM::ERFsError && r==KRFsError) );
+
+ if (r==KErrNone)
+ {
+ TInt s=lt.CloseDll(h);
+ test(s==KErrNone);
+ }
+ }
+ }
+ lt.Exit();
+ p.Close();
+ if (x==iCmdLine[1])
+ TraceOff();
+ }
+#else
+ test.Printf(_L("Only on DEBUG builds\n"));
+#endif
+ }
+
+class RLoaderTestHandle : public RSessionBase
+ {
+public:
+ TInt Connect();
+ void TryToGetPaniced();
+ };
+
+TInt RLoaderTestHandle::Connect()
+ {
+ return CreateSession(_L("!Loader"),TVersion(KLoaderMajorVersionNumber,KLoaderMinorVersionNumber,KE32BuildVersionNumber));
+ }
+
+void RLoaderTestHandle::TryToGetPaniced()
+ {
+ _LIT(KFoo,"foo");
+ TLdrInfo info;
+ TPckg<TLdrInfo> infoBuf(info);
+ TIpcArgs args;
+ args.Set(0,(TDes8*)&infoBuf);
+ args.Set(1,&KFoo);
+ args.Set(2,&KFoo);
+ SendReceive(ELoadLibrary, args);
+ }
+
+TInt PanicTestThread(TAny*)
+ {
+ RLoaderTestHandle t;
+ TInt r = t.Connect();
+ if (r==KErrNone) t.TryToGetPaniced();
+ return r;
+ }
+
+
+void TestCorruptedFiles()
+ {
+ test.Next(_L("Test corrupted files"));
+
+ TInt numCorruptFiles=0;
+ TInt r=0;
+ for (TInt x=0; x<KNumModules; ++x)
+ {
+ if (!(GetModuleFlags(x)&KModuleFlagExe))
+ continue;
+
+ const TPtrC fn = MODULE_FILENAME(x);
+ if (fn[1] != ':')
+ continue;
+
+ if (++numCorruptFiles > KNumberOfCorruptFiles)
+ break;
+
+ RProcess p;
+ TUint32 tt;
+ r=LoadExe(x, 0, p, tt);
+ test.Printf(_L("LoadCorruptExe(%d)->%d\n"),x,r);
+ test(r==KErrCorrupt);
+ }
+ }
+
+// -------- copying files to non-ROM media --------
+
+static void GetSpecialDrives()
+/**
+ Work out which physical drive corresponds to each
+ numeric drive in the list of filenames. This populates
+ SpecialDrives.
+
+ @see SpecialDrives
+ */
+ {
+ test.Printf(_L("NoRemovable=%d\n"),NoRemovable);
+
+ // mark each special drive as not present
+ for (TInt i = 0; i < KSpecialDriveCount; ++i)
+ {
+ SpecialDrives[i] = '!';
+ }
+
+ // cannot load binaries from emulated removable drives
+#if defined (__WINS__)
+ SpecialDrives[1] = 'c'; // "removable"
+#endif
+
+ TBuf<12> hashDir;
+ hashDir = KSysHash;
+ hashDir[0] = (TUint8) RFs::GetSystemDriveChar();
+
+ TInt r = Fs.MkDirAll(hashDir);
+ test(r == KErrNone || r == KErrAlreadyExists);
+
+ for (TInt d = 0; d <= (TInt)sizeof(SpecialDriveList); ++d)
+ {
+ TInt dr = SpecialDriveList[d];
+ TDriveInfo di;
+ test.Printf(_L("Drive %d\n"), dr);
+ test(Fs.Drive(di, dr) == KErrNone);
+ if (di.iType == EMediaNotPresent)
+ continue;
+
+ TChar ch0;
+ test(RFs::DriveToChar(dr, ch0) == KErrNone);
+
+ TText ch = static_cast<TText>(TUint(ch0));
+
+ // drive 0 == internal
+ if ((di.iDriveAtt & KDriveAttInternal) && SpecialDrives[0] == '!')
+ {
+ SpecialDrives[0] = ch;
+ if (NoRemovable)
+ SpecialDrives[1] = ch;
+ }
+ // drive 1 == removable
+ else if ((di.iDriveAtt & KDriveAttRemovable) && SpecialDrives[1] == '!' && !NoRemovable)
+ SpecialDrives[1] = ch;
+ else
+ {
+ // drive not useful so continue and don't create \sys\bin
+ continue;
+ }
+
+ TFileName fn;
+ fn.Append(ch);
+ fn.Append(_L(":\\sys\\bin\\"));
+ r = Fs.MkDirAll(fn);
+ test.Printf(_L("MkDirAll %S returns %d\n"), &fn, r);
+ test(r == KErrNone || r == KErrAlreadyExists);
+ }
+ }
+
+void GetNonZFileName(const TDesC& aOrigName, TDes& aNonZName)
+/**
+ Resolve a special drive to the target drive using the mappings in
+ SpecialDrives. This is used to load non-XIP binaries from pageable media.
+
+ @param aOrigName Fully-qualified filename with special drive number.
+ E.g., "3:\\sys\\bin\\dllt45.dll".
+ @param aNonZName Descriptor to populate with aOrigName and the transformed
+ drive, e.g. "c:\\sys\\bin\\dllt45.dll".
+ */
+ {
+ test.Printf(_L(">GetNonZFileName,\"%S\"\n"), &aOrigName);
+ test(aOrigName[1] == ':');
+ aNonZName.Copy(aOrigName);
+ TText replaceChar = SpecialDrives[aOrigName[0] - '0'];
+ test(TChar(replaceChar).IsAlpha());
+ aNonZName[0] = replaceChar;
+ test.Printf(_L("<GetNonZFileName,\"%S\"\n"), &aNonZName);
+ }
+
+static void GetHashFileName(const TDesC& aOrigName, TDes& aHashName)
+/**
+ Get name of the hash file used for an EXE or DLL which has been
+ copied to writable media.
+
+ @param aOrigName Name of EXE or DLL which has been copied to
+ writable media. This does not have to be
+ qualified because only the name and extension
+ are used.
+ @param aHashName On return this is set to the absolute filename
+ which should contain the file's hash. This
+ function does not create the file, or its containing
+ directory.
+ */
+ {
+ aHashName.Copy(KSysHash);
+ aHashName[0] = (TUint8) RFs::GetSystemDriveChar();
+ const TParsePtrC ppc(aOrigName);
+ aHashName.Append(ppc.NameAndExt());
+ }
+
+static void CopyExecutablesL(TBool aCorruptMode=EFalse)
+/**
+ Make a copy of each executable that should be copied
+ to a writable drive.
+
+ If aCorruptMode make KNumberOfCorruptFiles corrupted copies: truncated file and a file with corrupted header
+
+ */
+ {
+ TInt r;
+ TInt numCorruptFiles = 0;
+
+ GetSpecialDrives();
+
+ CFileMan* fm = CFileMan::NewL(Fs);
+
+ for (TInt i = 0; i < KNumModules; ++i)
+ {
+ if (aCorruptMode && numCorruptFiles==KNumberOfCorruptFiles)
+ break;
+
+ if (aCorruptMode && !(GetModuleFlags(i)&KModuleFlagExe))
+ continue;
+
+ const TPtrC fn = MODULE_FILENAME(i);
+
+ // if this is an absolute filename then copy it to
+ // the appropriate drive.
+ if (fn[1] != ':')
+ continue;
+
+ TFileName fnDest;
+ GetNonZFileName(fn, fnDest);
+
+
+ TFileName fnSrc(fn);
+ fnSrc[0] = 'z';
+
+ test.Printf(_L("CopyExecutables;%S,%S\n"), &fnSrc, &fnDest);
+
+#ifdef __WINS__
+ const TParsePtrC sppc(fnSrc);
+ TBuf<MAX_PATH> sName;
+ r = MapEmulatedFileName(sName, sppc.NameAndExt());
+ test(r == KErrNone);
+
+ TBuf<MAX_PATH> dName;
+ r = MapEmulatedFileName(dName, fnDest);
+ test(r == KErrNone);
+
+ BOOL b = Emulator::CopyFile((LPCTSTR)sName.PtrZ(),(LPCTSTR)dName.PtrZ(),FALSE);
+ test(b);
+#else
+ r = fm->Copy(fnSrc, fnDest);
+ test(r == KErrNone);
+#endif
+
+ r = Fs.SetAtt(fnDest, 0, KEntryAttReadOnly);
+ test.Printf(_L("CopyExecutables:setatt=%d\n"), r);
+ User::LeaveIfError(r);
+
+#ifdef __EPOC32__
+ TInt moduleFlags = GetModuleFlags(i);
+
+ // modify the new destination file by applying the required paging flags
+ RFile fNp;
+ r = fNp.Open(Fs, fnDest, EFileWrite | EFileStream);
+ User::LeaveIfError(r);
+ CleanupClosePushL(fNp);
+
+ // read the header and get the total number of bytes to checksum.
+ // (This may be greater than sizeof(E32ImageHeader).
+ TPckgBuf<E32ImageHeader> hdrBuf;
+ r = fNp.Read(0, hdrBuf);
+ User::LeaveIfError(r);
+ TInt totalSize = hdrBuf().TotalSize();
+ test.Printf(_L("np flags=0x%x,totalSize=%d\n"), hdrBuf().iFlags, totalSize);
+
+ // read in the actual bytes to checksum
+ TUint8* startBytes0 = (TUint8*) User::AllocLC(totalSize);
+ TPtr8 startBytes(startBytes0, 0, totalSize);
+ r = fNp.Read(0, startBytes);
+ User::LeaveIfError(r);
+ test(startBytes.Length() == totalSize);
+
+ // apply the required paging flags to the header
+ E32ImageHeader* hdr2 = reinterpret_cast<E32ImageHeader*>(startBytes0);
+ TUint& flags = hdr2->iFlags;
+ flags &= ~(KImageCodePaged | KImageCodeUnpaged);
+ if (moduleFlags & KModuleFlagPagedCode)
+ flags |= KImageCodePaged;
+ if (moduleFlags & KModuleFlagUnpagedCode)
+ flags |= KImageCodeUnpaged;
+ test.Printf(_L("setting new image flags 0x%x\n"), flags);
+
+ // corrupt header of the 2nd file
+ if (aCorruptMode && numCorruptFiles==1 && (moduleFlags&KModuleFlagExe))
+ {
+ hdr2->iCodeBase += 3;
+ hdr2->iDataBase += 1;
+ hdr2->iImportOffset += 1;
+ hdr2->iCodeRelocOffset += 3;
+ hdr2->iDataRelocOffset += 3;
+
+ ++numCorruptFiles;
+ }
+
+ // recalculate the checksum
+ hdr2->iHeaderCrc = KImageCrcInitialiser;
+ TUint32 crc = 0;
+ Mem::Crc32(crc, startBytes.Ptr(), totalSize);
+ hdr2->iHeaderCrc = crc;
+ r = fNp.Write(0, startBytes);
+ User::LeaveIfError(r);
+
+ // truncate 1st corrupted file
+ if (aCorruptMode && numCorruptFiles==0 && (moduleFlags&KModuleFlagExe))
+ {
+ TInt size;
+ r = fNp.Size(size);
+ User::LeaveIfError(r);
+ // if trncate by 1 it managed to load. if trancate by 3 it failed to load with KErrCorrupt as expected
+ r = fNp.SetSize(size-3);
+ User::LeaveIfError(r);
+ ++numCorruptFiles;
+ }
+
+ CleanupStack::PopAndDestroy(2, &fNp); // startBytes0, fNp
+#endif
+
+ // if copied to removable media, then generate hash
+ if (fn[0] == '0')
+ continue;
+
+ CSHA1* sha1 = CSHA1::NewL();
+ CleanupStack::PushL(sha1);
+
+ RFile fDest;
+ r = fDest.Open(Fs, fnDest, EFileRead | EFileStream);
+ User::LeaveIfError(r);
+ CleanupClosePushL(fDest);
+
+ TBool done;
+ TBuf8<512> content;
+ do
+ {
+ r = fDest.Read(content);
+ User::LeaveIfError(r);
+ done = (content.Length() == 0);
+ if (! done)
+ sha1->Update(content);
+ } while (! done);
+ CleanupStack::PopAndDestroy(&fDest);
+
+ // write hash to \sys\hash
+ TBuf8<SHA1_HASH> hashVal = sha1->Final();
+
+ // reuse fnSrc to save stack space
+ GetHashFileName(fnDest, fnSrc);
+ RFile fHash;
+ r = fHash.Replace(Fs, fnSrc, EFileWrite | EFileStream);
+ test.Printf(_L("hash file,%S,r=%d\n"), &fnSrc, r);
+ User::LeaveIfError(r);
+ CleanupClosePushL(fHash);
+ r = fHash.Write(hashVal);
+ User::LeaveIfError(r);
+
+ CleanupStack::PopAndDestroy(2, sha1);
+ }
+
+ delete fm;
+ }
+
+static void DeleteExecutables(TBool aCorruptMode=EFalse)
+/**
+ Delete any executables which were created by CopyExecutables.
+ This function is defined so the test cleans up when it has finished.
+ */
+ {
+ TInt numCorruptFiles = 0;
+
+ for (TInt i = 0; i < KNumModules; ++i)
+ {
+ if (aCorruptMode && numCorruptFiles==KNumberOfCorruptFiles)
+ break;
+
+ if (aCorruptMode && !(GetModuleFlags(i)&KModuleFlagExe))
+ continue;
+
+ const TPtrC fn = MODULE_FILENAME(i);
+
+ // if this is an absolute filename then copy it to
+ // the appropriate drive.
+ if (fn[1] != ':')
+ continue;
+
+ test.Printf(_L("DeleteExecutables:fn=%S\n"), &fn);
+ TFileName fnDest;
+ GetNonZFileName(fn, fnDest);
+
+ TInt r;
+
+ r = Fs.Delete(fnDest);
+ test.Printf(_L("DeleteExecutables:fnDest=%S,del=%d\n"), &fnDest, r);
+ test(r == KErrNone);
+
+ // only need to delete hash files for binaries copied to removable media,
+ // but simpler to delete and test for KErrNotFound
+ TFileName fnHash;
+ GetHashFileName(fnDest, fnHash);
+ r = Fs.Delete(fnHash);
+ test.Printf(_L("DeleteExecutables,h=%S,hdel=%d\n"), &fnHash, r);
+ test(r == KErrPathNotFound || r == KErrNotFound || r == KErrNone);
+
+ if (aCorruptMode)
+ ++numCorruptFiles;
+ }
+ }
+
+GLDEF_C TInt E32Main()
+ {
+ RThread().SetPriority(EPriorityLess);
+
+ test.Title();
+ test.Start(_L("Setup"));
+
+ RLoader l;
+ test(l.Connect()==KErrNone);
+ test(l.CancelLazyDllUnload()==KErrNone);
+ l.Close();
+
+ test(TestLdd.Open()==KErrNone);
+ LoaderTest* pL=LoaderTest::New();
+ TheLoaderTest=pL;
+
+ TInt tm=pL->iCmdLine[0];
+ TInt nr = (tm>>4)&3;
+ if (nr==1)
+ NoRemovable = ETrue;
+ else if (nr==2)
+ NoRemovable = EFalse;
+
+ test(Fs.Connect() == KErrNone);
+
+ // allocate a cleanup stack so can call CFileMan::NewL in CopyExecutables
+ test.Printf(_L("CopyExecutablesL()\n"));
+ CTrapCleanup* cleanup=CTrapCleanup::New();
+ TRAPD(r, CopyExecutablesL());
+ test(r == KErrNone);
+ delete cleanup;
+
+ if (tm&1)
+ pL->TestOneByOne();
+ if (tm&2)
+ pL->TestMultipleExeInstances();
+ if (tm&4)
+ pL->TestOOM();
+ if (tm&8)
+ pL->TestMultipleLoads();
+
+ pL->Close();
+
+ // Test loader error handling - will panic the client thread
+ test.Next(_L("Test loader error handling - will panic the client thread"));
+ RThread t;
+ t.Create(_L("Loader panic test"),PanicTestThread,KDefaultStackSize,0x1000,0x1000,NULL);
+ TRequestStatus s;
+ t.Logon(s);
+ TBool justInTime=User::JustInTime();
+ User::SetJustInTime(EFalse);
+ t.Resume();
+ User::WaitForRequest(s);
+ test(t.ExitType()==EExitPanic);
+ test(t.ExitCategory().Compare(_L("LOADER"))==0);
+ test(t.ExitReason()==0);
+ t.Close();
+ User::SetJustInTime(justInTime);
+
+ DeleteExecutables();
+
+#ifdef __EPOC32__
+ // test corrupted files
+ cleanup=CTrapCleanup::New();
+ test.Next(_L("CopyExecutablesL(ETrue)"));
+ TRAPD(rr, CopyExecutablesL(ETrue));
+ test(rr == KErrNone);
+ delete cleanup;
+ test.Next(_L("TestCorruptedFiles()"));
+ TestCorruptedFiles();
+ test.Next(_L("DeleteExecutables()"));
+ DeleteExecutables(ETrue);
+#endif
+
+ Fs.Close();
+
+ test.End();
+ return KErrNone;
+ }
+