os/kernelhwsrv/userlibandfileserver/fileserver/sfile/sf_lepoc.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of the License "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
// f32\sfile\sf_lepoc.cpp
sl@0
    15
// 
sl@0
    16
//
sl@0
    17
sl@0
    18
#include "sf_std.h"
sl@0
    19
sl@0
    20
#include <e32std.h>
sl@0
    21
#include <e32std_private.h>
sl@0
    22
#include <e32base.h>
sl@0
    23
#include <e32base_private.h>
sl@0
    24
#include <e32math.h>
sl@0
    25
#include <e32svr.h>
sl@0
    26
#include <e32ver.h>
sl@0
    27
#include <e32hal.h>
sl@0
    28
#include <u32exec.h>
sl@0
    29
#define INCLUDE_E32IMAGEHEADER_IMPLEMENTATION
sl@0
    30
#include "sf_ldr.h"
sl@0
    31
#include <f32image.h>
sl@0
    32
#include "sf_image.h"
sl@0
    33
#include <e32uid.h>
sl@0
    34
#include <e32rom.h>
sl@0
    35
#include "sf_cache.h"
sl@0
    36
sl@0
    37
#include "sf_pgcompr.h"
sl@0
    38
sl@0
    39
_LIT(KLitFinderInconsistent, "LDR-FINDER-INC");
sl@0
    40
_LIT(KLitSysBinError, "LDR-SYS\\BIN ERR");
sl@0
    41
_LIT8(KSysBin,":\\sys\\bin\\");
sl@0
    42
sl@0
    43
#ifdef _DEBUG
sl@0
    44
sl@0
    45
enum TLdrEpocPanic
sl@0
    46
	{
sl@0
    47
	EFuaiNoFixupTable = 0x10,
sl@0
    48
	EBcbmNotCodePaged = 0x20,
sl@0
    49
	ELfiCodePagingNotSupported = 0x30,
sl@0
    50
	EFprUnexpectedFixup = 0x40,
sl@0
    51
	};
sl@0
    52
sl@0
    53
static void Panic(TLdrEpocPanic aPanic)
sl@0
    54
	{
sl@0
    55
	_LIT(KPanicCat, "LDR-PNC");
sl@0
    56
	User::Panic(KPanicCat, aPanic);
sl@0
    57
	}
sl@0
    58
sl@0
    59
extern TRequestStatus* ProcessDestructStatPtr;
sl@0
    60
extern TBool ProcessCreated;
sl@0
    61
sl@0
    62
#endif
sl@0
    63
sl@0
    64
extern void DumpImageHeader(const E32ImageHeader*);
sl@0
    65
extern TDriveCacheHeader* gDriveFileNamesCache[];
sl@0
    66
sl@0
    67
TBuf8<KMaxPath> gLoadeePath;
sl@0
    68
TUint NextCodeSegId;
sl@0
    69
sl@0
    70
const TInt KMaxHeaderSize = sizeof(E32ImageHeaderV) + 65536/8;
sl@0
    71
sl@0
    72
sl@0
    73
#ifdef __X86__
sl@0
    74
extern TInt UseFloppy;
sl@0
    75
#endif
sl@0
    76
sl@0
    77
sl@0
    78
sl@0
    79
// -------- demand paging --------
sl@0
    80
sl@0
    81
/** Page size as a power of two. */
sl@0
    82
const TUint32 KPageSizeShift = 12;
sl@0
    83
/** Page size, as defined for code relocations.  This same page size is used for demand paging. */
sl@0
    84
const TUint32 KPageSize = 1<<KPageSizeShift;
sl@0
    85
/** Apply this mask to an address to get the page offset. */
sl@0
    86
const TUint32 KPageOffsetMask = KPageSize - 1;
sl@0
    87
sl@0
    88
/**
sl@0
    89
Calculate the number of pages required to contain the supplied number of bytes.
sl@0
    90
sl@0
    91
@param	aSizeInBytes	Size of are which has to be contained in whole blocks.
sl@0
    92
@return					Number of KPageSize pages required to contain area.
sl@0
    93
*/
sl@0
    94
inline TInt SizeToPageCount(TInt aSizeInBytes)
sl@0
    95
	{
sl@0
    96
	return (aSizeInBytes + KPageOffsetMask) >> KPageSizeShift;
sl@0
    97
	}
sl@0
    98
sl@0
    99
sl@0
   100
/**
sl@0
   101
Allocate a block which indexes the reallocations by page.  This can be used for demand paging.
sl@0
   102
sl@0
   103
@param	aSection			Pointer to relocation section to process.
sl@0
   104
@param	aAreaSize			Size in bytes of area described by reloc section.
sl@0
   105
@param  aLoadAddress		Address of relocation section in memory
sl@0
   106
@param	aProcessedBlock		On success (return == KErrNone) this is set to the processed
sl@0
   107
							relocation section which is allocated on the current thread's heap.
sl@0
   108
							The caller takes ownership.  The contents are undefined on failure.
sl@0
   109
@return						KErrNoMemory if could not allocate memory for processed block
sl@0
   110
							and auxiliary structures; KErrNone otherwise.
sl@0
   111
 */
sl@0
   112
TInt E32Image::AllocateRelocationData(E32RelocSection* aSection, TUint32 aAreaSize, TUint32 aLoadAddress, TUint32*& aProcessedBlock)
sl@0
   113
	{
sl@0
   114
	__IF_DEBUG(Printf("AllocateRelocationData"));
sl@0
   115
sl@0
   116
	TUint32 sectionSize = aSection->iSize;
sl@0
   117
	TUint32 numRelocs = aSection->iNumberOfRelocs;
sl@0
   118
	TInt pageCount = SizeToPageCount(aAreaSize);
sl@0
   119
sl@0
   120
	// The file format documentation (SOSI ch10) does not guarantee that each page has
sl@0
   121
	// relocation information, or that the pages are listed in order, so store them in
sl@0
   122
	// page order here.
sl@0
   123
	
sl@0
   124
	TUint8** subBlocks = (TUint8**)User::AllocZ(sizeof(TUint8*)*pageCount);
sl@0
   125
	if(subBlocks == 0)
sl@0
   126
		return KErrNoMemory;
sl@0
   127
sl@0
   128
	const TUint8* subBlockPtr = (TUint8*)(aSection+1);
sl@0
   129
	while(sectionSize > 0)
sl@0
   130
		{
sl@0
   131
		TUint32 pageOffset = *(TUint32*)(subBlockPtr);
sl@0
   132
		TUint32 subBlockSize = *(TUint32*)(subBlockPtr+4);
sl@0
   133
sl@0
   134
		subBlocks[pageOffset >> KPageSizeShift] = (TUint8*)subBlockPtr;
sl@0
   135
		
sl@0
   136
		sectionSize -= subBlockSize;
sl@0
   137
		subBlockPtr += subBlockSize;	// move to next sub-block
sl@0
   138
		}
sl@0
   139
sl@0
   140
	// now have each relocation page in memory, build lookup table	
sl@0
   141
	TUint32 indexSize = (pageCount + 1) * sizeof(TUint32);	// include sentinel
sl@0
   142
	TUint32 totalRelocations = numRelocs;
sl@0
   143
	iCodeRelocTableSize = indexSize + totalRelocations * sizeof(TUint16);
sl@0
   144
	TUint8* table = (TUint8*) User::Alloc(iCodeRelocTableSize);
sl@0
   145
sl@0
   146
	if(table == 0)
sl@0
   147
		{
sl@0
   148
		User::Free(subBlocks);
sl@0
   149
		return KErrNoMemory;
sl@0
   150
		}
sl@0
   151
sl@0
   152
	// where sub-block positions are written to in the table
sl@0
   153
	TUint32* destSubBlock = (TUint32*)table;
sl@0
   154
	// where entries are written to in the table
sl@0
   155
	TUint16* destEntry = (TUint16*)(table + indexSize);
sl@0
   156
sl@0
   157
	TInt i;
sl@0
   158
	for(i = 0; i < pageCount; ++i)
sl@0
   159
		{
sl@0
   160
		*destSubBlock++ = TUint32(destEntry) - TUint32(table);
sl@0
   161
		
sl@0
   162
		// see if a relocation page was defined for this page
sl@0
   163
		const TUint8* subBlock = subBlocks[i];
sl@0
   164
		if(subBlock == 0)
sl@0
   165
			continue;
sl@0
   166
		
sl@0
   167
		// get number of entries in this sub-block, including padding
sl@0
   168
		TUint32 sbEntryCount;
sl@0
   169
		TUint32 pageOffset = *(TUint32*)subBlock;	// offset of page from start of section
sl@0
   170
		sbEntryCount = *(TUint32*)(subBlock + 4);	// sub-block size
sl@0
   171
		sbEntryCount -= 8;							// exclude sub-block header
sl@0
   172
		sbEntryCount /= 2;							// each entry is two bytes
sl@0
   173
		const TUint16* srcEntry = (TUint16*)(subBlock + 8);
sl@0
   174
		 
sl@0
   175
		while(sbEntryCount--)
sl@0
   176
			{
sl@0
   177
			TUint16 entry = *srcEntry++;
sl@0
   178
			if(entry==0)		// ignore null padding values
sl@0
   179
				continue;
sl@0
   180
sl@0
   181
			// Replace inferred fixup type with actual fixup type
sl@0
   182
			TUint type = entry & 0xf000;
sl@0
   183
			if(type==KInferredRelocType)
sl@0
   184
				{
sl@0
   185
				TUint32* ptr = (TUint32*)(aLoadAddress + pageOffset + (entry & 0x0fff));
sl@0
   186
				TUint32 word = *ptr;
sl@0
   187
				type = (TUint(word - iHeader->iCodeBase) < TUint(iHeader->iCodeSize)) ? KTextRelocType : KDataRelocType;
sl@0
   188
				entry = (entry & 0x0fff) | type;
sl@0
   189
				}
sl@0
   190
			
sl@0
   191
			*destEntry++ = entry;
sl@0
   192
			}
sl@0
   193
		}
sl@0
   194
	
sl@0
   195
	// sentinel entry marks the byte following last sub-block in table
sl@0
   196
	// This gives the size of the last processed sub-block.
sl@0
   197
	*destSubBlock = TUint32(destEntry) - TUint32(table);
sl@0
   198
sl@0
   199
	aProcessedBlock = (TUint32*) table;
sl@0
   200
	User::Free(subBlocks);
sl@0
   201
sl@0
   202
#ifdef _DEBUG
sl@0
   203
	__IF_DEBUG(Printf("processed reloc table (size=%d,pageCount=%d)", iCodeRelocTableSize, pageCount));
sl@0
   204
sl@0
   205
	// dump the import fixup table if loader tracing enabled
sl@0
   206
	const TUint16* table16 = (const TUint16*)table;
sl@0
   207
	const TInt halfWordsInTable = iCodeRelocTableSize / 2;
sl@0
   208
	for(i = 0; i < halfWordsInTable; i += 4)
sl@0
   209
		{
sl@0
   210
		__IF_DEBUG(Printf(
sl@0
   211
			"reloc %04x: %04x %04x %04x %04x",
sl@0
   212
			i * 2, table16[i+0], table16[i+1], table16[i+2], table16[i+3]));
sl@0
   213
		}
sl@0
   214
#endif
sl@0
   215
	return KErrNone;
sl@0
   216
	}
sl@0
   217
sl@0
   218
sl@0
   219
/*******************************************************************************
sl@0
   220
 * These functions run in supervisor mode since they require access to the
sl@0
   221
 * chunks of the newly-created process or DLL while they are still in the
sl@0
   222
 * home section.
sl@0
   223
 ******************************************************************************/
sl@0
   224
sl@0
   225
/**
sl@0
   226
Vector which ::ExecuteInSupervisorMode invokes.
sl@0
   227
*/
sl@0
   228
TInt (*ExecuteInSupervisorModeVector)(TSupervisorFunction, TAny*);
sl@0
   229
sl@0
   230
/**
sl@0
   231
Executute aFunction in supervisor mode (if the memory model requires this.)
sl@0
   232
*/
sl@0
   233
TInt ExecuteInSupervisorMode(TSupervisorFunction aFunction, TAny* aParameter)
sl@0
   234
	{
sl@0
   235
	return(*ExecuteInSupervisorModeVector)(aFunction, aParameter);
sl@0
   236
	}
sl@0
   237
sl@0
   238
/**
sl@0
   239
Implementation of ::ExecuteInSupervisorMode which actually executes the
sl@0
   240
function in user mode.
sl@0
   241
*/
sl@0
   242
TInt UserModeExecuteInSupervisorMode(TSupervisorFunction aFunction, TAny* aParameter)
sl@0
   243
	{
sl@0
   244
	return (*aFunction)(aParameter);
sl@0
   245
	}
sl@0
   246
sl@0
   247
/**
sl@0
   248
Decide whether any Loader code actually needs to execute in supervisor mode
sl@0
   249
and set ::ExecuteInSupervisorModeVector so that invocations of ::ExecuteInSupervisorMode
sl@0
   250
call the appropriate function.
sl@0
   251
*/
sl@0
   252
void InitExecuteInSupervisorMode()
sl@0
   253
	{
sl@0
   254
	// work out if we need to really 'execute in supervisor mode'...
sl@0
   255
	TUint32 memModelAttrs = (TUint32)UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL);
sl@0
   256
	TUint32 memModel = memModelAttrs & EMemModelTypeMask;
sl@0
   257
	if(memModel==EMemModelTypeFlexible)
sl@0
   258
		{
sl@0
   259
		// we can do everything user side...
sl@0
   260
		ExecuteInSupervisorModeVector = UserModeExecuteInSupervisorMode;
sl@0
   261
		gExecutesInSupervisorMode = EFalse;
sl@0
   262
		}
sl@0
   263
	else
sl@0
   264
		{
sl@0
   265
		// we need to go kernel side...
sl@0
   266
		ExecuteInSupervisorModeVector = UserSvr::ExecuteInSupervisorMode;
sl@0
   267
		gExecutesInSupervisorMode = ETrue;
sl@0
   268
		}
sl@0
   269
	}
sl@0
   270
sl@0
   271
sl@0
   272
/**
sl@0
   273
Arguments for svRelocateSection.
sl@0
   274
sl@0
   275
The relocation information (at iRelocsBuf) has list sub blocks, each referring to a 4kB
sl@0
   276
page within the section. See E32RelocBlock.
sl@0
   277
*/
sl@0
   278
struct SRelocateSectionInfo
sl@0
   279
	{
sl@0
   280
	E32Image* iImage;		///< The executable being relocated.
sl@0
   281
	TUint8* iRelocsBuf;		///< Pointer to relocation info.
sl@0
   282
	TUint32 iNumRelocs;		///< Total number of relocations to apply.
sl@0
   283
	TUint32 iLoadAddress; 	///< Virtual address where section is currently located in memory.
sl@0
   284
	};
sl@0
   285
sl@0
   286
/**
sl@0
   287
Apply relocations to a code or data section.
sl@0
   288
sl@0
   289
@param aPtr Pointer to SRelocateSectionInfo.
sl@0
   290
*/
sl@0
   291
TInt svRelocateSection(TAny* aPtr)
sl@0
   292
	{
sl@0
   293
	SRelocateSectionInfo& info=*(SRelocateSectionInfo*)aPtr;
sl@0
   294
sl@0
   295
	E32Image& img = *(E32Image*)info.iImage;
sl@0
   296
	TUint8* relocs = info.iRelocsBuf;
sl@0
   297
	TUint32 numRelocs = info.iNumRelocs;
sl@0
   298
	TUint32 loadAddress = info.iLoadAddress;
sl@0
   299
sl@0
   300
	TUint32 codeStart = img.iHeader->iCodeBase;
sl@0
   301
	TUint32 codeFinish = codeStart+img.iHeader->iCodeSize;
sl@0
   302
	TUint32 codeDelta = img.iCodeDelta;
sl@0
   303
	TUint32 dataDelta = img.iDataDelta;
sl@0
   304
sl@0
   305
	while(numRelocs>0)
sl@0
   306
		{
sl@0
   307
		TUint32 pageAddress = ((TUint32*)relocs)[0];
sl@0
   308
		TUint32 pageSize = ((TUint32*)relocs)[1];
sl@0
   309
		TUint8* relocsEnd = relocs+pageSize;
sl@0
   310
		relocs += 8;
sl@0
   311
sl@0
   312
		while(relocs<relocsEnd)
sl@0
   313
			{
sl@0
   314
			TUint16 relocOffset = *(TUint16*)relocs;
sl@0
   315
			relocs += 2;
sl@0
   316
			if(!relocOffset)
sl@0
   317
				continue;
sl@0
   318
sl@0
   319
			TUint32 offset = pageAddress+(TUint32)(relocOffset&0x0fff);
sl@0
   320
			TUint32* destPtr = (TUint32*)(loadAddress+offset);
sl@0
   321
			TUint16 relocType = relocOffset&0xf000;
sl@0
   322
sl@0
   323
			TUint32 relocAddr = *destPtr;
sl@0
   324
			if(relocType==KTextRelocType)
sl@0
   325
				relocAddr += codeDelta; // points to text/rdata section
sl@0
   326
			else if(relocType==KDataRelocType)
sl@0
   327
				relocAddr += dataDelta; // points to data section
sl@0
   328
			else if (relocAddr>=codeStart && relocAddr<codeFinish)
sl@0
   329
				relocAddr += codeDelta; // points to text/rdata section
sl@0
   330
			else
sl@0
   331
				relocAddr += dataDelta; // points to data section
sl@0
   332
			*destPtr = relocAddr;
sl@0
   333
sl@0
   334
			--numRelocs;
sl@0
   335
			}
sl@0
   336
		}
sl@0
   337
	return 0;
sl@0
   338
	}
sl@0
   339
sl@0
   340
sl@0
   341
/**
sl@0
   342
Fix up the export directory
sl@0
   343
Only performed on PE images.  ELF image's exports are marked
sl@0
   344
as relocatable and therefore relocated by svRelocateSection when the 
sl@0
   345
text section is relocated up
sl@0
   346
*/
sl@0
   347
TInt svRelocateExports(TAny* aPtr)
sl@0
   348
	{
sl@0
   349
	E32Image* pI=(E32Image*)aPtr;
sl@0
   350
	TUint32* destExport=(TUint32*)pI->iExportDirLoad;
sl@0
   351
	TInt i=pI->iExportDirCount;
sl@0
   352
	TUint32 codeBase=pI->iCodeRunAddress;
sl@0
   353
	while (i-->0)
sl@0
   354
		*destExport+++=codeBase;
sl@0
   355
	return 0;
sl@0
   356
	}
sl@0
   357
sl@0
   358
sl@0
   359
struct SFixupImportAddressesInfo
sl@0
   360
	{
sl@0
   361
	TUint32* iIat;
sl@0
   362
	TUint32* iExportDir;
sl@0
   363
	TUint32 iExportDirEntryDelta;
sl@0
   364
	TInt iNumImports;
sl@0
   365
	E32Image* iExporter;
sl@0
   366
	/**
sl@0
   367
	For demand paging, this points to the buffer which is populated
sl@0
   368
	so each page can be fixed up as it is loaded in.
sl@0
   369
	*/
sl@0
   370
	TUint64* iFixup64;
sl@0
   371
	// For ElfDerived...
sl@0
   372
	TUint32 iCodeLoadAddress;
sl@0
   373
	TUint32* iImportOffsetList;
sl@0
   374
	};
sl@0
   375
sl@0
   376
sl@0
   377
/**
sl@0
   378
Fix up the import address table, used for 'PE derived' executables.
sl@0
   379
@param aPtr Pointer to function arguments (SFixupImportAddressesInfo structure).
sl@0
   380
			SFixupImportAddressesInfo::iIat is updated by this function.
sl@0
   381
*/
sl@0
   382
TInt svFixupImportAddresses(TAny* aPtr)
sl@0
   383
	{
sl@0
   384
	SFixupImportAddressesInfo& info = *(SFixupImportAddressesInfo*)aPtr;
sl@0
   385
sl@0
   386
	TUint32 maxOrdinal = (TUint32)info.iExporter->iExportDirCount;
sl@0
   387
	TUint32 absentOrdinal = (TUint32)info.iExporter->iFileEntryPoint;
sl@0
   388
sl@0
   389
	TUint32* exp_dir = info.iExportDir - KOrdinalBase; // address of 0th ordinal
sl@0
   390
	TUint32 exp_delta = info.iExportDirEntryDelta;
sl@0
   391
sl@0
   392
	TUint32* iat = info.iIat;
sl@0
   393
	TUint32* iatE = iat+info.iNumImports;
sl@0
   394
	for(; iat<iatE; ++iat)
sl@0
   395
		{
sl@0
   396
		TUint32 imp = *iat;
sl@0
   397
		if(imp>maxOrdinal)
sl@0
   398
			return KErrNotSupported;
sl@0
   399
sl@0
   400
		TUint32 writeValue;
sl@0
   401
		if(imp==0 && !(info.iExporter->iAttr&ECodeSegAttNmdExpData))
sl@0
   402
			{
sl@0
   403
			// attempt to import ordinal zero (symbol name data) from an executable
sl@0
   404
			// which doesn't export this information, use NULL for imported value in this case...
sl@0
   405
			writeValue = NULL;
sl@0
   406
			}
sl@0
   407
		else
sl@0
   408
			{
sl@0
   409
			// get imported value from exporter...
sl@0
   410
			TUint32 exp_addr = exp_dir[imp];
sl@0
   411
			if(exp_addr==0 || exp_addr==absentOrdinal)
sl@0
   412
				return KErrNotSupported;
sl@0
   413
			writeValue = exp_addr + exp_delta;
sl@0
   414
			}
sl@0
   415
sl@0
   416
		// if not code paging then directly fix up the import...
sl@0
   417
		if (info.iFixup64 == 0)
sl@0
   418
			*iat = writeValue;
sl@0
   419
		else
sl@0
   420
		// ...otherwise defer until the page is fixed up
sl@0
   421
			{
sl@0
   422
			TUint64 iat64 = reinterpret_cast<TUint64>(iat);
sl@0
   423
			*info.iFixup64++ = (iat64 << 32) | writeValue;
sl@0
   424
			}
sl@0
   425
		}
sl@0
   426
sl@0
   427
	info.iIat = iat;
sl@0
   428
	return KErrNone;
sl@0
   429
	}
sl@0
   430
sl@0
   431
sl@0
   432
/**
sl@0
   433
Fix up the import addresses, used for 'elf derived' executables.
sl@0
   434
@param aPtr Pointer to function arguments (SFixupImportAddressesInfo structure).
sl@0
   435
*/
sl@0
   436
TInt svElfDerivedFixupImportAddresses(TAny* aPtr)
sl@0
   437
	{
sl@0
   438
	SFixupImportAddressesInfo& info = *(SFixupImportAddressesInfo*)aPtr;
sl@0
   439
	TUint32 maxOrdinal = (TUint32)info.iExporter->iExportDirCount;
sl@0
   440
	TUint32 absentOrdinal = (TUint32)info.iExporter->iFileEntryPoint;
sl@0
   441
sl@0
   442
	TUint32* exp_dir = info.iExportDir - KOrdinalBase; // address of 0th ordinal
sl@0
   443
	TUint32 exp_delta = info.iExportDirEntryDelta;
sl@0
   444
	TUint32 code = info.iCodeLoadAddress;
sl@0
   445
sl@0
   446
	TUint32* iol = info.iImportOffsetList;
sl@0
   447
	TUint32* iolE = iol+info.iNumImports;
sl@0
   448
	for(; iol<iolE; ++iol)
sl@0
   449
		{
sl@0
   450
		TUint32* impPtr = (TUint32*)(code+*iol);
sl@0
   451
		TUint32 impd = *impPtr;
sl@0
   452
		TUint32 imp = impd & 0xffff;
sl@0
   453
		TUint32 offset = impd >> 16;
sl@0
   454
		if(imp>maxOrdinal)
sl@0
   455
			return KErrNotSupported;
sl@0
   456
sl@0
   457
		TUint32 writeValue;
sl@0
   458
		if(imp==0 && !(info.iExporter->iAttr&ECodeSegAttNmdExpData))
sl@0
   459
			{
sl@0
   460
			// attempt to import ordinal zero (symbol name data) from an executable
sl@0
   461
			// which doesn't export this information, use NULL for imported value in this case...
sl@0
   462
			writeValue = NULL;
sl@0
   463
			}
sl@0
   464
		else
sl@0
   465
			{
sl@0
   466
			// get imported value from exporter...
sl@0
   467
			TUint32 exp_addr = exp_dir[imp];
sl@0
   468
			if(exp_addr==0 || exp_addr==absentOrdinal)
sl@0
   469
				return KErrNotSupported;
sl@0
   470
			writeValue = exp_addr + exp_delta + offset;
sl@0
   471
			}
sl@0
   472
sl@0
   473
		// if not code paging then directly fix up the import...
sl@0
   474
		if (info.iFixup64 == 0)
sl@0
   475
			*impPtr = writeValue;
sl@0
   476
		// ...otherwise defer until the page is fixed up
sl@0
   477
		else
sl@0
   478
			{
sl@0
   479
			TUint64 impPtr64 = reinterpret_cast<TUint64>(impPtr);
sl@0
   480
			*info.iFixup64++ = (impPtr64 << 32) | writeValue;
sl@0
   481
			}
sl@0
   482
		}
sl@0
   483
	return KErrNone;
sl@0
   484
	}
