diff -r 000000000000 -r a41df078684a kerneltest/f32test/loader/t_ldrtst.cpp --- /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 + #include +#elif defined(__EPOC32__) + #include +#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 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 s=aTitle; + TInt i; + for (i=0; i=0; ++i) {} + iCount=i; + } + +void TModuleList::Display(const TDesC& aTitle) const + { + TBuf<256> s=aTitle; + TInt i; + for (i=0; i=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)=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 && 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=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%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%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%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%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%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%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%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%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 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 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(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(" sName; + r = MapEmulatedFileName(sName, sppc.NameAndExt()); + test(r == KErrNone); + + TBuf 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 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(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 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; + } +