Update contrib.
1 // Copyright (c) 1995-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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // f32\sfile\sf_lepoc.cpp
21 #include <e32std_private.h>
23 #include <e32base_private.h>
29 #define INCLUDE_E32IMAGEHEADER_IMPLEMENTATION
37 #include "sf_pgcompr.h"
39 _LIT(KLitFinderInconsistent, "LDR-FINDER-INC");
40 _LIT(KLitSysBinError, "LDR-SYS\\BIN ERR");
41 _LIT8(KSysBin,":\\sys\\bin\\");
47 EFuaiNoFixupTable = 0x10,
48 EBcbmNotCodePaged = 0x20,
49 ELfiCodePagingNotSupported = 0x30,
50 EFprUnexpectedFixup = 0x40,
53 static void Panic(TLdrEpocPanic aPanic)
55 _LIT(KPanicCat, "LDR-PNC");
56 User::Panic(KPanicCat, aPanic);
59 extern TRequestStatus* ProcessDestructStatPtr;
60 extern TBool ProcessCreated;
64 extern void DumpImageHeader(const E32ImageHeader*);
65 extern TDriveCacheHeader* gDriveFileNamesCache[];
67 TBuf8<KMaxPath> gLoadeePath;
70 const TInt KMaxHeaderSize = sizeof(E32ImageHeaderV) + 65536/8;
74 extern TInt UseFloppy;
79 // -------- demand paging --------
81 /** Page size as a power of two. */
82 const TUint32 KPageSizeShift = 12;
83 /** Page size, as defined for code relocations. This same page size is used for demand paging. */
84 const TUint32 KPageSize = 1<<KPageSizeShift;
85 /** Apply this mask to an address to get the page offset. */
86 const TUint32 KPageOffsetMask = KPageSize - 1;
89 Calculate the number of pages required to contain the supplied number of bytes.
91 @param aSizeInBytes Size of are which has to be contained in whole blocks.
92 @return Number of KPageSize pages required to contain area.
94 inline TInt SizeToPageCount(TInt aSizeInBytes)
96 return (aSizeInBytes + KPageOffsetMask) >> KPageSizeShift;
101 Allocate a block which indexes the reallocations by page. This can be used for demand paging.
103 @param aSection Pointer to relocation section to process.
104 @param aAreaSize Size in bytes of area described by reloc section.
105 @param aLoadAddress Address of relocation section in memory
106 @param aProcessedBlock On success (return == KErrNone) this is set to the processed
107 relocation section which is allocated on the current thread's heap.
108 The caller takes ownership. The contents are undefined on failure.
109 @return KErrNoMemory if could not allocate memory for processed block
110 and auxiliary structures; KErrNone otherwise.
112 TInt E32Image::AllocateRelocationData(E32RelocSection* aSection, TUint32 aAreaSize, TUint32 aLoadAddress, TUint32*& aProcessedBlock)
114 __IF_DEBUG(Printf("AllocateRelocationData"));
116 TUint32 sectionSize = aSection->iSize;
117 TUint32 numRelocs = aSection->iNumberOfRelocs;
118 TInt pageCount = SizeToPageCount(aAreaSize);
120 // The file format documentation (SOSI ch10) does not guarantee that each page has
121 // relocation information, or that the pages are listed in order, so store them in
124 TUint8** subBlocks = (TUint8**)User::AllocZ(sizeof(TUint8*)*pageCount);
128 const TUint8* subBlockPtr = (TUint8*)(aSection+1);
129 while(sectionSize > 0)
131 TUint32 pageOffset = *(TUint32*)(subBlockPtr);
132 TUint32 subBlockSize = *(TUint32*)(subBlockPtr+4);
134 subBlocks[pageOffset >> KPageSizeShift] = (TUint8*)subBlockPtr;
136 sectionSize -= subBlockSize;
137 subBlockPtr += subBlockSize; // move to next sub-block
140 // now have each relocation page in memory, build lookup table
141 TUint32 indexSize = (pageCount + 1) * sizeof(TUint32); // include sentinel
142 TUint32 totalRelocations = numRelocs;
143 iCodeRelocTableSize = indexSize + totalRelocations * sizeof(TUint16);
144 TUint8* table = (TUint8*) User::Alloc(iCodeRelocTableSize);
148 User::Free(subBlocks);
152 // where sub-block positions are written to in the table
153 TUint32* destSubBlock = (TUint32*)table;
154 // where entries are written to in the table
155 TUint16* destEntry = (TUint16*)(table + indexSize);
158 for(i = 0; i < pageCount; ++i)
160 *destSubBlock++ = TUint32(destEntry) - TUint32(table);
162 // see if a relocation page was defined for this page
163 const TUint8* subBlock = subBlocks[i];
167 // get number of entries in this sub-block, including padding
168 TUint32 sbEntryCount;
169 TUint32 pageOffset = *(TUint32*)subBlock; // offset of page from start of section
170 sbEntryCount = *(TUint32*)(subBlock + 4); // sub-block size
171 sbEntryCount -= 8; // exclude sub-block header
172 sbEntryCount /= 2; // each entry is two bytes
173 const TUint16* srcEntry = (TUint16*)(subBlock + 8);
175 while(sbEntryCount--)
177 TUint16 entry = *srcEntry++;
178 if(entry==0) // ignore null padding values
181 // Replace inferred fixup type with actual fixup type
182 TUint type = entry & 0xf000;
183 if(type==KInferredRelocType)
185 TUint32* ptr = (TUint32*)(aLoadAddress + pageOffset + (entry & 0x0fff));
187 type = (TUint(word - iHeader->iCodeBase) < TUint(iHeader->iCodeSize)) ? KTextRelocType : KDataRelocType;
188 entry = (entry & 0x0fff) | type;
191 *destEntry++ = entry;
195 // sentinel entry marks the byte following last sub-block in table
196 // This gives the size of the last processed sub-block.
197 *destSubBlock = TUint32(destEntry) - TUint32(table);
199 aProcessedBlock = (TUint32*) table;
200 User::Free(subBlocks);
203 __IF_DEBUG(Printf("processed reloc table (size=%d,pageCount=%d)", iCodeRelocTableSize, pageCount));
205 // dump the import fixup table if loader tracing enabled
206 const TUint16* table16 = (const TUint16*)table;
207 const TInt halfWordsInTable = iCodeRelocTableSize / 2;
208 for(i = 0; i < halfWordsInTable; i += 4)
211 "reloc %04x: %04x %04x %04x %04x",
212 i * 2, table16[i+0], table16[i+1], table16[i+2], table16[i+3]));
219 /*******************************************************************************
220 * These functions run in supervisor mode since they require access to the
221 * chunks of the newly-created process or DLL while they are still in the
223 ******************************************************************************/
226 Vector which ::ExecuteInSupervisorMode invokes.
228 TInt (*ExecuteInSupervisorModeVector)(TSupervisorFunction, TAny*);
231 Executute aFunction in supervisor mode (if the memory model requires this.)
233 TInt ExecuteInSupervisorMode(TSupervisorFunction aFunction, TAny* aParameter)
235 return(*ExecuteInSupervisorModeVector)(aFunction, aParameter);
239 Implementation of ::ExecuteInSupervisorMode which actually executes the
240 function in user mode.
242 TInt UserModeExecuteInSupervisorMode(TSupervisorFunction aFunction, TAny* aParameter)
244 return (*aFunction)(aParameter);
248 Decide whether any Loader code actually needs to execute in supervisor mode
249 and set ::ExecuteInSupervisorModeVector so that invocations of ::ExecuteInSupervisorMode
250 call the appropriate function.
252 void InitExecuteInSupervisorMode()
254 // work out if we need to really 'execute in supervisor mode'...
255 TUint32 memModelAttrs = (TUint32)UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL);
256 TUint32 memModel = memModelAttrs & EMemModelTypeMask;
257 if(memModel==EMemModelTypeFlexible)
259 // we can do everything user side...
260 ExecuteInSupervisorModeVector = UserModeExecuteInSupervisorMode;
261 gExecutesInSupervisorMode = EFalse;
265 // we need to go kernel side...
266 ExecuteInSupervisorModeVector = UserSvr::ExecuteInSupervisorMode;
267 gExecutesInSupervisorMode = ETrue;
273 Arguments for svRelocateSection.
275 The relocation information (at iRelocsBuf) has list sub blocks, each referring to a 4kB
276 page within the section. See E32RelocBlock.
278 struct SRelocateSectionInfo
280 E32Image* iImage; ///< The executable being relocated.
281 TUint8* iRelocsBuf; ///< Pointer to relocation info.
282 TUint32 iNumRelocs; ///< Total number of relocations to apply.
283 TUint32 iLoadAddress; ///< Virtual address where section is currently located in memory.
287 Apply relocations to a code or data section.
289 @param aPtr Pointer to SRelocateSectionInfo.
291 TInt svRelocateSection(TAny* aPtr)
293 SRelocateSectionInfo& info=*(SRelocateSectionInfo*)aPtr;
295 E32Image& img = *(E32Image*)info.iImage;
296 TUint8* relocs = info.iRelocsBuf;
297 TUint32 numRelocs = info.iNumRelocs;
298 TUint32 loadAddress = info.iLoadAddress;
300 TUint32 codeStart = img.iHeader->iCodeBase;
301 TUint32 codeFinish = codeStart+img.iHeader->iCodeSize;
302 TUint32 codeDelta = img.iCodeDelta;
303 TUint32 dataDelta = img.iDataDelta;
307 TUint32 pageAddress = ((TUint32*)relocs)[0];
308 TUint32 pageSize = ((TUint32*)relocs)[1];
309 TUint8* relocsEnd = relocs+pageSize;
312 while(relocs<relocsEnd)
314 TUint16 relocOffset = *(TUint16*)relocs;
319 TUint32 offset = pageAddress+(TUint32)(relocOffset&0x0fff);
320 TUint32* destPtr = (TUint32*)(loadAddress+offset);
321 TUint16 relocType = relocOffset&0xf000;
323 TUint32 relocAddr = *destPtr;
324 if(relocType==KTextRelocType)
325 relocAddr += codeDelta; // points to text/rdata section
326 else if(relocType==KDataRelocType)
327 relocAddr += dataDelta; // points to data section
328 else if (relocAddr>=codeStart && relocAddr<codeFinish)
329 relocAddr += codeDelta; // points to text/rdata section
331 relocAddr += dataDelta; // points to data section
332 *destPtr = relocAddr;
342 Fix up the export directory
343 Only performed on PE images. ELF image's exports are marked
344 as relocatable and therefore relocated by svRelocateSection when the
345 text section is relocated up
347 TInt svRelocateExports(TAny* aPtr)
349 E32Image* pI=(E32Image*)aPtr;
350 TUint32* destExport=(TUint32*)pI->iExportDirLoad;
351 TInt i=pI->iExportDirCount;
352 TUint32 codeBase=pI->iCodeRunAddress;
354 *destExport+++=codeBase;
359 struct SFixupImportAddressesInfo
363 TUint32 iExportDirEntryDelta;
367 For demand paging, this points to the buffer which is populated
368 so each page can be fixed up as it is loaded in.
372 TUint32 iCodeLoadAddress;
373 TUint32* iImportOffsetList;
378 Fix up the import address table, used for 'PE derived' executables.
379 @param aPtr Pointer to function arguments (SFixupImportAddressesInfo structure).
380 SFixupImportAddressesInfo::iIat is updated by this function.
382 TInt svFixupImportAddresses(TAny* aPtr)
384 SFixupImportAddressesInfo& info = *(SFixupImportAddressesInfo*)aPtr;
386 TUint32 maxOrdinal = (TUint32)info.iExporter->iExportDirCount;
387 TUint32 absentOrdinal = (TUint32)info.iExporter->iFileEntryPoint;
389 TUint32* exp_dir = info.iExportDir - KOrdinalBase; // address of 0th ordinal
390 TUint32 exp_delta = info.iExportDirEntryDelta;
392 TUint32* iat = info.iIat;
393 TUint32* iatE = iat+info.iNumImports;
394 for(; iat<iatE; ++iat)
398 return KErrNotSupported;
401 if(imp==0 && !(info.iExporter->iAttr&ECodeSegAttNmdExpData))
403 // attempt to import ordinal zero (symbol name data) from an executable
404 // which doesn't export this information, use NULL for imported value in this case...
409 // get imported value from exporter...
410 TUint32 exp_addr = exp_dir[imp];
411 if(exp_addr==0 || exp_addr==absentOrdinal)
412 return KErrNotSupported;
413 writeValue = exp_addr + exp_delta;
416 // if not code paging then directly fix up the import...
417 if (info.iFixup64 == 0)
420 // ...otherwise defer until the page is fixed up
422 TUint64 iat64 = reinterpret_cast<TUint64>(iat);
423 *info.iFixup64++ = (iat64 << 32) | writeValue;
433 Fix up the import addresses, used for 'elf derived' executables.
434 @param aPtr Pointer to function arguments (SFixupImportAddressesInfo structure).
436 TInt svElfDerivedFixupImportAddresses(TAny* aPtr)
438 SFixupImportAddressesInfo& info = *(SFixupImportAddressesInfo*)aPtr;
439 TUint32 maxOrdinal = (TUint32)info.iExporter->iExportDirCount;
440 TUint32 absentOrdinal = (TUint32)info.iExporter->iFileEntryPoint;
442 TUint32* exp_dir = info.iExportDir - KOrdinalBase; // address of 0th ordinal
443 TUint32 exp_delta = info.iExportDirEntryDelta;
444 TUint32 code = info.iCodeLoadAddress;
446 TUint32* iol = info.iImportOffsetList;
447 TUint32* iolE = iol+info.iNumImports;
448 for(; iol<iolE; ++iol)
450 TUint32* impPtr = (TUint32*)(code+*iol);
451 TUint32 impd = *impPtr;
452 TUint32 imp = impd & 0xffff;
453 TUint32 offset = impd >> 16;
455 return KErrNotSupported;
458 if(imp==0 && !(info.iExporter->iAttr&ECodeSegAttNmdExpData))
460 // attempt to import ordinal zero (symbol name data) from an executable
461 // which doesn't export this information, use NULL for imported value in this case...
466 // get imported value from exporter...
467 TUint32 exp_addr = exp_dir[imp];
468 if(exp_addr==0 || exp_addr==absentOrdinal)
469 return KErrNotSupported;
470 writeValue = exp_addr + exp_delta + offset;
473 // if not code paging then directly fix up the import...
474 if (info.iFixup64 == 0)
475 *impPtr = writeValue;
476 // ...otherwise defer until the page is fixed up
479 TUint64 impPtr64 = reinterpret_cast<TUint64>(impPtr);
480 *info.iFixup64++ = (impPtr64 << 32) | writeValue;
488 Wrapper for memory copy arguments.
499 Copies word aligned memory.
500 @param aPtr Pointer to function arguments (SCopyDataInfo structure).
502 TInt svWordCopy(TAny* aPtr)
504 SCopyDataInfo& info=*(SCopyDataInfo*)aPtr;
505 return (TInt) Mem::Move(info.iDest, info.iSource, info.iNumberOfBytes);
511 @param aPtr Pointer to function arguments (SCopyDataInfo structure).
513 TInt svMemCopy(TAny* aPtr)
515 SCopyDataInfo& info=*(SCopyDataInfo*)aPtr;
516 return (TInt) Mem::Copy(info.iDest, info.iSource, info.iNumberOfBytes);
521 Argument for svElfDerivedGetImportInfo.
523 struct SGetImportDataInfo
525 TInt iCount; // number to extract
526 TUint32* iDest; // destination address for data
527 TUint32 iCodeLoadAddress; // address where code has been loaded
528 TUint32* iImportOffsetList; // pointer to list of import offsets in E32ImportBlock
532 Extract import ordinals/data
533 @param aPtr Pointer to function arguments (SGetImportDataInfo structure).
535 TInt svElfDerivedGetImportInfo(TAny* aPtr)
537 SGetImportDataInfo& info = *(SGetImportDataInfo*)aPtr;
538 TInt count = info.iCount;
539 TUint32* dest = info.iDest;
540 TUint32 code = info.iCodeLoadAddress;
541 TUint32* iol = info.iImportOffsetList;
543 TUint32* iolEnd = iol+count;
545 *dest++ = *(TUint32*)(code + *iol++);
550 /*******************************************************************************
551 * End of supervisor mode functions
552 ******************************************************************************/
555 /*******************************************************************************
557 ******************************************************************************/
558 RImageInfo::RImageInfo()
560 memclr(this, sizeof(RImageInfo));
563 void RImageInfo::Close()
568 gFileDataAllocator.Free(iFileData);
572 void RImageInfo::Accept(RImageInfo& aInfo)
575 wordmove(this, &aInfo, sizeof(RImageInfo));
576 memclr(&aInfo.iFile, (_FOFF(RImageInfo,iFileSize) - _FOFF(RImageInfo,iFile)) );
579 /*******************************************************************************
580 * EPOC executable file finders
581 ******************************************************************************/
582 RImageFinder::RImageFinder()
583 : iNameMatches(0), iUidFail(0), iCapFail(0), iMajorVersionFail(0), iImportFail(0),
584 iCurrentVersion(KModuleVersionNull), iCurrentDrive(0), iFindExact(0), iNewValid(0),
585 iReq(0), iExisting(0)
589 TInt RImageFinder::Set(const RLdrReq& aReq)
592 TInt l = aReq.iFileNameInfo.BaseLen() + aReq.iFileNameInfo.ExtLen();
593 if (l > KMaxProcessName)
595 aReq.iFileNameInfo.GetName(iRootName, TFileNameInfo::EIncludeBaseExt);
599 void RImageFinder::Close()
604 _LIT8(KDefaultPathSysBin, "sys\\bin");
605 _LIT8(KDefaultPathSysBin2, "?:\\sys\\bin");
606 _LIT8(KDefaultExePath, "sys\\bin;system\\bin;system\\programs;system\\libs");
607 _LIT8(KDefaultDllPath, "sys\\bin;system\\bin;system\\libs");
608 _LIT8(KDefaultExePath2, "?:\\sys\\bin;?:\\system\\bin;?:\\system\\programs;?:\\system\\libs");
609 _LIT8(KDefaultDllPath2, "?:\\sys\\bin;?:\\system\\bin;?:\\system\\libs");
611 TInt RImageFinder::Search()
613 __LDRTRACE(iReq->Dump(">RImageFinder::Search"));
614 TBool exe = (iReq->iRequestedUids[0] == KExecutableImageUid);
615 const TFileNameInfo& fi = iReq->iFileNameInfo;
619 // path specified, so only look there
620 TPtrC8 drive_and_path(fi.DriveAndPath());
621 r = Search(&drive_and_path, 0);
629 drv = (*iReq->iFileName)[0];
631 // if a search path is specified look there
633 r = Search(iReq->iPath, drv);
634 if (r == KErrNoMemory) // ignore other errors as they are a potential denial of service
636 __LDRTRACE(Dump("<RImageFinder::Search", r));
639 const TDesC8* defpath;
640 if(PlatSec::ConfigSetting(PlatSec::EPlatSecEnforceSysBin))
641 defpath = (drv<0) ? &KDefaultPathSysBin() : &KDefaultPathSysBin2();
645 defpath = exe ? &KDefaultExePath() : &KDefaultDllPath();
647 defpath = exe ? &KDefaultExePath2() : &KDefaultDllPath2();
649 r = Search(defpath, drv);
651 if (r == KErrNoMemory) // ignore other errors as they are a potential denial of service
653 __LDRTRACE(Dump("<RImageFinder::Search", r));
656 if (iExisting || iNewValid)
657 r = KErrNone; // found something suitable
658 else if (!iNameMatches)
659 r = KErrNotFound; // nothing matched requested name
660 else if (iImportFail || iMajorVersionFail)
661 r = KErrNotSupported; // something failed only on missing imports or version
663 r = KErrPermissionDenied; // something failed capability check
665 r = KErrNotSupported; // something failed UID check
667 r = KErrCorrupt; // a file had the correct name but was not a valid E32Image file
668 __LDRTRACE(Dump("<RImageFinder::Search", r));
672 TInt RImageFinder::Search(const TDesC8* aPath, TInt aDrive)
674 __IF_DEBUG(Printf(">Path %S Drive %02x", aPath, aDrive));
676 TInt plen = aPath->Length();
679 TPtrC8 remain(aPath->Mid(ppos));
680 TInt pel = remain.Locate(';');
683 pel = remain.Length();
692 TBool alldrives = EFalse;
693 if (pel<2 || remain[1]!=':')
695 else if (remain[0]!='?')
697 TInt drive = EDriveY;
698 if (!alldrives && RFs::CharToDrive(TChar(aDrive), drive)!=KErrNone)
700 iCurrentDrive = (TUint8)drive;
701 TInt startpos = alldrives ? 0 : 2;
702 iCurrentPath.Set(remain.Mid(startpos, pel - startpos));
706 if (alldrives && iCurrentDrive<=EDriveB && iCurrentDrive!=UseFloppy)
709 r = SearchSingleDir();
710 if (r == KErrNoMemory) // ignore other errors as they are a potential denial of service
712 __IF_DEBUG(Printf("OOM!"));
718 if (!iCurrentDrive--)
719 iCurrentDrive = EDriveZ;
720 } while(alldrives && iCurrentDrive != EDriveY);
722 __IF_DEBUG(Printf("<Path %S Drive %02x", aPath, aDrive));
726 // Can't be looking for main loadee here, so iReq->iImporter is never NULL
727 // Also gExeAttr must be set up
728 TInt RImageFinder::SearchExisting(const RImageArray& aArray)
730 __IF_DEBUG(Printf(">RImageFinder::SearchExisting"));
731 TUint required_abi = gExeAttr & ECodeSegAttABIMask;
733 aArray.Find(iRootName, first, last);
734 for (i=first; i<last; ++i)
736 E32Image* e = aArray[i];
737 if (CheckUids(e->iUids, iReq->iRequestedUids) != KErrNone)
739 if (iReq->CheckSecInfo(e->iS) != KErrNone)
741 TInt action = DetailedCompareVersions(e->iModuleVersion, iReq->iRequestedVersion, iCurrentVersion, EFalse);
742 if (action == EAction_Skip)
744 if (action == EAction_CheckImports || action == EAction_CheckLastImport)
746 // Never optimistically link to something with a different ABI
747 if ((e->iAttr & ECodeSegAttABIMask) != required_abi)
749 TInt r = CheckRequiredImports(iReq->iImporter, e, action);
752 if (r != KErrNotSupported)
758 iCurrentVersion = e->iModuleVersion;
760 __IF_DEBUG(Printf("<RImageFinder::SearchExisting"));
764 // Called for each file found with matching root name but which is not a valid E32ImageFile
765 void RImageFinder::RecordCorruptFile()
767 __IF_DEBUG(Printf("RImageFinder::RecordCorruptFile"));
771 // Called for each valid E32Image file found with matching root name
772 TInt RImageFinder::Try(RImageInfo& aInfo, const TDesC8& aRootName, const TDesC8& aDriveAndPath)
774 __IF_DEBUG(Printf(">RImageFinder::Try %S%S", &aDriveAndPath, &aRootName));
775 __IF_DEBUG(Printf(">MA:%08x MV:%08x RV:%08x CV:%08x", aInfo.iAttr, aInfo.iModuleVersion, iReq->iRequestedVersion, iCurrentVersion));
779 if ( ((aInfo.iAttr & ECodeSegAttExpVer) && aInfo.iModuleVersion==iReq->iRequestedVersion)
780 || (!(aInfo.iAttr & ECodeSegAttExpVer) && iReq->iRequestedVersion==KModuleVersionWild)
783 __IF_DEBUG(Printf("<RImageFinder::Try Exact Match Found"));
786 SetName(aRootName, aDriveAndPath);
787 return KErrCompletion;
791 TUint required_abi = gExeAttr & ECodeSegAttABIMask;
792 TBool abi_mismatch = ((aInfo.iAttr & ECodeSegAttABIMask)!=required_abi);
793 TInt32* uid = (TInt32*)&iReq->iRequestedUids;
794 TBool dll_wanted = (uid[0] == KDynamicLibraryUidValue);
795 if (CheckUids(*(TUidType*)aInfo.iUid, iReq->iRequestedUids) != KErrNone)
798 __IF_DEBUG(Printf("<RImageFinder::Try UIDFAIL"));
801 if (iReq->CheckSecInfo(aInfo.iS) != KErrNone)
804 __IF_DEBUG(Printf("<RImageFinder::Try CAPFAIL"));
807 TInt action = DetailedCompareVersions(aInfo.iModuleVersion, iReq->iRequestedVersion, iCurrentVersion, !iReq->iImporter);
808 if (action == EAction_Skip)
810 if (DetailedCompareVersions(aInfo.iModuleVersion, iReq->iRequestedVersion) == EVersion_MajorSmaller)
812 __IF_DEBUG(Printf("<RImageFinder::Try VERFAIL"));
815 if (action == EAction_CheckImports || action == EAction_CheckLastImport)
817 // If we get here, can't be main loadee so gExeAttr must be valid
818 // Never optimistically link to something with a different ABI
819 if (abi_mismatch || CheckRequiredImports(iReq->iImporter, aInfo, action)!=KErrNone)
821 __IF_DEBUG(Printf("<RImageFinder::Try IMPFAIL"));
826 if (!iReq->iImporter && dll_wanted && abi_mismatch)
828 // Dynamically loading a DLL - ABI must match loading process
829 __IF_DEBUG(Printf("<RImageFinder::Try ABIFAIL"));
833 if(PlatSec::ConfigSetting(PlatSec::EPlatSecEnforceSysBin))
838 driveLetter=(TChar)aDriveAndPath[0];
839 RFs::CharToDrive(driveLetter,driveNumber);
840 TDriveCacheHeader* pDH=gDriveFileNamesCache[driveNumber];
843 driveAtt=pDH->iDriveAtt;
846 TDriveInfo driveInfo;
847 if ((r=gTheLoaderFs.Drive(driveInfo,driveNumber)) != KErrNone)
849 __IF_DEBUG(Printf("<RImageFinder::Try DINFFAIL"));
853 driveAtt=driveInfo.iDriveAtt;
856 if(driveAtt & KDriveAttRemovable)
858 __IF_DEBUG(Printf("** RImageFinder::Try %S%S is on a removable drive", &aDriveAndPath, &aRootName));
859 // If the cache says we already checked the hash of this file, accept it without checking again
860 // as any *legitimate* change to the file would've triggered the cache to be rebuilt.
861 if (!(aInfo.iCacheStatus & TImageInfo::EHashChecked))
863 //We have to pass aDriveAndPath as aInfo may not contain Drive
864 TRAP(r,CompareHashL(aInfo, aDriveAndPath));
865 if (r == KErrNoMemory)
869 __IF_DEBUG(Printf("<RImageFinder::Try Compare Hash Failed"));
873 aInfo.iCacheStatus |= TImageInfo::EHashChecked;
877 // We've skipped hash checking as an optimisation, however someone could potentially have
878 // used external hardware to switch the data on the card since the cached hash check. Setting
879 // this mark means that if we actually load the file, we'll hash it then; but if it turns out
880 // to be already loaded, we can save the effort.
881 aInfo.iNeedHashCheck = 1;
888 iCurrentVersion = aInfo.iModuleVersion;
889 SetName(aRootName, aDriveAndPath);
890 __IF_DEBUG(Printf("<MV:%08x RV:%08x CV:%08x", aInfo.iModuleVersion, iReq->iRequestedVersion, iCurrentVersion));
891 __IF_DEBUG(Printf("<RImageFinder::Try OK"));
895 void RImageFinder::CompareHashL(RImageInfo& aInfo, const TDesC8& aDriveAndPath)
897 // Calculate hash and compare after checking if one already exists in c:/system/caps
900 __IF_DEBUG(Printf(">RImageFinder::CompareHashL"));
903 TBuf8<KMaxFileName*sizeof(TText)> fileName;
904 TFileNameInfo fni = iReq->iFileNameInfo;
905 if (aInfo.iAttr & ECodeSegAttExpVer)
907 fni.iVersion = aInfo.iModuleVersion;
908 extraFlag = TFileNameInfo::EForceVer;
911 TFileName hashname(KSysHash);
912 hashname[0] = (TUint8) RFs::GetSystemDriveChar();
913 fileName.SetLength(0);
914 fni.GetName(fileName, TFileNameInfo::EIncludeBaseExt | extraFlag);
915 hashname.Append(fileName.Expand());
918 CleanupClosePushL(fHash);
920 __IF_DEBUG(Printf("RImageFinder::CompareHashL opening hash file %S ", &hashname));
921 User::LeaveIfError(fHash.Open(gTheLoaderFs,hashname,EFileRead|EFileReadDirectIO));
923 TBuf8<SHA1_HASH> installhash;
924 User::LeaveIfError(fHash.Read(installhash));
925 CleanupStack::PopAndDestroy(1);
927 // if we get this far, we have loaded a valid hash, so calculate the file's hash
929 CSHA1* hasher=CSHA1::NewL();
930 CleanupStack::PushL(hasher);
932 fileName.Copy(aDriveAndPath);
933 fni.GetName(fileName, TFileNameInfo::EIncludeBaseExt | extraFlag);
935 CleanupClosePushL(aInfo.iFile);
936 TBool b = aInfo.FileOpened();
939 __IF_DEBUG(Printf("RImageFinder::CompareHashL opening the file %S", &fileName));
940 User::LeaveIfError(aInfo.iFile.Open(gTheLoaderFs, fileName.Expand(), EFileRead|EFileReadDirectIO));
943 __IF_DEBUG(Printf("RImageFinder::CompareHashL calculate hash"));
945 User::LeaveIfError(aInfo.iFile.Size(size));
946 aInfo.iFileData = (TUint8*)gFileDataAllocator.Alloc(size);
948 aInfo.iFileSize = size;
950 User::Leave(KErrNoMemory);
951 TPtr8 filedata(aInfo.iFileData, size);
952 User::LeaveIfError(aInfo.iFile.Read(0, filedata, size));
953 if (filedata.Length() != size)
954 User::Leave(KErrCorrupt);
955 CleanupStack::PopAndDestroy(1); //the file handle only->aInfo.iFile.Close();
956 hasher->Update(filedata);
958 TBuf8<SHA1_HASH> hash;
959 hash=hasher->Final();
962 __IF_DEBUG(Printf("RImageFinder::CompareHashL comparing hashes..."));
963 if(0 != hash.Compare(installhash))
964 User::Leave(KErrPermissionDenied);
965 CleanupStack::PopAndDestroy(1);
967 // if we get this far the hash has passed and the file has been closed
968 // but some of the RImageInfo parameters will've been initialised by the cache
969 // and may be lies if we're being attacked, so compare them to be sure
971 // if we already had the header, throw it away: it's from untrusted data
974 delete aInfo.iHeader;
975 aInfo.iHeader = NULL;
978 // make the header and validate the cached parameters against it
979 User::LeaveIfError(E32ImageHeader::New(aInfo.iHeader, aInfo.iFileData, aInfo.iFileSize));
981 SSecurityInfo secinfo;
982 aInfo.iHeader->GetSecurityInfo(secinfo);
983 TUint32 attr = (aInfo.iHeader->iFlags & ECodeSegAttFixed) | aInfo.iHeader->ABI();
984 if(aInfo.iHeader->iFlags&KImageNmdExpData)
985 attr |= ECodeSegAttNmdExpData;
986 if (Mem::Compare((TUint8*)aInfo.iUid, sizeof(aInfo.iUid), (TUint8*)&aInfo.iHeader->iUid1, sizeof(aInfo.iUid))
987 || aInfo.iModuleVersion != aInfo.iHeader->ModuleVersion()
988 || Mem::Compare((TUint8*)&aInfo.iS, sizeof(aInfo.iS), (TUint8*)&secinfo, sizeof(secinfo))
989 || (aInfo.iAttr & ~ECodeSegAttExpVer) != attr)
990 User::Leave(KErrPermissionDenied);
992 __IF_DEBUG(Printf("<RImageFinder::CompareHashL passed"));
995 void RImageFinder::SetName(const TDesC8& aRootName, const TDesC8& aDriveAndPath)
997 iNewFileName = aDriveAndPath;
998 iNewFileName.Append(aRootName);
1001 RImageArray::RImageArray()
1002 : RPointerArray<E32Image>(8, 2*256)
1006 TInt RImageArray::Add(E32Image* aImage)
1008 return InsertInOrderAllowRepeats(aImage, &E32Image::Order);
1011 void RImageArray::Find(const TDesC8& aRootName, TInt& aFirst, TInt& aLast) const
1013 TCodeSegCreateInfo name;
1014 name.iFileName.Copy(aRootName);
1015 name.iRootNameOffset = 0;
1016 name.iRootNameLength = aRootName.Length();
1017 aFirst = SpecificFindInOrder((const E32Image*)&name, &E32Image::Order, EArrayFindMode_First);
1020 aLast = SpecificFindInOrder((const E32Image*)&name, &E32Image::Order, EArrayFindMode_Last);
1023 E32Image* RImageArray::Find(const TRomImageHeader* a) const
1028 E32Image* const * ee = &(*this)[0];
1029 E32Image* const * eE = ee + c;
1030 for (; ee<eE && (*ee)->iRomImageHeader != a; ++ee) {}
1031 return (ee<eE) ? *ee : NULL;
1034 TInt E32Image::LoadProcess(const RLdrReq& aReq)
1036 __LDRTRACE(aReq.Dump("E32Image::LoadProcess"));
1038 RImageFinder finder;
1039 TInt r = finder.Set(aReq);
1041 r = finder.Search();
1047 r = Construct(finder); // needs to find it if it's already loaded
1054 return KErrNotSupported;
1055 r = aReq.iMsg->Client((RThread&)aReq.iClientThread);
1060 iClientHandle=aReq.iClientThread.Handle();
1062 if(iStackSize < aReq.iMinStackSize)
1063 iStackSize=aReq.iMinStackSize; // If the process required larger stack than the default.
1065 //initialise to zero
1067 iDestructStat = ProcessDestructStatPtr;
1069 iDebugAttributes = 0;
1070 if (iRomImageHeader)
1072 if (iRomImageHeader->iFlags & KRomImageDebuggable)
1073 iDebugAttributes |= EDebugAllowed;
1077 if (iHeader->iFlags & KImageDebuggable)
1078 iDebugAttributes |= EDebugAllowed;
1081 // Get the data paging flags and pass to the kernel.
1082 __ASSERT_COMPILE(EDataPagingUnspecified == 0);
1083 if (iRomImageHeader)
1085 TUint dataPaging = iRomImageHeader->iFlags & KRomImageDataPagingMask;
1086 if (dataPaging == KRomImageDataPagingMask)
1087 RETURN_FAILURE(KErrCorrupt);
1088 if (dataPaging == KRomImageFlagDataPaged)
1089 iFlags |= EDataPaged;
1090 if (dataPaging == KRomImageFlagDataUnpaged)
1091 iFlags |= EDataUnpaged;
1095 TUint dataPaging = iHeader->iFlags & KImageDataPagingMask;
1096 if (dataPaging == KImageDataPagingMask)
1097 RETURN_FAILURE(KErrCorrupt);
1098 if (dataPaging == KImageDataPaged)
1099 iFlags |= EDataPaged;
1100 if (dataPaging == KImageDataUnpaged)
1101 iFlags |= EDataUnpaged;
1104 r=E32Loader::ProcessCreate(*this, aReq.iCmd);
1105 __IF_DEBUG(Printf("Done E32Loader::ProcessCreate %d",r));
1111 ProcessCreated = ETrue;
1113 iClientProcessHandle=iProcessHandle;
1114 if (!iAlreadyLoaded)
1116 gExeCodeSeg=iHandle; // implicitly linked DLLs must load into the new process
1118 if (!iRomImageHeader)
1121 r=ProcessImports(); // this sets up gLoadeePath
1123 // transfers ownership of clamp handle to codeseg; nulls handle if successful
1126 r=E32Loader::ProcessLoaded(*this);
1127 if ((r==KErrNone) && iUseCodePaging)
1129 iFileClamp.iCookie[0]=0;// null handle to indicate
1130 iFileClamp.iCookie[1]=0;// transfer of ownership of clamp handle to proc's codeseg
1133 __IF_DEBUG(Printf("Done E32Image::LoadProcess %d",r));
1137 // Load a code segment, plus all imports if main loadee
1138 TInt E32Image::LoadCodeSeg(const RLdrReq& aReq)
1140 __LDRTRACE(aReq.Dump(">E32Image::LoadCodeSeg"));
1143 if (iMain==this && iClientProcessHandle)
1146 p.SetHandle(iClientProcessHandle);
1147 TFileName f(p.FileName());
1148 if (f.Length()>=2 && f[1]==':')
1151 if (d=='a' || d=='A')
1152 UseFloppy = EDriveA;
1153 else if (d=='b' || d=='B')
1154 UseFloppy = EDriveB;
1159 RImageFinder finder;
1160 TInt r = finder.Set(aReq);
1162 r = finder.Search();
1168 return DoLoadCodeSeg(aReq, finder);
1171 // Load a code segment, plus all imports if main loadee
1172 TInt E32Image::DoLoadCodeSeg(const RLdrReq& aReq, RImageFinder& aFinder)
1174 __LDRTRACE(aReq.Dump(">E32Image::DoLoadCodeSeg"));
1176 TInt r = Construct(aFinder); // needs to find it if it's already loaded
1182 __IF_DEBUG(Printf("epv=%x, fep=%x, codesize=%x, textsize=%x, uid3=%x",iEntryPtVeneer,iFileEntryPoint,iCodeSize,iTextSize,iUids[2]));
1183 __IF_DEBUG(Printf("attr=%08x, gExeAttr=%08x",iAttr,gExeAttr));
1185 // If EXE and not main loadee, EXE code segment must be the same as the client process or newly loaded process
1186 if (gExeCodeSeg && !iIsDll && iMain!=this && iHandle!=gExeCodeSeg)
1187 return KErrNotSupported;
1189 // If DLL and main loadee, ABI must match the process
1190 if (iIsDll && iMain==this && (iAttr & ECodeSegAttABIMask)!=(gExeAttr & ECodeSegAttABIMask) )
1191 return KErrNotSupported;
1193 // code segment already loaded
1194 if (iAlreadyLoaded || (iMain!=this && AlwaysLoaded()) )
1197 __IF_DEBUG(Printf("CodeSeg create"));
1198 r=E32Loader::CodeSegCreate(*this);
1202 iCloseCodeSeg=iHandle; // so new code segment is removed if the load fails
1203 if (!iRomImageHeader)
1210 r=ProcessImports(); // this sets up gLoadeePath
1211 // transfers ownership of clamp handle to codeseg; nulls handle if successful
1214 r=E32Loader::CodeSegLoaded(*this);
1215 if ((r==KErrNone) && iUseCodePaging)
1217 iFileClamp.iCookie[0]=0;// null handle to indicate
1218 iFileClamp.iCookie[1]=0;// transfer of ownership of clamp handle to codeseg
1224 __IF_DEBUG(Printf("<DoLoadCodeSeg, r=%d, iIsDll=%d",r,iIsDll));
1228 // Load a ROM XIP code segment as part of another load
1229 TInt E32Image::DoLoadCodeSeg(const TRomImageHeader& a)
1231 __IF_DEBUG(Printf("E32Image::DoLoadCodeSeg ROM XIP @%08x",&a));
1239 TInt r=CheckRomXIPAlreadyLoaded();
1240 if (r!=KErrNone || iAlreadyLoaded)
1245 r=E32Loader::CodeSegCreate(*this);
1247 __IF_DEBUG(Printf("<DoLoadCodeSeg, r=%d",r));
1251 /******************************************************************************
1252 * EPOC specific E32Image functions
1253 ******************************************************************************/
1256 Construct an image object which represents an XIP ROM executable.
1258 void E32Image::Construct(const TRomImageHeader& a)
1260 __IF_DEBUG(Printf("E32Image::Construct ROM %08x",&a));
1262 iRomImageHeader = &a;
1263 iUids = *(const TUidType*)&a.iUid1;
1265 iCodeSize = a.iCodeSize;
1266 iTextSize = a.iTextSize;
1267 iDataSize = a.iDataSize;
1268 iBssSize = a.iBssSize;
1269 iTotalDataSize = a.iTotalDataSize;
1271 iFileEntryPoint = a.iEntryPoint;
1272 iDepCount = a.iDllRefTable ? a.iDllRefTable->iNumberOfEntries : 0;
1273 iExportDir = a.iExportDir;
1274 iExportDirCount = a.iExportDirCount;
1275 iCodeLoadAddress = (TUint32)&a;
1276 iDataRunAddress = a.iDataBssLinearBase; // for fixed processes
1277 iHeapSizeMin = a.iHeapSizeMin;
1278 iHeapSizeMax = a.iHeapSizeMax;
1279 iStackSize = a.iStackSize;
1280 iPriority = a.iPriority;
1281 iIsDll = (a.iFlags & KImageDll)!=0;
1283 iExportDirLoad = iExportDir;
1285 // setup attributes...
1286 iAttr &= ~(ECodeSegAttKernel|ECodeSegAttGlobal|ECodeSegAttFixed|ECodeSegAttABIMask|ECodeSegAttNmdExpData);
1287 if(a.iFlags&KRomImageFlagsKernelMask)
1288 iAttr |= ECodeSegAttKernel;
1290 iAttr |= ECodeSegAttGlobal;
1291 if(a.iFlags&KRomImageFlagFixedAddressExe)
1292 iAttr |= ECodeSegAttFixed;
1293 iAttr |= (a.iFlags & KRomImageABIMask);
1294 if(a.iFlags&KRomImageNmdExpData)
1295 iAttr |= ECodeSegAttNmdExpData;
1296 if(a.iFlags&KRomImageSMPSafe)
1297 iAttr |= ECodeSegAttSMPSafe;
1299 iExceptionDescriptor = a.iExceptionDescriptor;
1303 TBool E32Image::AlwaysLoaded()
1305 // If loaded from ROM and EXE or DLL with no static data or extension or variant, don't need code segment
1307 __IF_DEBUG(Printf(">E32Image::AlwaysLoaded %08x",iRomImageHeader));
1308 if (iRomImageHeader)
1310 if (iIsDll && (iRomImageHeader->iFlags & KRomImageFlagDataPresent)==0)
1313 __IF_DEBUG(Printf("<E32Image::AlwaysLoaded %x",r));
1318 void E32Image::GetRomFileName()
1320 TBuf8<KMaxFileName> fn = _S8("z:\\");
1322 TPtr8 path_and_name(((TText8*)fn.Ptr())+3, 0, KMaxFileName-3);
1323 const TRomDir& rootdir = *(const TRomDir*)UserSvr::RomRootDirectoryAddress();
1324 if (!TraverseDirs(rootdir, iRomImageHeader, path_and_name))
1325 *(const TAny**)1=iRomImageHeader; // DIE!
1326 fn.SetLength(path_and_name.Length()+3);
1329 fni.GetName(iFileName, TFileNameInfo::EIncludeDrivePathBaseExt);
1331 iAttr |= ECodeSegAttExpVer;
1332 iRootNameOffset = fni.iBasePos;
1333 iRootNameLength = fni.BaseLen() + fni.ExtLen();
1334 iExtOffset = iFileName.Length() - fni.ExtLen();
1335 __IF_DEBUG(Printf("GetRomFileName(%08x)->%S,%d,%d,%d Attr %08x",iRomImageHeader,&iFileName,iRootNameOffset,iRootNameLength,iExtOffset,iAttr));
1340 Starting from aDir, search for XIP executable specified by aHdr.
1341 If found, return true and set aName to file path and name, (will cause descriptor panics if max size of aName isn't big enough.)
1342 If not found, return false.
1344 TBool E32Image::TraverseDirs(const TRomDir& aDir, const TRomImageHeader* aHdr, TDes8& aName)
1346 const TRomEntry* pE=&aDir.iEntry;
1347 const TRomEntry* pEnd=(const TRomEntry*)((TUint8*)pE+aDir.iSize);
1350 if ( (pE->iAtt & KEntryAttXIP) && (pE->iAddressLin==(TLinAddr)aHdr) )
1352 // ROM XIP file found
1353 aName.Copy(TPtrC16((const TText*)pE->iName, pE->iNameLength));
1356 if (pE->iAtt & KEntryAttDir)
1358 // subdirectory found
1359 const TRomDir& subdir = *(const TRomDir*)pE->iAddressLin;
1360 TText8* p = (TText8*)aName.Ptr();
1361 TInt m = aName.MaxLength();
1362 TInt nl = pE->iNameLength;
1363 TPtr8 ptr(p+nl+1, 0, m-nl-1);
1364 if (TraverseDirs(subdir, aHdr, ptr))
1366 // match found in subdirectory
1367 aName.SetLength(ptr.Length()+nl+1);
1368 const TText* s = (const TText*)pE->iName;
1371 *p++ = (TText8)*s++;
1375 TInt entry_size = KRomEntrySize + pE->iNameLength*sizeof(TText);
1376 entry_size = (entry_size+sizeof(TInt)-1)&~(sizeof(TInt)-1);
1377 pE=(const TRomEntry*)((TUint8*)pE+entry_size);
1384 Read data from a file.
1386 TInt FileRead(RFile& aFile, TUint8* aDest, TInt aSize)
1388 TPtr8 p(aDest,aSize,aSize);
1389 TInt r = aFile.Read(p,aSize);
1390 if(r==KErrNone && p.Size()!=aSize)
1391 RETURN_FAILURE(KErrCorrupt);
1397 Construct a new image header by reading a file. File must not be XIP.
1399 TInt E32ImageHeader::New(E32ImageHeader*& aHdr, RFile& aFile)
1404 TInt r = aFile.Size(fileSize);
1408 E32ImageHeaderV tempHeader;
1409 r = FileRead(aFile, (TUint8*)&tempHeader, sizeof(tempHeader));
1413 TUint headerSize = tempHeader.TotalSize();
1414 if(headerSize<sizeof(tempHeader) || headerSize>TUint(KMaxHeaderSize))
1415 RETURN_FAILURE(KErrCorrupt);
1417 E32ImageHeaderV* header = (E32ImageHeaderV*)User::Alloc(headerSize);
1419 return KErrNoMemory;
1421 wordmove(header, &tempHeader, sizeof(tempHeader));
1422 if(headerSize>sizeof(tempHeader))
1423 r = FileRead(aFile, ((TUint8*)header)+sizeof(tempHeader), headerSize-sizeof(tempHeader));
1426 r = header->ValidateAndAdjust(fileSize);
1438 Construct a new image header using data from the supplied buffer.
1440 TInt E32ImageHeader::New(E32ImageHeader*& aHdr, TUint8* aFileData, TUint32 aFileSize)
1444 E32ImageHeaderV& tempHeader = *(E32ImageHeaderV*)aFileData;
1446 if(aFileSize<sizeof(tempHeader))
1447 RETURN_FAILURE(KErrCorrupt); // too small to contain a header
1449 TUint headerSize = tempHeader.TotalSize();
1450 if(headerSize<sizeof(tempHeader) || headerSize>TUint(KMaxHeaderSize))
1451 RETURN_FAILURE(KErrCorrupt);
1452 if(headerSize>aFileSize)
1453 RETURN_FAILURE(KErrCorrupt);
1455 E32ImageHeaderV* header = (E32ImageHeaderV*)User::Alloc(headerSize);
1457 return KErrNoMemory;
1459 wordmove(header, &tempHeader, headerSize);
1461 TInt r = header->ValidateAndAdjust(aFileSize);
1472 Validate header, then adjust:
1473 - iUncompressedSize to contain size of data even when file is not compressed.
1474 - Platform security capability to include all disabled capabilities and exclude invalid ones.
1476 @param aFileSize Total size of the file containing the image data.
1478 TInt E32ImageHeaderV::ValidateAndAdjust(TUint32 aFileSize)
1480 // check header is valid...
1481 TUint32 uncompressedSize;
1482 TInt r = ValidateHeader(aFileSize,uncompressedSize);
1486 // set size of data when uncompressed...
1487 iUncompressedSize = uncompressedSize;
1489 // override capabilities in image to conform to system wide configuration...
1490 for(TInt i=0; i<SCapabilitySet::ENCapW; i++)
1492 iS.iCaps[i] |= DisabledCapabilities[i];
1493 iS.iCaps[i] &= AllCapabilities[i];
1500 TInt E32Image::Construct(RImageFinder& aFinder)
1502 __IF_DEBUG(Printf("E32Image::iMain=%08x", iMain));
1503 __LDRTRACE(aFinder.Dump(">E32Image::Construct", 0));
1504 __ASSERT_ALWAYS(aFinder.iNewValid, User::Panic(KLitFinderInconsistent, 0));
1506 // fallback security check to ensure we don't try and load an executable from an insecure location...
1507 if(PlatSec::ConfigSetting(PlatSec::EPlatSecEnforceSysBin))
1509 __ASSERT_ALWAYS(aFinder.iNewFileName.Length()>=11, User::Panic(KLitSysBinError, 0));
1510 __ASSERT_ALWAYS(KSysBin().CompareF(TPtrC8(aFinder.iNewFileName.Ptr()+1,10))==0, User::Panic(KLitSysBinError, 1));
1515 // setup file name info...
1516 iFileName.Copy(aFinder.iNewFileName);
1518 fi.Set(iFileName, 0);
1519 iRootNameOffset = fi.iBasePos;
1520 iRootNameLength = fi.iLen - fi.iBasePos;
1521 iExtOffset = fi.iExtPos;
1524 iAttr |= aFinder.iNew.iAttr & ECodeSegAttExpVer;
1525 iModuleVersion = aFinder.iNew.iModuleVersion;
1527 if(aFinder.iNew.iRomImageHeader)
1529 // we're 'loading' an XIP executable from ROM...
1530 Construct(*aFinder.iNew.iRomImageHeader);
1531 if(!AlwaysLoaded() || iMain==this)
1532 r = CheckRomXIPAlreadyLoaded();
1536 // setup more image info...
1537 iAttr |= aFinder.iNew.iAttr & (ECodeSegAttFixed|ECodeSegAttABIMask|ECodeSegAttNmdExpData);
1538 iUids = *(const TUidType*)&aFinder.iNew.iUid;
1539 iIsDll = !(iUids[0].iUid == KExecutableImageUidValue);
1540 iS = aFinder.iNew.iS;
1542 // check if executable has already been loaded...
1543 r = CheckAlreadyLoaded();
1547 // if we are going to need to load it...
1548 if(!iAlreadyLoaded || !iIsDll)
1550 if (aFinder.iNew.iNeedHashCheck)
1552 // we need to check the file hash; the check in RImageFinder::Try
1553 // was skipped based on the cache. If it fails here, though, someone
1554 // is tampering with us and we can just fail the load.
1555 TRAP(r,aFinder.CompareHashL(aFinder.iNew, fi.DriveAndPath()));
1560 if(aFinder.iNew.iFileData)
1562 // take ownership of the file data aFinder has already read in...
1563 iFileData = aFinder.iNew.iFileData;
1564 aFinder.iNew.iFileData = NULL;
1565 iFileSize = aFinder.iNew.iFileSize;
1567 else if(aFinder.iNew.FileOpened())
1569 // take ownership of the file handle that aFinder has already opened...
1570 iFile = aFinder.iNew.iFile;
1571 memclr(&aFinder.iNew.iFile, sizeof(RFile));
1575 // no resource obtained from aFinder, so create a file handle for ourselves...
1581 // take ownership of header...
1582 iHeader = aFinder.iNew.iHeader;
1583 aFinder.iNew.iHeader = NULL;
1585 // if there wast't a header, then create one now...
1589 r = E32ImageHeader::New(iHeader, iFileData, iFileSize);
1591 r = E32ImageHeader::New(iHeader, iFile);
1596 // setup info needed for process creation...
1597 iHeapSizeMin = iHeader->iHeapSizeMin;
1598 iHeapSizeMax = iHeader->iHeapSizeMax;
1599 iStackSize = iHeader->iStackSize;
1600 iPriority = iHeader->ProcessPriority();
1603 // if already loaded...
1605 return KErrNone; // nothing more to do
1607 // setup info needed to load an executable...
1608 iDepCount = iHeader->iDllRefTableCount;
1609 iExportDirCount = iHeader->iExportDirCount;
1610 iExportDir = iHeader->iExportDirOffset-iHeader->iCodeOffset;
1611 iTextSize = iHeader->iTextSize;
1612 iCodeSize = iHeader->iCodeSize;
1613 __IF_DEBUG(Printf("Code + const %x",iCodeSize));
1614 iDataSize = iHeader->iDataSize;
1615 __IF_DEBUG(Printf("Data %x",iDataSize));
1616 iBssSize = iHeader->iBssSize;
1617 __IF_DEBUG(Printf("Bss %x",iBssSize));
1618 iTotalDataSize = iDataSize+iBssSize;
1620 iFileEntryPoint = iHeader->iEntryPoint; // just an offset at this stage
1622 iExceptionDescriptor = iHeader->ExceptionDescriptor();
1623 if(iHeader->iExportDirOffset)
1624 iExportDirLoad = iExportDir; // only set this if not already loaded
1626 // initialise the SMP safe flag from the image header
1627 // this will get cleared during ProcessImports if any import is not SMP safe
1628 if(iHeader->iFlags & KImageSMPSafe)
1629 iAttr |= ECodeSegAttSMPSafe;
1632 __IF_DEBUG(Printf("%S is not marked SMP safe", &iFileName));
1633 iAttr &= ~ECodeSegAttSMPSafe;
1636 // check if executable is to be demand paged...
1637 r = ShouldBeCodePaged(iUseCodePaging);
1638 __IF_DEBUG(Printf("ShouldBeCodePaged r=%d,iUseCodePaging=%d", r, iUseCodePaging));
1639 if(iUseCodePaging==EFalse || r!=KErrNone)
1642 // image needs demand paging, create the additional information needed for this...
1644 // read compression info...
1645 iCompressionType = iHeader->iCompressionType;
1646 r = LoadCompressionData();
1647 if(r==KErrNotSupported)
1649 // Compression type not supported, so just load executable as normal, (without paging)...
1650 iUseCodePaging = EFalse;
1653 else if (r!=KErrNone)
1656 // clamp file so it doesn't get modified whilst it is being demand paged...
1657 r = iFileClamp.Clamp(iFile);
1658 // The clamp API will return KErrNotSupported if the media is removable:
1659 // this implies that paging is not possible but the binary can still be loaded
1662 iUseCodePaging = EFalse;
1663 return r == KErrNotSupported ? KErrNone : r;
1666 // get blockmap data which indicates location of media where file contents are stored...
1667 r = BuildCodeBlockMap();
1668 __IF_DEBUG(Printf("BuildCodeBlockMap r=%d", r));
1669 if(r==KErrNotSupported)
1671 // media doesn't support demand paging, so just load executable as normal, (without paging)...
1672 iUseCodePaging = EFalse;
1673 iFileClamp.Close(gTheLoaderFs);
1681 TInt E32Image::CheckRomXIPAlreadyLoaded()
1683 __IF_DEBUG(Printf("ROM XIP %08x CheckAlreadyLoaded",iRomImageHeader));
1685 find.iRomImgHdr=iRomImageHeader;
1686 E32Loader::CodeSegDeferDeletes();
1689 E32Loader::CodeSegNext(h, find);
1693 r=E32Loader::CodeSegOpen(h, iClientProcessHandle);
1695 E32Loader::CodeSegInfo(iHandle, *this);
1697 E32Loader::CodeSegEndDeferDeletes();
1698 if (iHandle && r==KErrNone)
1700 iAlreadyLoaded=ETrue;
1701 __IF_DEBUG(Printf("ROM XIP %08x already loaded", iHandle));
1703 __IF_DEBUG(Printf("ROM XIP CheckAlreadyLoaded returns %d",r));
1709 Read the E32Image file into its code and data chunks, relocating them
1711 Create a dll reference table from the names of dlls referenced.
1712 Fix up the import address table and the export table for real addresses.
1714 TInt E32Image::LoadToRam()
1716 __IF_DEBUG(Printf("E32Image::LoadToRam %S",&iFileName));
1718 // offset of data after code which will be erad into iRestOfFileData...
1719 iConversionOffset = iHeader->iCodeOffset + iHeader->iCodeSize;
1721 // calculate sizes...
1722 TUint totalSize = ((E32ImageHeaderV*)iHeader)->iUncompressedSize;
1723 TUint remainder = totalSize-iConversionOffset;
1724 if(remainder>totalSize)
1725 RETURN_FAILURE(KErrCorrupt); // Fuzzer can't trigger this because header validation prevents it
1727 iRestOfFileData = (TUint8*)User::Alloc(remainder);
1728 if(!iRestOfFileData)
1729 return KErrNoMemory;
1730 iRestOfFileSize = remainder;
1732 TInt r = LoadFile(); // Read everything in
1736 __IF_DEBUG(Printf("iHeader->iCodeRelocOffset %d",iHeader->iCodeRelocOffset));
1737 r = ((E32ImageHeaderV*)iHeader)->ValidateRelocations(iRestOfFileData,iRestOfFileSize,iHeader->iCodeRelocOffset,iHeader->iCodeSize,iCodeRelocSection);
1741 __IF_DEBUG(Printf("iHeader->iDataRelocOffset %d",iHeader->iDataRelocOffset));
1742 r = ((E32ImageHeaderV*)iHeader)->ValidateRelocations(iRestOfFileData,iRestOfFileSize,iHeader->iDataRelocOffset,iHeader->iDataSize,iDataRelocSection);
1746 iCodeDelta = iCodeRunAddress-iHeader->iCodeBase;
1747 iDataDelta = iDataRunAddress-iHeader->iDataBase;
1752 r = LoadAndRelocateData();
1754 r = ReadImportData();
1760 TInt E32Image::ShouldBeCodePaged(TBool& aPage)
1762 Determine whether this binary should be paged. Some of this
1763 function is unimplemented because it requires the media pageable
1766 @param aPage On success, this variable is set to
1767 whether the binary should be paged. Its
1768 value is undefined if the return code is
1770 @return Symbian OS error code.
1772 See S3.1.3.2 of PREQ1110 Design Sketch.
1777 // kernel and global dlls can't be paged...
1778 if(iAttr&(ECodeSegAttKernel|ECodeSegAttGlobal))
1781 // 1. if paging policy is NOPAGING then executable is unpaged
1782 TUint32 policy = E32Loader::PagingPolicy();
1784 __IF_DEBUG(Printf("sbcp,policy=0x%x", policy));
1785 if (policy == EKernelConfigCodePagingPolicyNoPaging)
1788 // 2. if executable is on media without Pageable Media Attribute then unpaged
1789 // 3. if executable is on removable media then unpaged
1790 // both superseded by the BlockMap API
1792 // 3a. if executable has already been loaded into RAM for tamperproofing then
1793 // it can't be paged
1794 if (iFileData != NULL)
1797 // 4. if not compressed with bytepair or uncompressed then unpaged
1798 __IF_DEBUG(Printf("sbcp,iHeader=0x%08x", iHeader));
1799 TUint32 comp = iHeader->CompressionType();
1800 __IF_DEBUG(Printf("sbcp,comp=0x%x", comp));
1801 if (comp != KUidCompressionBytePair && comp != KFormatNotCompressed)
1806 // 5. if policy is ALWAYSPAGE then page
1807 if (policy == EKernelConfigCodePagingPolicyAlwaysPage)
1811 TUint KPagedMask = (KImageCodePaged | KImageCodeUnpaged);
1812 TUint pagedFlags = iHeader->iFlags & KPagedMask;
1813 __IF_DEBUG(Printf("sbcp,iHeader->iFlags=0x%x,pagedFlags=0x%x", iHeader->iFlags, pagedFlags));
1815 // if KImageCodePaged and KImageCodeUnpaged flags present then corrupt
1816 if (pagedFlags == KPagedMask)
1817 RETURN_FAILURE(KErrCorrupt);
1819 // if KImageCodePaged set in executable then page
1820 if (pagedFlags == KImageCodePaged)
1823 // if KImageCodeUnpaged set in executable then do not page
1824 if (pagedFlags == KImageCodeUnpaged)
1830 // 7. otherwise (neither paged nor unpaged set) use paging policy
1832 // policy must be EKernelConfigCodePagingPolicyDefaultUnpaged or EKernelConfigCodePagingPolicyDefaultPaged
1833 aPage = (policy == EKernelConfigCodePagingPolicyDefaultPaged);
1837 TInt E32Image::BuildCodeBlockMap()
1839 Use the block map API to build an array of TBlockMapInfo
1840 objects which the kernel can use to page in code as required.
1842 @return Symbian OS error code. KErrNotSupported means the
1843 Block Map functionality does not support paging from
1844 the binary's location.
1847 __IF_DEBUG(Printf("BuildCodeBlockMap,iCodeStartInFile=%d,iCodeLengthInFile=%d", iCodeStartInFile, iCodeLengthInFile));
1849 __ASSERT_DEBUG(iUseCodePaging, Panic(EBcbmNotCodePaged));
1851 // do nothing if no code section
1852 if (iCodeLengthInFile == 0)
1855 // RFile::BlockMap populates an instance of this object. Need to
1856 // retain information such as granularity which applies to all entries.
1859 TInt curEntriesSize = 0;
1860 TUint8* entries8 = 0; // points to heap cell containing TBlockMapEntryBase array
1863 TInt64 bmEnd = iCodeStartInFile + iCodeLengthInFile;
1867 __IF_DEBUG(Printf("lfbpu:BlockMap,in,bmPos=%ld,bmEnd=%ld", bmPos, bmEnd));
1868 r = iFile.BlockMap(bmi, bmPos, bmEnd, EBlockMapUsagePaging); // updates bmPos to end of mapped range
1870 Printf("lfbpu:BlockMap,out,r=%d,bmPos=%ld,bmEnd=%ld,maplen=%d(%d)",
1871 r, bmPos, bmEnd, bmi.iMap.Length(), bmi.iMap.Length() / sizeof(TBlockMapEntryBase)));
1873 Printf("lfbpu:BlockMap,out,iBlockGranularity=%u,iBlockStartOffset=%u,iStartBlockAddress=%ld,iLocalDriveNumber=%d",
1874 bmi.iBlockGranularity, bmi.iBlockStartOffset, bmi.iStartBlockAddress, bmi.iLocalDriveNumber));
1875 if (r != KErrNone && r != KErrCompletion)
1878 // Copy info the first time round as this gets overwritten on subsequent passes
1879 if (curEntriesSize == 0)
1880 iCodeBlockMapCommon = bmi; // slices the SBlockMapCommon subclass data
1882 // grow the buffer which contains the entries
1883 TInt newEntriesSize = bmi.iMap.Length();
1884 TInt newArraySize = curEntriesSize + newEntriesSize;
1885 TUint8* newEntries8 = (TUint8*) User::ReAlloc(entries8, newArraySize);
1886 if (newEntries8 == 0)
1891 entries8 = newEntries8;
1894 // dump the newly-returned block entries
1895 for (TInt i = 0; i < newEntriesSize; i += sizeof(TBlockMapEntryBase))
1897 const TBlockMapEntryBase& bme = *reinterpret_cast<const TBlockMapEntryBase*>(bmi.iMap.Ptr() + i);
1898 __IF_DEBUG(Printf("lfbpu:bme,iNumberOfBlocks=%d,iStartBlock=%d", bme.iNumberOfBlocks, bme.iStartBlock));
1902 // append the new entries to the array.
1903 Mem::Copy(entries8 + curEntriesSize, bmi.iMap.Ptr(), newEntriesSize);
1904 curEntriesSize = newArraySize;
1905 } while (r != KErrCompletion);
1907 // r == KErrCompletion when mapped code section range
1908 if (r != KErrCompletion)
1910 User::Free(entries8);
1915 // dump the block map table
1916 __IF_DEBUG(Printf("lfbpu:endbme,r=%d,curEntriesSize=%d", r, curEntriesSize));
1917 for (TInt i = 0; i < curEntriesSize; i += 8)
1920 "entries[0x%08x], %02x %02x %02x %02x %02x %02x %02x %02x",
1921 entries8[i+0], entries8[i+1], entries8[i+2], entries8[i+3],
1922 entries8[i+4], entries8[i+5], entries8[i+6], entries8[i+7]));
1926 iCodeBlockMapEntries = reinterpret_cast<TBlockMapEntryBase*>(entries8);
1927 iCodeBlockMapEntriesSize = curEntriesSize;
1934 Get the compression data relevant to demand paging
1936 TInt E32Image::LoadCompressionData()
1938 __IF_DEBUG(Printf("E32Image::LoadCompressionData %S 0x%08x",&iFileName,iHeader->CompressionType()));
1940 TUint compression = iHeader->CompressionType();
1943 if(compression==KFormatNotCompressed)
1945 r = LoadCompressionDataNoCompress();
1947 else if(compression==KUidCompressionBytePair)
1949 TRAP(r,LoadCompressionDataBytePairUnpakL());
1953 r = KErrNotSupported;
1956 __IF_DEBUG(Printf("E32Image::LoadCompressionData exiting %S r=%d",&iFileName,r));
1961 TInt E32Image::LoadCompressionDataNoCompress()
1963 __IF_DEBUG(Printf("E32Image::LoadCompressionDataNoCompress %S",&iFileName));
1964 if (iHeader->iCodeSize)
1966 iCodeStartInFile = iHeader->iCodeOffset;
1967 iCodeLengthInFile = iCodeSize;
1973 void E32Image::LoadCompressionDataBytePairUnpakL()
1975 __IF_DEBUG(Printf("E32Image::LoadCompressionDataBytePairUnpakL %S",&iFileName));
1978 User::Leave(KErrNotSupported); // if the file data has been loaded into RAM we can't page it!
1980 TInt pos = iHeader->TotalSize();
1981 User::LeaveIfError(iFile.Seek(ESeekStart,pos)); // Start at beginning of compressed data
1983 CBytePairReader* reader = CBytePairFileReader::NewLC(iFile);
1985 if (iHeader->iCodeSize)
1987 __IF_DEBUG(Printf("Code & const size %x",iCodeSize));
1988 __IF_DEBUG(Printf("Code & const offset %x",iHeader->iCodeOffset));
1989 __IF_DEBUG(Printf("Code & const dest %x",iCodeLoadAddress));
1992 reader->GetPageOffsetsL(pos, pageCount, iCodePageOffsets);
1995 for (TInt i = 0; i <= pageCount; ++i)
1997 __IF_DEBUG(Printf("lfbpu:raw iCodePageOffsets[%d] = %d", i, iCodePageOffsets[i]));
2001 // record the code start position in the file and its compressed length
2002 // so BuildCodeBlockMap can construct a block map for the kernel if this
2003 // file is demand paged.
2004 iCodeStartInFile = iCodePageOffsets[0];
2005 iCodeLengthInFile = iCodePageOffsets[pageCount] - iCodePageOffsets[0];
2008 CleanupStack::PopAndDestroy(reader);
2013 Read all image data into memory, decompressing it using the method indicated in the image header..
2014 If code isn't being demand paged the code part is read into #iCodeLoadAddress.
2015 The rest of the file data after the code part is read into #iRestOfFileData.
2017 TInt E32Image::LoadFile()
2019 __IF_DEBUG(Printf("E32Image::LoadFile %S 0x%08x",&iFileName,iHeader->CompressionType()));
2021 TUint compression = iHeader->CompressionType();
2024 if(compression==KFormatNotCompressed)
2026 r = LoadFileNoCompress();
2027 CHECK_FAILURE(r); // Fuzzer can't trigger this because it only happens on file i/o error
2029 else if(compression==KUidCompressionDeflate)
2031 TRAP(r,LoadFileInflateL());
2034 else if(compression==KUidCompressionBytePair)
2036 TRAP(r,LoadFileBytePairUnpakL());
2041 r = KErrNotSupported;
2042 CHECK_FAILURE(r); // Fuzzer can't trigger this because header validation ensures compression type is OK
2045 // we're done with the file contents now, free up memory before resolving imports
2048 gFileDataAllocator.Free(iFileData);
2052 __IF_DEBUG(Printf("E32Image::LoadFile exiting %S r=%d",&iFileName,r));
2058 Read data from the image's file (or the preloaded data at #iFileData if present).
2060 TInt E32Image::Read(TUint aPos, TUint8* aDest, TUint aSize, TBool aSvPerms)
2062 TPtr8 p(aDest,aSize,aSize);
2065 // get data from pre-loaded image data...
2066 if(aPos+aSize>iFileSize)
2067 RETURN_FAILURE(KErrCorrupt); // Fuzzer can't trigger this because earlier validation prevents sizes being wrong
2069 WordCopy(aDest,iFileData+aPos,aSize);
2071 p.Copy(iFileData+aPos,aSize);
2075 // get data from file...
2076 TInt r = iFile.Read(aPos,p,aSize);
2081 // check we got the amount of data requested...
2082 if(TUint(p.Length())!=aSize)
2084 __IF_DEBUG(Printf("E32Image::Read() Expected:%d, read:%d", aSize, p.Length() ));
2085 RETURN_FAILURE(KErrCorrupt); // Fuzzer can't trigger this because requires file length to change during load
2093 Read all image data into memory.
2094 If code isn't being demand paged the code part is read into #iCodeLoadAddress.
2095 The rest of the file data after the code part is read into #iRestOfFileData.
2097 TInt E32Image::LoadFileNoCompress()
2099 __IF_DEBUG(Printf("E32Image::LoadFileNoCompress exiting %S",&iFileName));
2102 if(iHeader->iCodeSize && !iUseCodePaging)
2104 __IF_DEBUG(Printf("Code & const size %x",iCodeSize));
2105 __IF_DEBUG(Printf("Code & const offset %x",iHeader->iCodeOffset));
2106 __IF_DEBUG(Printf("Code & const dest %x",iCodeLoadAddress));
2107 r = Read(iHeader->iCodeOffset, (TText8*)iCodeLoadAddress, iCodeSize, ETrue);
2113 r = Read(iConversionOffset, iRestOfFileData, iRestOfFileSize);
2119 void FileCleanup(TAny* aPtr)
2121 TFileInput* f=(TFileInput*)aPtr;
2127 Read all image data into memory, decompressing it using the Inflate method.
2128 If code isn't being demand paged the code part is read into #iCodeLoadAddress.
2129 The rest of the file data after the code part is read into #iRestOfFileData.
2131 void E32Image::LoadFileInflateL()
2133 __IF_DEBUG(Printf("E32Image::LoadFileInflateL %S",&iFileName));
2134 __ASSERT_DEBUG(!iUseCodePaging, Panic(ELfiCodePagingNotSupported));
2136 TInt pos = iHeader->TotalSize();
2141 User::Leave(KErrArgument);
2142 file = new (ELeave) TBitInput(iFileData, iFileSize*8, pos*8);
2143 CleanupStack::PushL(file);
2147 User::LeaveIfError(iFile.Seek(ESeekStart,pos)); // Start at beginning of compressed data
2148 file = new (ELeave) TFileInput(iFile);
2149 CleanupStack::PushL(TCleanupItem(&FileCleanup,file));
2152 CInflater* inflater=CInflater::NewLC(*file);
2154 if(iHeader->iCodeSize)
2156 __IF_DEBUG(Printf("Code & const size %x",iCodeSize));
2157 __IF_DEBUG(Printf("Code & const offset %x",iHeader->iCodeOffset));
2158 __IF_DEBUG(Printf("Code & const dest %x",iCodeLoadAddress));
2160 TInt count = inflater->ReadL((TUint8*)iCodeLoadAddress,iCodeSize,&WordCopy);
2161 if(count!=iCodeSize)
2162 User::Leave(KErrCorrupt);
2167 TUint32 count = inflater->ReadL(iRestOfFileData,iRestOfFileSize,&Mem::Copy);
2168 if(count!=iRestOfFileSize)
2169 User::Leave(KErrCorrupt);
2172 CleanupStack::PopAndDestroy(2,file);
2177 Read all image data into memory, decompressing it using the BytePair method.
2178 If code isn't being demand paged the code part is read into #iCodeLoadAddress.
2179 The rest of the file data after the code part is read into #iRestOfFileData.
2181 void E32Image::LoadFileBytePairUnpakL()
2183 __IF_DEBUG(Printf("E32Image::LoadFileBytePairUnpak %S",&iFileName));
2185 // code starts after header
2186 TInt pos = iHeader->TotalSize();
2188 CBytePairReader* reader;
2190 reader = CBytePairReader::NewLC(iFileData+pos, iFileSize-pos);
2193 iFile.Seek(ESeekStart, pos);
2194 reader = CBytePairFileReader::NewLC(iFile);
2197 TBool codeLoaded = false;
2198 if(iHeader->iCodeSize && !iUseCodePaging)
2200 __IF_DEBUG(Printf("Code & const size %x",iCodeSize));
2201 __IF_DEBUG(Printf("Code & const offset %x",iHeader->iCodeOffset));
2202 __IF_DEBUG(Printf("Code & const dest %x",iCodeLoadAddress));
2204 TUint32 bytes = reader->DecompressPagesL((TUint8*)iCodeLoadAddress,iCodeSize,&WordCopy);
2206 __IF_DEBUG(Printf("bytes:%x",bytes));
2207 if((TInt)bytes!=iCodeSize)
2208 User::Leave(KErrCorrupt);
2217 // skip past code part of file...
2218 TInt pageCount = (iCodeSize + KPageOffsetMask) >> KPageSizeShift;
2220 TInt pos = KIndexTableHeaderSize
2221 + pageCount * sizeof(TUint16)
2222 + iCodeLengthInFile;
2224 __IF_DEBUG(Printf("lfpbu:pos=%x", pos));
2225 reader->SeekForwardL(pos);
2228 __IF_DEBUG(Printf(" iRestOfFileSize==%x, iRestOfFileData==%x", iRestOfFileSize, iRestOfFileData));
2230 TUint32 bytes = reader->DecompressPagesL(iRestOfFileData,iRestOfFileSize,NULL);
2231 __IF_DEBUG(Printf("bytes:%x",bytes));
2232 if(bytes!=iRestOfFileSize)
2233 User::Leave(KErrCorrupt);
2236 CleanupStack::PopAndDestroy(reader);
2243 TInt E32Image::RelocateCode()
2245 if(iHeader->iExportDirOffset)
2246 iExportDirLoad += iCodeLoadAddress; // only for RAM modules which are not already loaded
2248 __IF_DEBUG(Printf("**EntryPointVeneer %08x FileEntryPoint %08x",iEntryPtVeneer,iFileEntryPoint));
2249 __IF_DEBUG(Printf("**ExportDir load@%08x run@%08x",iExportDirLoad,iExportDir));
2251 if(iHeader->iCodeRelocOffset)
2253 __IF_DEBUG(Printf("Relocate code & const"));
2256 r = RelocateSection(iCodeRelocSection, iCodeLoadAddress);
2259 r = AllocateRelocationData(iCodeRelocSection, iHeader->iCodeSize, iCodeLoadAddress, iCodeRelocTable);
2260 iExportDirEntryDelta = iCodeDelta; // so exports get relocated
2265 r = RelocateExports();
2269 // put a unique ID into the third word after the entry point
2271 // address for ID...
2272 TLinAddr csid_addr = iFileEntryPoint+KCodeSegIdOffset-iCodeRunAddress+iCodeLoadAddress;
2273 __IF_DEBUG(Printf("csid_addr %08x", csid_addr));
2275 // get existing ID...
2277 WordCopy(&x, (const TAny*)csid_addr, sizeof(x));
2280 // generate next ID...
2281 if(++NextCodeSegId == 0xffffffffu)
2282 Fault(ELdrCsIdWrap);
2283 __IF_DEBUG(Printf("NextCSID %08x", NextCodeSegId));
2286 WordCopy((TAny*)csid_addr, &NextCodeSegId, sizeof(NextCodeSegId));
2289 // demand paged code needs modifying when paged in, so add ID as a new 'fixup'...
2290 TUint64* fixup = ExpandFixups(1);
2294 *fixup = MAKE_TUINT64(csid_addr,NextCodeSegId);
2304 Copy the data section from buffer #iRestOfFileData to the memory allocated at #iDataLoadAddress.
2305 Then relocate this data ready for use at the executables run addresses.
2307 TInt E32Image::LoadAndRelocateData()
2309 __IF_DEBUG(Printf("E32Image::LoadAndRelocateData %S",&iFileName));
2310 if(!iHeader->iDataOffset)
2311 return KErrNone; // do data section
2314 __IF_DEBUG(Printf("Read Data: size %x->%08x",iDataSize,iDataLoadAddress));
2315 TUint32 bufferOffset=iHeader->iDataOffset-iConversionOffset;
2316 TUint8* source=iRestOfFileData+bufferOffset;
2317 MemCopy((TText8*)iDataLoadAddress,source,iDataSize);
2320 __IF_DEBUG(Printf("Relocate data section"));
2321 __IF_DEBUG(Printf("iDataRelocOffset %08x",iHeader->iDataRelocOffset));
2323 if(iHeader->iDataRelocOffset)
2324 r = RelocateSection(iDataRelocSection, iDataLoadAddress);
2331 Copies data from aDestination to aSource by running in supervisor mode.
2332 aDest, aSource & aNumberOfBytes must be word aligned.
2334 TUint8* E32Image::WordCopy(TAny* aDestination, const TAny* aSource, TInt aNumberOfBytes)
2336 aNumberOfBytes &= ~3; // Avoid panics for corrupt data which is not word size
2337 SCopyDataInfo info = {aDestination,aSource, aNumberOfBytes};
2338 return (TUint8*) ExecuteInSupervisorMode(&svWordCopy, &info);
2343 Copies data from aDestination to aSource by running in supervisor mode.
2345 TUint8* E32Image::MemCopy(TAny* aDestination, const TAny* aSource, TInt aNumberOfBytes)
2347 SCopyDataInfo info={aDestination,aSource, aNumberOfBytes};
2348 return (TUint8*) ExecuteInSupervisorMode(&svMemCopy, &info);
2353 Relocate a section, applying relocations for run addresses to values currently at their load addresses.
2355 TInt E32Image::RelocateSection(E32RelocSection* aSection, TUint32 aLoadAddress)
2360 __IF_DEBUG(Printf("Relocate: NRelocs:%08x LoadAddr:%08x", aSection->iNumberOfRelocs, aLoadAddress));
2362 SRelocateSectionInfo info={this, (TUint8*)(aSection+1), aSection->iNumberOfRelocs, aLoadAddress};
2364 // call function in supervisor mode to relocate the section
2365 TInt r = ExecuteInSupervisorMode(&svRelocateSection, &info);
2367 __IF_DEBUG(Printf("Relocate returning %d",r));
2373 Relocate the export directory for the code's run address
2375 TInt E32Image::RelocateExports()
2377 // This only has to be done for PE-derived images, ELF marks all
2378 // export table entries as 'relocations' so this job has already been done.
2379 TUint impfmt = iHeader->ImportFormat();
2380 if (impfmt == KImageImpFmt_ELF)
2383 __IF_DEBUG(Printf("E32Image::RelocateExports %S",&iFileName));
2385 if(iHeader->iExportDirOffset)
2387 // call function in supervisor mode to fix up export directory
2388 ExecuteInSupervisorMode(&svRelocateExports, this);
2395 Validate import section data structures in iRestOfFileData.
2396 Set iImportData to point to point to start of this.
2397 Allocate memory (iCurrentImportList) which is big enough to store imports for a single dependency.
2399 TInt E32Image::ReadImportData()
2401 __IF_DEBUG(Printf("E32Image::ReadImportData %S",&iFileName));
2403 if(!iHeader->iImportOffset)
2406 TUint biggestImportCount;
2407 TInt r = ((E32ImageHeaderV*)iHeader)->ValidateImports(iRestOfFileData,iRestOfFileSize,biggestImportCount);
2411 iImportData = (TUint32*)(iRestOfFileData+iHeader->iImportOffset-iConversionOffset);
2412 iCurrentImportList = (TUint32*)User::Alloc(biggestImportCount * sizeof(TUint32));
2413 __IF_DEBUG(Printf("E32Image::ReadImportData - alloc %d current import slots at %08x", biggestImportCount, iCurrentImportList));
2414 if(!iCurrentImportList)
2415 return KErrNoMemory;
2421 void E32Image::SortCurrentImportList()
2423 if (!iCurrentImportListSorted)
2425 RArray<TUint> array((TUint*)iCurrentImportList, iCurrentImportCount);
2427 iCurrentImportListSorted = (TUint8)ETrue;
2432 TInt CheckRomExports(const TRomImageHeader* aR, const E32Image* aI)
2434 __IF_DEBUG(Printf("CheckRomExports"));
2435 if (aR->iExportDirCount == 0)
2436 return aI->iCurrentImportCount ? KErrNotSupported : KErrNone;
2437 const TUint32* xd = (const TUint32*)aR->iExportDir;
2438 const TUint32* p = aI->iCurrentImportList;
2439 const TUint32* pE = p + aI->iCurrentImportCount;
2442 return KErrNotSupported;
2447 TInt CheckRamExports(TUint aEDT, const TUint8* aED, TUint aEDC, E32Image* aI)
2449 __IF_DEBUG(Printf("CheckRamExports"));
2451 return aI->iCurrentImportCount ? KErrNotSupported : KErrNone;
2452 if (aEDT == KImageHdr_ExpD_NoHoles)
2453 return KErrNone; // nothing missing
2455 const TUint32* p = aI->iCurrentImportList;
2456 const TUint32* pE = p + aI->iCurrentImportCount;
2458 if (aEDT == KImageHdr_ExpD_FullBitmap)
2463 if ( !(aED[x>>3] & (1u<<(x&7))) )
2464 return KErrNotSupported;
2469 if (aEDT != KImageHdr_ExpD_SparseBitmap8)
2470 return KErrNotSupported; // don't know what this is
2471 aI->SortCurrentImportList(); // sort imports to increasing order
2472 TUint32 memsz = (aEDC + 7) >> 3; // size of complete bitmap
2473 TUint32 mbs = (memsz + 7) >> 3; // size of meta-bitmap
2474 const TUint8* mptr = aED;
2475 const TUint8* gptr = mptr + mbs;
2476 const TUint8* mptrE = mptr + mbs;
2478 for (; mptr<mptrE && p<pE; ++mptr, xlim+=64)
2483 // nothing missing in this block of 64 exports; step to next block
2484 for (; p<pE && *p<=xlim; ++p) {}
2487 // expand this block of 64
2488 TUint32 g32[2] = {0xffffffffu, 0xffffffffu};
2489 TUint8* g = (TUint8*)g32;
2490 for (; m; m>>=1, ++g)
2494 for (; p<pE && *p<=xlim; ++p)
2496 TUint ix = *p - (xlim - 64) - 1;
2497 if ( !(g[ix>>3] & (1u<<(ix&7))) )
2498 return KErrNotSupported;
2505 TInt CheckRequiredImports(E32Image* aImporter, E32Image* aExporter, TInt aAction)
2507 __IF_DEBUG(Printf("E32Image::CheckRequiredImports (existing) %d", aAction));
2508 TInt last = aImporter->LastCurrentImport();
2509 if (last > aExporter->iExportDirCount)
2510 return KErrNotSupported;
2511 if (aAction == EAction_CheckLastImport)
2513 if (aExporter->iRomImageHeader)
2514 return CheckRomExports(aExporter->iRomImageHeader, aImporter);
2515 if (aExporter->iHeader)
2517 E32ImageHeaderV* v = (E32ImageHeaderV*)aExporter->iHeader;
2518 return CheckRamExports(v->iExportDescType, v->iExportDesc, v->iExportDirCount, aImporter);
2520 TInt r = aExporter->ReadExportDirLoad();
2522 return r; // could fail with OOM
2523 TBool hasNmdExp = (aExporter->iAttr & ECodeSegAttNmdExpData);
2524 const TUint32* p = aImporter->iCurrentImportList;
2525 const TUint32* pE = p + aImporter->iCurrentImportCount;
2526 const TUint32* pX = (const TUint32*)aExporter->iExportDirLoad - 1;
2527 TUint32 xep = aExporter->iFileEntryPoint;
2532 if ((xx==0 && (x!=0 || (x==0&&hasNmdExp))) || xx==xep)
2533 return KErrNotSupported;
2539 TInt CheckRequiredImports(E32Image* aImporter, const RImageInfo& aExporter, TInt aAction)
2541 __IF_DEBUG(Printf("E32Image::CheckRequiredImports (new) %d", aAction));
2542 TInt last = aImporter->LastCurrentImport();
2543 if (last > aExporter.iExportDirCount)
2544 return KErrNotSupported;
2545 if (aAction == EAction_CheckLastImport)
2547 if (aExporter.iRomImageHeader)
2548 return CheckRomExports(aExporter.iRomImageHeader, aImporter);
2549 return CheckRamExports(aExporter.iExportDescType, aExporter.iExportDesc, aExporter.iExportDirCount, aImporter);
2553 TInt E32Image::GetCurrentImportList(const E32ImportBlock* a)
2555 __IF_DEBUG(Printf("E32Image::GetCurrentImportList(E32ImportBlock* a:%08X)", a));
2557 TInt n = a->iNumberOfImports;
2558 iCurrentImportCount = n;
2559 iCurrentImportListSorted = (TUint8)EFalse;
2560 __IF_DEBUG(Printf("iCurrentImportCount:%d, iCurrentImportListSorted:%d)", iCurrentImportCount, iCurrentImportListSorted));
2561 __IF_DEBUG(Printf("iHeader->ImportFormat() == KImageImpFmt_ELF:%d", (iHeader->ImportFormat() == KImageImpFmt_ELF) ));
2563 if (iHeader->ImportFormat() == KImageImpFmt_ELF)
2565 SGetImportDataInfo info;
2567 info.iDest = iCurrentImportList;
2568 info.iCodeLoadAddress = iCodeLoadAddress;
2569 info.iImportOffsetList = (TUint32*)a->Imports();
2570 r = ExecuteInSupervisorMode(&svElfDerivedGetImportInfo, &info);
2574 TUint32* iat = (TUint32*)(iCodeLoadAddress + iTextSize);
2575 WordCopy(iCurrentImportList, iat + iNextImportPos, n * sizeof(TUint32));
2578 iNextImportPos += n;
2579 __IF_DEBUG(Printf("End of E32Image::GetCurrentImportList:%d)", r));
2584 TInt E32Image::LastCurrentImport()
2587 if (iCurrentImportListSorted)
2588 last = iCurrentImportList[iCurrentImportCount - 1];
2591 const TUint32* p = iCurrentImportList;
2592 const TUint32* pE = p + iCurrentImportCount;
2594 if (*p > last) last = *p;
2596 __IF_DEBUG(Printf("E32Image::LastCurrentImport = %d", last));
2601 TInt E32Image::ProcessImports()
2603 // This function is only ever called on the exe/dll which is loaded from
2604 // the RProcess/RLibrary load.
2605 // It reads this DLL/EXE's imports section and builds up a table of dlls referenced.
2606 // It never goes recursive.
2609 __IF_DEBUG(Printf("E32Image::ProcessImports %S",&iFileName));
2610 __IF_DEBUG(Printf("DepCount=%d",iDepCount));
2612 if (iDepCount==0 || AlwaysLoaded())
2613 return KErrNone; // no imports
2616 fi.Set(iFileName, 0);
2618 fi.GetName(gLoadeePath, TFileNameInfo::EIncludeDrivePath);
2619 if (PlatSec::ConfigSetting(PlatSec::EPlatSecEnforceSysBin)
2620 && gLoadeePath.Length()==11
2621 && KSysBin().CompareF(TPtrC8(gLoadeePath.Ptr()+1,10))==0)
2623 // Main loadee is in the default path, so unset this in order to
2624 // search normally for dependents
2628 if (gLoadeePath.Length()>=2 && gLoadeePath[1]==':')
2630 TInt d = gLoadeePath[0];
2631 if (d=='a' || d=='A')
2632 UseFloppy = EDriveA;
2633 else if (d=='b' || d=='B')
2634 UseFloppy = EDriveB;
2638 TInt r = array.Add(this);
2640 r = LoadDlls(array);
2642 r = FixupDlls(array);
2644 r = FinaliseDlls(array);
2648 __IF_DEBUG(Printf("E32Image::ProcessImports returns %d",r));
2652 void E32Image::CleanupDlls(RImageArray& aArray)
2654 // Free the space used in fixing up the dlls.
2655 // Don't free the entry corresponding to the main loadee.
2659 __IF_DEBUG(Printf("CleanupDlls"));
2660 TInt n = aArray.Count();
2664 E32Image* e = aArray[i];
2670 TInt E32Image::FinaliseDlls(RImageArray& aArray)
2672 __IF_DEBUG(Printf("E32Image::FinaliseDlls"));
2674 TInt c = aArray.Count();
2676 for(i=0; i<c && r==KErrNone; i++)
2678 E32Image* e = aArray[i];
2679 if(e!=this && !e->iAlreadyLoaded)
2681 // transfers ownership of clamp handle to codeseg; nulls handle if successful
2682 if(!e->AlwaysLoaded())
2683 r = E32Loader::CodeSegLoaded(*e);
2684 if(r==KErrNone && e->iUseCodePaging)
2686 e->iFileClamp.iCookie[0]=0;// null handle to indicate
2687 e->iFileClamp.iCookie[1]=0;// transfer of ownership of clamp handle to codeseg
2691 __IF_DEBUG(Printf("E32Image::FinaliseDlls returns %d",r));
2696 TInt E32Image::LoadDlls(RImageArray& aArray)
2698 // Build a matrix of all DLLs referenced by the one we're loading, and
2699 // ensure they're all loaded.
2702 __IF_DEBUG(Printf("E32Image::LoadDlls"));
2704 E32ImportSection* importSection=(E32ImportSection *)iImportData;
2705 E32ImportBlock* block;
2707 block=(E32ImportBlock*)(importSection+1);
2710 const TRomImageHeader* const * pR=NULL;
2711 if (iRomImageHeader)
2712 pR=iRomImageHeader->iDllRefTable->iEntry;
2715 // For each module referenced by this module
2716 for (TInt i=0; i<iDepCount; ++i)
2718 RImageFinder finder;
2719 E32ImportBlock* thisBlock = block;
2720 E32Image* e = NULL; // will represent referenced module
2721 const TRomImageHeader* rih = NULL;
2722 RLdrReq req; // new loader request to load referenced module
2723 TBuf8<KMaxKernelName> rootname;
2724 req.iFileName = (HBufC8*)&rootname;
2728 // Processing imports for ROM XIP module
2730 __IF_DEBUG(Printf("Importing from ROM XIP %08x", rih));
2731 e = aArray.Find(rih);
2735 // Processing imports for RAM module
2736 __IF_DEBUG(Printf("Import block address %08x",block));
2737 TPtrC8 dllname = (const TText8*)((TUint32)iImportData + block->iOffsetOfDllName);
2738 if (dllname.Length() > KMaxKernelName)
2740 __IF_DEBUG(Printf("Import DLL name too big: %S",&dllname));
2741 RETURN_FAILURE(KErrNotSupported);
2744 r = fni.Set(dllname, TFileNameInfo::EAllowUid);
2746 RETURN_FAILURE(KErrCorrupt);
2747 fni.GetName(rootname, TFileNameInfo::EIncludeBaseExt);
2748 TUint32* uid=(TUint32*)&req.iRequestedUids;
2750 req.iRequestedVersion = fni.Version();
2751 if (gLoadeePath.Length() > 0)
2752 req.iPath = (HBufC8*)&gLoadeePath;
2753 req.iPlatSecCaps = iS.iCaps;
2754 req.iFileNameInfo.Set(rootname, 0);
2755 req.iImporter = this;
2756 r = GetCurrentImportList(block); // get list of required exports from this exporter
2761 TUint impfmt = iHeader->ImportFormat();
2762 block = (E32ImportBlock*)block->NextBlock(impfmt);
2764 r = finder.Set(req);
2766 r = finder.SearchExisting(aArray); // see what we've already got
2769 TBool search = ETrue;
2770 if (finder.iExisting)
2772 // Found an existing DLL - check for an exact version match
2773 if (DetailedCompareVersions(finder.iCurrentVersion, finder.iReq->iRequestedVersion) <= EVersion_Exact)
2774 search = EFalse; // if exact match, don't need to continue search
2777 r = finder.Search(); // see what else is available
2784 if (finder.iExisting)
2785 e = finder.iExisting; // already have the required module
2788 // If it's already in the array, go on to the next module
2791 __IF_DEBUG(Printf("Already there"));
2795 // Not already in the array
2796 __IF_DEBUG(Printf("Not in array, add it"));
2801 return KErrNoMemory;
2804 e->iClientProcessHandle = iMain->iClientProcessHandle;
2805 if (iMain->iAttr & ECodeSegAttKernel)
2806 e->iAttr |= ECodeSegAttKernel;
2809 // loading a specified ROM XIP DLL
2810 r = e->DoLoadCodeSeg(*rih);
2814 // loading a DLL by name
2815 r = e->DoLoadCodeSeg(req, finder); // also closes 'finder'
2816 __IF_DEBUG(Printf("%S DoLoadCodeSeg returned %d",req.iFileName,r));
2819 // Add the new entry to the array
2822 __IF_DEBUG(Printf("Add to the array"));
2831 // Now go nice and recursive, and call LoadDlls on this latest dll, if it
2833 // This recursive horror *will* terminate because it is only called
2835 if (e->iDepCount && !e->iAlreadyLoaded && e->iIsDll)
2837 __IF_DEBUG(Printf("****Go recursive****"));
2838 r = e->LoadDlls(aArray);
2847 // If we added an SMP unsafe dependent, this image is SMP unsafe.
2848 // This is done after recursing into LoadDlls, so a single unsafe
2849 // dependent anywhere down the tree will poison everything above it.
2850 // This isn't sufficient to deal with cycles, though, so the kernel
2851 // also has to update the flag in DCodeSeg::FinaliseRecursiveFlags.
2852 // It has to be done here first because the kernel doesn't know
2853 // about XIP DLLs that don't have a codeseg created.
2854 if (!(e->iAttr & ECodeSegAttSMPSafe))
2856 __IF_DEBUG(Printf("%S is not SMP safe because it loads %S", &iFileName, &e->iFileName));
2857 iAttr &= ~ECodeSegAttSMPSafe;
2860 // If exporter is an EXE it must be the same as the client process or newly created process
2861 __IF_DEBUG(Printf("Check EXE->EXE"));
2862 if (gExeCodeSeg && !e->iIsDll && e->iHandle!=gExeCodeSeg)
2863 return KErrNotSupported;
2865 // A globally-visible module may only link to other globally visible modules
2866 __IF_DEBUG(Printf("Check Global Attribute"));
2867 if ( (iAttr&ECodeSegAttGlobal) && !(e->iAttr&ECodeSegAttGlobal) )
2868 return KErrNotSupported;
2870 // A ram-loaded globally-visible module may only link to ROM XIP modules with no static data
2871 __IF_DEBUG(Printf("Check RAM Global"));
2872 if ( (iAttr&ECodeSegAttGlobal) && !iRomImageHeader && e->iHandle)
2873 return KErrNotSupported;
2876 thisBlock->iOffsetOfDllName=(TUint32)e; // For easy access when fixing up imports
2879 // Record the dependence of this on e
2880 r=E32Loader::CodeSegAddDependency(iHandle, e->iHandle);
2887 __IF_DEBUG(Printf("E32Image::LoadDlls OK"));
2892 TInt E32Image::ReadExportDirLoad()
2894 // Get the exporter's export directory
2895 __IF_DEBUG(Printf("ReadExportDirLoad exp_dir=%08x", iExportDirLoad));
2896 if (!iExportDirLoad)
2898 // already loaded nonglobal DLL - must read the export directory
2899 if (iExportDirCount==0 && !(iAttr&ECodeSegAttNmdExpData))
2900 return KErrGeneral; // DLL has no exports, something must be wrong
2901 iCopyOfExportDir = (TUint32*)User::Alloc((iExportDirCount+1) * sizeof(TUint32));
2902 if (!iCopyOfExportDir)
2903 return KErrNoMemory;
2904 __IF_DEBUG(Printf("Reading %d exports", iExportDirCount));
2905 E32Loader::ReadExportDir(iHandle, iCopyOfExportDir);
2906 iExportDirLoad = (TUint32)(iCopyOfExportDir+1);
2912 TInt E32Image::FixupDlls(RImageArray& aArray)
2914 // Go through the array, fixing up the files
2917 __IF_DEBUG(Printf("E32Image::FixupDlls"));
2919 // For each E32Image file in the array
2921 TInt c = aArray.Count();
2927 E32Image* imp = aArray[i];
2928 __IF_DEBUG(Printf("Dll number %d %S",i,&imp->iFileName));
2930 const E32ImportSection* importSection = (const E32ImportSection*)imp->iImportData;
2933 __IF_DEBUG(Printf("Has no imports to fixup"));
2934 continue; // No imports, skip this dll (true of ALL ROM dlls)
2937 const E32ImportBlock* block = (const E32ImportBlock*)(importSection + 1);
2939 SFixupImportAddressesInfo info;
2940 info.iIat = (TUint32*)(imp->iCodeLoadAddress + imp->iTextSize);
2941 info.iCodeLoadAddress = imp->iCodeLoadAddress;
2943 // fix up imports from each dependent DLL, building a table of all the imports for the binary
2944 TInt depCount = imp->iDepCount;
2947 // declare variables at start of loop body to prevent 'crosses initialization' errors
2950 // E32Image::LoadDlls() will have set iOffsetOfDllName of the
2951 // import block to point to the E32Image object of the exporter
2953 E32Image* exp = (E32Image*)(block->iOffsetOfDllName); // LoadDlls() set this to exporter
2955 // Get the exporter's export directory
2956 r = exp->ReadExportDirLoad();
2959 info.iExportDir = (TUint32*)exp->iExportDirLoad;
2960 info.iExportDirEntryDelta = exp->iExportDirEntryDelta;
2961 info.iNumImports = block->iNumberOfImports;
2962 info.iExporter = exp;
2964 // if demand paging, expand the import fixup buffer for this next exporting DLL
2965 if (! imp->iUseCodePaging)
2969 info.iFixup64 = imp->ExpandFixups(block->iNumberOfImports);
2971 return KErrNoMemory;
2974 // call function in supervisor mode to fix up the import addresses.
2975 impfmt = imp->iHeader->ImportFormat();
2976 if (impfmt == KImageImpFmt_ELF)
2978 info.iImportOffsetList = (TUint32*)(block+1);
2979 r = ExecuteInSupervisorMode(&svElfDerivedFixupImportAddresses, &info);
2982 r = ExecuteInSupervisorMode(&svFixupImportAddresses, &info);
2986 __IF_DEBUG(Printf("svFixupImportAddresses returns %d", r));
2990 // Next import block...
2991 block = block->NextBlock(impfmt);
2992 } // while (depCount--)
2994 if (imp->iUseCodePaging && imp->iFixupCount > 0)
2996 // convert the <addr,val> pairs to an import fixup tab which can be used when
2997 // the code is paged.
2998 r = imp->BuildImportFixupTable();
3004 __IF_DEBUG(Printf("E32Image::FixupDlls OK"));
3010 This function is defined because RArray does not natively support
3011 sorting 64-bit integers.
3013 It is used by FixupDlls to order the import fixup locations in the image
3014 so they can be organized by page.
3016 @param aLeft 64-bit unsigned integer to compare against aRight.
3017 @param aRight 64-bit unsigned integer to compare against aLeft.
3018 @return -1 if aLeft < aRight; 0 if aLeft == aRight; and
3019 +1 if aLeft > aRight. This conforms to the behavior
3020 which is expected from a function used by TLinearOrder.
3022 static TInt Uint64LinearOrderFunc(const TUint64& aLeft, const TUint64& aRight)
3026 else if (aLeft > aRight)
3033 TUint64* E32Image::ExpandFixups(TInt aNumFixups)
3035 __IF_DEBUG(Printf("ExpandFixups,%d+%d", iFixupCount,aNumFixups));
3036 TInt newCount = iFixupCount+aNumFixups;
3037 TUint64* fixups = (TUint64*) User::ReAlloc(iFixups, sizeof(TUint64) * newCount);
3040 TUint64* newFixups = fixups+iFixupCount;
3041 iFixupCount = newCount;
3048 Helper function for FixupImports. Takes the set of
3049 64-bit <addr,val> fixups, and organizes them into pages.
3051 Each page is stored as fXXX YYYY ZZZZ where YYYY ZZZZ is written
3052 to the word at offset XXX. (See PREQ1110 Design Sketch v1.0 S3.1.1.2.3.2.)
3054 On success iImportFixupTableSize is set to the table size in bytes,
3055 and iImportFixupTable is a cell containing the table.
3057 @return Symbian OS error code.
3059 TInt E32Image::BuildImportFixupTable()
3061 __IF_DEBUG(Printf(">BuildImportFixupTable,0x%08x,%d", iFixups, iFixupCount));
3063 // sort the array in address order, to organize by page
3064 RArray<TUint64> fixup64ToSort(sizeof(TUint64), iFixups, iFixupCount);
3065 // SortUnsigned doesn't work on TUint64
3066 fixup64ToSort.Sort(TLinearOrder<TUint64>(Uint64LinearOrderFunc));
3068 // now have <address | new-value> pairs, organize into pages.
3069 // Each page is stored as fXXX YYYY ZZZZ where YYYY ZZZZ is written
3070 // to the word at offset XXX. (See PREQ1110 Design Sketch v1.0 S3.1.1.2.3.2.)
3072 TUint32 pageCount = SizeToPageCount(iCodeSize);
3073 iImportFixupTableSize = (pageCount+1) * sizeof(TUint32) + iFixupCount * 3 * sizeof(TUint16);
3074 iImportFixupTable = (TUint32*) User::Alloc(iImportFixupTableSize);
3075 __IF_DEBUG(Printf("iImportFixupTable=0x%08x", iImportFixupTable));
3076 if (iImportFixupTable == 0)
3077 return KErrNoMemory;
3079 // byte offsets of pages into the table are written as 32-bit words at
3080 // the start of the table
3082 TUint32 lastPage = 0;
3083 // byte index of first 48-bit entry in the table, after sentinel index
3084 iImportFixupTable[0] = (pageCount + 1) * sizeof(TUint32);;
3086 // location to which 48-bit imports are written
3087 TUint16* importOffset = (TUint16*)(iImportFixupTable + pageCount + 1);
3089 // location from where 64-bit <addr,val> pairs are read
3090 const TUint64* avEnd = iFixups + iFixupCount;
3092 for (const TUint64* avPtr = iFixups; avPtr < avEnd; ++avPtr)
3094 TUint64 addr_val = *avPtr;
3095 TUint32 addr = I64HIGH(addr_val) - iCodeLoadAddress;
3096 TUint32 page = addr >> 12;
3097 if (page > lastPage)
3099 // calculate new start index for current page
3100 TUint32 newStart = TUint32(importOffset) - TUint32(iImportFixupTable);
3102 __IF_DEBUG(Printf("page=%d, lastPage=%d, newStart=0x%08x", page, lastPage, newStart));
3104 // mark intermediate pages as zero-length, starting and ending at
3106 while (++lastPage <= page)
3107 iImportFixupTable[lastPage] = newStart;
3111 TUint16 offsetIntoPage;
3112 offsetIntoPage = (addr & KPageOffsetMask);
3113 *importOffset++ = offsetIntoPage;
3115 TUint32 val = I64LOW(addr_val);
3116 *importOffset++ = val; // low halfword stored first (YYYY)
3117 *importOffset++ = val >> 16; // high halfword stored second (ZZZZ)
3120 // sentinel value marks end of table
3121 while (++lastPage <= pageCount)
3122 iImportFixupTable[lastPage] = iImportFixupTableSize;
3124 __IF_DEBUG(Printf("processed table (size=%d,pageCount=%d)", iImportFixupTableSize, pageCount));
3127 // dump the import fixup table if loader tracing enabled
3128 const TUint16* table16 = (const TUint16*)iImportFixupTable;
3129 const TInt halfWordsInTable = iImportFixupTableSize / 2;
3130 for (TInt i = 0; i < halfWordsInTable; i += 4)
3133 "%04x: %04x %04x %04x %04x",
3134 i * 2, table16[i+0], table16[i+1], table16[i+2], table16[i+3]));
3138 User::Free(iFixups);
3144 TInt GetModuleInfo(RLdrReq& aReq)
3146 // Read capabilities from file found
3149 __IF_DEBUG(Printf("ReadModuleInfo %S",aReq.iFileName));
3150 TFileNameInfo& fi = aReq.iFileNameInfo;
3151 RImageFinder finder;
3152 TInt r = finder.Set(aReq);
3155 finder.iFindExact = ETrue;
3157 r = KErrNotSupported;
3159 // must specify a fully qualified name
3160 if (fi.DriveLen() && fi.PathLen())
3163 aReq.iRequestedVersion = fi.iVersion;
3165 aReq.iRequestedVersion = KModuleVersionWild;
3166 r = finder.Search();
3169 RLibrary::TInfo ret_info;
3170 memclr(&ret_info,sizeof(ret_info));
3171 ret_info.iModuleVersion = finder.iNew.iModuleVersion;
3172 ret_info.iUids = *(const TUidType*)finder.iNew.iUid;
3173 *(SSecurityInfo*)&ret_info.iSecurityInfo = finder.iNew.iS;
3174 TPckgC<RLibrary::TInfo> ret_pckg(ret_info);
3175 r = aReq.iMsg->Write(2, ret_pckg);
3183 TInt GetInfoFromHeader(const RLoaderMsg& aMsg)
3187 // Get size of header supplied by client
3189 size = aMsg.GetDesLength(0);
3192 if(size>RLibrary::KRequiredImageHeaderSize)
3193 size = RLibrary::KRequiredImageHeaderSize;
3194 if((TUint)size<sizeof(E32ImageHeaderV))
3195 return KErrUnderflow;
3198 TUint8* data = new TUint8[size];
3200 return KErrNoMemory;
3201 TPtr8 ptr(data,size);
3202 r = aMsg.Read(0,ptr);
3205 // Check header is valid
3206 E32ImageHeaderV* header=(E32ImageHeaderV*)data;
3207 if(header->TotalSize()>size)
3211 TUint32 uncompressedSize;
3212 r = header->ValidateHeader(-1,uncompressedSize);
3217 RLibrary::TInfoV2 ret_info;
3218 memclr(&ret_info,sizeof(ret_info));
3219 ret_info.iModuleVersion = header->ModuleVersion();
3220 ret_info.iUids = (TUidType&)header->iUid1;
3221 header->GetSecurityInfo((SSecurityInfo&)ret_info.iSecurityInfo);
3222 ret_info.iHardwareFloatingPoint = (header->iFlags & KImageHWFloatMask) >> KImageHWFloatShift;
3224 ret_info.iDebugAttributes = 0; // default
3225 if (header->iFlags & KImageDebuggable)
3226 ret_info.iDebugAttributes |= RLibrary::TInfoV2::EDebugAllowed;
3228 TPckg<RLibrary::TInfoV2> ret_pckg(ret_info);
3229 TInt max = aMsg.GetDesMaxLength(1);
3230 if (ret_pckg.Length() > max)
3231 ret_pckg.SetLength(max);
3232 r = aMsg.Write(1, ret_pckg);
3240 #if defined(_DEBUG) || defined(_DEBUG_RELEASE)
3241 void memory_dump(const TAny* a, TUint l)
3244 const TUint8* s = (const TUint8*)a;
3249 buf.AppendNumFixedWidth(*s++, EHex, 2);
3254 RDebug::Printf((const char*)buf.PtrZ());
3261 void RImageFinder::Dump(const char* aTitle, TInt aR)
3263 RDebug::Printf(aTitle);
3264 RDebug::Printf("r=%d",aR);
3267 RDebug::Printf("Existing image found");
3268 RDebug::Printf("Filename=%S Attr=%08x", &iExisting->iFileName, iExisting->iAttr);
3269 RDebug::Printf("SID %08x Caps %08x %08x", iExisting->iS.iSecureId, iExisting->iS.iCaps[1], iExisting->iS.iCaps[0]);
3270 const TUint32* uid = (const TUint32*)&iExisting->iUids;
3271 RDebug::Printf("UIDs %08x %08x %08x VER %08x", uid[0], uid[1], uid[2], iExisting->iModuleVersion);
3272 RDebug::Printf("Rom %08x", iExisting->iRomImageHeader);
3276 RDebug::Printf("New image found");
3277 RDebug::Printf("Filename=%S Attr=%08x", &iNewFileName, iNew.iAttr);
3278 RDebug::Printf("SID %08x Caps %08x %08x", iNew.iS.iSecureId, iNew.iS.iCaps[1], iNew.iS.iCaps[0]);
3279 const TUint32* uid = (const TUint32*)iNew.iUid;
3280 RDebug::Printf("UIDs %08x %08x %08x VER %08x", uid[0], uid[1], uid[2], iNew.iModuleVersion);
3281 RDebug::Printf("Rom %08x", iNew.iRomImageHeader);
3285 RDebug::Printf("No suitable image found");
3286 RDebug::Printf("#NM=%d #UidFail=%d #CapFail=%d #MajVFail=%d #ImpFail=%d", iNameMatches, iUidFail, iCapFail, iMajorVersionFail, iImportFail);
3290 void DumpImageHeader(const E32ImageHeader* a)
3292 RDebug::Printf("E32ImageHeader at %08x :", a);
3293 TUint abi = a->ABI();
3294 TUint hdrfmt = a->HeaderFormat();
3295 TUint impfmt = a->ImportFormat();
3296 TUint eptfmt = a->EntryPointFormat();
3297 RDebug::Printf("Header format %d", hdrfmt>>KImageHdrFmtShift);
3298 RDebug::Printf("Import format %d", impfmt>>KImageImpFmtShift);
3299 RDebug::Printf("EntryPoint format %d", eptfmt>>KImageEptShift);
3300 RDebug::Printf("ABI %d", abi>>KImageABIShift);
3301 RDebug::Printf("UIDs %08x %08x %08x (%08x)", a->iUid1, a->iUid2, a->iUid3, a->iUidChecksum);
3302 RDebug::Printf("Header CRC %08x", a->iHeaderCrc);
3303 RDebug::Printf("Signature %08x", a->iSignature);
3304 RDebug::Printf("CPU %08x", (TUint)a->CpuIdentifier());
3305 RDebug::Printf("ModuleVersion %08x", a->ModuleVersion());
3306 RDebug::Printf("Compression Type %08x", a->CompressionType());
3307 RDebug::Printf("Tools Version %d.%02d(%d)", a->iToolsVersion.iMajor, a->iToolsVersion.iMinor, a->iToolsVersion.iBuild);
3308 RDebug::Printf("Flags %08x", a->iFlags);
3309 RDebug::Printf("Code Size %08x", a->iCodeSize);
3310 RDebug::Printf("Text Size %08x", a->iTextSize);
3311 RDebug::Printf("Data Size %08x", a->iDataSize);
3312 RDebug::Printf("BSS Size %08x", a->iBssSize);
3313 RDebug::Printf("Stack Size %08x", a->iStackSize);
3314 RDebug::Printf("HeapSizeMin %08x", a->iHeapSizeMin);
3315 RDebug::Printf("HeapSizeMax %08x", a->iHeapSizeMax);
3316 RDebug::Printf("iEntryPoint %08x", a->iEntryPoint);
3317 RDebug::Printf("iCodeBase %08x", a->iCodeBase);
3318 RDebug::Printf("iDataBase %08x", a->iDataBase);
3319 RDebug::Printf("DLL Ref Table Count %d", a->iDllRefTableCount);
3320 RDebug::Printf("Export Dir Count %d", a->iExportDirCount);
3321 RDebug::Printf("Code Offset %08x", a->iCodeOffset);
3322 RDebug::Printf("Data Offset %08x", a->iDataOffset);
3323 RDebug::Printf("Code Reloc Offset %08x", a->iCodeRelocOffset);
3324 RDebug::Printf("Data Reloc Offset %08x", a->iDataRelocOffset);
3325 RDebug::Printf("Import Offset %08x", a->iImportOffset);
3326 RDebug::Printf("Export Dir Offset %08x", a->iExportDirOffset);
3327 RDebug::Printf("Priority %d", (TUint)a->ProcessPriority());
3329 RDebug::Printf("iUncompressedSize %08x", ((E32ImageHeaderComp*)a)->iUncompressedSize);
3331 E32ImageHeaderV* v = (E32ImageHeaderV*)a;
3332 RDebug::Printf("SID %08x VID %08x CAP %08x %08x", v->iS.iSecureId, v->iS.iVendorId, v->iS.iCaps[1], v->iS.iCaps[0]);
3333 RDebug::Printf("iExportDescType %02x", v->iExportDescType);
3334 RDebug::Printf("iExportDescSize %04x", v->iExportDescSize);
3335 if (v->iExportDescSize)
3336 memory_dump(v->iExportDesc, v->iExportDescSize);