sl@0
   485
sl@0
   486
sl@0
   487
/**
sl@0
   488
Wrapper for memory copy arguments.
sl@0
   489
*/
sl@0
   490
struct SCopyDataInfo
sl@0
   491
	{
sl@0
   492
	TAny* iDest;
sl@0
   493
	const TAny* iSource;
sl@0
   494
	TInt iNumberOfBytes;
sl@0
   495
	};
sl@0
   496
sl@0
   497
sl@0
   498
/**
sl@0
   499
Copies word aligned memory.
sl@0
   500
@param aPtr Pointer to function arguments (SCopyDataInfo structure).
sl@0
   501
*/
sl@0
   502
TInt svWordCopy(TAny* aPtr)
sl@0
   503
	{
sl@0
   504
	SCopyDataInfo& info=*(SCopyDataInfo*)aPtr;
sl@0
   505
	return (TInt) Mem::Move(info.iDest, info.iSource, info.iNumberOfBytes);
sl@0
   506
	}
sl@0
   507
sl@0
   508
sl@0
   509
/**
sl@0
   510
Copies memory.
sl@0
   511
@param aPtr Pointer to function arguments (SCopyDataInfo structure).
sl@0
   512
*/
sl@0
   513
TInt svMemCopy(TAny* aPtr)
sl@0
   514
	{
sl@0
   515
	SCopyDataInfo& info=*(SCopyDataInfo*)aPtr;
sl@0
   516
	return (TInt) Mem::Copy(info.iDest, info.iSource, info.iNumberOfBytes);
sl@0
   517
	}
sl@0
   518
sl@0
   519
sl@0
   520
/**
sl@0
   521
Argument for svElfDerivedGetImportInfo.
sl@0
   522
*/
sl@0
   523
struct SGetImportDataInfo
sl@0
   524
	{
sl@0
   525
	TInt iCount;					// number to extract
sl@0
   526
	TUint32* iDest;					// destination address for data
sl@0
   527
	TUint32 iCodeLoadAddress;		// address where code has been loaded
sl@0
   528
	TUint32* iImportOffsetList;		// pointer to list of import offsets in E32ImportBlock
sl@0
   529
	};
sl@0
   530
sl@0
   531
/**
sl@0
   532
Extract import ordinals/data
sl@0
   533
@param aPtr Pointer to function arguments (SGetImportDataInfo structure).
sl@0
   534
*/
sl@0
   535
TInt svElfDerivedGetImportInfo(TAny* aPtr)
sl@0
   536
	{
sl@0
   537
	SGetImportDataInfo& info = *(SGetImportDataInfo*)aPtr;
sl@0
   538
	TInt count = info.iCount;
sl@0
   539
	TUint32* dest = info.iDest;
sl@0
   540
	TUint32 code = info.iCodeLoadAddress;
sl@0
   541
	TUint32* iol = info.iImportOffsetList;
sl@0
   542
sl@0
   543
	TUint32* iolEnd = iol+count;
sl@0
   544
	while(iol<iolEnd)
sl@0
   545
		*dest++ = *(TUint32*)(code + *iol++);
sl@0
   546
		
sl@0
   547
	return 0;
sl@0
   548
	}
sl@0
   549
sl@0
   550
/*******************************************************************************
sl@0
   551
 * End of supervisor mode functions
sl@0
   552
 ******************************************************************************/
sl@0
   553
sl@0
   554
sl@0
   555
/*******************************************************************************
sl@0
   556
 * RImageInfo
sl@0
   557
 ******************************************************************************/
sl@0
   558
RImageInfo::RImageInfo()
sl@0
   559
	{
sl@0
   560
	memclr(this, sizeof(RImageInfo));
sl@0
   561
	}
sl@0
   562
sl@0
   563
void RImageInfo::Close()
sl@0
   564
	{
sl@0
   565
	iFile.Close();
sl@0
   566
	delete iHeader;
sl@0
   567
	iHeader=NULL;
sl@0
   568
	gFileDataAllocator.Free(iFileData);
sl@0
   569
	iFileData=NULL;
sl@0
   570
	}
sl@0
   571
sl@0
   572
void RImageInfo::Accept(RImageInfo& aInfo)
sl@0
   573
	{
sl@0
   574
	Close();
sl@0
   575
	wordmove(this, &aInfo, sizeof(RImageInfo));
sl@0
   576
	memclr(&aInfo.iFile, (_FOFF(RImageInfo,iFileSize) - _FOFF(RImageInfo,iFile)) );
sl@0
   577
	}
sl@0
   578
sl@0
   579
/*******************************************************************************
sl@0
   580
 * EPOC executable file finders
sl@0
   581
 ******************************************************************************/
sl@0
   582
RImageFinder::RImageFinder()
sl@0
   583
	:	iNameMatches(0), iUidFail(0), iCapFail(0), iMajorVersionFail(0), iImportFail(0),
sl@0
   584
		iCurrentVersion(KModuleVersionNull), iCurrentDrive(0), iFindExact(0), iNewValid(0),
sl@0
   585
		iReq(0), iExisting(0)
sl@0
   586
	{
sl@0
   587
	}
sl@0
   588
sl@0
   589
TInt RImageFinder::Set(const RLdrReq& aReq)
sl@0
   590
	{
sl@0
   591
	iReq = &aReq;
sl@0
   592
	TInt l = aReq.iFileNameInfo.BaseLen() + aReq.iFileNameInfo.ExtLen();
sl@0
   593
	if (l > KMaxProcessName)
sl@0
   594
		return KErrBadName;
sl@0
   595
	aReq.iFileNameInfo.GetName(iRootName, TFileNameInfo::EIncludeBaseExt);
sl@0
   596
	return KErrNone;
sl@0
   597
	}
sl@0
   598
sl@0
   599
void RImageFinder::Close()
sl@0
   600
	{
sl@0
   601
	iNew.Close();
sl@0
   602
	}
sl@0
   603
sl@0
   604
_LIT8(KDefaultPathSysBin, "sys\\bin");
sl@0
   605
_LIT8(KDefaultPathSysBin2, "?:\\sys\\bin");
sl@0
   606
_LIT8(KDefaultExePath, "sys\\bin;system\\bin;system\\programs;system\\libs");
sl@0
   607
_LIT8(KDefaultDllPath, "sys\\bin;system\\bin;system\\libs");
sl@0
   608
_LIT8(KDefaultExePath2, "?:\\sys\\bin;?:\\system\\bin;?:\\system\\programs;?:\\system\\libs");
sl@0
   609
_LIT8(KDefaultDllPath2, "?:\\sys\\bin;?:\\system\\bin;?:\\system\\libs");
sl@0
   610
sl@0
   611
TInt RImageFinder::Search()
sl@0
   612
	{
sl@0
   613
	__LDRTRACE(iReq->Dump(">RImageFinder::Search"));
sl@0
   614
	TBool exe = (iReq->iRequestedUids[0] == KExecutableImageUid);
sl@0
   615
	const TFileNameInfo& fi = iReq->iFileNameInfo;
sl@0
   616
	TInt r = KErrNone;
sl@0
   617
	if (fi.PathLen())
sl@0
   618
		{
sl@0
   619
		// path specified, so only look there
sl@0
   620
		TPtrC8 drive_and_path(fi.DriveAndPath());
sl@0
   621
		r = Search(&drive_and_path, 0);
sl@0
   622
		}
sl@0
   623
	else
sl@0
   624
		{
sl@0
   625
		TInt drv = -1;
sl@0
   626
		if (fi.DriveLen())
sl@0
   627
			{
sl@0
   628
			// drive specified
sl@0
   629
			drv = (*iReq->iFileName)[0];
sl@0
   630
			}
sl@0
   631
		// if a search path is specified look there
sl@0
   632
		if (iReq->iPath)
sl@0
   633
			r = Search(iReq->iPath, drv);
sl@0
   634
		if (r == KErrNoMemory) // ignore other errors as they are a potential denial of service
sl@0
   635
			{
sl@0
   636
			__LDRTRACE(Dump("<RImageFinder::Search", r));
sl@0
   637
			return r;
sl@0
   638
			}
sl@0
   639
		const TDesC8* defpath;
sl@0
   640
		if(PlatSec::ConfigSetting(PlatSec::EPlatSecEnforceSysBin))
sl@0
   641
			defpath = (drv<0) ? &KDefaultPathSysBin() : &KDefaultPathSysBin2();
sl@0
   642
		else
sl@0
   643
			{
sl@0
   644
			if (drv<0)
sl@0
   645
				defpath = exe ? &KDefaultExePath() : &KDefaultDllPath();
sl@0
   646
			else
sl@0
   647
				defpath = exe ? &KDefaultExePath2() : &KDefaultDllPath2();
sl@0
   648
			}
sl@0
   649
		r = Search(defpath, drv);
sl@0
   650
		}
sl@0
   651
	if (r == KErrNoMemory)  // ignore other errors as they are a potential denial of service
sl@0
   652
		{
sl@0
   653
		__LDRTRACE(Dump("<RImageFinder::Search", r));
sl@0
   654
		return r;
sl@0
   655
		}
sl@0
   656
	if (iExisting || iNewValid)
sl@0
   657
		r = KErrNone;			// found something suitable
sl@0
   658
	else if (!iNameMatches)
sl@0
   659
		r = KErrNotFound;		// nothing matched requested name
sl@0
   660
	else if (iImportFail || iMajorVersionFail)
sl@0
   661
		r = KErrNotSupported;	// something failed only on missing imports or version
sl@0
   662
	else if (iCapFail)
sl@0
   663
		r = KErrPermissionDenied;	// something failed capability check
sl@0
   664
	else if (iUidFail)
sl@0
   665
		r = KErrNotSupported;	// something failed UID check
sl@0
   666
	else
sl@0
   667
		r = KErrCorrupt;		// a file had the correct name but was not a valid E32Image file
sl@0
   668
	__LDRTRACE(Dump("<RImageFinder::Search", r));
sl@0
   669
	return r;
sl@0
   670
	}
sl@0
   671
sl@0
   672
TInt RImageFinder::Search(const TDesC8* aPath, TInt aDrive)
sl@0
   673
	{
sl@0
   674
	__IF_DEBUG(Printf(">Path %S Drive %02x", aPath, aDrive));
sl@0
   675
	TInt ppos = 0;
sl@0
   676
	TInt plen = aPath->Length();
sl@0
   677
	while (ppos < plen)
sl@0
   678
		{
sl@0
   679
		TPtrC8 remain(aPath->Mid(ppos));
sl@0
   680
		TInt pel = remain.Locate(';');
sl@0
   681
		if (pel < 0)
sl@0
   682
			{
sl@0
   683
			pel = remain.Length();
sl@0
   684
			ppos += pel;
sl@0
   685
			}
sl@0
   686
		else
sl@0
   687
			{
sl@0
   688
			ppos += pel + 1;
sl@0
   689
			}
sl@0
   690
		if (pel == 0)
sl@0
   691
			continue;
sl@0
   692
		TBool alldrives = EFalse;
sl@0
   693
		if (pel<2 || remain[1]!=':')
sl@0
   694
			alldrives = ETrue;
sl@0
   695
		else if (remain[0]!='?')
sl@0
   696
			aDrive = remain[0];
sl@0
   697
		TInt drive = EDriveY;
sl@0
   698
		if (!alldrives && RFs::CharToDrive(TChar(aDrive), drive)!=KErrNone)
sl@0
   699
			continue;
sl@0
   700
		iCurrentDrive = (TUint8)drive;
sl@0
   701
		TInt startpos = alldrives ? 0 : 2;
sl@0
   702
		iCurrentPath.Set(remain.Mid(startpos, pel - startpos));
sl@0
   703
		do	{
sl@0
   704
			TInt r;
sl@0
   705
#ifdef __X86__
sl@0
   706
			if (alldrives && iCurrentDrive<=EDriveB && iCurrentDrive!=UseFloppy)
sl@0
   707
				goto bypass_drive;
sl@0
   708
#endif
sl@0
   709
			r = SearchSingleDir();
sl@0
   710
			if (r == KErrNoMemory) // ignore other errors as they are a potential denial of service
sl@0
   711
				{
sl@0
   712
				__IF_DEBUG(Printf("OOM!"));
sl@0
   713
				return r;
sl@0
   714
				}
sl@0
   715
#ifdef __X86__
sl@0
   716
bypass_drive:
sl@0
   717
#endif
sl@0
   718
			if (!iCurrentDrive--)
sl@0
   719
				iCurrentDrive = EDriveZ;
sl@0
   720
			} while(alldrives && iCurrentDrive != EDriveY);
sl@0
   721
		}
sl@0
   722
	__IF_DEBUG(Printf("<Path %S Drive %02x", aPath, aDrive));
sl@0
   723
	return KErrNone;
sl@0
   724
	}
sl@0
   725
sl@0
   726
// Can't be looking for main loadee here, so iReq->iImporter is never NULL
sl@0
   727
// Also gExeAttr must be set up
sl@0
   728
TInt RImageFinder::SearchExisting(const RImageArray& aArray)
sl@0
   729
	{
sl@0
   730
	__IF_DEBUG(Printf(">RImageFinder::SearchExisting"));
sl@0
   731
	TUint required_abi = gExeAttr & ECodeSegAttABIMask;
sl@0
   732
	TInt first, last, i;
sl@0
   733
	aArray.Find(iRootName, first, last);
sl@0
   734
	for (i=first; i<last; ++i)
sl@0
   735
		{
sl@0
   736
		E32Image* e = aArray[i];
sl@0
   737
		if (CheckUids(e->iUids, iReq->iRequestedUids) != KErrNone)
sl@0
   738
			continue;
sl@0
   739
		if (iReq->CheckSecInfo(e->iS) != KErrNone)
sl@0
   740
			continue;
sl@0
   741
		TInt action = DetailedCompareVersions(e->iModuleVersion, iReq->iRequestedVersion, iCurrentVersion, EFalse);
sl@0
   742
		if (action == EAction_Skip)
sl@0
   743
			continue;
sl@0
   744
		if (action == EAction_CheckImports || action == EAction_CheckLastImport)
sl@0
   745
			{
sl@0
   746
			// Never optimistically link to something with a different ABI
sl@0
   747
			if ((e->iAttr & ECodeSegAttABIMask) != required_abi)
sl@0
   748
				continue;
sl@0
   749
			TInt r = CheckRequiredImports(iReq->iImporter, e, action);
sl@0
   750
			if (r != KErrNone)
sl@0
   751
				{
sl@0
   752
				if (r != KErrNotSupported)
sl@0
   753
					return r;
sl@0
   754
				continue;
sl@0
   755
				}
sl@0
   756
			}
sl@0
   757
		iExisting = e;
sl@0
   758
		iCurrentVersion = e->iModuleVersion;
sl@0
   759
		}
sl@0
   760
	__IF_DEBUG(Printf("<RImageFinder::SearchExisting"));
sl@0
   761
	return KErrNone;
sl@0
   762
	}
sl@0
   763
sl@0
   764
// Called for each file found with matching root name but which is not a valid E32ImageFile
sl@0
   765
void RImageFinder::RecordCorruptFile()
sl@0
   766
	{
sl@0
   767
	__IF_DEBUG(Printf("RImageFinder::RecordCorruptFile"));
sl@0
   768
	++iNameMatches;
sl@0
   769
	}
sl@0
   770
sl@0
   771
// Called for each valid E32Image file found with matching root name
sl@0
   772
TInt RImageFinder::Try(RImageInfo& aInfo, const TDesC8& aRootName, const TDesC8& aDriveAndPath)
sl@0
   773
	{
sl@0
   774
	__IF_DEBUG(Printf(">RImageFinder::Try %S%S", &aDriveAndPath, &aRootName));
sl@0
   775
	__IF_DEBUG(Printf(">MA:%08x MV:%08x RV:%08x CV:%08x", aInfo.iAttr, aInfo.iModuleVersion, iReq->iRequestedVersion, iCurrentVersion));
sl@0
   776
	++iNameMatches;
sl@0
   777
	if (iFindExact)
sl@0
   778
		{
sl@0
   779
		if ( ((aInfo.iAttr & ECodeSegAttExpVer) && aInfo.iModuleVersion==iReq->iRequestedVersion)
sl@0
   780
			|| (!(aInfo.iAttr & ECodeSegAttExpVer) && iReq->iRequestedVersion==KModuleVersionWild)
sl@0
   781
			)
sl@0
   782
			{
sl@0
   783
			__IF_DEBUG(Printf("<RImageFinder::Try Exact Match Found"));
sl@0
   784
			iNewValid = 1;
sl@0
   785
			iNew.Accept(aInfo);
sl@0
   786
			SetName(aRootName, aDriveAndPath);
sl@0
   787
			return KErrCompletion;
sl@0
   788
			}
sl@0
   789
		return KErrNotFound;
sl@0
   790
		}
sl@0
   791
	TUint required_abi = gExeAttr & ECodeSegAttABIMask;
sl@0
   792
	TBool abi_mismatch = ((aInfo.iAttr & ECodeSegAttABIMask)!=required_abi);
sl@0
   793
	TInt32* uid = (TInt32*)&iReq->iRequestedUids;
sl@0
   794
	TBool dll_wanted = (uid[0] == KDynamicLibraryUidValue);
sl@0
   795
	if (CheckUids(*(TUidType*)aInfo.iUid, iReq->iRequestedUids) != KErrNone)
sl@0
   796
		{
sl@0
   797
		++iUidFail;
sl@0
   798
		__IF_DEBUG(Printf("<RImageFinder::Try UIDFAIL"));
sl@0
   799
		return KErrNotFound;
sl@0
   800
		}
sl@0
   801
	if (iReq->CheckSecInfo(aInfo.iS) != KErrNone)
sl@0
   802
		{
sl@0
   803
		++iCapFail;
sl@0
   804
		__IF_DEBUG(Printf("<RImageFinder::Try CAPFAIL"));
sl@0
   805
		return KErrNotFound;
sl@0
   806
		}
sl@0
   807
	TInt action = DetailedCompareVersions(aInfo.iModuleVersion, iReq->iRequestedVersion, iCurrentVersion, !iReq->iImporter);
sl@0
   808
	if (action == EAction_Skip)
sl@0
   809
		{
sl@0
   810
		if (DetailedCompareVersions(aInfo.iModuleVersion, iReq->iRequestedVersion) == EVersion_MajorSmaller)
sl@0
   811
			++iMajorVersionFail;
sl@0
   812
		__IF_DEBUG(Printf("<RImageFinder::Try VERFAIL"));
sl@0
   813
		return KErrNotFound;
sl@0
   814
		}
sl@0
   815
	if (action == EAction_CheckImports || action == EAction_CheckLastImport)
sl@0
   816
		{
sl@0
   817
		// If we get here, can't be main loadee so gExeAttr must be valid
sl@0
   818
		// Never optimistically link to something with a different ABI
sl@0
   819
		if (abi_mismatch || CheckRequiredImports(iReq->iImporter, aInfo, action)!=KErrNone)
sl@0
   820
			{
sl@0
   821
			__IF_DEBUG(Printf("<RImageFinder::Try IMPFAIL"));
sl@0
   822
			++iImportFail;
sl@0
   823
			return KErrNotFound;
sl@0
   824
			}
sl@0
   825
		}
sl@0
   826
	if (!iReq->iImporter && dll_wanted && abi_mismatch)
sl@0
   827
		{
sl@0
   828
		// Dynamically loading a DLL - ABI must match loading process
sl@0
   829
		__IF_DEBUG(Printf("<RImageFinder::Try ABIFAIL"));
sl@0
   830
		++iImportFail;
sl@0
   831
		return KErrNotFound;
sl@0
   832
		}
sl@0
   833
	if(PlatSec::ConfigSetting(PlatSec::EPlatSecEnforceSysBin))
sl@0
   834
		{
sl@0
   835
		TChar driveLetter;
sl@0
   836
		TInt driveNumber;
sl@0
   837
		TInt r;
sl@0
   838
		driveLetter=(TChar)aDriveAndPath[0];
sl@0
   839
		RFs::CharToDrive(driveLetter,driveNumber);
sl@0
   840
		TDriveCacheHeader* pDH=gDriveFileNamesCache[driveNumber];
sl@0
   841
		TUint driveAtt=0;
sl@0
   842
		if(pDH)
sl@0
   843
			driveAtt=pDH->iDriveAtt;
sl@0
   844
		else
sl@0
   845
			{
sl@0
   846
			TDriveInfo driveInfo;
sl@0
   847
			if ((r=gTheLoaderFs.Drive(driveInfo,driveNumber)) != KErrNone)
sl@0
   848
				{
sl@0
   849
				__IF_DEBUG(Printf("<RImageFinder::Try DINFFAIL"));
sl@0
   850
				++iImportFail;
sl@0
   851
				return r;
sl@0
   852
				}
sl@0
   853
			driveAtt=driveInfo.iDriveAtt;
sl@0
   854
			}
sl@0
   855
sl@0
   856
		if(driveAtt & KDriveAttRemovable)
sl@0
   857
			{
sl@0
   858
			__IF_DEBUG(Printf("** RImageFinder::Try %S%S is on a removable drive", &aDriveAndPath, &aRootName));
sl@0
   859
			// If the cache says we already checked the hash of this file, accept it without checking again
sl@0
   860
			// as any *legitimate* change to the file would've triggered the cache to be rebuilt.
sl@0
   861
			if (!(aInfo.iCacheStatus & TImageInfo::EHashChecked))
sl@0
   862
				{
sl@0
   863
				//We have to pass aDriveAndPath as aInfo may not contain Drive
sl@0
   864
				TRAP(r,CompareHashL(aInfo, aDriveAndPath));
sl@0
   865
				if (r == KErrNoMemory)
sl@0
   866
					return r;
sl@0
   867
				if(r!=KErrNone)
sl@0
   868
					{
sl@0
   869
					__IF_DEBUG(Printf("<RImageFinder::Try Compare Hash Failed"));
sl@0
   870
					iCapFail++;
sl@0
   871
					return r;
sl@0
   872
					}
sl@0
   873
				aInfo.iCacheStatus |= TImageInfo::EHashChecked;
sl@0
   874
				}
sl@0
   875
			else
sl@0
   876
				{
sl@0
   877
				// We've skipped hash checking as an optimisation, however someone could potentially have
sl@0
   878
				// used external hardware to switch the data on the card since the cached hash check. Setting
sl@0
   879
				// this mark means that if we actually load the file, we'll hash it then; but if it turns out
sl@0
   880
				// to be already loaded, we can save the effort.
sl@0
   881
				aInfo.iNeedHashCheck = 1;
sl@0
   882
				}
sl@0
   883
			}
sl@0
   884
		}
sl@0
   885
	iExisting = NULL;
sl@0
   886
	iNew.Accept(aInfo);
sl@0
   887
	iNewValid = 1;
sl@0
   888
	iCurrentVersion = aInfo.iModuleVersion;
sl@0
   889
	SetName(aRootName, aDriveAndPath);
sl@0
   890
	__IF_DEBUG(Printf("<MV:%08x RV:%08x CV:%08x", aInfo.iModuleVersion, iReq->iRequestedVersion, iCurrentVersion));
sl@0
   891
	__IF_DEBUG(Printf("<RImageFinder::Try OK"));
sl@0
   892
	return KErrNone;
sl@0
   893
	}
