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