sl@0
   894
sl@0
   895
void RImageFinder::CompareHashL(RImageInfo& aInfo, const TDesC8& aDriveAndPath)
sl@0
   896
//
sl@0
   897
//	Calculate hash and compare after checking if one already exists in c:/system/caps
sl@0
   898
//
sl@0
   899
	{
sl@0
   900
	__IF_DEBUG(Printf(">RImageFinder::CompareHashL"));
sl@0
   901
	
sl@0
   902
	TInt extraFlag = 0;
sl@0
   903
	TBuf8<KMaxFileName*sizeof(TText)> fileName;
sl@0
   904
	TFileNameInfo fni = iReq->iFileNameInfo;
sl@0
   905
	if (aInfo.iAttr & ECodeSegAttExpVer)
sl@0
   906
		{
sl@0
   907
		fni.iVersion = aInfo.iModuleVersion;
sl@0
   908
		extraFlag = TFileNameInfo::EForceVer;				
sl@0
   909
		}
sl@0
   910
	
sl@0
   911
	TFileName hashname(KSysHash);
sl@0
   912
    hashname[0] = (TUint8) RFs::GetSystemDriveChar();
sl@0
   913
	fileName.SetLength(0);
sl@0
   914
	fni.GetName(fileName, TFileNameInfo::EIncludeBaseExt | extraFlag);
sl@0
   915
	hashname.Append(fileName.Expand());
sl@0
   916
sl@0
   917
	RFile fHash;
sl@0
   918
	CleanupClosePushL(fHash);
sl@0
   919
sl@0
   920
	__IF_DEBUG(Printf("RImageFinder::CompareHashL opening hash file %S ", &hashname));
sl@0
   921
	User::LeaveIfError(fHash.Open(gTheLoaderFs,hashname,EFileRead|EFileReadDirectIO));
sl@0
   922
sl@0
   923
	TBuf8<SHA1_HASH> installhash;
sl@0
   924
	User::LeaveIfError(fHash.Read(installhash));
sl@0
   925
	CleanupStack::PopAndDestroy(1);
sl@0
   926
sl@0
   927
	// if we get this far, we have loaded a valid hash, so calculate the file's hash
sl@0
   928
sl@0
   929
	CSHA1* hasher=CSHA1::NewL(); 
sl@0
   930
	CleanupStack::PushL(hasher);
sl@0
   931
sl@0
   932
	fileName.Copy(aDriveAndPath);
sl@0
   933
	fni.GetName(fileName, TFileNameInfo::EIncludeBaseExt | extraFlag);
sl@0
   934
sl@0
   935
	CleanupClosePushL(aInfo.iFile);
sl@0
   936
	TBool b = aInfo.FileOpened();
sl@0
   937
	if(!b)		
sl@0
   938
		{
sl@0
   939
		__IF_DEBUG(Printf("RImageFinder::CompareHashL opening the file %S", &fileName));
sl@0
   940
		User::LeaveIfError(aInfo.iFile.Open(gTheLoaderFs, fileName.Expand(), EFileRead|EFileReadDirectIO));
sl@0
   941
		}
sl@0
   942
	
sl@0
   943
	__IF_DEBUG(Printf("RImageFinder::CompareHashL calculate hash"));
sl@0
   944
	TInt size;
sl@0
   945
	User::LeaveIfError(aInfo.iFile.Size(size));
sl@0
   946
	aInfo.iFileData = (TUint8*)gFileDataAllocator.Alloc(size);
sl@0
   947
	if (aInfo.iFileData)
sl@0
   948
		aInfo.iFileSize = size;
sl@0
   949
	else
sl@0
   950
		User::Leave(KErrNoMemory);
sl@0
   951
	TPtr8 filedata(aInfo.iFileData, size);
sl@0
   952
	User::LeaveIfError(aInfo.iFile.Read(0, filedata, size));
sl@0
   953
	if (filedata.Length() != size)
sl@0
   954
		User::Leave(KErrCorrupt);
sl@0
   955
	CleanupStack::PopAndDestroy(1);	//the file handle only->aInfo.iFile.Close();
sl@0
   956
	hasher->Update(filedata);
sl@0
   957
		
sl@0
   958
	TBuf8<SHA1_HASH> hash;
sl@0
   959
	hash=hasher->Final(); 
sl@0
   960
sl@0
   961
sl@0
   962
	__IF_DEBUG(Printf("RImageFinder::CompareHashL comparing hashes..."));
sl@0
   963
	if(0 != hash.Compare(installhash))
sl@0
   964
		User::Leave(KErrPermissionDenied);
sl@0
   965
	CleanupStack::PopAndDestroy(1);
sl@0
   966
	
sl@0
   967
	// if we get this far the hash has passed and the file has been closed
sl@0
   968
	// but some of the RImageInfo parameters will've been initialised by the cache
sl@0
   969
	// and may be lies if we're being attacked, so compare them to be sure
sl@0
   970
sl@0
   971
	// if we already had the header, throw it away: it's from untrusted data
sl@0
   972
	if (aInfo.iHeader)
sl@0
   973
		{
sl@0
   974
		delete aInfo.iHeader;
sl@0
   975
		aInfo.iHeader = NULL;
sl@0
   976
		}
sl@0
   977
sl@0
   978
	// make the header and validate the cached parameters against it
sl@0
   979
	User::LeaveIfError(E32ImageHeader::New(aInfo.iHeader, aInfo.iFileData, aInfo.iFileSize));
sl@0
   980
sl@0
   981
	SSecurityInfo secinfo;
sl@0
   982
	aInfo.iHeader->GetSecurityInfo(secinfo);
sl@0
   983
	TUint32 attr = (aInfo.iHeader->iFlags & ECodeSegAttFixed) | aInfo.iHeader->ABI();
sl@0
   984
	if(aInfo.iHeader->iFlags&KImageNmdExpData)
sl@0
   985
		attr |= ECodeSegAttNmdExpData;
sl@0
   986
	if (Mem::Compare((TUint8*)aInfo.iUid, sizeof(aInfo.iUid), (TUint8*)&aInfo.iHeader->iUid1, sizeof(aInfo.iUid))
sl@0
   987
			|| aInfo.iModuleVersion != aInfo.iHeader->ModuleVersion()
sl@0
   988
			|| Mem::Compare((TUint8*)&aInfo.iS, sizeof(aInfo.iS), (TUint8*)&secinfo, sizeof(secinfo))
sl@0
   989
			|| (aInfo.iAttr & ~ECodeSegAttExpVer) != attr)
sl@0
   990
		User::Leave(KErrPermissionDenied);
sl@0
   991
sl@0
   992
	__IF_DEBUG(Printf("<RImageFinder::CompareHashL passed"));
sl@0
   993
	}
sl@0
   994
sl@0
   995
void RImageFinder::SetName(const TDesC8& aRootName, const TDesC8& aDriveAndPath)
sl@0
   996
	{
sl@0
   997
	iNewFileName = aDriveAndPath;
sl@0
   998
	iNewFileName.Append(aRootName);
sl@0
   999
	}
sl@0
  1000
sl@0
  1001
RImageArray::RImageArray()
sl@0
  1002
	:	RPointerArray<E32Image>(8, 2*256)
sl@0
  1003
	{
sl@0
  1004
	}
sl@0
  1005
sl@0
  1006
TInt RImageArray::Add(E32Image* aImage)
sl@0
  1007
	{
sl@0
  1008
	return InsertInOrderAllowRepeats(aImage, &E32Image::Order);
sl@0
  1009
	}
sl@0
  1010
sl@0
  1011
void RImageArray::Find(const TDesC8& aRootName, TInt& aFirst, TInt& aLast) const
sl@0
  1012
	{
sl@0
  1013
	TCodeSegCreateInfo name;
sl@0
  1014
	name.iFileName.Copy(aRootName);
sl@0
  1015
	name.iRootNameOffset = 0;
sl@0
  1016
	name.iRootNameLength = aRootName.Length();
sl@0
  1017
	aFirst = SpecificFindInOrder((const E32Image*)&name, &E32Image::Order, EArrayFindMode_First);
sl@0
  1018
	aLast = aFirst;
sl@0
  1019
	if (aFirst >= 0)
sl@0
  1020
		aLast = SpecificFindInOrder((const E32Image*)&name, &E32Image::Order, EArrayFindMode_Last);
sl@0
  1021
	}
sl@0
  1022
sl@0
  1023
E32Image* RImageArray::Find(const TRomImageHeader* a) const
sl@0
  1024
	{
sl@0
  1025
	TInt c = Count();
sl@0
  1026
	if (!c)
sl@0
  1027
		return NULL;
sl@0
  1028
	E32Image* const * ee = &(*this)[0];
sl@0
  1029
	E32Image* const * eE = ee + c;
sl@0
  1030
	for (; ee<eE && (*ee)->iRomImageHeader != a; ++ee) {}
sl@0
  1031
	return (ee<eE) ? *ee : NULL;
sl@0
  1032
	}
sl@0
  1033
sl@0
  1034
TInt E32Image::LoadProcess(const RLdrReq& aReq)
sl@0
  1035
	{
sl@0
  1036
	__LDRTRACE(aReq.Dump("E32Image::LoadProcess"));
sl@0
  1037
sl@0
  1038
	RImageFinder finder;
sl@0
  1039
	TInt r = finder.Set(aReq);
sl@0
  1040
	if (r == KErrNone)
sl@0
  1041
		r = finder.Search();
sl@0
  1042
	if (r!=KErrNone)
sl@0
  1043
		{
sl@0
  1044
		finder.Close();
sl@0
  1045
		return r;
sl@0
  1046
		}
sl@0
  1047
	r = Construct(finder);	// needs to find it if it's already loaded
sl@0
  1048
	finder.Close();
sl@0
  1049
	if (r!=KErrNone)
sl@0
  1050
		{
sl@0
  1051
		return r;
sl@0
  1052
		}
sl@0
  1053
	if (iIsDll)
sl@0
  1054
		return KErrNotSupported;
sl@0
  1055
	r = aReq.iMsg->Client((RThread&)aReq.iClientThread);
sl@0
  1056
	if (r!=KErrNone)
sl@0
  1057
		{
sl@0
  1058
		return r;
sl@0
  1059
		}
sl@0
  1060
	iClientHandle=aReq.iClientThread.Handle();
sl@0
  1061
	
sl@0
  1062
	if(iStackSize < aReq.iMinStackSize)
sl@0
  1063
		iStackSize=aReq.iMinStackSize;		// If the process required larger stack than the default.
sl@0
  1064
sl@0
  1065
	//initialise to zero
sl@0
  1066
#ifdef _DEBUG
sl@0
  1067
	iDestructStat = ProcessDestructStatPtr;
sl@0
  1068
#endif
sl@0
  1069
	iDebugAttributes = 0;
sl@0
  1070
	if (iRomImageHeader)
sl@0
  1071
		{
sl@0
  1072
		if (iRomImageHeader->iFlags & KRomImageDebuggable)
sl@0
  1073
			iDebugAttributes |= EDebugAllowed;
sl@0
  1074
		}
sl@0
  1075
	else if (iHeader)
sl@0
  1076
		{
sl@0
  1077
		if (iHeader->iFlags & KImageDebuggable)
sl@0
  1078
			iDebugAttributes |= EDebugAllowed;
sl@0
  1079
		}
sl@0
  1080
	
sl@0
  1081
	// Get the data paging flags and pass to the kernel.
sl@0
  1082
	__ASSERT_COMPILE(EDataPagingUnspecified == 0);
sl@0
  1083
	if (iRomImageHeader)
sl@0
  1084
		{
sl@0
  1085
		TUint dataPaging = iRomImageHeader->iFlags & KRomImageDataPagingMask;
sl@0
  1086
		if (dataPaging == KRomImageDataPagingMask)
sl@0
  1087
			RETURN_FAILURE(KErrCorrupt);
sl@0
  1088
		if (dataPaging == KRomImageFlagDataPaged)
sl@0
  1089
			iFlags |= EDataPaged;
sl@0
  1090
		if (dataPaging == KRomImageFlagDataUnpaged)
sl@0
  1091
			iFlags |= EDataUnpaged;
sl@0
  1092
		}
sl@0
  1093
	else if (iHeader)
sl@0
  1094
		{
sl@0
  1095
		TUint dataPaging = iHeader->iFlags & KImageDataPagingMask;
sl@0
  1096
		if (dataPaging == KImageDataPagingMask)
sl@0
  1097
			RETURN_FAILURE(KErrCorrupt);
sl@0
  1098
		if (dataPaging == KImageDataPaged)
sl@0
  1099
			iFlags |= EDataPaged;
sl@0
  1100
		if (dataPaging == KImageDataUnpaged)
sl@0
  1101
			iFlags |= EDataUnpaged;
sl@0
  1102
		}
sl@0
  1103
		
sl@0
  1104
	r=E32Loader::ProcessCreate(*this, aReq.iCmd);
sl@0
  1105
	__IF_DEBUG(Printf("Done E32Loader::ProcessCreate %d",r));
sl@0
  1106
	if (r!=KErrNone)
sl@0
  1107
		{
sl@0
  1108
		return r;
sl@0
  1109
		}
sl@0
  1110
#ifdef _DEBUG
sl@0
  1111
	ProcessCreated = ETrue;
sl@0
  1112
#endif
sl@0
  1113
	iClientProcessHandle=iProcessHandle;
sl@0
  1114
	if (!iAlreadyLoaded)
sl@0
  1115
		{
sl@0
  1116
		gExeCodeSeg=iHandle;	// implicitly linked DLLs must load into the new process
sl@0
  1117
		gExeAttr=iAttr;
sl@0
  1118
		if (!iRomImageHeader)
sl@0
  1119
			r=LoadToRam();
sl@0
  1120
		if (r==KErrNone)
sl@0
  1121
			r=ProcessImports();	// this sets up gLoadeePath
sl@0
  1122
		}
sl@0
  1123
	// transfers ownership of clamp handle to codeseg; nulls handle if successful
sl@0
  1124
	if (r==KErrNone)
sl@0
  1125
		{
sl@0
  1126
		r=E32Loader::ProcessLoaded(*this);
sl@0
  1127
		if ((r==KErrNone) && iUseCodePaging)
sl@0
  1128
			{
sl@0
  1129
			iFileClamp.iCookie[0]=0;// null handle to indicate 
sl@0
  1130
			iFileClamp.iCookie[1]=0;// transfer of ownership of clamp handle to proc's codeseg
sl@0
  1131
			}
sl@0
  1132
		}
sl@0
  1133
	__IF_DEBUG(Printf("Done E32Image::LoadProcess %d",r));
sl@0
  1134
	return r;
sl@0
  1135
	}
sl@0
  1136
sl@0
  1137
// Load a code segment, plus all imports if main loadee
sl@0
  1138
TInt E32Image::LoadCodeSeg(const RLdrReq& aReq)
sl@0
  1139
	{
sl@0
  1140
	__LDRTRACE(aReq.Dump(">E32Image::LoadCodeSeg"));
sl@0
  1141
sl@0
  1142
#ifdef __X86__
sl@0
  1143
	if (iMain==this && iClientProcessHandle)
sl@0
  1144
		{
sl@0
  1145
		RProcess p;
sl@0
  1146
		p.SetHandle(iClientProcessHandle);
sl@0
  1147
		TFileName f(p.FileName());
sl@0
  1148
		if (f.Length()>=2 && f[1]==':')
sl@0
  1149
			{
sl@0
  1150
			TInt d = f[0];
sl@0
  1151
			if (d=='a' || d=='A')
sl@0
  1152
				UseFloppy = EDriveA;
sl@0
  1153
			else if (d=='b' || d=='B')
sl@0
  1154
				UseFloppy = EDriveB;
sl@0
  1155
			}
sl@0
  1156
		}
sl@0
  1157
#endif
sl@0
  1158
sl@0
  1159
	RImageFinder finder;
sl@0
  1160
	TInt r = finder.Set(aReq);
sl@0
  1161
	if (r == KErrNone)
sl@0
  1162
		r = finder.Search();
sl@0
  1163
	if (r!=KErrNone)
sl@0
  1164
		{
sl@0
  1165
		finder.Close();
sl@0
  1166
		return r;
sl@0
  1167
		}
sl@0
  1168
	return DoLoadCodeSeg(aReq, finder);
sl@0
  1169
	}
sl@0
  1170
sl@0
  1171
// Load a code segment, plus all imports if main loadee
sl@0
  1172
TInt E32Image::DoLoadCodeSeg(const RLdrReq& aReq, RImageFinder& aFinder)
sl@0
  1173
	{
sl@0
  1174
	__LDRTRACE(aReq.Dump(">E32Image::DoLoadCodeSeg"));
sl@0
  1175
sl@0
  1176
	TInt r = Construct(aFinder);	// needs to find it if it's already loaded
sl@0
  1177
	aFinder.Close();
sl@0
  1178
	if (r!=KErrNone)
sl@0
  1179
		{
sl@0
  1180
		return r;
sl@0
  1181
		}
sl@0
  1182
	__IF_DEBUG(Printf("epv=%x, fep=%x, codesize=%x, textsize=%x, uid3=%x",iEntryPtVeneer,iFileEntryPoint,iCodeSize,iTextSize,iUids[2]));
sl@0
  1183
	__IF_DEBUG(Printf("attr=%08x, gExeAttr=%08x",iAttr,gExeAttr));
sl@0
  1184
sl@0
  1185
	// If EXE and not main loadee, EXE code segment must be the same as the client process or newly loaded process
sl@0
  1186
	if (gExeCodeSeg && !iIsDll && iMain!=this && iHandle!=gExeCodeSeg)
sl@0
  1187
		return KErrNotSupported;
sl@0
  1188
sl@0
  1189
	// If DLL and main loadee, ABI must match the process
sl@0
  1190
	if (iIsDll && iMain==this && (iAttr & ECodeSegAttABIMask)!=(gExeAttr & ECodeSegAttABIMask) )
sl@0
  1191
		return KErrNotSupported;
sl@0
  1192
sl@0
  1193
	// code segment already loaded
sl@0
  1194
	if (iAlreadyLoaded || (iMain!=this && AlwaysLoaded()) )
sl@0
  1195
		return KErrNone;
sl@0
  1196
sl@0
  1197
	__IF_DEBUG(Printf("CodeSeg create"));
sl@0
  1198
	r=E32Loader::CodeSegCreate(*this);
sl@0
  1199
	if (r!=KErrNone)
sl@0
  1200
		return r;
sl@0
  1201
	
sl@0
  1202
	iCloseCodeSeg=iHandle;	// so new code segment is removed if the load fails
sl@0
  1203
	if (!iRomImageHeader)
sl@0
  1204
		r=LoadToRam();
sl@0
  1205
	if (r==KErrNone)
sl@0
  1206
		{
sl@0
  1207
		iCloseCodeSeg=NULL;
sl@0
  1208
		if (iMain==this)
sl@0
  1209
			{
sl@0
  1210
			r=ProcessImports();	// this sets up gLoadeePath
sl@0
  1211
			// transfers ownership of clamp handle to codeseg; nulls handle if successful
sl@0
  1212
			if (r==KErrNone)
sl@0
  1213
				{
sl@0
  1214
				r=E32Loader::CodeSegLoaded(*this);
sl@0
  1215
				if ((r==KErrNone) && iUseCodePaging)
sl@0
  1216
					{
sl@0
  1217
					iFileClamp.iCookie[0]=0;// null handle to indicate 
sl@0
  1218
					iFileClamp.iCookie[1]=0;// transfer of ownership of clamp handle to codeseg
sl@0
  1219
					}
sl@0
  1220
				}
sl@0
  1221
			}
sl@0
  1222
		}
sl@0
  1223
sl@0
  1224
	__IF_DEBUG(Printf("<DoLoadCodeSeg, r=%d, iIsDll=%d",r,iIsDll));
sl@0
  1225
	return r;
sl@0
  1226
	}
sl@0
  1227
sl@0
  1228
// Load a ROM XIP code segment as part of another load
sl@0
  1229
TInt E32Image::DoLoadCodeSeg(const TRomImageHeader& a)
sl@0
  1230
	{
sl@0
  1231
	__IF_DEBUG(Printf("E32Image::DoLoadCodeSeg ROM XIP @%08x",&a));
sl@0
  1232
	
sl@0
  1233
	Construct(a);
sl@0
  1234
	if (AlwaysLoaded())
sl@0
  1235
		{
sl@0
  1236
		GetRomFileName();
sl@0
  1237
		return KErrNone;
sl@0
  1238
		}
sl@0
  1239
	TInt r=CheckRomXIPAlreadyLoaded();
sl@0
  1240
	if (r!=KErrNone || iAlreadyLoaded)
sl@0
  1241
		{
sl@0
  1242
		return r;
sl@0
  1243
		}
sl@0
  1244
	GetRomFileName();
sl@0
  1245
	r=E32Loader::CodeSegCreate(*this);
sl@0
  1246
sl@0
  1247
	__IF_DEBUG(Printf("<DoLoadCodeSeg, r=%d",r));
sl@0
  1248
	return r;
sl@0
  1249
	}
sl@0
  1250
sl@0
  1251
/******************************************************************************
sl@0
  1252
 * EPOC specific E32Image functions
sl@0
  1253
 ******************************************************************************/
sl@0
  1254
sl@0
  1255
/**
sl@0
  1256
Construct an image object which represents an XIP ROM executable.
sl@0
  1257
*/
sl@0
  1258
void E32Image::Construct(const TRomImageHeader& a)
sl@0
  1259
	{
sl@0
  1260
	__IF_DEBUG(Printf("E32Image::Construct ROM %08x",&a));
sl@0
  1261
sl@0
  1262
	iRomImageHeader = &a;
sl@0
  1263
	iUids = *(const TUidType*)&a.iUid1;
sl@0
  1264
	iS = a.iS;
sl@0
  1265
	iCodeSize = a.iCodeSize;
sl@0
  1266
	iTextSize = a.iTextSize;
sl@0
  1267
	iDataSize = a.iDataSize;
sl@0
  1268
	iBssSize = a.iBssSize;
sl@0
  1269
	iTotalDataSize = a.iTotalDataSize;
sl@0
  1270
	iEntryPtVeneer = 0;
sl@0
  1271
	iFileEntryPoint = a.iEntryPoint;
sl@0
  1272
	iDepCount = a.iDllRefTable ? a.iDllRefTable->iNumberOfEntries : 0;
sl@0
  1273
	iExportDir = a.iExportDir;
sl@0
  1274
	iExportDirCount = a.iExportDirCount;
sl@0
  1275
	iCodeLoadAddress = (TUint32)&a;
sl@0
  1276
	iDataRunAddress = a.iDataBssLinearBase;	// for fixed processes
sl@0
  1277
	iHeapSizeMin = a.iHeapSizeMin;
sl@0
  1278
	iHeapSizeMax = a.iHeapSizeMax;
sl@0
  1279
	iStackSize = a.iStackSize;
sl@0
  1280
	iPriority = a.iPriority;
sl@0
  1281
	iIsDll = (a.iFlags & KImageDll)!=0;
sl@0
  1282
	if(iExportDirCount)
sl@0
  1283
		iExportDirLoad = iExportDir;
sl@0
  1284
sl@0
  1285
	// setup attributes...
sl@0
  1286
	iAttr &= ~(ECodeSegAttKernel|ECodeSegAttGlobal|ECodeSegAttFixed|ECodeSegAttABIMask|ECodeSegAttNmdExpData);
sl@0
  1287
	if(a.iFlags&KRomImageFlagsKernelMask)
sl@0
  1288
		iAttr |= ECodeSegAttKernel;
sl@0
  1289
	else
sl@0
  1290
		iAttr |= ECodeSegAttGlobal;
sl@0
  1291
	if(a.iFlags&KRomImageFlagFixedAddressExe)
sl@0
  1292
		iAttr |= ECodeSegAttFixed;
sl@0
  1293
	iAttr |= (a.iFlags & KRomImageABIMask);
sl@0
  1294
	if(a.iFlags&KRomImageNmdExpData)
sl@0
  1295
		iAttr |= ECodeSegAttNmdExpData;
sl@0
  1296
	if(a.iFlags&KRomImageSMPSafe)
sl@0
  1297
		iAttr |= ECodeSegAttSMPSafe;
sl@0
  1298
	
sl@0
  1299
	iExceptionDescriptor = a.iExceptionDescriptor;
sl@0
  1300
	}
sl@0
  1301
sl@0
  1302
sl@0
  1303
TBool E32Image::AlwaysLoaded()
sl@0
  1304
	{
sl@0
  1305
	// If loaded from ROM and EXE or DLL with no static data or extension or variant, don't need code segment
sl@0
  1306
	TBool r=EFalse;
sl@0
  1307
	__IF_DEBUG(Printf(">E32Image::AlwaysLoaded %08x",iRomImageHeader));
sl@0
  1308
	if (iRomImageHeader)
sl@0
  1309
		{
sl@0
  1310
		if (iIsDll && (iRomImageHeader->iFlags & KRomImageFlagDataPresent)==0)
sl@0
  1311
			r=ETrue;
sl@0
  1312
		}
sl@0
  1313
	__IF_DEBUG(Printf("<E32Image::AlwaysLoaded %x",r));
sl@0
  1314
	return r;
sl@0
  1315
	}
sl@0
  1316
sl@0
  1317
sl@0
  1318
void E32Image::GetRomFileName()
sl@0
  1319
	{
sl@0
  1320
	TBuf8<KMaxFileName> fn = _S8("z:\\");
sl@0
  1321
	TFileNameInfo fni;
sl@0
  1322
	TPtr8 path_and_name(((TText8*)fn.Ptr())+3, 0, KMaxFileName-3);
sl@0
  1323
	const TRomDir& rootdir = *(const TRomDir*)UserSvr::RomRootDirectoryAddress();
sl@0
  1324
	if (!TraverseDirs(rootdir, iRomImageHeader, path_and_name))
sl@0
  1325
		*(const TAny**)1=iRomImageHeader;	// DIE!
sl@0
  1326
	fn.SetLength(path_and_name.Length()+3);
sl@0
  1327
	fni.Set(fn, 0);
sl@0
  1328
	iFileName.Zero();
sl@0
  1329
	fni.GetName(iFileName, TFileNameInfo::EIncludeDrivePathBaseExt);
sl@0
  1330
	if (fni.VerLen())
sl@0
  1331
		iAttr |= ECodeSegAttExpVer;
sl@0
  1332
	iRootNameOffset = fni.iBasePos;
sl@0
  1333
	iRootNameLength = fni.BaseLen() + fni.ExtLen();
sl@0
  1334
	iExtOffset = iFileName.Length() - fni.ExtLen();
sl@0
  1335
	__IF_DEBUG(Printf("GetRomFileName(%08x)->%S,%d,%d,%d Attr %08x",iRomImageHeader,&iFileName,iRootNameOffset,iRootNameLength,iExtOffset,iAttr));
sl@0
  1336
	}
sl@0
  1337
sl@0
  1338
sl@0
  1339
/**
sl@0
  1340
Starting from aDir, search for XIP executable specified by aHdr.
sl@0
  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.)
sl@0
  1342
If not found, return false.
sl@0
  1343
*/
sl@0
  1344
TBool E32Image::TraverseDirs(const TRomDir& aDir, const TRomImageHeader* aHdr, TDes8& aName)
sl@0
  1345
	{
sl@0
  1346
	const TRomEntry* pE=&aDir.iEntry;
sl@0
  1347
	const TRomEntry* pEnd=(const TRomEntry*)((TUint8*)pE+aDir.iSize);
sl@0
  1348
	while(pE<pEnd)
sl@0
  1349
		{
sl@0
  1350
		if ( (pE->iAtt & KEntryAttXIP) && (pE->iAddressLin==(TLinAddr)aHdr) )
sl@0
  1351
			{
sl@0
  1352
			// ROM XIP file found
sl@0
  1353
			aName.Copy(TPtrC16((const TText*)pE->iName, pE->iNameLength));
sl@0
  1354
			return ETrue;
sl@0
  1355
			}
sl@0
  1356
		if (pE->iAtt & KEntryAttDir)
sl@0
  1357
			{
sl@0
  1358
			// subdirectory found
sl@0
  1359
			const TRomDir& subdir = *(const TRomDir*)pE->iAddressLin;
sl@0
  1360
			TText8* p = (TText8*)aName.Ptr();
sl@0
  1361
			TInt m = aName.MaxLength();
sl@0
  1362
			TInt nl = pE->iNameLength;
sl@0
  1363
			TPtr8 ptr(p+nl+1, 0, m-nl-1);
sl@0
  1364
			if (TraverseDirs(subdir, aHdr, ptr))
sl@0
  1365
				{
sl@0
  1366
				// match found in subdirectory
sl@0
  1367
				aName.SetLength(ptr.Length()+nl+1);
sl@0
  1368
				const TText* s = (const TText*)pE->iName;
sl@0
  1369
				p[nl]='\\';
sl@0
  1370
				while (nl--)
sl@0
  1371
					*p++ = (TText8)*s++;
sl@0
  1372
				return ETrue;
sl@0
  1373
				}
sl@0
  1374
			}
sl@0
  1375
		TInt entry_size = KRomEntrySize + pE->iNameLength*sizeof(TText);
sl@0
  1376
		entry_size = (entry_size+sizeof(TInt)-1)&~(sizeof(TInt)-1);
sl@0
  1377
		pE=(const TRomEntry*)((TUint8*)pE+entry_size);
sl@0
  1378
		}
sl@0
  1379
	return EFalse;
sl@0
  1380
	}
sl@0
  1381
sl@0
  1382
sl@0
  1383
/**
sl@0
  1384
Read data from a file.
sl@0
  1385
*/
sl@0
  1386
TInt FileRead(RFile& aFile, TUint8* aDest, TInt aSize)
sl@0
  1387
	{
sl@0
  1388
	TPtr8 p(aDest,aSize,aSize);
sl@0
  1389
	TInt r = aFile.Read(p,aSize);
sl@0
  1390
	if(r==KErrNone && p.Size()!=aSize)
sl@0
  1391
		RETURN_FAILURE(KErrCorrupt);
sl@0
  1392
	return r;
sl@0
  1393
	}
sl@0
  1394
sl@0
  1395
sl@0
  1396
/**
sl@0
  1397
Construct a new image header by reading a file. File must not be XIP.
sl@0
  1398
*/
sl@0
  1399
TInt E32ImageHeader::New(E32ImageHeader*& aHdr, RFile& aFile)
sl@0
  1400
	{
sl@0
  1401
	aHdr = NULL;
sl@0
  1402
sl@0
  1403
	TInt fileSize;
sl@0
  1404
	TInt r = aFile.Size(fileSize);
sl@0
  1405
	if(r!=KErrNone)
sl@0
  1406
		return r;
sl@0
  1407
sl@0
  1408
	E32ImageHeaderV tempHeader;
sl@0
  1409
	r = FileRead(aFile, (TUint8*)&tempHeader, sizeof(tempHeader));
sl@0
  1410
	if(r!=KErrNone)
sl@0
  1411
		return r;
sl@0
  1412
sl@0
  1413
	TUint headerSize = tempHeader.TotalSize();
sl@0
  1414
	if(headerSize<sizeof(tempHeader) || headerSize>TUint(KMaxHeaderSize))
sl@0
  1415
		RETURN_FAILURE(KErrCorrupt);
sl@0
  1416
sl@0
  1417
	E32ImageHeaderV* header = (E32ImageHeaderV*)User::Alloc(headerSize);
sl@0
  1418
	if(!header)
sl@0
  1419
		return KErrNoMemory;
sl@0
  1420
sl@0
  1421
	wordmove(header, &tempHeader, sizeof(tempHeader));
sl@0
  1422
	if(headerSize>sizeof(tempHeader))
sl@0
  1423
		r = FileRead(aFile, ((TUint8*)header)+sizeof(tempHeader), headerSize-sizeof(tempHeader));
sl@0
  1424
sl@0
  1425
	if(r==KErrNone)
sl@0
  1426
		r = header->ValidateAndAdjust(fileSize);
sl@0
  1427
sl@0
  1428
	if(r==KErrNone)
sl@0
  1429
		aHdr = header;
sl@0
  1430
	else
sl@0
  1431
		delete header;
sl@0
  1432
sl@0
  1433
	return r;
sl@0
  1434
	}
sl@0
  1435
sl@0
  1436
sl@0
  1437
/**
sl@0
  1438
Construct a new image header using data from the supplied buffer.
sl@0
  1439
*/
sl@0
  1440
TInt E32ImageHeader::New(E32ImageHeader*& aHdr, TUint8* aFileData, TUint32 aFileSize)
sl@0
  1441
	{
sl@0
  1442
	aHdr = NULL;
sl@0
  1443
sl@0
  1444
	E32ImageHeaderV& tempHeader = *(E32ImageHeaderV*)aFileData;
sl@0
  1445
sl@0
  1446
	if(aFileSize<sizeof(tempHeader))
sl@0
  1447
		RETURN_FAILURE(KErrCorrupt); // too small to contain a header
sl@0
  1448
sl@0
  1449
	TUint headerSize = tempHeader.TotalSize();
sl@0
  1450
	if(headerSize<sizeof(tempHeader) || headerSize>TUint(KMaxHeaderSize))
sl@0
  1451
		RETURN_FAILURE(KErrCorrupt);
sl@0
  1452
	if(headerSize>aFileSize)
sl@0
  1453
		RETURN_FAILURE(KErrCorrupt);
sl@0
  1454
sl@0
  1455
	E32ImageHeaderV* header = (E32ImageHeaderV*)User::Alloc(headerSize);
sl@0
  1456
	if(!header)
sl@0
  1457
		return KErrNoMemory;
sl@0
  1458
sl@0
  1459
	wordmove(header, &tempHeader, headerSize);
sl@0
  1460
sl@0
  1461
	TInt r = header->ValidateAndAdjust(aFileSize);
sl@0
  1462
	if(r==KErrNone)
sl@0
  1463
		aHdr = header;
sl@0
  1464
	else
sl@0
  1465
		delete header;
sl@0
  1466
sl@0
  1467
	return r;
sl@0
  1468
	}
sl@0
  1469
sl@0
  1470
sl@0
  1471
/**
sl@0
  1472
Validate header, then adjust:
sl@0
  1473
- iUncompressedSize to contain size of data even when file is not compressed.
sl@0
  1474
- Platform security capability to include all disabled capabilities and exclude invalid ones.
sl@0
  1475
sl@0
  1476
@param aFileSize Total size of the file containing the image data.
sl@0
  1477
*/
sl@0
  1478
TInt E32ImageHeaderV::ValidateAndAdjust(TUint32 aFileSize)
sl@0
  1479
	{
sl@0
  1480
	// check header is valid...
sl@0
  1481
	TUint32 uncompressedSize;
sl@0
  1482
	TInt r = ValidateHeader(aFileSize,uncompressedSize);
sl@0
  1483
	if(r!=KErrNone)
sl@0
  1484
		return r;
sl@0
  1485
sl@0
  1486
	// set size of data when uncompressed...
sl@0
  1487
	iUncompressedSize = uncompressedSize;
sl@0
  1488
sl@0
  1489
	// override capabilities in image to conform to system wide configuration...
sl@0
  1490
	for(TInt i=0; i<SCapabilitySet::ENCapW; i++)
sl@0
  1491
		{
sl@0
  1492
		iS.iCaps[i] |= DisabledCapabilities[i];
sl@0
  1493
		iS.iCaps[i] &= AllCapabilities[i];
sl@0
  1494
		}
sl@0
  1495
sl@0
  1496
	return KErrNone;
sl@0
  1497
	}
sl@0
  1498
sl@0
  1499
sl@0
  1500
TInt E32Image::Construct(RImageFinder& aFinder)
sl@0
  1501
	{
sl@0
  1502
	__IF_DEBUG(Printf("E32Image::iMain=%08x", iMain));
sl@0
  1503
	__LDRTRACE(aFinder.Dump(">E32Image::Construct", 0));
sl@0
  1504
	__ASSERT_ALWAYS(aFinder.iNewValid, User::Panic(KLitFinderInconsistent, 0));
sl@0
  1505
sl@0
  1506
	// fallback security check to ensure we don't try and load an executable from an insecure location...
sl@0
  1507
	if(PlatSec::ConfigSetting(PlatSec::EPlatSecEnforceSysBin))
sl@0
  1508
		{
sl@0
  1509
		__ASSERT_ALWAYS(aFinder.iNewFileName.Length()>=11, User::Panic(KLitSysBinError, 0));
sl@0
  1510
		__ASSERT_ALWAYS(KSysBin().CompareF(TPtrC8(aFinder.iNewFileName.Ptr()+1,10))==0, User::Panic(KLitSysBinError, 1));
sl@0
  1511
		}
sl@0
  1512
sl@0
  1513
	TInt r = KErrNone;
sl@0
  1514
sl@0
  1515
	// setup file name info...
sl@0
  1516
	iFileName.Copy(aFinder.iNewFileName);
sl@0
  1517
	TFileNameInfo fi;
sl@0
  1518
	fi.Set(iFileName, 0);
sl@0
  1519
	iRootNameOffset = fi.iBasePos;
sl@0
  1520
	iRootNameLength = fi.iLen - fi.iBasePos;
sl@0
  1521
	iExtOffset = fi.iExtPos;
sl@0
  1522
sl@0
  1523
	// setup version...
sl@0
  1524
	iAttr |= aFinder.iNew.iAttr & ECodeSegAttExpVer;
sl@0
  1525
	iModuleVersion = aFinder.iNew.iModuleVersion;
sl@0
  1526
sl@0
  1527
	if(aFinder.iNew.iRomImageHeader)
sl@0
  1528
		{
sl@0
  1529
		// we're 'loading' an XIP executable from ROM...
sl@0
  1530
		Construct(*aFinder.iNew.iRomImageHeader);
sl@0
  1531
		if(!AlwaysLoaded() || iMain==this)
sl@0
  1532
			r = CheckRomXIPAlreadyLoaded();
sl@0
  1533
		return r;
sl@0
  1534
		}
sl@0
  1535
sl@0
  1536
	// setup more image info...
sl@0
  1537
	iAttr |= aFinder.iNew.iAttr & (ECodeSegAttFixed|ECodeSegAttABIMask|ECodeSegAttNmdExpData);
sl@0
  1538
	iUids = *(const TUidType*)&aFinder.iNew.iUid;
sl@0
  1539
	iIsDll = !(iUids[0].iUid == KExecutableImageUidValue);
sl@0
  1540
	iS = aFinder.iNew.iS;
sl@0
  1541
sl@0
  1542
	// check if executable has already been loaded...
sl@0
  1543
	r = CheckAlreadyLoaded();
sl@0
  1544
	if(r!=KErrNone)
sl@0
  1545
		return r;
sl@0
  1546
sl@0
  1547
	// if we are going to need to load it...
sl@0
  1548
	if(!iAlreadyLoaded || !iIsDll)
sl@0
  1549
		{
sl@0
  1550
		if (aFinder.iNew.iNeedHashCheck)
sl@0
  1551
			{
sl@0
  1552
			// we need to check the file hash; the check in RImageFinder::Try
sl@0
  1553
			// was skipped based on the cache. If it fails here, though, someone
sl@0
  1554
			// is tampering with us and we can just fail the load.
sl@0
  1555
			TRAP(r,aFinder.CompareHashL(aFinder.iNew, fi.DriveAndPath()));
sl@0
  1556
			if (r != KErrNone)
sl@0
  1557
				return r;
sl@0
  1558
			}
sl@0
  1559
sl@0
  1560
		if(aFinder.iNew.iFileData)
sl@0
  1561
			{
sl@0
  1562
			// take ownership of the file data aFinder has already read in...
sl@0
  1563
			iFileData = aFinder.iNew.iFileData;
sl@0
  1564
			aFinder.iNew.iFileData = NULL;
sl@0
  1565
			iFileSize = aFinder.iNew.iFileSize;
sl@0
  1566
			}
sl@0
  1567
		else if(aFinder.iNew.FileOpened())
sl@0
  1568
			{
sl@0
  1569
			// take ownership of the file handle that aFinder has already opened...
sl@0
  1570
			iFile = aFinder.iNew.iFile;
sl@0
  1571
			memclr(&aFinder.iNew.iFile, sizeof(RFile));
sl@0
  1572
			}
sl@0
  1573
		else
sl@0
  1574
			{
sl@0
  1575
			// no resource obtained from aFinder, so create a file handle for ourselves...
sl@0
  1576
			r = OpenFile();
sl@0
  1577
			if(r!=KErrNone)
sl@0
  1578
				return r;
sl@0
  1579
			}
sl@0
  1580
sl@0
  1581
		// take ownership of header...
sl@0
  1582
		iHeader = aFinder.iNew.iHeader;
sl@0
  1583
		aFinder.iNew.iHeader = NULL;
sl@0
  1584
sl@0
  1585
		// if there wast't a header, then create one now...
sl@0
  1586
		if(!iHeader)
sl@0
  1587
			{
sl@0
  1588
			if(iFileData)
sl@0
  1589
				r = E32ImageHeader::New(iHeader, iFileData, iFileSize);
sl@0
  1590
			else
sl@0
  1591
				r = E32ImageHeader::New(iHeader, iFile);
sl@0
  1592
			if(r!=KErrNone)
sl@0
  1593
				return r;
sl@0
  1594
			}
sl@0
  1595
sl@0
  1596
		// setup info needed for process creation...
sl@0
  1597
		iHeapSizeMin = iHeader->iHeapSizeMin;
sl@0
  1598
		iHeapSizeMax = iHeader->iHeapSizeMax;
sl@0
  1599
		iStackSize = iHeader->iStackSize;
sl@0
  1600
		iPriority = iHeader->ProcessPriority();
sl@0
  1601
		}
sl@0
  1602
sl@0
  1603
	// if already loaded...
sl@0
  1604
	if(iAlreadyLoaded)
sl@0
  1605
		return KErrNone; // nothing more to do
sl@0
  1606
sl@0
  1607
	// setup info needed to load an executable...
sl@0
  1608
	iDepCount = iHeader->iDllRefTableCount;
sl@0
  1609
	iExportDirCount = iHeader->iExportDirCount;
sl@0
  1610
	iExportDir = iHeader->iExportDirOffset-iHeader->iCodeOffset;
sl@0
  1611
	iTextSize = iHeader->iTextSize;
sl@0
  1612
	iCodeSize = iHeader->iCodeSize;
sl@0
  1613
	__IF_DEBUG(Printf("Code + const %x",iCodeSize));
sl@0
  1614
	iDataSize = iHeader->iDataSize;
sl@0
  1615
	__IF_DEBUG(Printf("Data %x",iDataSize));
sl@0
  1616
	iBssSize = iHeader->iBssSize;
sl@0
  1617
	__IF_DEBUG(Printf("Bss %x",iBssSize));
sl@0
  1618
	iTotalDataSize = iDataSize+iBssSize;
sl@0
  1619
sl@0
  1620
	iFileEntryPoint = iHeader->iEntryPoint;	// just an offset at this stage
sl@0
  1621
	iEntryPtVeneer = 0;
sl@0
  1622
	iExceptionDescriptor = iHeader->ExceptionDescriptor();
sl@0
  1623
	if(iHeader->iExportDirOffset)
sl@0
  1624
		iExportDirLoad = iExportDir;		// only set this if not already loaded
sl@0
  1625
sl@0
  1626
	// initialise the SMP safe flag from the image header
sl@0
  1627
	// this will get cleared during ProcessImports if any import is not SMP safe
sl@0
  1628
	if(iHeader->iFlags & KImageSMPSafe)
sl@0
  1629
		iAttr |= ECodeSegAttSMPSafe;
sl@0
  1630
	else
sl@0
  1631
		{
sl@0
  1632
		__IF_DEBUG(Printf("%S is not marked SMP safe", &iFileName));
sl@0
  1633
		iAttr &= ~ECodeSegAttSMPSafe;
sl@0
  1634
		}
sl@0
  1635
sl@0
  1636
	// check if executable is to be demand paged...
sl@0
  1637
	r = ShouldBeCodePaged(iUseCodePaging);
sl@0
  1638
	__IF_DEBUG(Printf("ShouldBeCodePaged r=%d,iUseCodePaging=%d", r, iUseCodePaging));
sl@0
  1639
	if(iUseCodePaging==EFalse || r!=KErrNone)
sl@0
  1640
		return r;
sl@0
  1641
sl@0
  1642
	// image needs demand paging, create the additional information needed for this...
sl@0
  1643
sl@0
  1644
	// read compression info...
sl@0
  1645
	iCompressionType = iHeader->iCompressionType;
sl@0
  1646
	r = LoadCompressionData();
sl@0
  1647
	if(r==KErrNotSupported)
sl@0
  1648
		{
sl@0
  1649
		// Compression type not supported, so just load executable as normal, (without paging)...
sl@0
  1650
		iUseCodePaging = EFalse;
sl@0
  1651
		return KErrNone;
sl@0
  1652
		}
sl@0
  1653
	else if (r!=KErrNone)
sl@0
  1654
		return r;
sl@0
  1655
sl@0
  1656
	// clamp file so it doesn't get modified whilst it is being demand paged...
sl@0
  1657
	r = iFileClamp.Clamp(iFile);
sl@0
  1658
	// The clamp API will return KErrNotSupported if the media is removable: 
sl@0
  1659
	// this implies that paging is not possible but the binary can still be loaded
sl@0
  1660
	if (r != KErrNone)
sl@0
  1661
		{
sl@0
  1662
		iUseCodePaging = EFalse;
sl@0
  1663
		return r == KErrNotSupported ? KErrNone : r;
sl@0
  1664
		}
sl@0
  1665
sl@0
  1666
	// get blockmap data which indicates location of media where file contents are stored...
sl@0
  1667
	r = BuildCodeBlockMap();
sl@0
  1668
	__IF_DEBUG(Printf("BuildCodeBlockMap r=%d", r));
sl@0
  1669
	if(r==KErrNotSupported)
sl@0
  1670
		{
sl@0
  1671
		// media doesn't support demand paging, so just load executable as normal, (without paging)...
sl@0
  1672
		iUseCodePaging = EFalse;
sl@0
  1673
		iFileClamp.Close(gTheLoaderFs);
sl@0
  1674
		r = KErrNone;
sl@0
  1675
		}
sl@0
  1676
sl@0
  1677
	return r;
sl@0
  1678
	}
sl@0
  1679
sl@0
  1680
sl@0
  1681
TInt E32Image::CheckRomXIPAlreadyLoaded()
sl@0
  1682
	{
sl@0
  1683
	__IF_DEBUG(Printf("ROM XIP %08x CheckAlreadyLoaded",iRomImageHeader));
sl@0
  1684
	TFindCodeSeg find;
sl@0
  1685
	find.iRomImgHdr=iRomImageHeader;
sl@0
  1686
	E32Loader::CodeSegDeferDeletes();
sl@0
  1687
	TAny* h=NULL;
sl@0
  1688
	TInt r=KErrNone;
sl@0
  1689
	E32Loader::CodeSegNext(h, find);
sl@0
  1690
	if (h)
sl@0
  1691
		{
sl@0
  1692
		iHandle=h;
sl@0
  1693
		r=E32Loader::CodeSegOpen(h, iClientProcessHandle);
sl@0
  1694
		if (r==KErrNone)
sl@0
  1695
			E32Loader::CodeSegInfo(iHandle, *this);
sl@0
  1696
		}
sl@0
  1697
	E32Loader::CodeSegEndDeferDeletes();
sl@0
  1698
	if (iHandle && r==KErrNone)
sl@0
  1699
		{
sl@0
  1700
		iAlreadyLoaded=ETrue;
sl@0
  1701
		__IF_DEBUG(Printf("ROM XIP %08x already loaded", iHandle));
sl@0
  1702
		}
sl@0
  1703
	__IF_DEBUG(Printf("ROM XIP CheckAlreadyLoaded returns %d",r));
sl@0
  1704
	return r;
sl@0
  1705
	}
sl@0
  1706
sl@0
  1707
sl@0
  1708
/**
sl@0
  1709
Read the E32Image file into its code and data chunks, relocating them
sl@0
  1710
as necessary.
sl@0
  1711
Create a dll reference table from the names of dlls referenced.
sl@0
  1712
Fix up the import address table and the export table for real addresses.
sl@0
  1713
*/
sl@0
  1714
TInt E32Image::LoadToRam()
sl@0
  1715
	{
sl@0
  1716
	__IF_DEBUG(Printf("E32Image::LoadToRam %S",&iFileName));
sl@0
  1717
sl@0
  1718
	// offset of data after code which will be erad into iRestOfFileData...
sl@0
  1719
	iConversionOffset = iHeader->iCodeOffset + iHeader->iCodeSize;
sl@0
  1720
sl@0
  1721
	// calculate sizes...
sl@0
  1722
	TUint totalSize = ((E32ImageHeaderV*)iHeader)->iUncompressedSize;
sl@0
  1723
	TUint remainder = totalSize-iConversionOffset;
sl@0
  1724
	if(remainder>totalSize)
sl@0
  1725
		RETURN_FAILURE(KErrCorrupt); // Fuzzer can't trigger this because header validation prevents it
sl@0
  1726
sl@0
  1727
	iRestOfFileData = (TUint8*)User::Alloc(remainder);
sl@0
  1728
	if(!iRestOfFileData)
sl@0
  1729
		return KErrNoMemory;
sl@0
  1730
	iRestOfFileSize = remainder;
sl@0
  1731
sl@0
  1732
	TInt r = LoadFile(); // Read everything in
sl@0
  1733
	if(r!=KErrNone)
sl@0
  1734
		return r;
sl@0
  1735
sl@0
  1736
	__IF_DEBUG(Printf("iHeader->iCodeRelocOffset %d",iHeader->iCodeRelocOffset));
sl@0
  1737
	r = ((E32ImageHeaderV*)iHeader)->ValidateRelocations(iRestOfFileData,iRestOfFileSize,iHeader->iCodeRelocOffset,iHeader->iCodeSize,iCodeRelocSection);
sl@0
  1738
	if(r!=KErrNone)
sl@0
  1739
		return r;
sl@0
  1740
sl@0
  1741
	__IF_DEBUG(Printf("iHeader->iDataRelocOffset %d",iHeader->iDataRelocOffset));
sl@0
  1742
	r = ((E32ImageHeaderV*)iHeader)->ValidateRelocations(iRestOfFileData,iRestOfFileSize,iHeader->iDataRelocOffset,iHeader->iDataSize,iDataRelocSection);
sl@0
  1743
	if(r!=KErrNone)
sl@0
  1744
		return r;
sl@0
  1745
		
sl@0
  1746
	iCodeDelta = iCodeRunAddress-iHeader->iCodeBase;
sl@0
  1747
	iDataDelta = iDataRunAddress-iHeader->iDataBase;
sl@0
  1748
	
sl@0
  1749
	if(r==KErrNone)
sl@0
  1750
	   	r = RelocateCode();
sl@0
  1751
	if(r==KErrNone)
sl@0
  1752
		r = LoadAndRelocateData();
sl@0
  1753
	if(r==KErrNone)
sl@0
  1754
    	r = ReadImportData();
sl@0
  1755
sl@0
  1756
	return r;
sl@0
  1757
	}
sl@0
  1758
sl@0
  1759
sl@0
  1760
TInt E32Image::ShouldBeCodePaged(TBool& aPage)
sl@0
  1761
/**
sl@0
  1762
	Determine whether this binary should be paged.  Some of this
sl@0
  1763
	function is unimplemented because it requires the media pageable
sl@0
  1764
	attribute
sl@0
  1765
sl@0
  1766
	@param	aPage			On success, this variable is set to
sl@0
  1767
							whether the binary should be paged.  Its
sl@0
  1768
							value is undefined if the return code is
sl@0
  1769
							not KErrNone.
sl@0
  1770
	@return					Symbian OS error code.
sl@0
  1771
sl@0
  1772
	See S3.1.3.2 of PREQ1110 Design Sketch.
sl@0
  1773
 */
sl@0
  1774
	{
sl@0
  1775
	aPage = EFalse;
sl@0
  1776
sl@0
  1777
	// kernel and global dlls can't be paged...
sl@0
  1778
	if(iAttr&(ECodeSegAttKernel|ECodeSegAttGlobal))
sl@0
  1779
		return KErrNone;
sl@0
  1780
sl@0
  1781
	// 1. if paging policy is NOPAGING then executable is unpaged
sl@0
  1782
	TUint32 policy = E32Loader::PagingPolicy();
sl@0
  1783
sl@0
  1784
	__IF_DEBUG(Printf("sbcp,policy=0x%x", policy));
sl@0
  1785
	if (policy == EKernelConfigCodePagingPolicyNoPaging)
sl@0
  1786
		return KErrNone;
sl@0
  1787
sl@0
  1788
	// 2. if executable is on media without Pageable Media Attribute then unpaged
sl@0
  1789
	// 3. if executable is on removable media then unpaged
sl@0
  1790
	//	both superseded by the BlockMap API
sl@0
  1791
sl@0
  1792
	// 3a. if executable has already been loaded into RAM for tamperproofing then
sl@0
  1793
	//     it can't be paged
sl@0
  1794
	if (iFileData != NULL)
sl@0
  1795
		return KErrNone;
sl@0
  1796
sl@0
  1797
	// 4. if not compressed with bytepair or uncompressed then unpaged
sl@0
  1798
	__IF_DEBUG(Printf("sbcp,iHeader=0x%08x", iHeader));
sl@0
  1799
	TUint32 comp = iHeader->CompressionType();
sl@0
  1800
	__IF_DEBUG(Printf("sbcp,comp=0x%x", comp));
sl@0
  1801
	if (comp != KUidCompressionBytePair && comp != KFormatNotCompressed)
sl@0
  1802
		return KErrNone;
sl@0
  1803
sl@0
  1804
	aPage = ETrue;
sl@0
  1805
sl@0
  1806
	// 5. if policy is ALWAYSPAGE then page
sl@0
  1807
	if (policy == EKernelConfigCodePagingPolicyAlwaysPage)
sl@0
  1808
		return KErrNone;
sl@0
  1809
sl@0
  1810
	// 6. 
sl@0
  1811
	TUint KPagedMask = (KImageCodePaged | KImageCodeUnpaged);
sl@0
  1812
	TUint pagedFlags = iHeader->iFlags & KPagedMask;
sl@0
  1813
	__IF_DEBUG(Printf("sbcp,iHeader->iFlags=0x%x,pagedFlags=0x%x", iHeader->iFlags, pagedFlags));
sl@0
  1814
sl@0
  1815
	// if KImageCodePaged and KImageCodeUnpaged flags present then corrupt
sl@0
  1816
	if (pagedFlags == KPagedMask)
sl@0
  1817
		RETURN_FAILURE(KErrCorrupt);
sl@0
  1818
sl@0
  1819
	// if KImageCodePaged set in executable then page
sl@0
  1820
	if (pagedFlags == KImageCodePaged)
sl@0
  1821
		return KErrNone;
sl@0
  1822
sl@0
  1823
	// if KImageCodeUnpaged set in executable then do not page
sl@0
  1824
	if (pagedFlags == KImageCodeUnpaged)
sl@0
  1825
		{
sl@0
  1826
		aPage = EFalse;
sl@0
  1827
		return KErrNone;
sl@0
  1828
		}
sl@0
  1829
sl@0
  1830
	// 7. otherwise (neither paged nor unpaged set) use paging policy
sl@0
  1831
sl@0
  1832
	// policy must be EKernelConfigCodePagingPolicyDefaultUnpaged or EKernelConfigCodePagingPolicyDefaultPaged
sl@0
  1833
	aPage = (policy == EKernelConfigCodePagingPolicyDefaultPaged);
sl@0
  1834
	return KErrNone;
sl@0
  1835
	}
sl@0
  1836
sl@0
  1837
TInt E32Image::BuildCodeBlockMap()
sl@0
  1838
/**
sl@0
  1839
	Use the block map API to build an array of TBlockMapInfo
sl@0
  1840
	objects which the kernel can use to page in code as required.
sl@0
  1841
sl@0
  1842
	@return					Symbian OS error code.  KErrNotSupported means the
sl@0
  1843
							Block Map functionality does not support paging from
sl@0
  1844
							the binary's location.
sl@0
  1845
 */
sl@0
  1846
	{
sl@0
  1847
	__IF_DEBUG(Printf("BuildCodeBlockMap,iCodeStartInFile=%d,iCodeLengthInFile=%d", iCodeStartInFile, iCodeLengthInFile));
sl@0
  1848
sl@0
  1849
	__ASSERT_DEBUG(iUseCodePaging, Panic(EBcbmNotCodePaged));
sl@0
  1850
sl@0
  1851
	// do nothing if no code section
sl@0
  1852
	if (iCodeLengthInFile == 0)
sl@0
  1853
		return KErrNone;
sl@0
  1854
sl@0
  1855
	// RFile::BlockMap populates an instance of this object.  Need to
sl@0
  1856
	// retain information such as granularity which applies to all entries.
sl@0
  1857
	SBlockMapInfo bmi;
sl@0
  1858
sl@0
  1859
	TInt curEntriesSize = 0;
sl@0
  1860
	TUint8* entries8 = 0;		// points to heap cell containing TBlockMapEntryBase array
sl@0
  1861
sl@0
  1862
	TInt64 bmPos = 0;
sl@0
  1863
	TInt64 bmEnd = iCodeStartInFile + iCodeLengthInFile;
sl@0
  1864
	TInt r;
sl@0
  1865
	do
sl@0
  1866
		{
sl@0
  1867
		__IF_DEBUG(Printf("lfbpu:BlockMap,in,bmPos=%ld,bmEnd=%ld", bmPos, bmEnd));
sl@0
  1868
		r = iFile.BlockMap(bmi, bmPos, bmEnd, EBlockMapUsagePaging);	// updates bmPos to end of mapped range
sl@0
  1869
		__IF_DEBUG(
sl@0
  1870
			Printf("lfbpu:BlockMap,out,r=%d,bmPos=%ld,bmEnd=%ld,maplen=%d(%d)",
sl@0
  1871
			r, bmPos, bmEnd, bmi.iMap.Length(), bmi.iMap.Length() / sizeof(TBlockMapEntryBase)));
sl@0
  1872
		__IF_DEBUG(
sl@0
  1873
			Printf("lfbpu:BlockMap,out,iBlockGranularity=%u,iBlockStartOffset=%u,iStartBlockAddress=%ld,iLocalDriveNumber=%d",
sl@0
  1874
			bmi.iBlockGranularity, bmi.iBlockStartOffset, bmi.iStartBlockAddress, bmi.iLocalDriveNumber));
sl@0
  1875
		if (r != KErrNone && r != KErrCompletion)
sl@0
  1876
			break;
sl@0
  1877
sl@0
  1878
		// Copy info the first time round as this gets overwritten on subsequent passes
sl@0
  1879
		if (curEntriesSize == 0)
sl@0
  1880
			iCodeBlockMapCommon = bmi;	// slices the SBlockMapCommon subclass data
sl@0
  1881
		
sl@0
  1882
		// grow the buffer which contains the entries
sl@0
  1883
		TInt newEntriesSize = bmi.iMap.Length();
sl@0
  1884
		TInt newArraySize = curEntriesSize + newEntriesSize;
sl@0
  1885
		TUint8* newEntries8 = (TUint8*) User::ReAlloc(entries8, newArraySize);
sl@0
  1886
		if (newEntries8 == 0)
sl@0
  1887
			{
sl@0
  1888
			r = KErrNoMemory;
sl@0
  1889
			break;
sl@0
  1890
			}
sl@0
  1891
		entries8 = newEntries8;
sl@0
  1892
sl@0
  1893
#ifdef _DEBUG
sl@0
  1894
		// dump the newly-returned block entries
sl@0
  1895
		for (TInt i = 0; i < newEntriesSize; i += sizeof(TBlockMapEntryBase))
sl@0
  1896
			{
sl@0
  1897
			const TBlockMapEntryBase& bme = *reinterpret_cast<const TBlockMapEntryBase*>(bmi.iMap.Ptr() + i);
sl@0
  1898
			__IF_DEBUG(Printf("lfbpu:bme,iNumberOfBlocks=%d,iStartBlock=%d", bme.iNumberOfBlocks, bme.iStartBlock));
sl@0
  1899
			}
sl@0
  1900
#endif
sl@0
  1901
sl@0
  1902
		// append the new entries to the array.
sl@0
  1903
		Mem::Copy(entries8 + curEntriesSize, bmi.iMap.Ptr(), newEntriesSize);
sl@0
  1904
		curEntriesSize = newArraySize;
sl@0
  1905
		} while (r != KErrCompletion);
sl@0
  1906
sl@0
  1907
	// r == KErrCompletion when mapped code section range
sl@0
  1908
	if (r != KErrCompletion)
sl@0
  1909
		{
sl@0
  1910
		User::Free(entries8);
sl@0
  1911
		return r;
sl@0
  1912
		}
sl@0
  1913
	
sl@0
  1914
#ifdef _DEBUG
sl@0
  1915
	// dump the block map table
sl@0
  1916
	__IF_DEBUG(Printf("lfbpu:endbme,r=%d,curEntriesSize=%d", r, curEntriesSize));
sl@0
  1917
	for (TInt i = 0; i < curEntriesSize; i += 8)
sl@0
  1918
		{
sl@0
  1919
		__IF_DEBUG(Printf(
sl@0
  1920
			"entries[0x%08x], %02x %02x %02x %02x %02x %02x %02x %02x",
sl@0
  1921
			entries8[i+0], entries8[i+1], entries8[i+2], entries8[i+3],
sl@0
  1922
			entries8[i+4], entries8[i+5], entries8[i+6], entries8[i+7]));
sl@0
  1923
		}
sl@0
  1924
#endif
sl@0
  1925
sl@0
  1926
	iCodeBlockMapEntries = reinterpret_cast<TBlockMapEntryBase*>(entries8);
sl@0
  1927
	iCodeBlockMapEntriesSize = curEntriesSize;
sl@0
  1928
sl@0
  1929
	return KErrNone;
sl@0
  1930
	}
sl@0
  1931
sl@0
  1932
sl@0
  1933
/**
sl@0
  1934
Get the compression data relevant to demand paging
sl@0
  1935
*/
sl@0
  1936
TInt E32Image::LoadCompressionData()
sl@0
  1937
	{
sl@0
  1938
	__IF_DEBUG(Printf("E32Image::LoadCompressionData %S 0x%08x",&iFileName,iHeader->CompressionType()));
sl@0
  1939
sl@0
  1940
	TUint compression = iHeader->CompressionType();
sl@0
  1941
sl@0
  1942
	TInt r = KErrNone;
sl@0
  1943
	if(compression==KFormatNotCompressed)
sl@0
  1944
		{
sl@0
  1945
		r = LoadCompressionDataNoCompress();
sl@0
  1946
		}
sl@0
  1947
	else if(compression==KUidCompressionBytePair)
sl@0
  1948
		{
sl@0
  1949
		TRAP(r,LoadCompressionDataBytePairUnpakL());
sl@0
  1950
		}
sl@0
  1951
	else
sl@0
  1952
		{
sl@0
  1953
		r = KErrNotSupported;
sl@0
  1954
		}
sl@0
  1955
sl@0
  1956
	__IF_DEBUG(Printf("E32Image::LoadCompressionData exiting %S r=%d",&iFileName,r));
sl@0
  1957
	return r;	
sl@0
  1958
	}
sl@0
  1959
sl@0
  1960
sl@0
  1961
TInt E32Image::LoadCompressionDataNoCompress()
sl@0
  1962
	{
sl@0
  1963
	__IF_DEBUG(Printf("E32Image::LoadCompressionDataNoCompress %S",&iFileName));
sl@0
  1964
	if (iHeader->iCodeSize)
sl@0
  1965
		{
sl@0
  1966
		iCodeStartInFile = iHeader->iCodeOffset;
sl@0
  1967
		iCodeLengthInFile = iCodeSize;
sl@0
  1968
		}
sl@0
  1969
	return KErrNone;
sl@0
  1970
	}
sl@0
  1971
sl@0
  1972
sl@0
  1973
void E32Image::LoadCompressionDataBytePairUnpakL()
sl@0
  1974
	{
sl@0
  1975
	__IF_DEBUG(Printf("E32Image::LoadCompressionDataBytePairUnpakL %S",&iFileName));
sl@0
  1976
sl@0
  1977
	if (iFileData)
sl@0
  1978
		User::Leave(KErrNotSupported); // if the file data has been loaded into RAM we can't page it!
sl@0
  1979
sl@0
  1980
	TInt pos = iHeader->TotalSize();
sl@0
  1981
	User::LeaveIfError(iFile.Seek(ESeekStart,pos)); // Start at beginning of compressed data
sl@0
  1982
sl@0
  1983
	CBytePairReader* reader = CBytePairFileReader::NewLC(iFile);
sl@0
  1984
sl@0
  1985
	if (iHeader->iCodeSize)
sl@0
  1986
		{
sl@0
  1987
		__IF_DEBUG(Printf("Code & const size %x",iCodeSize));
sl@0
  1988
		__IF_DEBUG(Printf("Code & const offset %x",iHeader->iCodeOffset));
sl@0
  1989
		__IF_DEBUG(Printf("Code & const dest %x",iCodeLoadAddress));
sl@0
  1990
		
sl@0
  1991
		TInt pageCount;
sl@0
  1992
		reader->GetPageOffsetsL(pos, pageCount, iCodePageOffsets);
sl@0
  1993
sl@0
  1994
#ifdef _DEBUG
sl@0
  1995
		for (TInt i = 0; i <= pageCount; ++i)
sl@0
  1996
			{
sl@0
  1997
			__IF_DEBUG(Printf("lfbpu:raw iCodePageOffsets[%d] = %d", i, iCodePageOffsets[i]));
sl@0
  1998
			}
sl@0
  1999
#endif
sl@0
  2000
sl@0
  2001
		// record the code start position in the file and its compressed length
sl@0
  2002
		// so BuildCodeBlockMap can construct a block map for the kernel if this
sl@0
  2003
		// file is demand paged.
sl@0
  2004
		iCodeStartInFile = iCodePageOffsets[0];
sl@0
  2005
		iCodeLengthInFile = iCodePageOffsets[pageCount] - iCodePageOffsets[0];
sl@0
  2006
		}
sl@0
  2007
		
sl@0
  2008
	CleanupStack::PopAndDestroy(reader);
sl@0
  2009
	}
sl@0
  2010
sl@0
  2011
sl@0
  2012
/**
sl@0
  2013
Read all image data into memory, decompressing it using the method indicated in the image header..
sl@0
  2014
If code isn't being demand paged the code part is read into #iCodeLoadAddress.
sl@0
  2015
The rest of the file data after the code part is read into #iRestOfFileData.
sl@0
  2016
*/
sl@0
  2017
TInt E32Image::LoadFile()
sl@0
  2018
	{
sl@0
  2019
	__IF_DEBUG(Printf("E32Image::LoadFile %S 0x%08x",&iFileName,iHeader->CompressionType()));
sl@0
  2020
sl@0
  2021
	TUint compression = iHeader->CompressionType();
sl@0
  2022
sl@0
  2023
	TInt r=KErrNone;
sl@0
  2024
	if(compression==KFormatNotCompressed)
sl@0
  2025
		{
sl@0
  2026
		r = LoadFileNoCompress();
sl@0
  2027
		CHECK_FAILURE(r); // Fuzzer can't trigger this because it only happens on file i/o error
sl@0
  2028
		}
sl@0
  2029
	else if(compression==KUidCompressionDeflate)
sl@0
  2030
		{
sl@0
  2031
		TRAP(r,LoadFileInflateL());
sl@0
  2032
		CHECK_FAILURE(r);
sl@0
  2033
		}
sl@0
  2034
	else if(compression==KUidCompressionBytePair)
sl@0
  2035
		{
sl@0
  2036
		TRAP(r,LoadFileBytePairUnpakL());
sl@0
  2037
		CHECK_FAILURE(r);
sl@0
  2038
		}
sl@0
  2039
	else
sl@0
  2040
		{
sl@0
  2041
		r = KErrNotSupported;
sl@0
  2042
		CHECK_FAILURE(r); // Fuzzer can't trigger this because header validation ensures compression type is OK
sl@0
  2043
		}
sl@0
  2044
sl@0
  2045
	// we're done with the file contents now, free up memory before resolving imports
sl@0
  2046
	if(iFileData)
sl@0
  2047
		{
sl@0
  2048
		gFileDataAllocator.Free(iFileData);
sl@0
  2049
		iFileData=NULL;
sl@0
  2050
		}
sl@0
  2051
sl@0
  2052
	__IF_DEBUG(Printf("E32Image::LoadFile exiting %S r=%d",&iFileName,r));
sl@0
  2053
	return r;
sl@0
  2054
	}
sl@0
  2055
sl@0
  2056
sl@0
  2057
/**
sl@0
  2058
Read data from the image's file (or the preloaded data at #iFileData if present).
sl@0
  2059
*/
sl@0
  2060
TInt E32Image::Read(TUint aPos, TUint8* aDest, TUint aSize, TBool aSvPerms)
sl@0
  2061
	{
sl@0
  2062
	TPtr8 p(aDest,aSize,aSize);
sl@0
  2063
	if(iFileData)
sl@0
  2064
		{
sl@0
  2065
		// get data from pre-loaded image data...
sl@0
  2066
		if(aPos+aSize>iFileSize)
sl@0
  2067
			RETURN_FAILURE(KErrCorrupt); // Fuzzer can't trigger this because earlier validation prevents sizes being wrong
sl@0
  2068
		if (aSvPerms)
sl@0
  2069
			WordCopy(aDest,iFileData+aPos,aSize);
sl@0
  2070
		else
sl@0
  2071
			p.Copy(iFileData+aPos,aSize);
sl@0
  2072
		}
sl@0
  2073
	else
sl@0
  2074
		{
sl@0
  2075
		// get data from file...
sl@0
  2076
		TInt r = iFile.Read(aPos,p,aSize);
sl@0
  2077
		if(r!=KErrNone)
sl@0
  2078
			return r;
sl@0
  2079
		}
sl@0
  2080
sl@0
  2081
	// check we got the amount of data requested...
sl@0
  2082
	if(TUint(p.Length())!=aSize)
sl@0
  2083
		{
sl@0
  2084
		__IF_DEBUG(Printf("E32Image::Read() Expected:%d, read:%d", aSize, p.Length() ));
sl@0
  2085
		RETURN_FAILURE(KErrCorrupt); // Fuzzer can't trigger this because requires file length to change during load
sl@0
  2086
		}
sl@0
  2087
sl@0
  2088
	return KErrNone;
sl@0
  2089
	}
sl@0
  2090
sl@0
  2091
sl@0
  2092
/**
sl@0
  2093
Read all image data into memory.
sl@0
  2094
If code isn't being demand paged the code part is read into #iCodeLoadAddress.
sl@0
  2095
The rest of the file data after the code part is read into #iRestOfFileData.
sl@0
  2096
*/
sl@0
  2097
TInt E32Image::LoadFileNoCompress()
sl@0
  2098
	{
sl@0
  2099
	__IF_DEBUG(Printf("E32Image::LoadFileNoCompress exiting %S",&iFileName));
sl@0
  2100
	TInt r = KErrNone;
sl@0
  2101
	
sl@0
  2102
	if(iHeader->iCodeSize && !iUseCodePaging)
sl@0
  2103
		{
sl@0
  2104
		__IF_DEBUG(Printf("Code & const size %x",iCodeSize));
sl@0
  2105
		__IF_DEBUG(Printf("Code & const offset %x",iHeader->iCodeOffset));
sl@0
  2106
		__IF_DEBUG(Printf("Code & const dest %x",iCodeLoadAddress));
sl@0
  2107
		r = Read(iHeader->iCodeOffset, (TText8*)iCodeLoadAddress, iCodeSize, ETrue);
sl@0
  2108
		if(r!=KErrNone)
sl@0
  2109
			return r;
sl@0
  2110
		}
sl@0
  2111
sl@0
  2112
	if(iRestOfFileSize)
sl@0
  2113
		r = Read(iConversionOffset, iRestOfFileData, iRestOfFileSize);
sl@0
  2114
	
sl@0
  2115
	return r;
sl@0
  2116
	}
sl@0
  2117
sl@0
  2118
sl@0
  2119
void FileCleanup(TAny* aPtr)
sl@0
  2120
	{
sl@0
  2121
	TFileInput* f=(TFileInput*)aPtr;
sl@0
  2122
	f->Cancel();
sl@0
  2123
	delete f;
sl@0
  2124
	}
sl@0
  2125
sl@0
  2126
/**
sl@0
  2127
Read all image data into memory, decompressing it using the Inflate method.
sl@0
  2128
If code isn't being demand paged the code part is read into #iCodeLoadAddress.
sl@0
  2129
The rest of the file data after the code part is read into #iRestOfFileData.
sl@0
  2130
*/
sl@0
  2131
void E32Image::LoadFileInflateL()
sl@0
  2132
	{
sl@0
  2133
	__IF_DEBUG(Printf("E32Image::LoadFileInflateL %S",&iFileName));
sl@0
  2134
	__ASSERT_DEBUG(!iUseCodePaging, Panic(ELfiCodePagingNotSupported));
sl@0
  2135
	
sl@0
  2136
	TInt pos = iHeader->TotalSize();
sl@0
  2137
	TBitInput* file;
sl@0
  2138
	if(iFileData)
sl@0
  2139
		{
sl@0
  2140
		if(pos < 0)
sl@0
  2141
			User::Leave(KErrArgument);
sl@0
  2142
		file = new (ELeave) TBitInput(iFileData, iFileSize*8, pos*8);
sl@0
  2143
		CleanupStack::PushL(file);
sl@0
  2144
		}
sl@0
  2145
	else
sl@0
  2146
		{
sl@0
  2147
		User::LeaveIfError(iFile.Seek(ESeekStart,pos)); // Start at beginning of compressed data
sl@0
  2148
		file = new (ELeave) TFileInput(iFile);
sl@0
  2149
		CleanupStack::PushL(TCleanupItem(&FileCleanup,file));
sl@0
  2150
		}
sl@0
  2151
sl@0
  2152
	CInflater* inflater=CInflater::NewLC(*file);
sl@0
  2153
	
sl@0
  2154
	if(iHeader->iCodeSize)
sl@0
  2155
		{
sl@0
  2156
		__IF_DEBUG(Printf("Code & const size %x",iCodeSize));
sl@0
  2157
		__IF_DEBUG(Printf("Code & const offset %x",iHeader->iCodeOffset));
sl@0
  2158
		__IF_DEBUG(Printf("Code & const dest %x",iCodeLoadAddress));
sl@0
  2159
sl@0
  2160
		TInt count = inflater->ReadL((TUint8*)iCodeLoadAddress,iCodeSize,&WordCopy);
sl@0
  2161
		if(count!=iCodeSize)
sl@0
  2162
			User::Leave(KErrCorrupt);
sl@0
  2163
		}
sl@0
  2164
sl@0
  2165
	if(iRestOfFileSize)
sl@0
  2166
		{
sl@0
  2167
		TUint32 count = inflater->ReadL(iRestOfFileData,iRestOfFileSize,&Mem::Copy);
sl@0
  2168
		if(count!=iRestOfFileSize)
sl@0
  2169
			User::Leave(KErrCorrupt);
sl@0
  2170
		}
sl@0
  2171
sl@0
  2172
	CleanupStack::PopAndDestroy(2,file);
sl@0
  2173
	}
sl@0
  2174
	
sl@0
  2175
sl@0
  2176
/**
sl@0
  2177
Read all image data into memory, decompressing it using the BytePair method.
sl@0
  2178
If code isn't being demand paged the code part is read into #iCodeLoadAddress.
sl@0
  2179
The rest of the file data after the code part is read into #iRestOfFileData.
sl@0
  2180
*/
sl@0
  2181
void E32Image::LoadFileBytePairUnpakL()
sl@0
  2182
	{
sl@0
  2183
	__IF_DEBUG(Printf("E32Image::LoadFileBytePairUnpak %S",&iFileName));
sl@0
  2184
sl@0
  2185
	// code starts after header
sl@0
  2186
	TInt pos = iHeader->TotalSize();
sl@0
  2187
sl@0
  2188
	CBytePairReader* reader;
sl@0
  2189
	if(iFileData)
sl@0
  2190
		reader = CBytePairReader::NewLC(iFileData+pos, iFileSize-pos);
sl@0
  2191
	else
sl@0
  2192
		{
sl@0
  2193
		iFile.Seek(ESeekStart, pos);
sl@0
  2194
		reader = CBytePairFileReader::NewLC(iFile);
sl@0
  2195
		}
sl@0
  2196
sl@0
  2197
	TBool codeLoaded = false;
sl@0
  2198
	if(iHeader->iCodeSize && !iUseCodePaging)
sl@0
  2199
		{
sl@0
  2200
		__IF_DEBUG(Printf("Code & const size %x",iCodeSize));
sl@0
  2201
		__IF_DEBUG(Printf("Code & const offset %x",iHeader->iCodeOffset));
sl@0
  2202
		__IF_DEBUG(Printf("Code & const dest %x",iCodeLoadAddress));
sl@0
  2203
sl@0
  2204
		TUint32 bytes = reader->DecompressPagesL((TUint8*)iCodeLoadAddress,iCodeSize,&WordCopy);
sl@0
  2205
sl@0
  2206
		__IF_DEBUG(Printf("bytes:%x",bytes));
sl@0
  2207
		if((TInt)bytes!=iCodeSize)
sl@0
  2208
			User::Leave(KErrCorrupt);
sl@0
  2209
sl@0
  2210
		codeLoaded = true;
sl@0
  2211
		}
sl@0
  2212
	
sl@0
  2213
	if(iRestOfFileSize)
sl@0
  2214
		{
sl@0
  2215
		if(!codeLoaded)
sl@0
  2216
			{
sl@0
  2217
			// skip past code part of file...
sl@0
  2218
			TInt pageCount = (iCodeSize + KPageOffsetMask) >> KPageSizeShift;
sl@0
  2219
		
sl@0
  2220
			TInt pos = 	KIndexTableHeaderSize
sl@0
  2221
					+	pageCount * sizeof(TUint16)
sl@0
  2222
					+   iCodeLengthInFile;
sl@0
  2223
	 
sl@0
  2224
			__IF_DEBUG(Printf("lfpbu:pos=%x", pos));
sl@0
  2225
			reader->SeekForwardL(pos);
sl@0
  2226
			}
sl@0
  2227
		
sl@0
  2228
		__IF_DEBUG(Printf("  iRestOfFileSize==%x, iRestOfFileData==%x", iRestOfFileSize, iRestOfFileData));
sl@0
  2229
		
sl@0
  2230
		TUint32 bytes = reader->DecompressPagesL(iRestOfFileData,iRestOfFileSize,NULL);
sl@0
  2231
		__IF_DEBUG(Printf("bytes:%x",bytes));
sl@0
  2232
		if(bytes!=iRestOfFileSize)
sl@0
  2233
			User::Leave(KErrCorrupt);
sl@0
  2234
		}
sl@0
  2235
		
sl@0
  2236
	CleanupStack::PopAndDestroy(reader);
sl@0
  2237
	}
sl@0
  2238
sl@0
  2239
sl@0
  2240
/**
sl@0
  2241
Relocate code.
sl@0
  2242
*/
sl@0
  2243
TInt E32Image::RelocateCode()
sl@0
  2244
	{
sl@0
  2245
	if(iHeader->iExportDirOffset)
sl@0
  2246
		iExportDirLoad += iCodeLoadAddress;	// only for RAM modules which are not already loaded
sl@0
  2247
sl@0
  2248
	__IF_DEBUG(Printf("**EntryPointVeneer %08x FileEntryPoint %08x",iEntryPtVeneer,iFileEntryPoint));
sl@0
  2249
	__IF_DEBUG(Printf("**ExportDir load@%08x run@%08x",iExportDirLoad,iExportDir));
sl@0
  2250
	TInt r = KErrNone;	
sl@0
  2251
	if(iHeader->iCodeRelocOffset)
sl@0
  2252
		{
sl@0
  2253
		__IF_DEBUG(Printf("Relocate code & const"));
sl@0
  2254
sl@0
  2255
		if(!iUseCodePaging)
sl@0
  2256
			r = RelocateSection(iCodeRelocSection, iCodeLoadAddress);
sl@0
  2257
		else
sl@0
  2258
			{
sl@0
  2259
			r = AllocateRelocationData(iCodeRelocSection, iHeader->iCodeSize, iCodeLoadAddress, iCodeRelocTable);
sl@0
  2260
			iExportDirEntryDelta = iCodeDelta; // so exports get relocated
sl@0
  2261
			}
sl@0
  2262
		}
sl@0
  2263
sl@0
  2264
	if(r==KErrNone)
sl@0
  2265
		r = RelocateExports();
sl@0
  2266
sl@0
  2267
	if(r==KErrNone)
sl@0
  2268
		{
sl@0
  2269
		// put a unique ID into the third word after the entry point
sl@0
  2270
sl@0
  2271
		// address for ID...
sl@0
  2272
		TLinAddr csid_addr = iFileEntryPoint+KCodeSegIdOffset-iCodeRunAddress+iCodeLoadAddress;
sl@0
  2273
		__IF_DEBUG(Printf("csid_addr %08x", csid_addr));
sl@0
  2274
sl@0
  2275
		// get existing ID...
sl@0
  2276
		TUint x;
sl@0
  2277
		WordCopy(&x, (const TAny*)csid_addr, sizeof(x));
sl@0
  2278
		if(x==0)
sl@0
  2279
			{
sl@0
  2280
			// generate next ID...
sl@0
  2281
			if(++NextCodeSegId == 0xffffffffu)
sl@0
  2282
				Fault(ELdrCsIdWrap);
sl@0
  2283
			__IF_DEBUG(Printf("NextCSID %08x", NextCodeSegId));
sl@0
  2284
			// store ID...
sl@0
  2285
			if(!iUseCodePaging)
sl@0
  2286
				WordCopy((TAny*)csid_addr, &NextCodeSegId, sizeof(NextCodeSegId));
sl@0
  2287
			else
sl@0
  2288
				{
sl@0
  2289
				// demand paged code needs modifying when paged in, so add ID as a new 'fixup'...
sl@0
  2290
				TUint64* fixup = ExpandFixups(1);
sl@0
  2291
				if(!fixup)
sl@0
  2292
					r = KErrNoMemory;
sl@0
  2293
				else
sl@0
  2294
					*fixup = MAKE_TUINT64(csid_addr,NextCodeSegId);
sl@0
  2295
				}
sl@0
  2296
			}
sl@0
  2297
		}
sl@0
  2298
sl@0
  2299
	return r;
sl@0
  2300
	}
sl@0
  2301
sl@0
  2302
sl@0
  2303
/**
sl@0
  2304
Copy the data section from buffer #iRestOfFileData to the memory allocated at #iDataLoadAddress.
sl@0
  2305
Then relocate this data ready for use at the executables run addresses.
sl@0
  2306
*/
sl@0
  2307
TInt E32Image::LoadAndRelocateData()
sl@0
  2308
	{
sl@0
  2309
	__IF_DEBUG(Printf("E32Image::LoadAndRelocateData %S",&iFileName));
sl@0
  2310
	if(!iHeader->iDataOffset)
sl@0
  2311
		return KErrNone; // do data section
sl@0
  2312
sl@0
  2313
	// copy data...
sl@0
  2314
	__IF_DEBUG(Printf("Read Data: size %x->%08x",iDataSize,iDataLoadAddress));
sl@0
  2315
	TUint32 bufferOffset=iHeader->iDataOffset-iConversionOffset;
sl@0
  2316
	TUint8* source=iRestOfFileData+bufferOffset;
sl@0
  2317
	MemCopy((TText8*)iDataLoadAddress,source,iDataSize);
sl@0
  2318
sl@0
  2319
	// relocate data...
sl@0
  2320
	__IF_DEBUG(Printf("Relocate data section"));
sl@0
  2321
	__IF_DEBUG(Printf("iDataRelocOffset %08x",iHeader->iDataRelocOffset));
sl@0
  2322
	TInt r = KErrNone;	
sl@0
  2323
	if(iHeader->iDataRelocOffset)
sl@0
  2324
		r = RelocateSection(iDataRelocSection, iDataLoadAddress);
sl@0
  2325
sl@0
  2326
	return r;
sl@0
  2327
	}
sl@0
  2328
sl@0
  2329
sl@0
  2330
/**
sl@0
  2331
Copies data from aDestination to aSource by running in supervisor mode.
sl@0
  2332
aDest, aSource & aNumberOfBytes must be word aligned.
sl@0
  2333
*/
sl@0
  2334
TUint8* E32Image::WordCopy(TAny* aDestination, const TAny* aSource, TInt aNumberOfBytes)
sl@0
  2335
	{
sl@0
  2336
	aNumberOfBytes &= ~3; // Avoid panics for corrupt data which is not word size
sl@0
  2337
	SCopyDataInfo info = {aDestination,aSource, aNumberOfBytes};
sl@0
  2338
	return (TUint8*) ExecuteInSupervisorMode(&svWordCopy, &info);
sl@0
  2339
	}
sl@0
  2340
sl@0
  2341
sl@0
  2342
/**
sl@0
  2343
Copies data from aDestination to aSource by running in supervisor mode.
sl@0
  2344
*/
sl@0
  2345
TUint8* E32Image::MemCopy(TAny* aDestination, const TAny* aSource, TInt aNumberOfBytes)
sl@0
  2346
	{
sl@0
  2347
	SCopyDataInfo info={aDestination,aSource, aNumberOfBytes};
sl@0
  2348
	return (TUint8*) ExecuteInSupervisorMode(&svMemCopy, &info);
sl@0
  2349
	}
sl@0
  2350
sl@0
  2351
sl@0
  2352
/**
sl@0
  2353
Relocate a section, applying relocations for run addresses to values currently at their load addresses.
sl@0
  2354
*/
sl@0
  2355
TInt E32Image::RelocateSection(E32RelocSection* aSection, TUint32 aLoadAddress)
sl@0
  2356
	{
sl@0
  2357
	if(!aSection)
sl@0
  2358
		return KErrNone;
sl@0
  2359
sl@0
  2360
	__IF_DEBUG(Printf("Relocate: NRelocs:%08x LoadAddr:%08x", aSection->iNumberOfRelocs, aLoadAddress));
sl@0
  2361
sl@0
  2362
	SRelocateSectionInfo info={this, (TUint8*)(aSection+1), aSection->iNumberOfRelocs, aLoadAddress};
sl@0
  2363
sl@0
  2364
	// call function in supervisor mode to relocate the section
sl@0
  2365
	TInt r = ExecuteInSupervisorMode(&svRelocateSection, &info);
sl@0
  2366
sl@0
  2367
	__IF_DEBUG(Printf("Relocate returning %d",r));
sl@0
  2368
	return r;
sl@0
  2369
	}
sl@0
  2370
sl@0
  2371
sl@0
  2372
/**
sl@0
  2373
Relocate the export directory for the code's run address
sl@0
  2374
*/
sl@0
  2375
TInt E32Image::RelocateExports()
sl@0
  2376
	{
sl@0
  2377
	// This only has to be done for PE-derived images, ELF marks all
sl@0
  2378
	// export table entries as 'relocations' so this job has already been done.
sl@0
  2379
	TUint impfmt = iHeader->ImportFormat();
sl@0
  2380
	if (impfmt == KImageImpFmt_ELF)
sl@0
  2381
		return KErrNone;
sl@0
  2382
sl@0
  2383
	__IF_DEBUG(Printf("E32Image::RelocateExports %S",&iFileName));
sl@0
  2384
sl@0
  2385
	if(iHeader->iExportDirOffset)
sl@0
  2386
		{
sl@0
  2387
		// call function in supervisor mode to fix up export directory
sl@0
  2388
		ExecuteInSupervisorMode(&svRelocateExports, this);
sl@0
  2389
		}
sl@0
  2390
	return KErrNone;
sl@0
  2391
	}
sl@0
  2392
sl@0
  2393
sl@0
  2394
/**
sl@0
  2395
Validate import section data structures in iRestOfFileData.
sl@0
  2396
Set iImportData to point to point to start of this.
sl@0
  2397
Allocate memory (iCurrentImportList) which is big enough to store imports for a single dependency.
sl@0
  2398
*/
sl@0
  2399
TInt E32Image::ReadImportData()
sl@0
  2400
	{
sl@0
  2401
	__IF_DEBUG(Printf("E32Image::ReadImportData %S",&iFileName));
sl@0
  2402
sl@0
  2403
	if(!iHeader->iImportOffset)
sl@0
  2404
		return KErrNone;
sl@0
  2405
sl@0
  2406
	TUint biggestImportCount; 
sl@0
  2407
	TInt r = ((E32ImageHeaderV*)iHeader)->ValidateImports(iRestOfFileData,iRestOfFileSize,biggestImportCount);
sl@0
  2408
	if(r!=KErrNone)
sl@0
  2409
		return r;
sl@0
  2410
sl@0
  2411
	iImportData = (TUint32*)(iRestOfFileData+iHeader->iImportOffset-iConversionOffset);
sl@0
  2412
	iCurrentImportList = (TUint32*)User::Alloc(biggestImportCount * sizeof(TUint32));
sl@0
  2413
	__IF_DEBUG(Printf("E32Image::ReadImportData - alloc %d current import slots at %08x", biggestImportCount, iCurrentImportList));
sl@0
  2414
	if(!iCurrentImportList)
sl@0
  2415
		return KErrNoMemory;
sl@0
  2416
sl@0
  2417
	return KErrNone;
sl@0
  2418
	}
sl@0
  2419
sl@0
  2420
sl@0
  2421
void E32Image::SortCurrentImportList()
sl@0
  2422
	{
sl@0
  2423
	if (!iCurrentImportListSorted)
sl@0
  2424
		{
sl@0
  2425
		RArray<TUint> array((TUint*)iCurrentImportList, iCurrentImportCount);
sl@0
  2426
		array.Sort();
sl@0
  2427
		iCurrentImportListSorted = (TUint8)ETrue;
sl@0
  2428
		}
sl@0
  2429
	}
sl@0
  2430
sl@0
  2431
sl@0
  2432
TInt CheckRomExports(const TRomImageHeader* aR, const E32Image* aI)
sl@0
  2433
	{
sl@0
  2434
	__IF_DEBUG(Printf("CheckRomExports"));
sl@0
  2435
	if (aR->iExportDirCount == 0)
sl@0
  2436
		return aI->iCurrentImportCount ? KErrNotSupported : KErrNone;
sl@0
  2437
	const TUint32* xd = (const TUint32*)aR->iExportDir;
sl@0
  2438
	const TUint32* p = aI->iCurrentImportList;
sl@0
  2439
	const TUint32* pE = p + aI->iCurrentImportCount;
sl@0
  2440
	for (; p<pE; ++p)
sl@0
  2441
		if (xd[*p] == 0)
sl@0
  2442
			return KErrNotSupported;
sl@0
  2443
	return KErrNone;
sl@0
  2444
	}
sl@0
  2445
sl@0
  2446
sl@0
  2447
TInt CheckRamExports(TUint aEDT, const TUint8* aED, TUint aEDC, E32Image* aI)
sl@0
  2448
	{
sl@0
  2449
	__IF_DEBUG(Printf("CheckRamExports"));
sl@0
  2450
	if (aEDC == 0)
sl@0
  2451
		return aI->iCurrentImportCount ? KErrNotSupported : KErrNone;
sl@0
  2452
	if (aEDT == KImageHdr_ExpD_NoHoles)
sl@0
  2453
		return KErrNone;	// nothing missing
sl@0
  2454
sl@0
  2455
	const TUint32* p = aI->iCurrentImportList;
sl@0
  2456
	const TUint32* pE = p + aI->iCurrentImportCount;
sl@0
  2457
sl@0
  2458
	if (aEDT == KImageHdr_ExpD_FullBitmap)
sl@0
  2459
		{
sl@0
  2460
		for (; p<pE; ++p)
sl@0
  2461
			{
sl@0
  2462
			TUint32 x = *p - 1;
sl@0
  2463
			if ( !(aED[x>>3] & (1u<<(x&7))) )
sl@0
  2464
				return KErrNotSupported;
sl@0
  2465
			}
sl@0
  2466
		return KErrNone;
sl@0
  2467
		}
sl@0
  2468
sl@0
  2469
	if (aEDT != KImageHdr_ExpD_SparseBitmap8)
sl@0
  2470
		return KErrNotSupported;		// don't know what this is
sl@0
  2471
	aI->SortCurrentImportList();		// sort imports to increasing order
sl@0
  2472
	TUint32 memsz = (aEDC + 7) >> 3;	// size of complete bitmap
sl@0
  2473
	TUint32 mbs = (memsz + 7) >> 3;		// size of meta-bitmap
sl@0
  2474
	const TUint8* mptr = aED;
sl@0
  2475
	const TUint8* gptr = mptr + mbs;
sl@0
  2476
	const TUint8* mptrE = mptr + mbs;
sl@0
  2477
	TUint xlim = 64;
sl@0
  2478
	for (; mptr<mptrE && p<pE; ++mptr, xlim+=64)
sl@0
  2479
		{
sl@0
  2480
		TUint m = *mptr;
sl@0
  2481
		if (m==0)
sl@0
  2482
			{
sl@0
  2483
			// nothing missing in this block of 64 exports; step to next block
sl@0
  2484
			for (; p<pE && *p<=xlim; ++p) {}
sl@0
  2485
			continue;
sl@0
  2486
			}
sl@0
  2487
		// expand this block of 64
sl@0
  2488
		TUint32 g32[2] = {0xffffffffu, 0xffffffffu};
sl@0
  2489
		TUint8* g = (TUint8*)g32;
sl@0
  2490
		for (; m; m>>=1, ++g)
sl@0
  2491
			if (m&1)
sl@0
  2492
				*g = *gptr++;
sl@0
  2493
		g = (TUint8*)g32;
sl@0
  2494
		for (; p<pE && *p<=xlim; ++p)
sl@0
  2495
			{
sl@0
  2496
			TUint ix = *p - (xlim - 64) - 1;
sl@0
  2497
			if ( !(g[ix>>3] & (1u<<(ix&7))) )
sl@0
  2498
				return KErrNotSupported;
sl@0
  2499
			}
sl@0
  2500
		}
sl@0
  2501
	return KErrNone;
sl@0
  2502
	}
sl@0
  2503
sl@0
  2504
sl@0
  2505
TInt CheckRequiredImports(E32Image* aImporter, E32Image* aExporter, TInt aAction)
sl@0
  2506
	{
sl@0
  2507
	__IF_DEBUG(Printf("E32Image::CheckRequiredImports (existing) %d", aAction));
sl@0
  2508
	TInt last = aImporter->LastCurrentImport();
sl@0
  2509
	if (last > aExporter->iExportDirCount)
sl@0
  2510
		return KErrNotSupported;
sl@0
  2511
	if (aAction == EAction_CheckLastImport)
sl@0
  2512
		return KErrNone;
sl@0
  2513
	if (aExporter->iRomImageHeader)
sl@0
  2514
		return CheckRomExports(aExporter->iRomImageHeader, aImporter);
sl@0
  2515
	if (aExporter->iHeader)
sl@0
  2516
		{
sl@0
  2517
		E32ImageHeaderV* v = (E32ImageHeaderV*)aExporter->iHeader;
sl@0
  2518
		return CheckRamExports(v->iExportDescType, v->iExportDesc, v->iExportDirCount, aImporter);
sl@0
  2519
		}
sl@0
  2520
	TInt r = aExporter->ReadExportDirLoad();
sl@0
  2521
	if (r != KErrNone)
sl@0
  2522
		return r;				// could fail with OOM
sl@0
  2523
	TBool hasNmdExp = (aExporter->iAttr & ECodeSegAttNmdExpData);
sl@0
  2524
	const TUint32* p = aImporter->iCurrentImportList;
sl@0
  2525
	const TUint32* pE = p + aImporter->iCurrentImportCount;
sl@0
  2526
	const TUint32* pX = (const TUint32*)aExporter->iExportDirLoad - 1;
sl@0
  2527
	TUint32 xep = aExporter->iFileEntryPoint;
sl@0
  2528
	for (; p<pE; ++p)
sl@0
  2529
		{
sl@0
  2530
		TUint32 x = *p;
sl@0
  2531
		TUint32 xx = pX[x];
sl@0
  2532
		if ((xx==0 && (x!=0 || (x==0&&hasNmdExp))) || xx==xep)
sl@0
  2533
			return KErrNotSupported;
sl@0
  2534
		}
sl@0
  2535
	return KErrNone;
sl@0
  2536
	}
sl@0
  2537
sl@0
  2538
sl@0
  2539
TInt CheckRequiredImports(E32Image* aImporter, const RImageInfo& aExporter, TInt aAction)
sl@0
  2540
	{
sl@0
  2541
	__IF_DEBUG(Printf("E32Image::CheckRequiredImports (new) %d", aAction));
sl@0
  2542
	TInt last = aImporter->LastCurrentImport();
sl@0
  2543
	if (last > aExporter.iExportDirCount)
sl@0
  2544
		return KErrNotSupported;
sl@0
  2545
	if (aAction == EAction_CheckLastImport)
sl@0
  2546
		return KErrNone;
sl@0
  2547
	if (aExporter.iRomImageHeader)
sl@0
  2548
		return CheckRomExports(aExporter.iRomImageHeader, aImporter);
sl@0
  2549
	return CheckRamExports(aExporter.iExportDescType, aExporter.iExportDesc, aExporter.iExportDirCount, aImporter);
sl@0
  2550
	}
sl@0
  2551
sl@0
  2552
sl@0
  2553
TInt E32Image::GetCurrentImportList(const E32ImportBlock* a)
sl@0
  2554
	{
sl@0
  2555
	__IF_DEBUG(Printf("E32Image::GetCurrentImportList(E32ImportBlock* a:%08X)", a));
sl@0
  2556
	TInt r;
sl@0
  2557
	TInt n = a->iNumberOfImports;
sl@0
  2558
	iCurrentImportCount = n;
sl@0
  2559
	iCurrentImportListSorted = (TUint8)EFalse;
sl@0
  2560
	__IF_DEBUG(Printf("iCurrentImportCount:%d, iCurrentImportListSorted:%d)", iCurrentImportCount, iCurrentImportListSorted));
sl@0
  2561
	__IF_DEBUG(Printf("iHeader->ImportFormat() == KImageImpFmt_ELF:%d", (iHeader->ImportFormat() == KImageImpFmt_ELF) ));
sl@0
  2562
	
sl@0
  2563
	if (iHeader->ImportFormat() == KImageImpFmt_ELF)
sl@0
  2564
		{
sl@0
  2565
		SGetImportDataInfo info;
sl@0
  2566
		info.iCount = n;
sl@0
  2567
		info.iDest = iCurrentImportList;
sl@0
  2568
		info.iCodeLoadAddress = iCodeLoadAddress;
sl@0
  2569
		info.iImportOffsetList = (TUint32*)a->Imports();
sl@0
  2570
		r = ExecuteInSupervisorMode(&svElfDerivedGetImportInfo, &info);
sl@0
  2571
		}
sl@0
  2572
	else
sl@0
  2573
		{
sl@0
  2574
		TUint32* iat = (TUint32*)(iCodeLoadAddress + iTextSize);
sl@0
  2575
		WordCopy(iCurrentImportList, iat + iNextImportPos, n * sizeof(TUint32));
sl@0
  2576
		r = KErrNone;
sl@0
  2577
		}
sl@0
  2578
	iNextImportPos += n;
sl@0
  2579
	__IF_DEBUG(Printf("End of E32Image::GetCurrentImportList:%d)", r));
sl@0
  2580
	return r;
sl@0
  2581
	}
sl@0
  2582
sl@0
  2583
sl@0
  2584
TInt E32Image::LastCurrentImport()
sl@0
  2585
	{
sl@0
  2586
	TUint32 last = 0;
sl@0
  2587
	if (iCurrentImportListSorted)
sl@0
  2588
		last = iCurrentImportList[iCurrentImportCount - 1];
sl@0
  2589
	else
sl@0
  2590
		{
sl@0
  2591
		const TUint32* p = iCurrentImportList;
sl@0
  2592
		const TUint32* pE = p + iCurrentImportCount;
sl@0
  2593
		for (; p<pE; ++p)
sl@0
  2594
			if (*p > last) last = *p;
sl@0
  2595
		}
sl@0
  2596
	__IF_DEBUG(Printf("E32Image::LastCurrentImport = %d", last));
sl@0
  2597
	return last;
sl@0
  2598
	}
sl@0
  2599
sl@0
  2600
sl@0
  2601
TInt E32Image::ProcessImports()
sl@0
  2602
//
sl@0
  2603
//	This function is only ever called on the exe/dll which is loaded from 
sl@0
  2604
//	the RProcess/RLibrary load.
sl@0
  2605
//	It reads this DLL/EXE's imports section and builds up a table of dlls referenced.
sl@0
  2606
//	It never goes recursive.
sl@0
  2607
//
sl@0
  2608
	{
sl@0
  2609
	__IF_DEBUG(Printf("E32Image::ProcessImports %S",&iFileName));
sl@0
  2610
	__IF_DEBUG(Printf("DepCount=%d",iDepCount));
sl@0
  2611
	
sl@0
  2612
	if (iDepCount==0 || AlwaysLoaded())
sl@0
  2613
		return KErrNone;	// no imports
sl@0
  2614
sl@0
  2615
	TFileNameInfo fi;
sl@0
  2616
	fi.Set(iFileName, 0);
sl@0
  2617
	gLoadeePath.Zero();
sl@0
  2618
	fi.GetName(gLoadeePath, TFileNameInfo::EIncludeDrivePath);
sl@0
  2619
	if (PlatSec::ConfigSetting(PlatSec::EPlatSecEnforceSysBin)
sl@0
  2620
			&& gLoadeePath.Length()==11
sl@0
  2621
			&& KSysBin().CompareF(TPtrC8(gLoadeePath.Ptr()+1,10))==0)
sl@0
  2622
		{
sl@0
  2623
		// Main loadee is in the default path, so unset this in order to
sl@0
  2624
		// search normally for dependents
sl@0
  2625
		gLoadeePath.Zero();
sl@0
  2626
		}
sl@0
  2627
#ifdef __X86__
sl@0
  2628
	if (gLoadeePath.Length()>=2 && gLoadeePath[1]==':')
sl@0
  2629
		{
sl@0
  2630
		TInt d = gLoadeePath[0];
sl@0
  2631
		if (d=='a' || d=='A')
sl@0
  2632
			UseFloppy = EDriveA;
sl@0
  2633
		else if (d=='b' || d=='B')
sl@0
  2634
			UseFloppy = EDriveB;
sl@0
  2635
		}
sl@0
  2636
#endif
sl@0
  2637
	RImageArray array;
sl@0
  2638
	TInt r = array.Add(this);
sl@0
  2639
	if (r==KErrNone)
sl@0
  2640
		r = LoadDlls(array);
sl@0
  2641
	if (r==KErrNone)
sl@0
  2642
		r = FixupDlls(array);
sl@0
  2643
	if (r==KErrNone)
sl@0
  2644
		r = FinaliseDlls(array);
sl@0
  2645
	CleanupDlls(array);
sl@0
  2646
	array.Close();
sl@0
  2647
sl@0
  2648
	__IF_DEBUG(Printf("E32Image::ProcessImports returns %d",r));
sl@0
  2649
	return r;
sl@0
  2650
	}
sl@0
  2651
sl@0
  2652
void E32Image::CleanupDlls(RImageArray& aArray)
sl@0
  2653
//
sl@0
  2654
// Free the space used in fixing up the dlls.
sl@0
  2655
// Don't free the entry corresponding to the main loadee.
sl@0
  2656
//
sl@0
  2657
	{
sl@0
  2658
sl@0
  2659
	__IF_DEBUG(Printf("CleanupDlls"));
sl@0
  2660
	TInt n = aArray.Count();
sl@0
  2661
	TInt i;
sl@0
  2662
	for (i=0; i<n; ++i)
sl@0
  2663
		{
sl@0
  2664
		E32Image* e = aArray[i];
sl@0
  2665
		if (e != this)
sl@0
  2666
			delete e;
sl@0
  2667
		}
sl@0
  2668
	}
sl@0
  2669
sl@0
  2670
TInt E32Image::FinaliseDlls(RImageArray& aArray)
sl@0
  2671
	{
sl@0
  2672
	__IF_DEBUG(Printf("E32Image::FinaliseDlls"));
sl@0
  2673
	TInt i;
sl@0
  2674
	TInt c = aArray.Count();
sl@0
  2675
	TInt r = KErrNone;
sl@0
  2676
	for(i=0; i<c && r==KErrNone; i++)
sl@0
  2677
		{
sl@0
  2678
		E32Image* e = aArray[i];
sl@0
  2679
		if(e!=this && !e->iAlreadyLoaded)
sl@0
  2680
			{
sl@0
  2681
			// transfers ownership of clamp handle to codeseg; nulls handle if successful
sl@0
  2682
			if(!e->AlwaysLoaded())
sl@0
  2683
				r = E32Loader::CodeSegLoaded(*e);
sl@0
  2684
			if(r==KErrNone && e->iUseCodePaging)
sl@0
  2685
				{
sl@0
  2686
				e->iFileClamp.iCookie[0]=0;// null handle to indicate 
sl@0
  2687
				e->iFileClamp.iCookie[1]=0;// transfer of ownership of clamp handle to codeseg
sl@0
  2688
				}
sl@0
  2689
			}
sl@0
  2690
		}
sl@0
  2691
	__IF_DEBUG(Printf("E32Image::FinaliseDlls returns %d",r));
sl@0
  2692
	return r;
sl@0
  2693
	}
sl@0
  2694
sl@0
  2695
sl@0
  2696
TInt E32Image::LoadDlls(RImageArray& aArray)
sl@0
  2697
//
sl@0
  2698
// Build a matrix of all DLLs referenced by the one we're loading, and
sl@0
  2699
// ensure they're all loaded.
sl@0
  2700
//
sl@0
  2701
	{
sl@0
  2702
	__IF_DEBUG(Printf("E32Image::LoadDlls"));
sl@0
  2703
	TInt r=KErrNone;
sl@0
  2704
	E32ImportSection* importSection=(E32ImportSection *)iImportData;
sl@0
  2705
	E32ImportBlock* block;
sl@0
  2706
	if(importSection)
sl@0
  2707
		block=(E32ImportBlock*)(importSection+1);
sl@0
  2708
	else
sl@0
  2709
		block=NULL;
sl@0
  2710
	const TRomImageHeader* const * pR=NULL;
sl@0
  2711
	if (iRomImageHeader)
sl@0
  2712
		pR=iRomImageHeader->iDllRefTable->iEntry;
sl@0
  2713
	iNextImportPos = 0;
sl@0
  2714
sl@0
  2715
	// For each module referenced by this module
sl@0
  2716
	for (TInt i=0; i<iDepCount; ++i)
sl@0
  2717
		{
sl@0
  2718
		RImageFinder finder;
sl@0
  2719
		E32ImportBlock* thisBlock = block;
sl@0
  2720
		E32Image* e = NULL;	// will represent referenced module
sl@0
  2721
		const TRomImageHeader* rih = NULL;
sl@0
  2722
		RLdrReq req;		// new loader request to load referenced module
sl@0
  2723
		TBuf8<KMaxKernelName> rootname;
sl@0
  2724
		req.iFileName = (HBufC8*)&rootname;
sl@0
  2725
sl@0
  2726
		if (pR)
sl@0
  2727
			{
sl@0
  2728
			// Processing imports for ROM XIP module
sl@0
  2729
			rih = *pR++;
sl@0
  2730
			__IF_DEBUG(Printf("Importing from ROM XIP %08x", rih));
sl@0
  2731
			e = aArray.Find(rih);
sl@0
  2732
			}
sl@0
  2733
		else
sl@0
  2734
			{
sl@0
  2735
			// Processing imports for RAM module
sl@0
  2736
			__IF_DEBUG(Printf("Import block address %08x",block));
sl@0
  2737
			TPtrC8 dllname = (const TText8*)((TUint32)iImportData + block->iOffsetOfDllName);
sl@0
  2738
			if (dllname.Length() > KMaxKernelName)
sl@0
  2739
				{
sl@0
  2740
				__IF_DEBUG(Printf("Import DLL name too big: %S",&dllname));
sl@0
  2741
				RETURN_FAILURE(KErrNotSupported);
sl@0
  2742
				}
sl@0
  2743
			TFileNameInfo fni;
sl@0
  2744
			r = fni.Set(dllname, TFileNameInfo::EAllowUid);
sl@0
  2745
			if (r!=KErrNone)
sl@0
  2746
				RETURN_FAILURE(KErrCorrupt);
sl@0
  2747
			fni.GetName(rootname, TFileNameInfo::EIncludeBaseExt);
sl@0
  2748
			TUint32* uid=(TUint32*)&req.iRequestedUids;
sl@0
  2749
			uid[2] = fni.Uid();
sl@0
  2750
			req.iRequestedVersion = fni.Version();
sl@0
  2751
			if (gLoadeePath.Length() > 0)
sl@0
  2752
				req.iPath = (HBufC8*)&gLoadeePath;
sl@0
  2753
			req.iPlatSecCaps = iS.iCaps;
sl@0
  2754
			req.iFileNameInfo.Set(rootname, 0);
sl@0
  2755
			req.iImporter = this;
sl@0
  2756
			r = GetCurrentImportList(block);	// get list of required exports from this exporter
sl@0
  2757
			if (r!=KErrNone)
sl@0
  2758
				{
sl@0
  2759
				return r;
sl@0
  2760
				}
sl@0
  2761
			TUint impfmt = iHeader->ImportFormat();
sl@0
  2762
			block = (E32ImportBlock*)block->NextBlock(impfmt);
sl@0
  2763
sl@0
  2764
			r = finder.Set(req);
sl@0
  2765
			if (r == KErrNone)
sl@0
  2766
				r = finder.SearchExisting(aArray);	// see what we've already got
sl@0
  2767
			if (r == KErrNone)
sl@0
  2768
				{
sl@0
  2769
				TBool search = ETrue;
sl@0
  2770
				if (finder.iExisting)
sl@0
  2771
					{
sl@0
  2772
					// Found an existing DLL - check for an exact version match
sl@0
  2773
					if (DetailedCompareVersions(finder.iCurrentVersion, finder.iReq->iRequestedVersion) <= EVersion_Exact)
sl@0
  2774
						search = EFalse;		// if exact match, don't need to continue search
sl@0
  2775
					}
sl@0
  2776
				if (search)
sl@0
  2777
					r = finder.Search();		// see what else is available
sl@0
  2778
				}
sl@0
  2779
			if (r!=KErrNone)
sl@0
  2780
				{
sl@0
  2781
				finder.Close();
sl@0
  2782
				return r;
sl@0
  2783
				}
sl@0
  2784
			if (finder.iExisting)
sl@0
  2785
				e = finder.iExisting;			// already have the required module
sl@0
  2786
			}
sl@0
  2787
sl@0
  2788
		// If it's already in the array, go on to the next module
sl@0
  2789
		if (e)
sl@0
  2790
		    {
sl@0
  2791
			__IF_DEBUG(Printf("Already there"));
sl@0
  2792
			}
sl@0
  2793
		else
sl@0
  2794
			{
sl@0
  2795
			//	Not already in the array
sl@0
  2796
			__IF_DEBUG(Printf("Not in array, add it"));
sl@0
  2797
			e = new E32Image;
sl@0
  2798
			if (!e)
sl@0
  2799
				{
sl@0
  2800
				finder.Close();
sl@0
  2801
				return KErrNoMemory;
sl@0
  2802
				}
sl@0
  2803
			e->iMain = iMain;
sl@0
  2804
			e->iClientProcessHandle = iMain->iClientProcessHandle;
sl@0
  2805
			if (iMain->iAttr & ECodeSegAttKernel)
sl@0
  2806
				e->iAttr |= ECodeSegAttKernel;
sl@0
  2807
			if (rih)
sl@0
  2808
				{
sl@0
  2809
				// loading a specified ROM XIP DLL
sl@0
  2810
				r = e->DoLoadCodeSeg(*rih);
sl@0
  2811
				}
sl@0
  2812
			else
sl@0
  2813
				{
sl@0
  2814
				// loading a DLL by name
sl@0
  2815
				r = e->DoLoadCodeSeg(req, finder); // also closes 'finder'
sl@0
  2816
				__IF_DEBUG(Printf("%S DoLoadCodeSeg returned %d",req.iFileName,r));
sl@0
  2817
				}
sl@0
  2818
sl@0
  2819
			//	Add the new entry to the array
sl@0
  2820
			if (r==KErrNone)
sl@0
  2821
				{
sl@0
  2822
				__IF_DEBUG(Printf("Add to the array"));
sl@0
  2823
				r = aArray.Add(e);
sl@0
  2824
				}
sl@0
  2825
			if (r!=KErrNone)
sl@0
  2826
				{
sl@0
  2827
				delete e;
sl@0
  2828
				return r;
sl@0
  2829
				}
sl@0
  2830
						
sl@0
  2831
			//	Now go nice and recursive, and call LoadDlls on this latest dll, if it 
sl@0
  2832
			//	imports anything
sl@0
  2833
			//	This recursive horror *will* terminate because it is only called
sl@0
  2834
			//	on "new" dlls
sl@0
  2835
			if (e->iDepCount && !e->iAlreadyLoaded && e->iIsDll)
sl@0
  2836
				{
sl@0
  2837
				__IF_DEBUG(Printf("****Go recursive****"));
sl@0
  2838
				r = e->LoadDlls(aArray);
sl@0
  2839
				if (r!=KErrNone)
sl@0
  2840
					{
sl@0
  2841
					return r;
sl@0
  2842
					}
sl@0
  2843
				}
sl@0
  2844
sl@0
  2845
			}
sl@0
  2846
sl@0
  2847
		// If we added an SMP unsafe dependent, this image is SMP unsafe.
sl@0
  2848
		// This is done after recursing into LoadDlls, so a single unsafe
sl@0
  2849
		// dependent anywhere down the tree will poison everything above it.
sl@0
  2850
		// This isn't sufficient to deal with cycles, though, so the kernel
sl@0
  2851
		// also has to update the flag in DCodeSeg::FinaliseRecursiveFlags.
sl@0
  2852
		// It has to be done here first because the kernel doesn't know
sl@0
  2853
		// about XIP DLLs that don't have a codeseg created.
sl@0
  2854
		if (!(e->iAttr & ECodeSegAttSMPSafe))
sl@0
  2855
			{
sl@0
  2856
			__IF_DEBUG(Printf("%S is not SMP safe because it loads %S", &iFileName, &e->iFileName));
sl@0
  2857
			iAttr &= ~ECodeSegAttSMPSafe;
sl@0
  2858
			}
sl@0
  2859
sl@0
  2860
		// If exporter is an EXE it must be the same as the client process or newly created process
sl@0
  2861
		__IF_DEBUG(Printf("Check EXE->EXE"));
sl@0
  2862
		if (gExeCodeSeg && !e->iIsDll && e->iHandle!=gExeCodeSeg)
sl@0
  2863
			return KErrNotSupported;
sl@0
  2864
sl@0
  2865
		// A globally-visible module may only link to other globally visible modules
sl@0
  2866
		__IF_DEBUG(Printf("Check Global Attribute"));
sl@0
  2867
		if ( (iAttr&ECodeSegAttGlobal) && !(e->iAttr&ECodeSegAttGlobal) )
sl@0
  2868
			return KErrNotSupported;
sl@0
  2869
sl@0
  2870
		// A ram-loaded globally-visible module may only link to ROM XIP modules with no static data
sl@0
  2871
		__IF_DEBUG(Printf("Check RAM Global"));
sl@0
  2872
		if ( (iAttr&ECodeSegAttGlobal) && !iRomImageHeader && e->iHandle)
sl@0
  2873
			return KErrNotSupported;
sl@0
  2874
sl@0
  2875
		if (thisBlock)
sl@0
  2876
			thisBlock->iOffsetOfDllName=(TUint32)e;   // For easy access when fixing up imports
sl@0
  2877
		if (e->iHandle)
sl@0
  2878
			{
sl@0
  2879
			//	Record the dependence of this on e
sl@0
  2880
			r=E32Loader::CodeSegAddDependency(iHandle, e->iHandle);
sl@0
  2881
			if (r!=KErrNone)
sl@0
  2882
				{
sl@0
  2883
				return r;
sl@0
  2884
				}
sl@0
  2885
			}
sl@0
  2886
		}
sl@0
  2887
	__IF_DEBUG(Printf("E32Image::LoadDlls OK"));
sl@0
  2888
	return KErrNone;
sl@0
  2889
	}
sl@0
  2890
sl@0
  2891
sl@0
  2892
TInt E32Image::ReadExportDirLoad()
sl@0
  2893
	{
sl@0
  2894
	//	Get the exporter's export directory
sl@0
  2895
	__IF_DEBUG(Printf("ReadExportDirLoad exp_dir=%08x", iExportDirLoad));
sl@0
  2896
	if (!iExportDirLoad)
sl@0
  2897
		{
sl@0
  2898
		// already loaded nonglobal DLL - must read the export directory
sl@0
  2899
		if (iExportDirCount==0 && !(iAttr&ECodeSegAttNmdExpData))
sl@0
  2900
			return KErrGeneral; // DLL has no exports, something must be wrong
sl@0
  2901
		iCopyOfExportDir = (TUint32*)User::Alloc((iExportDirCount+1) * sizeof(TUint32));
sl@0
  2902
		if (!iCopyOfExportDir)
sl@0
  2903
			return KErrNoMemory;
sl@0
  2904
		__IF_DEBUG(Printf("Reading %d exports", iExportDirCount));
sl@0
  2905
		E32Loader::ReadExportDir(iHandle, iCopyOfExportDir);
sl@0
  2906
		iExportDirLoad = (TUint32)(iCopyOfExportDir+1);
sl@0
  2907
		}
sl@0
  2908
	return KErrNone;
sl@0
  2909
	}
sl@0
  2910
sl@0
  2911
sl@0
  2912
TInt E32Image::FixupDlls(RImageArray& aArray)
sl@0
  2913
//
sl@0
  2914
// Go through the array, fixing up the files
sl@0
  2915
//
sl@0
  2916
	{
sl@0
  2917
	__IF_DEBUG(Printf("E32Image::FixupDlls"));
sl@0
  2918
sl@0
  2919
	// For each E32Image file in the array
sl@0
  2920
	TInt i;
sl@0
  2921
	TInt c = aArray.Count();
sl@0
  2922
sl@0
  2923
	for (i=0; i<c; ++i)
sl@0
  2924
		{
sl@0
  2925
		TInt r;
sl@0
  2926
sl@0
  2927
		E32Image* imp = aArray[i];
sl@0
  2928
		__IF_DEBUG(Printf("Dll number %d %S",i,&imp->iFileName));
sl@0
  2929
sl@0
  2930
		const E32ImportSection* importSection = (const E32ImportSection*)imp->iImportData;
sl@0
  2931
		if (!importSection)
sl@0
  2932
			{
sl@0
  2933
			__IF_DEBUG(Printf("Has no imports to fixup"));
sl@0
  2934
			continue;	//	No imports, skip this dll (true of ALL ROM dlls)
sl@0
  2935
			}
sl@0
  2936
sl@0
  2937
		const E32ImportBlock* block = (const E32ImportBlock*)(importSection + 1);
sl@0
  2938
sl@0
  2939
		SFixupImportAddressesInfo info;
sl@0
  2940
		info.iIat = (TUint32*)(imp->iCodeLoadAddress + imp->iTextSize);
sl@0
  2941
		info.iCodeLoadAddress = imp->iCodeLoadAddress;
sl@0
  2942
sl@0
  2943
		// fix up imports from each dependent DLL, building a table of all the imports for the binary
sl@0
  2944
		TInt depCount = imp->iDepCount;
sl@0
  2945
		while (depCount--)
sl@0
  2946
			{
sl@0
  2947
			// declare variables at start of loop body to prevent 'crosses initialization' errors
sl@0
  2948
			TUint impfmt;
sl@0
  2949
sl@0
  2950
			// E32Image::LoadDlls() will have set iOffsetOfDllName of the 
sl@0
  2951
			// import block to point to the E32Image object of the exporter
sl@0
  2952
			// it's importing
sl@0
  2953
			E32Image* exp = (E32Image*)(block->iOffsetOfDllName);   // LoadDlls() set this to exporter
sl@0
  2954
sl@0
  2955
			//	Get the exporter's export directory
sl@0
  2956
			r = exp->ReadExportDirLoad();
sl@0
  2957
			if (r != KErrNone)
sl@0
  2958
				return r;
sl@0
  2959
			info.iExportDir = (TUint32*)exp->iExportDirLoad;
sl@0
  2960
			info.iExportDirEntryDelta = exp->iExportDirEntryDelta;
sl@0
  2961
			info.iNumImports = block->iNumberOfImports;
sl@0
  2962
			info.iExporter = exp;
sl@0
  2963
sl@0
  2964
			// if demand paging, expand the import fixup buffer for this next exporting DLL
sl@0
  2965
			if (! imp->iUseCodePaging)
sl@0
  2966
				info.iFixup64 = 0;
sl@0
  2967
			else
sl@0
  2968
				{
sl@0
  2969
				info.iFixup64 = imp->ExpandFixups(block->iNumberOfImports);
sl@0
  2970
				if (!info.iFixup64)
sl@0
  2971
					return KErrNoMemory;
sl@0
  2972
				}
sl@0
  2973
sl@0
  2974
			// call function in supervisor mode to fix up the import addresses.
sl@0
  2975
			impfmt = imp->iHeader->ImportFormat();
sl@0
  2976
			if (impfmt == KImageImpFmt_ELF)
sl@0
  2977
				{
sl@0
  2978
				info.iImportOffsetList = (TUint32*)(block+1);
sl@0
  2979
				r = ExecuteInSupervisorMode(&svElfDerivedFixupImportAddresses, &info);
sl@0
  2980
				}
sl@0
  2981
			else
sl@0
  2982
				r = ExecuteInSupervisorMode(&svFixupImportAddresses, &info);
sl@0
  2983
sl@0
  2984
			if (r != KErrNone)
sl@0
  2985
				{
sl@0
  2986
				__IF_DEBUG(Printf("svFixupImportAddresses returns %d", r));
sl@0
  2987
				return r;
sl@0
  2988
				}
sl@0
  2989
sl@0
  2990
			// Next import block...
sl@0
  2991
			block = block->NextBlock(impfmt);
sl@0
  2992
			}	// while (depCount--)
sl@0
  2993
sl@0
  2994
		if (imp->iUseCodePaging && imp->iFixupCount > 0)
sl@0
  2995
			{
sl@0
  2996
			// convert the <addr,val> pairs to an import fixup tab which can be used when
sl@0
  2997
			// the code is paged.
sl@0
  2998
			r = imp->BuildImportFixupTable();
sl@0
  2999
			if (r != KErrNone)
sl@0
  3000
				return r;
sl@0
  3001
			}
sl@0
  3002
		}
sl@0
  3003
sl@0
  3004
	__IF_DEBUG(Printf("E32Image::FixupDlls OK"));
sl@0
  3005
	return KErrNone;
sl@0
  3006
	}
sl@0
  3007
sl@0
  3008
sl@0
  3009
/**
sl@0
  3010
This function is defined because RArray does not natively support
sl@0
  3011
sorting 64-bit integers.
sl@0
  3012
sl@0
  3013
It is used by FixupDlls to order the import fixup locations in the image
sl@0
  3014
so they can be organized by page.
sl@0
  3015
sl@0
  3016
@param	aLeft			64-bit unsigned integer to compare against aRight.
sl@0
  3017
@param	aRight			64-bit unsigned integer to compare against aLeft.
sl@0
  3018
@return					-1 if aLeft < aRight; 0 if aLeft == aRight; and
sl@0
  3019
						+1 if aLeft > aRight.  This conforms to the behavior
sl@0
  3020
						which is expected from a function used by TLinearOrder.
sl@0
  3021
*/
sl@0
  3022
static TInt Uint64LinearOrderFunc(const TUint64& aLeft, const TUint64& aRight)
sl@0
  3023
	{
sl@0
  3024
	if (aLeft < aRight)
sl@0
  3025
		return -1;
sl@0
  3026
	else if (aLeft > aRight)
sl@0
  3027
		return 1;
sl@0
  3028
	else
sl@0
  3029
		return 0;
sl@0
  3030
	}
sl@0
  3031
sl@0
  3032
sl@0
  3033
TUint64* E32Image::ExpandFixups(TInt aNumFixups)
sl@0
  3034
	{
sl@0
  3035
	__IF_DEBUG(Printf("ExpandFixups,%d+%d", iFixupCount,aNumFixups));
sl@0
  3036
	TInt newCount = iFixupCount+aNumFixups;
sl@0
  3037
	TUint64* fixups = (TUint64*) User::ReAlloc(iFixups, sizeof(TUint64) * newCount);
sl@0
  3038
	if(!fixups)
sl@0
  3039
		return 0;
sl@0
  3040
	TUint64* newFixups = fixups+iFixupCount;
sl@0
  3041
	iFixupCount = newCount;
sl@0
  3042
	iFixups = fixups;
sl@0
  3043
	return newFixups;
sl@0
  3044
	}
sl@0
  3045
sl@0
  3046
sl@0
  3047
/**
sl@0
  3048
Helper function for FixupImports.  Takes the set of
sl@0
  3049
64-bit <addr,val> fixups, and organizes them into pages.
sl@0
  3050
sl@0
  3051
Each page is stored as fXXX YYYY ZZZZ where YYYY ZZZZ is written
sl@0
  3052
to the word at offset XXX.  (See PREQ1110 Design Sketch v1.0 S3.1.1.2.3.2.)
sl@0
  3053
sl@0
  3054
On success iImportFixupTableSize is set to the table size in bytes,
sl@0
  3055
and iImportFixupTable is a cell containing the table.
sl@0
  3056
sl@0
  3057
@return					Symbian OS error code.
sl@0
  3058
*/
sl@0
  3059
TInt E32Image::BuildImportFixupTable()
sl@0
  3060
	{
sl@0
  3061
	__IF_DEBUG(Printf(">BuildImportFixupTable,0x%08x,%d", iFixups, iFixupCount));
sl@0
  3062
sl@0
  3063
	// sort the array in address order, to organize by page
sl@0
  3064
	RArray<TUint64> fixup64ToSort(sizeof(TUint64), iFixups, iFixupCount);
sl@0
  3065
	// SortUnsigned doesn't work on TUint64
sl@0
  3066
	fixup64ToSort.Sort(TLinearOrder<TUint64>(Uint64LinearOrderFunc));
sl@0
  3067
sl@0
  3068
	// now have <address | new-value> pairs, organize into pages.
sl@0
  3069
	// Each page is stored as fXXX YYYY ZZZZ where YYYY ZZZZ is written
sl@0
  3070
	// to the word at offset XXX.  (See PREQ1110 Design Sketch v1.0 S3.1.1.2.3.2.)
sl@0
  3071
sl@0
  3072
	TUint32 pageCount = SizeToPageCount(iCodeSize);
sl@0
  3073
	iImportFixupTableSize = (pageCount+1) * sizeof(TUint32) + iFixupCount * 3 * sizeof(TUint16);
sl@0
  3074
	iImportFixupTable = (TUint32*) User::Alloc(iImportFixupTableSize);
sl@0
  3075
	__IF_DEBUG(Printf("iImportFixupTable=0x%08x", iImportFixupTable));
sl@0
  3076
	if (iImportFixupTable == 0)
sl@0
  3077
		return KErrNoMemory;
sl@0
  3078
sl@0
  3079
	// byte offsets of pages into the table are written as 32-bit words at
sl@0
  3080
	// the start of the table
sl@0
  3081
sl@0
  3082
	TUint32 lastPage = 0;
sl@0
  3083
	// byte index of first 48-bit entry in the table, after sentinel index
sl@0
  3084
	iImportFixupTable[0] = (pageCount + 1) * sizeof(TUint32);;
sl@0
  3085
sl@0
  3086
	// location to which 48-bit imports are written
sl@0
  3087
	TUint16* importOffset = (TUint16*)(iImportFixupTable + pageCount + 1);
sl@0
  3088
sl@0
  3089
	// location from where 64-bit <addr,val> pairs are read
sl@0
  3090
	const TUint64* avEnd = iFixups + iFixupCount;
sl@0
  3091
sl@0
  3092
	for (const TUint64* avPtr = iFixups; avPtr < avEnd; ++avPtr)
sl@0
  3093
		{
sl@0
  3094
		TUint64 addr_val = *avPtr;
sl@0
  3095
		TUint32 addr = I64HIGH(addr_val) - iCodeLoadAddress;
sl@0
  3096
		TUint32 page = addr >> 12;
sl@0
  3097
		if (page > lastPage)
sl@0
  3098
			{
sl@0
  3099
			// calculate new start index for current page
sl@0
  3100
			TUint32 newStart = TUint32(importOffset) - TUint32(iImportFixupTable);
sl@0
  3101
sl@0
  3102
			__IF_DEBUG(Printf("page=%d, lastPage=%d, newStart=0x%08x", page, lastPage, newStart));
sl@0
  3103
sl@0
  3104
			// mark intermediate pages as zero-length, starting and ending at
sl@0
  3105
			// current offset
sl@0
  3106
			while (++lastPage <= page)
sl@0
  3107
				iImportFixupTable[lastPage] = newStart;
sl@0
  3108
			--lastPage;
sl@0
  3109
			}
sl@0
  3110
sl@0
  3111
		TUint16 offsetIntoPage;
sl@0
  3112
		offsetIntoPage = (addr & KPageOffsetMask);
sl@0
  3113
		*importOffset++ = offsetIntoPage;
sl@0
  3114
sl@0
  3115
		TUint32 val = I64LOW(addr_val);
sl@0
  3116
		*importOffset++ = val;				// low halfword stored first (YYYY)
sl@0
  3117
		*importOffset++ = val >> 16;		// high halfword stored second (ZZZZ)
sl@0
  3118
		}
sl@0
  3119
sl@0
  3120
	// sentinel value marks end of table
sl@0
  3121
	while (++lastPage <= pageCount)
sl@0
  3122
		iImportFixupTable[lastPage] = iImportFixupTableSize;
sl@0
  3123
sl@0
  3124
	__IF_DEBUG(Printf("processed table (size=%d,pageCount=%d)", iImportFixupTableSize, pageCount));
sl@0
  3125
sl@0
  3126
#ifdef _DEBUG
sl@0
  3127
	// dump the import fixup table if loader tracing enabled
sl@0
  3128
	const TUint16* table16 = (const TUint16*)iImportFixupTable;
sl@0
  3129
	const TInt halfWordsInTable = iImportFixupTableSize / 2;
sl@0
  3130
	for (TInt i = 0; i < halfWordsInTable; i += 4)
sl@0
  3131
		{
sl@0
  3132
		__IF_DEBUG(Printf(
sl@0
  3133
			"%04x: %04x %04x %04x %04x",
sl@0
  3134
			i * 2, table16[i+0], table16[i+1], table16[i+2], table16[i+3]));
sl@0
  3135
		}
sl@0
  3136
#endif
sl@0
  3137
sl@0
  3138
	User::Free(iFixups);
sl@0
  3139
	iFixups = 0;
sl@0
  3140
	return KErrNone;
sl@0
  3141
	}
sl@0
  3142
sl@0
  3143
sl@0
  3144
TInt GetModuleInfo(RLdrReq& aReq)
sl@0
  3145
//
sl@0
  3146
//	Read capabilities from file found
sl@0
  3147
//
sl@0
  3148
	{
sl@0
  3149
	__IF_DEBUG(Printf("ReadModuleInfo %S",aReq.iFileName));
sl@0
  3150
	TFileNameInfo& fi = aReq.iFileNameInfo;
sl@0
  3151
	RImageFinder finder;
sl@0
  3152
	TInt r = finder.Set(aReq);
sl@0
  3153
	if (r == KErrNone)
sl@0
  3154
		{
sl@0
  3155
		finder.iFindExact = ETrue;
sl@0
  3156
sl@0
  3157
		r = KErrNotSupported;
sl@0
  3158
sl@0
  3159
		// must specify a fully qualified name
sl@0
  3160
		if (fi.DriveLen() && fi.PathLen())
sl@0
  3161
			{
sl@0
  3162
			if (fi.VerLen())
sl@0
  3163
				aReq.iRequestedVersion = fi.iVersion;
sl@0
  3164
			else
sl@0
  3165
				aReq.iRequestedVersion = KModuleVersionWild;
sl@0
  3166
			r = finder.Search();
sl@0
  3167
			if (r == KErrNone)
sl@0
  3168
				{
sl@0
  3169
				RLibrary::TInfo ret_info;
sl@0
  3170
				memclr(&ret_info,sizeof(ret_info));
sl@0
  3171
				ret_info.iModuleVersion = finder.iNew.iModuleVersion;
sl@0
  3172
				ret_info.iUids = *(const TUidType*)finder.iNew.iUid;
sl@0
  3173
				*(SSecurityInfo*)&ret_info.iSecurityInfo = finder.iNew.iS;
sl@0
  3174
				TPckgC<RLibrary::TInfo> ret_pckg(ret_info);
sl@0
  3175
				r = aReq.iMsg->Write(2, ret_pckg);
sl@0
  3176
				}
sl@0
  3177
			}
sl@0
  3178
		}
sl@0
  3179
	finder.Close();
sl@0
  3180
	return r;
sl@0
  3181
	}
sl@0
  3182
sl@0
  3183
TInt GetInfoFromHeader(const RLoaderMsg& aMsg)
sl@0
  3184
	{
sl@0
  3185
	TInt r;
sl@0
  3186
sl@0
  3187
	// Get size of header supplied by client
sl@0
  3188
	TInt size;
sl@0
  3189
	size = aMsg.GetDesLength(0);
sl@0
  3190
	if(size<0)
sl@0
  3191
		return size;
sl@0
  3192
	if(size>RLibrary::KRequiredImageHeaderSize)
sl@0
  3193
		size = RLibrary::KRequiredImageHeaderSize;
sl@0
  3194
	if((TUint)size<sizeof(E32ImageHeaderV))
sl@0
  3195
		return KErrUnderflow;
sl@0
  3196
sl@0
  3197
	// Get header data
sl@0
  3198
	TUint8* data = new TUint8[size];
sl@0
  3199
	if(!data)
sl@0
  3200
		return KErrNoMemory;
sl@0
  3201
	TPtr8 ptr(data,size);
sl@0
  3202
	r = aMsg.Read(0,ptr);
sl@0
  3203
	if(r==KErrNone)
sl@0
  3204
		{
sl@0
  3205
		// Check header is valid
sl@0
  3206
		E32ImageHeaderV* header=(E32ImageHeaderV*)data;
sl@0
  3207
		if(header->TotalSize()>size)
sl@0
  3208
			r = KErrUnderflow;
sl@0
  3209
		else
sl@0
  3210
			{
sl@0
  3211
			TUint32 uncompressedSize;
sl@0
  3212
			r = header->ValidateHeader(-1,uncompressedSize);
sl@0
  3213
			}
sl@0
  3214
		if(r==KErrNone)
sl@0
  3215
			{
sl@0
  3216
			// Get info
sl@0
  3217
			RLibrary::TInfoV2 ret_info;
sl@0
  3218
			memclr(&ret_info,sizeof(ret_info));
sl@0
  3219
			ret_info.iModuleVersion = header->ModuleVersion();
sl@0
  3220
			ret_info.iUids = (TUidType&)header->iUid1;
sl@0
  3221
			header->GetSecurityInfo((SSecurityInfo&)ret_info.iSecurityInfo);
sl@0
  3222
			ret_info.iHardwareFloatingPoint = (header->iFlags & KImageHWFloatMask) >> KImageHWFloatShift;
sl@0
  3223
sl@0
  3224
			ret_info.iDebugAttributes = 0;	// default
sl@0
  3225
			if (header->iFlags & KImageDebuggable)
sl@0
  3226
				ret_info.iDebugAttributes |= RLibrary::TInfoV2::EDebugAllowed;
sl@0
  3227
sl@0
  3228
			TPckg<RLibrary::TInfoV2> ret_pckg(ret_info);
sl@0
  3229
			TInt max = aMsg.GetDesMaxLength(1);
sl@0
  3230
			if (ret_pckg.Length() > max)
sl@0
  3231
				ret_pckg.SetLength(max);
sl@0
  3232
			r = aMsg.Write(1, ret_pckg);
sl@0
  3233
			}
sl@0
  3234
		}
sl@0
  3235
sl@0
  3236
	delete[] data;
sl@0
  3237
	return r;
sl@0
  3238
	}
sl@0
  3239
sl@0
  3240
#if defined(_DEBUG) || defined(_DEBUG_RELEASE)
sl@0
  3241
void memory_dump(const TAny* a, TUint l)
sl@0
  3242
	{
sl@0
  3243
	TBuf8<80> buf;
sl@0
  3244
	const TUint8* s = (const TUint8*)a;
sl@0
  3245
	TInt n=0;
sl@0
  3246
	while (l)
sl@0
  3247
		{
sl@0
  3248
		buf.Append(' ');
sl@0
  3249
		buf.AppendNumFixedWidth(*s++, EHex, 2);
sl@0
  3250
		--l;
sl@0
  3251
		++n;
sl@0
  3252
		if (l==0 || n==16)
sl@0
  3253
			{
sl@0
  3254
			RDebug::Printf((const char*)buf.PtrZ());
sl@0
  3255
			buf.Zero();
sl@0
  3256
			n=0;
sl@0
  3257
			}
sl@0
  3258
		}
sl@0
  3259
	}
sl@0
  3260
sl@0
  3261
void RImageFinder::Dump(const char* aTitle, TInt aR)
sl@0
  3262
	{
sl@0
  3263
	RDebug::Printf(aTitle);
sl@0
  3264
	RDebug::Printf("r=%d",aR);
sl@0
  3265
	if (iExisting)
sl@0
  3266
		{
sl@0
  3267
		RDebug::Printf("Existing image found");
sl@0
  3268
		RDebug::Printf("Filename=%S Attr=%08x", &iExisting->iFileName, iExisting->iAttr);
sl@0
  3269
		RDebug::Printf("SID %08x Caps %08x %08x", iExisting->iS.iSecureId, iExisting->iS.iCaps[1], iExisting->iS.iCaps[0]);
sl@0
  3270
		const TUint32* uid = (const TUint32*)&iExisting->iUids;
sl@0
  3271
		RDebug::Printf("UIDs %08x %08x %08x VER %08x", uid[0], uid[1], uid[2], iExisting->iModuleVersion);
sl@0
  3272
		RDebug::Printf("Rom %08x", iExisting->iRomImageHeader);
sl@0
  3273
		}
sl@0
  3274
	else if (iNewValid)
sl@0
  3275
		{
sl@0
  3276
		RDebug::Printf("New image found");
sl@0
  3277
		RDebug::Printf("Filename=%S Attr=%08x", &iNewFileName, iNew.iAttr);
sl@0
  3278
		RDebug::Printf("SID %08x Caps %08x %08x", iNew.iS.iSecureId, iNew.iS.iCaps[1], iNew.iS.iCaps[0]);
sl@0
  3279
		const TUint32* uid = (const TUint32*)iNew.iUid;
sl@0
  3280
		RDebug::Printf("UIDs %08x %08x %08x VER %08x", uid[0], uid[1], uid[2], iNew.iModuleVersion);
sl@0
  3281
		RDebug::Printf("Rom %08x", iNew.iRomImageHeader);
sl@0
  3282
		}
sl@0
  3283
	else
sl@0
  3284
		{
sl@0
  3285
		RDebug::Printf("No suitable image found");
sl@0
  3286
		RDebug::Printf("#NM=%d #UidFail=%d #CapFail=%d #MajVFail=%d #ImpFail=%d", iNameMatches, iUidFail, iCapFail, iMajorVersionFail, iImportFail);
sl@0
  3287
		}
sl@0
  3288
	}
sl@0
  3289
sl@0
  3290
void DumpImageHeader(const E32ImageHeader* a)
sl@0
  3291
	{
sl@0
  3292
	RDebug::Printf("E32ImageHeader at %08x :", a);
sl@0
  3293
	TUint abi = a->ABI();
sl@0
  3294
	TUint hdrfmt = a->HeaderFormat();
sl@0
  3295
	TUint impfmt = a->ImportFormat();
sl@0
  3296
	TUint eptfmt = a->EntryPointFormat();
sl@0
  3297
	RDebug::Printf("Header format %d", hdrfmt>>KImageHdrFmtShift);
sl@0
  3298
	RDebug::Printf("Import format %d", impfmt>>KImageImpFmtShift);
sl@0
  3299
	RDebug::Printf("EntryPoint format %d", eptfmt>>KImageEptShift);
sl@0
  3300
	RDebug::Printf("ABI %d", abi>>KImageABIShift);
sl@0
  3301
	RDebug::Printf("UIDs %08x %08x %08x (%08x)", a->iUid1, a->iUid2, a->iUid3, a->iUidChecksum);
sl@0
  3302
	RDebug::Printf("Header CRC %08x", a->iHeaderCrc);
sl@0
  3303
	RDebug::Printf("Signature %08x", a->iSignature);
sl@0
  3304
	RDebug::Printf("CPU %08x", (TUint)a->CpuIdentifier());
sl@0
  3305
	RDebug::Printf("ModuleVersion %08x", a->ModuleVersion());
sl@0
  3306
	RDebug::Printf("Compression Type %08x", a->CompressionType());
sl@0
  3307
	RDebug::Printf("Tools Version %d.%02d(%d)", a->iToolsVersion.iMajor, a->iToolsVersion.iMinor, a->iToolsVersion.iBuild);
sl@0
  3308
	RDebug::Printf("Flags %08x", a->iFlags);
sl@0
  3309
	RDebug::Printf("Code Size %08x", a->iCodeSize);
sl@0
  3310
	RDebug::Printf("Text Size %08x", a->iTextSize);
sl@0
  3311
	RDebug::Printf("Data Size %08x", a->iDataSize);
sl@0
  3312
	RDebug::Printf("BSS Size %08x", a->iBssSize);
sl@0
  3313
	RDebug::Printf("Stack Size %08x", a->iStackSize);
sl@0
  3314
	RDebug::Printf("HeapSizeMin %08x", a->iHeapSizeMin);
sl@0
  3315
	RDebug::Printf("HeapSizeMax %08x", a->iHeapSizeMax);
sl@0
  3316
	RDebug::Printf("iEntryPoint %08x", a->iEntryPoint);
sl@0
  3317
	RDebug::Printf("iCodeBase %08x", a->iCodeBase);
sl@0
  3318
	RDebug::Printf("iDataBase %08x", a->iDataBase);
sl@0
  3319
	RDebug::Printf("DLL Ref Table Count %d", a->iDllRefTableCount);
sl@0
  3320
	RDebug::Printf("Export Dir Count %d", a->iExportDirCount);
sl@0
  3321
	RDebug::Printf("Code Offset %08x", a->iCodeOffset);
sl@0
  3322
	RDebug::Printf("Data Offset %08x", a->iDataOffset);
sl@0
  3323
	RDebug::Printf("Code Reloc Offset %08x", a->iCodeRelocOffset);
sl@0
  3324
	RDebug::Printf("Data Reloc Offset %08x", a->iDataRelocOffset);
sl@0
  3325
	RDebug::Printf("Import Offset %08x", a->iImportOffset);
sl@0
  3326
	RDebug::Printf("Export Dir Offset %08x", a->iExportDirOffset);
sl@0
  3327
	RDebug::Printf("Priority %d", (TUint)a->ProcessPriority());
sl@0
  3328
	// KImageHdrFmt_J
sl@0
  3329
	RDebug::Printf("iUncompressedSize %08x", ((E32ImageHeaderComp*)a)->iUncompressedSize);
sl@0
  3330
	// KImageHdrFmt_V
sl@0
  3331
	E32ImageHeaderV* v = (E32ImageHeaderV*)a;
sl@0
  3332
	RDebug::Printf("SID %08x VID %08x CAP %08x %08x", v->iS.iSecureId, v->iS.iVendorId, v->iS.iCaps[1], v->iS.iCaps[0]);
sl@0
  3333
	RDebug::Printf("iExportDescType %02x", v->iExportDescType);
sl@0
  3334
	RDebug::Printf("iExportDescSize %04x", v->iExportDescSize);
sl@0
  3335
	if (v->iExportDescSize)
sl@0
  3336
		memory_dump(v->iExportDesc, v->iExportDescSize);
sl@0
  3337
	}
sl@0
  3338
#endif
sl@0
  3339