1 // Copyright (c) 1996-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 "Symbian Foundation License v1.0" to Symbian Foundation members and "Symbian Foundation End User License Agreement v1.0" to non-members
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.symbianfoundation.org/legal/licencesv10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
21 @file f32\inc\f32image.h
25 #ifndef __F32IMAGE_H__
26 #define __F32IMAGE_H__
30 Value used for E32ImageHeader::iCpuIdentifier.
34 ECpuUnknown=0, ECpuX86=0x1000, ECpuArmV4=0x2000, ECpuArmV5=0x2001, ECpuArmV6=0x2002, ECpuMCore=0x4000
38 Ordinal value of the first entry in an executables export directory.
39 @see E32ImageHeader::iExportDirOffset.
41 const TInt KOrdinalBase=1;
44 Value used to initialise E32ImageHeader::iHeaderCrc prior to CRC generation.
46 const TUint32 KImageCrcInitialiser = 0xc90fdaa2u;
50 Byte offset from an executable's entrypoint to the code segment ID storage location.
52 const TUint KCodeSegIdOffset = 12;
55 // Flags fields for E32ImageHeader::iFlags
58 const TUint KImageDll = 0x00000001u; ///< Flag set if executable is a DLL, clear if an EXE.
60 const TUint KImageNoCallEntryPoint = 0x00000002u; ///< Obsolete flag ignored since Symbian OS version 8.1b.
62 const TUint KImageFixedAddressExe = 0x00000004u; ///< Executable's data should not move when running on the moving memory model.
64 const TUint KImageABIMask = 0x00000018u; ///< Bitmask for ABI value.
65 const TInt KImageABIShift = 3; ///< Bit shift count for ABI value.
66 const TUint KImageABI_GCC98r2 = 0x00000000u; ///< Obsolete ABI for ARM targets.
67 const TUint KImageABI_EABI = 0x00000008u; ///< ARM EABI
69 const TUint KImageEptMask = 0x000000e0u; ///< Bitmask for Entrypoint value.
70 const TInt KImageEptShift = 5; ///< Bit shift count for Entrypoint value
71 const TUint KImageEpt_Eka1 = 0x00000000u; ///< @removed Obsolete format not used since Symbian OS version 8.1b.
72 const TUint KImageEpt_Eka2 = 0x00000020u; ///< Standard entrypoint for ARM executable.
74 const TUint KImageUnpaged = 0x00000100u; ///< Executable image should not be demand paged. Exclusive with KImagePaged,
75 const TUint KImagePaged = 0x00000200u; ///< Executable image should be demand paged. Exclusive with KImageUnpaged,
77 const TUint KImageNmdExpData = 0x00000400u; ///< Flag to indicate when named symbol export data present in image
79 const TUint KImageDebuggable = 0x00000800u; ///< Flag to indicate image is debuggable
81 const TUint KImageHWFloatMask = 0x00f00000u; ///< Bitmask for Floating Point type.
82 const TInt KImageHWFloatShift = 20; ///< Bit shift count for Floating Point type.
83 const TUint KImageHWFloat_None = EFpTypeNone << KImageHWFloatShift; ///< No hardware floating point used.
84 const TUint KImageHWFloat_VFPv2 = EFpTypeVFPv2 << KImageHWFloatShift; ///< ARM VFPv2 floating point used.
86 const TUint KImageHdrFmtMask = 0x0f000000u; ///< Bitmask for header format type.
87 const TInt KImageHdrFmtShift = 24; ///< Bit shift count for header format type.
88 const TUint KImageHdrFmt_Original = 0x00000000u; ///< @removed Obsolete format not used since Symbian OS version 8.1b.
89 const TUint KImageHdrFmt_J = 0x01000000u; ///< @removed Obsolete format not used since Symbian OS version 8.1b.
90 const TUint KImageHdrFmt_V = 0x02000000u; ///< Header has format given by class E32ImageHeaderV.
92 const TUint KImageImpFmtMask = 0xf0000000u; ///< Bitmask for import section format type.
93 const TInt KImageImpFmtShift = 28; ///< Bit shift count for import section format type.
94 const TUint KImageImpFmt_PE = 0x00000000u; ///< PE-derived imports.
95 const TUint KImageImpFmt_ELF = 0x10000000u; ///< ELF-derived imports.
96 const TUint KImageImpFmt_PE2 = 0x20000000u; ///< PE-derived imports without redundant copy of import ordinals.
101 // forward references...
103 class E32RelocSection;
107 Structure for an executable image's header.
108 This is extended by E32ImageHeaderComp and E32ImageHeaderV.
109 All executables since Symbian OS version 8.1b have an header given by class E32ImageHeaderV.
111 Summary of an executable image structure...
113 - Header, 0..iCodeOffset-1
114 - Code part, iCodeOffset..iCodeOffset+iCodeSize-1
115 - .text section, 0 + iTextSize
116 - Import Address Table (IAT), iText + ?
117 - Export Directory, iExportDirOffset + iExportDirCount*4 (in .text Section)
118 - Rest of data, iCodeOffset+iCodeSize..EOF
119 - .data section, iDataOffset + iDataSize
120 - Import section, iImportOffset + sizeof(E32ImportSection)+?
121 - Code relocation section, iCodeRelocOffset + sizeof(E32RelocSection)+?
122 - Data relocation section, iDataRelocOffset + sizeof(E32RelocSection)+?
127 static TInt New(E32ImageHeader*& aHdr, RFile& aFile);
128 static TInt New(E32ImageHeader*& aHdr, TUint8* aFileData, TUint32 aFileSize);
129 TInt ValidateHeader(TInt aFileSize, TUint32& aUncompressedSize) const;
131 inline static TUint ABIFromFlags(TUint aFlags);
132 inline static TUint EptFromFlags(TUint aFlags);
133 inline static TUint HdrFmtFromFlags(TUint aFlags);
134 inline static TUint ImpFmtFromFlags(TUint aFlags);
136 inline TUint ABI() const;
137 inline TUint EntryPointFormat() const;
138 inline TUint HeaderFormat() const;
139 inline TUint ImportFormat() const;
141 inline TUint32 CompressionType() const;
142 inline TUint32 ModuleVersion() const;
143 inline TInt TotalSize() const;
144 inline TInt UncompressedFileSize() const;
145 inline void GetSecurityInfo(SSecurityInfo& aInfo) const;
146 inline TCpu CpuIdentifier() const;
147 inline TProcessPriority ProcessPriority() const;
148 inline TUint32 ExceptionDescriptor() const;
150 TUint32 iUid1; ///< KDynamicLibraryUidValue or KExecutableImageUidValue
151 TUint32 iUid2; ///< Second UID for executable.
152 TUint32 iUid3; ///< Third UID for executable.
153 TUint32 iUidChecksum; ///< Checksum for iUid1, iUid2 and iUid3.
154 TUint iSignature; ///< Contains 'EPOC'.
155 TUint32 iHeaderCrc; ///< CRC-32 of entire header. @see #KImageCrcInitialiser.
156 TUint32 iModuleVersion; ///< Version number for this executable (used in link resolution).
157 TUint32 iCompressionType; ///< Type of compression used for file contents located after the header. (UID or 0 for none).
158 TVersion iToolsVersion; ///< Version number of tools which generated this file.
159 TUint32 iTimeLo; ///< Least significant 32 bits of the time of image creation, in milliseconds since since midnight Jan 1st, 2000.
160 TUint32 iTimeHi; ///< Most significant 32 bits of the time of image creation, in milliseconds since since midnight Jan 1st, 2000.
161 TUint iFlags; ///< Contains various bit-fields of attributes for the image.
162 TInt iCodeSize; ///< Size of executables code. Includes import address table, constant data and export directory.
163 TInt iDataSize; ///< Size of executables initialised data.
164 TInt iHeapSizeMin; ///< Minimum size for an EXEs runtime heap memory.
165 TInt iHeapSizeMax; ///< Maximum size for an EXEs runtime heap memory.
166 TInt iStackSize; ///< Size for stack required by an EXEs initial thread.
167 TInt iBssSize; ///< Size of executables uninitialised data.
168 TUint iEntryPoint; ///< Offset into code of the entry point.
169 TUint iCodeBase; ///< Virtual address that the executables code is linked for.
170 TUint iDataBase; ///< Virtual address that the executables data is linked for.
171 TInt iDllRefTableCount; ///< Number of executable against which this executable is linked. The number of files mention in the import section at iImportOffset.
172 TUint iExportDirOffset; ///< Byte offset into file of the export directory.
173 TInt iExportDirCount; ///< Number of entries in the export directory.
174 TInt iTextSize; ///< Size of just the text section, also doubles as the offset for the Import Address Table w.r.t. the code section.
175 TUint iCodeOffset; ///< Offset into file of the code section. Also doubles the as header size.
176 TUint iDataOffset; ///< Offset into file of the data section.
177 TUint iImportOffset; ///< Offset into file of the import section (E32ImportSection).
178 TUint iCodeRelocOffset; ///< Offset into file of the code relocation section (E32RelocSection).
179 TUint iDataRelocOffset; ///< Offset into file of the data relocation section (E32RelocSection).
180 TUint16 iProcessPriority; ///< Initial runtime process priorty for an EXE. (Value from enum TProcessPriority.)
181 TUint16 iCpuIdentifier; ///< Value from enum TCpu which indicates the CPU architecture for which the image was created
186 Extends E32ImageHeader.
188 class E32ImageHeaderComp : public E32ImageHeader
191 TUint32 iUncompressedSize; ///< Uncompressed size of file data after the header, or zero if file not compressed.
196 Extends E32ImageHeaderComp.
197 All Symbian OS executable files have a header in this format since OS version 8.1b.
199 class E32ImageHeaderV : public E32ImageHeaderComp
202 SSecurityInfo iS; ///< Platform Security information of executable.
203 TUint32 iExceptionDescriptor; ///< Offset in bytes from start of code section to Exception Descriptor, bit 0 set if valid.
204 TUint32 iSpare2; ///< Reserved for future use. Set to zero.
205 TUint16 iExportDescSize; ///< Size of export description stored in iExportDesc.
206 TUint8 iExportDescType; ///< Type of description of holes in export table
207 TUint8 iExportDesc[1]; ///< Description of holes in export table, size given by iExportDescSize..
209 TInt ValidateWholeImage(TAny* aBufferStart, TUint aBufferSize) const;
210 TInt ValidateHeader(TInt aFileSize, TUint32& aUncompressedSize) const;
211 TInt ValidateExportDescription() const;
212 TInt ValidateRelocations(TAny* aBufferStart, TUint aBufferSize, TUint aRelocationInfoOffset, TUint aRelocatedSectionSize, E32RelocSection*& aRelocationSection) const;
213 TInt ValidateImports(TAny* aBufferStart, TUint aBufferSize, TUint& aBiggestImportCount) const;
214 TInt ValidateAndAdjust(TUint32 aFileSize);
217 // export description type E32ImageHeaderV::iExportDescType
218 const TUint KImageHdr_ExpD_NoHoles =0x00; ///< No holes, all exports present.
219 const TUint KImageHdr_ExpD_FullBitmap =0x01; ///< Full bitmap present at E32ImageHeaderV::iExportDesc
220 const TUint KImageHdr_ExpD_SparseBitmap8 =0x02; ///< Sparse bitmap present at E32ImageHeaderV::iExportDesc, granularity 8
221 const TUint KImageHdr_ExpD_Xip =0xff; ///< XIP file
225 // inline getters for E32ImageHeader
229 Extract ABI type from aFlags.
231 inline TUint E32ImageHeader::ABIFromFlags(TUint aFlags)
233 return aFlags & KImageABIMask;
237 Extract ABI type from #iFlags.
239 inline TUint E32ImageHeader::ABI() const
241 return ABIFromFlags(iFlags);
245 Extract entrypoint format from aFlags.
247 inline TUint E32ImageHeader::EptFromFlags(TUint aFlags)
249 return aFlags & KImageEptMask;
253 Extract entrypoint format from #iFlags.
255 inline TUint E32ImageHeader::EntryPointFormat() const
257 return EptFromFlags(iFlags);
261 Extract header format from aFlags.
263 inline TUint E32ImageHeader::HdrFmtFromFlags(TUint aFlags)
265 return aFlags & KImageHdrFmtMask;
269 Extract header format from #iFlags.
271 inline TUint E32ImageHeader::HeaderFormat() const
273 return HdrFmtFromFlags(iFlags);
277 Extract import format from aFlags.
279 inline TUint E32ImageHeader::ImpFmtFromFlags(TUint aFlags)
281 return aFlags & KImageImpFmtMask;
285 Extract import format from #iFlags.
287 inline TUint E32ImageHeader::ImportFormat() const
289 return ImpFmtFromFlags(iFlags);
293 Return #iCompressionType.
295 inline TUint32 E32ImageHeader::CompressionType() const
297 return iCompressionType;
301 Return #iModuleVersion.
303 inline TUint32 E32ImageHeader::ModuleVersion() const
305 return iModuleVersion;
309 Return size of this header.
311 inline TInt E32ImageHeader::TotalSize() const
317 Return total size of file after decompression, or -1 if file not compressed.
319 inline TInt E32ImageHeader::UncompressedFileSize() const
321 if(iCompressionType==0)
322 return -1; // not compressed
324 return ((E32ImageHeaderComp*)this)->iUncompressedSize + TotalSize();
328 Return copy of security info, #E32ImageHeaderV::iS.
330 inline void E32ImageHeader::GetSecurityInfo(SSecurityInfo& aInfo) const
332 aInfo = ((E32ImageHeaderV*)this)->iS;
336 Return #iCpuIdentifier.
338 inline TCpu E32ImageHeader::CpuIdentifier() const
340 return (TCpu)iCpuIdentifier;
344 Return #iProcessPriority.
346 inline TProcessPriority E32ImageHeader::ProcessPriority() const
348 return (TProcessPriority)iProcessPriority;
352 Return fffset in bytes from start of code section for the Exception Descriptor.
353 Or zero if not present.
355 inline TUint32 E32ImageHeader::ExceptionDescriptor() const
357 TUint32 xd = ((E32ImageHeaderV*)this)->iExceptionDescriptor;
359 if((xd & 1) && (xd != 0xffffffffu))
367 A block of imports from a single executable.
368 These structures are conatined in a images Import Section (E32ImportSection).
373 inline const E32ImportBlock* NextBlock(TUint aImpFmt) const;
374 inline TInt Size(TUint aImpFmt) const;
375 inline const TUint* Imports() const; // import list if present
377 TUint32 iOffsetOfDllName; ///< Offset from start of import section for a NUL terminated executable (DLL or EXE) name.
378 TInt iNumberOfImports; ///< Number of imports from this executable.
379 // TUint iImport[iNumberOfImports]; ///< For ELF-derived executes: list of code section offsets. For PE, list of imported ordinals. Omitted in PE2 import format
383 Return size of this import block.
384 @param aImpFmt Import format as obtained from image header.
386 inline TInt E32ImportBlock::Size(TUint aImpFmt) const
388 TInt r = sizeof(E32ImportBlock);
389 if(aImpFmt!=KImageImpFmt_PE2)
390 r += iNumberOfImports * sizeof(TUint);
395 Return pointer to import block which immediately follows this one.
396 @param aImpFmt Import format as obtained from image header.
398 inline const E32ImportBlock* E32ImportBlock::NextBlock(TUint aImpFmt) const
400 const E32ImportBlock* next = this + 1;
401 if(aImpFmt!=KImageImpFmt_PE2)
402 next = (const E32ImportBlock*)( (TUint8*)next + iNumberOfImports * sizeof(TUint) );
407 Return address of first import in this block.
408 For import format KImageImpFmt_ELF, imports are list of code section offsets.
409 For import format KImageImpFmt_PE, imports are a list of imported ordinals.
410 For import format KImageImpFmt_PE2, the import list is not present and should not be accessed.
412 inline const TUint* E32ImportBlock::Imports() const
414 return (const TUint*)(this + 1);
419 Header for the Import Section in an image, as referenced by E32ImageHeader::iImportOffset.
420 Immediately following this structure are an array of E32ImportBlock structures.
421 The number of these is given by E32ImageHeader::iDllRefTableCount.
423 class E32ImportSection
426 TInt iSize; ///< Size of this section excluding 'this' structure
427 // E32ImportBlock iImportBlock[iDllRefTableCount];
432 A block of relocations for a single page (4kB) of code/data.
434 Immediately following this structure are an array of TUint16 values
435 each representing a single value in the page which is to be relocated.
436 The lower 12 bits of each entry is the offset, in bytes, from start of this page.
437 The Upper 4 bits are the relocation type to be applied to the 32-bit value located
439 - 1 means relocate relative to code section.
440 - 2 means relocate relative to data section.
441 - 3 means relocate relative to code or data section; calculate which.
443 A value of all zeros (0x0000) is ignored. (Used for padding structure to 4 byte alignment).
448 TUint32 iPageOffset; ///< Offset, in bytes, for the page being relocated; relative to the section start. Always a multiple of the page size: 4096 bytes.
449 TUint32 iBlockSize; ///< Size, in bytes, for this block structure. Always a multiple of 4.
455 Header for a Relocation Section in an image, as referenced by E32ImageHeader::iCodeRelocOffset
456 or E32ImageHeader::iDataRelocOffset.
458 Immediately following this structure are an array of E32RelocBlock structures.
460 class E32RelocSection
463 TInt iSize; ///< Size of this relocation section including 'this' structure. Always a multiple of 4.
464 TInt iNumberOfRelocs; ///< Number of relocations in this section.
465 // E32RelocBlock iRelockBlock[];
470 Structure contained in the export directory in text section of the stdexe/stddll.
471 It contains information on the names of symbols exported by this stdexe/stddll and
472 pointers to a E32EpocExpSymInfoHdr structure of any stddlls that are dependencies of
475 This is not used for emulator images see E32EmulExpSymInfoHdr below.
476 @see E32EmulExpSymInfoHdr
478 class E32EpocExpSymInfoHdr
481 TInt iSize; // size of this Table
483 TInt16 iSymCount; // number of symbols
484 TInt iSymbolTblOffset; // start of the symbol table - offset from byte 0 of this header
485 TInt iStringTableSz; // size of the string table
486 TInt iStringTableOffset; // start of the string table having names of the symbols - offset from byte 0 of this header
487 TInt iDllCount; // Number of dependent DLLs
488 TInt iDepDllZeroOrdTableOffset; // offset of the DLL dependency table - offset from byte 0 of this header.
493 Header of the structure contained in the 'KWin32SectionName_NmdExpData'
494 segment of emulator stdexe & stddll images.
495 The segment contains addresses of symbols and NULL
496 terminated ASCII strings of the names of static dependencies.
497 For a stdexe, this segment contains the following:
498 a) symbol count (iSymCount) and static dependency count (iDllCount)
499 b) iSymCount * symbol addresses
500 c) iSymCount * symbol names
501 d) iDllCount * dependency names
503 For a stddll, this segment contains the following:
504 a) symbol count (iSymCout) is always 0
505 b) static dependency count (iDllCount)
506 c) iDllCount * dependency names
507 The symbol addresses and names are not required for a stddll as the Windows API,
508 GetProcAddress may be used to get the addresses for symbol names.
509 Since this API works only on DLL handles, we explicitly list them for stdexes.
510 This is used for emulator images only.
512 class E32EmulExpSymInfoHdr
515 TInt32 iSymCount; // Number of symbols
516 TInt32 iDllCount; // Number of static dependency DLLs
521 #ifdef INCLUDE_E32IMAGEHEADER_IMPLEMENTATION
523 // include code which implements validation functions...
525 #ifndef RETURN_FAILURE
526 #define RETURN_FAILURE(_r) return (_r)
529 #ifndef E32IMAGEHEADER_TRACE
530 #define E32IMAGEHEADER_TRACE(_t) ((void)0)
538 Validate this image header.
540 After successful validation the following are true:
541 - File size is big enough to contain the entire header.
542 - Values #iUidChecksum, #iSignature and #iHeaderCrc are correct.
543 - CPU type (#iCpuIdentifier), ABI type (#iFlags&#KImageABIMask) and
544 entrypoint type (#iFlags&#KImageEptMask) are valid for this system.
545 - Code part of file as specified by #iCodeOffset and #iCodeSize is fully within the file.
546 - Text section size (#iTextSize) is within code part.
547 - Entrypoint value (#iEntryPoint) lies within the code part and is aligned correctly.
548 - Export directory as specified by #iExportDirCount and #iExportDirOffset is fully
549 within code part and is aligned correctly.
550 - Exception description (E32ImageHeaderV::iExceptionDescriptor), if present,
551 lies within the code part.
552 - Data part of file as specified by #iDataOffset and #iDataSize is fully within the file.
553 Or data is not present (#iDataOffset==#iDataSize==0).
554 - Import section (class E32ImportSection at #iImportOffset) is within 'rest of data'
555 and aligned correctly. Data following the E32ImportSection header is NOT validated or
556 checked if it is fully contained within the file.
557 - Code relocations (class E32RelocSection at #iCodeRelocOffset) is within 'rest of data'
558 and aligned correctly. Data following the E32RelocSection header is NOT validated or
559 checked if it is fully contained within the file.
560 - Data relocations (class E32RelocSection at #iDataRelocOffset) is within 'rest of data'
561 and aligned correctly. Data following the E32RelocSection header is NOT validated or
562 checked if it is fully contained within the file.
563 - Export description is validated by E32ImageHeaderV::ValidateExportDescription().
564 - #iUid1 is consistant with #iFlags&#KImageDll. I.e. if flaged as a DLL, #iUid1 is
565 KDynamicLibraryUidValue, otherwise it is KExecutableImageUidValue.
566 - Version number (#iModuleVersion) is valid. (Major and minor versions are <32768).
567 - File compression type (#iCompressionType) is supported.
568 - #iHeapSizeMax>=#iHeapSizeMin
569 - All signed values in header are not negative.
571 @param aFileSize Total size of the file from which this header was created.
572 @param[out] aUncompressedSize Returns the total size that the file data would be once decompressed.
574 @return KErrNone if no errors detected;
575 KErrCorrupt if errors found;
576 KErrNotSupported if image format not supported on this platform.
578 TInt E32ImageHeader::ValidateHeader(TInt aFileSize, TUint32& aUncompressedSize) const
580 // check file is big enough for any header...
581 if(TUint(aFileSize)<sizeof(*this))
584 TUint hdrfmt = HeaderFormat();
585 if(hdrfmt==KImageHdrFmt_V)
586 return ((E32ImageHeaderV*)this)->ValidateHeader(aFileSize,aUncompressedSize);
588 return KErrNotSupported; // header format unrecognised
592 Validate this image header.
594 @param aFileSize Total size of the file from which this header was created.
595 @param[out] aUncompressedSize Returns the total size that the file data would be once decompressed.
597 @return KErrNone if no errors detected;
598 KErrCorrupt if errors found;
599 KErrNotSupported if image format not supported on this platform.
601 TInt E32ImageHeaderV::ValidateHeader(TInt aFileSize, TUint32& aUncompressedSize) const
603 const TUint KMaxDesSize = 0x0fffffffu; // maximum size of descriptor
606 // file size unknown, set to maximum valid so rest of validation works...
607 aFileSize = KMaxDesSize;
609 if(TUint(aFileSize)>KMaxDesSize)
610 RETURN_FAILURE(KErrCorrupt); // file size negative or too big
612 aUncompressedSize = 0;
614 // check file is big enough to contain this header...
615 if(aFileSize<(TInt)sizeof(*this))
616 RETURN_FAILURE(KErrCorrupt);
618 // check header format version...
619 if((iFlags&KImageHdrFmtMask)!=KImageHdrFmt_V)
620 RETURN_FAILURE(KErrNotSupported);
622 // check header size...
623 TUint headerSize = iCodeOffset;
624 if(headerSize>TUint(aFileSize))
625 RETURN_FAILURE(KErrCorrupt); // Fuzzer can't trigger this because Loader will fail earlier when reading header from file
627 // check iCpuIdentifier...
628 TCpu cpu = (TCpu)iCpuIdentifier;
629 TBool isARM = (cpu==ECpuArmV4 || cpu==ECpuArmV5 || cpu==ECpuArmV6);
630 #if defined(__CPU_ARM)
632 RETURN_FAILURE(KErrNotSupported);
633 #elif defined(__CPU_X86)
635 RETURN_FAILURE(KErrNotSupported);
637 TUint32 pointerAlignMask = isARM ? 3 : 0; // mask of bits which must be zero for aligned pointers/offsets
639 // check iUid1,iUid2,iUid3,iUidChecksum...
640 TUidType uids = *(const TUidType*)&iUid1;
641 TCheckedUid chkuid(uids);
642 const TUint32* pChkUid = (const TUint32*)&chkuid; // need hackery to verify the UID checksum since everything is private
643 if(pChkUid[3]!=iUidChecksum)
644 RETURN_FAILURE(KErrCorrupt);
646 // check iSignature...
647 if(iSignature!=0x434f5045) // 'EPOC'
648 RETURN_FAILURE(KErrCorrupt);
650 // check iHeaderCrc...
651 TUint32 supplied_crc = iHeaderCrc;
652 ((E32ImageHeaderV*)this)->iHeaderCrc = KImageCrcInitialiser;
654 Mem::Crc32(crc, this, headerSize);
655 ((E32ImageHeaderV*)this)->iHeaderCrc = supplied_crc;
656 if(crc!=supplied_crc)
657 RETURN_FAILURE(KErrCorrupt);
659 // check iModuleVersion...
660 TUint32 mv = iModuleVersion;
661 if(mv>=0x80000000u || (mv&0x0000ffffu)>0x8000u)
662 RETURN_FAILURE(KErrNotSupported);
664 // check iCompressionType and get uncompressed size...
665 TUint compression = iCompressionType;
666 TUint uncompressedSize = aFileSize;
667 if(compression!=KFormatNotCompressed)
669 if(compression!=KUidCompressionDeflate && compression!=KUidCompressionBytePair)
670 RETURN_FAILURE(KErrNotSupported); // unknown compression method
671 uncompressedSize = headerSize+iUncompressedSize;
672 if(uncompressedSize<headerSize)
673 RETURN_FAILURE(KErrCorrupt); // size overflowed 32 bits
676 // check sizes won't overflow the limit for a descriptor (many Loader uses won't like that).
677 if(uncompressedSize>KMaxDesSize)
678 RETURN_FAILURE(KErrCorrupt);
680 // check KImageDll in iFlags...
683 if(iUid1!=TUint32(KDynamicLibraryUidValue))
684 RETURN_FAILURE(KErrNotSupported);
686 else if(iUid1!=TUint32(KExecutableImageUidValue))
687 RETURN_FAILURE(KErrNotSupported);
689 // check iFlags for ABI and entry point types...
692 if((iFlags&KImageEptMask)!=KImageEpt_Eka2)
693 RETURN_FAILURE(KErrNotSupported);
694 #if defined(__EABI__)
695 if((iFlags&KImageABIMask)!=KImageABI_EABI)
696 RETURN_FAILURE(KErrNotSupported);
697 #elif defined(__GCC32__)
698 if((iFlags&KImageABIMask)!=KImageABI_GCC98r2)
699 RETURN_FAILURE(KErrNotSupported);
704 if(iFlags&KImageEptMask)
705 RETURN_FAILURE(KErrNotSupported); // no special entry point type allowed on non-ARM targets
706 if(iFlags&KImageABIMask)
707 RETURN_FAILURE(KErrNotSupported);
710 // check iFlags for import format...
711 if((iFlags&KImageImpFmtMask)>KImageImpFmt_PE2)
712 RETURN_FAILURE(KErrNotSupported);
714 // check iHeapSizeMin...
716 RETURN_FAILURE(KErrCorrupt);
718 // check iHeapSizeMax...
719 if(iHeapSizeMax<iHeapSizeMin)
720 RETURN_FAILURE(KErrCorrupt);
722 // check iStackSize...
724 RETURN_FAILURE(KErrCorrupt);
728 RETURN_FAILURE(KErrCorrupt);
730 // check iEntryPoint...
731 if(iEntryPoint>=TUint(iCodeSize))
732 RETURN_FAILURE(KErrCorrupt);
733 if(iEntryPoint+KCodeSegIdOffset+sizeof(TUint32)>TUint(iCodeSize))
734 RETURN_FAILURE(KErrCorrupt);
735 if(iEntryPoint&pointerAlignMask)
736 RETURN_FAILURE(KErrCorrupt); // not aligned
738 // check iCodeBase...
740 RETURN_FAILURE(KErrCorrupt); // not aligned
742 // check iDataBase...
744 RETURN_FAILURE(KErrCorrupt); // not aligned
746 // check iDllRefTableCount...
747 if(iDllRefTableCount<0)
748 RETURN_FAILURE(KErrCorrupt);
749 if(iDllRefTableCount)
752 RETURN_FAILURE(KErrCorrupt); // we link to DLLs but have no import data
755 // check iCodeOffset and iCodeSize specify region in file...
756 TUint codeStart = iCodeOffset;
757 TUint codeEnd = codeStart+iCodeSize;
758 if(codeEnd<codeStart)
759 RETURN_FAILURE(KErrCorrupt);
760 // if(codeStart<headerSize)
761 // RETURN_FAILURE(KErrCorrupt); // can't happen because headerSize is defined as iCodeOffset (codeStart)
762 if(codeEnd>uncompressedSize)
763 RETURN_FAILURE(KErrCorrupt);
765 // check iDataOffset and iDataSize specify region in file...
766 TUint dataStart = iDataOffset;
767 TUint dataEnd = dataStart+iDataSize;
768 if(dataEnd<dataStart)
769 RETURN_FAILURE(KErrCorrupt);
774 RETURN_FAILURE(KErrCorrupt);
778 if(dataStart<codeEnd)
779 RETURN_FAILURE(KErrCorrupt);
780 if(dataEnd>uncompressedSize)
781 RETURN_FAILURE(KErrCorrupt);
782 if((dataStart-codeStart)&pointerAlignMask)
783 RETURN_FAILURE(KErrCorrupt); // data not aligned with respect to code
787 // check total data size isn't too bit...
788 TUint totalDataSize = iDataSize+iBssSize;
789 if(totalDataSize>0x7fff0000)
790 RETURN_FAILURE(KErrNoMemory);
792 // check iExportDirOffset and iExportDirCount specify region in code part...
793 if(TUint(iExportDirCount)>65535)
794 RETURN_FAILURE(KErrCorrupt); // too many exports
797 TUint exportsStart = iExportDirOffset;
798 TUint exportsEnd = exportsStart+iExportDirCount*sizeof(TUint32);
799 if(iFlags&KImageNmdExpData)
800 exportsStart -= sizeof(TUint32); // allow for 0th ordinal
801 if(exportsEnd<exportsStart)
802 RETURN_FAILURE(KErrCorrupt);
803 if(exportsStart<codeStart)
804 RETURN_FAILURE(KErrCorrupt);
805 if(exportsEnd>codeEnd)
806 RETURN_FAILURE(KErrCorrupt);
807 if((exportsStart-codeStart)&pointerAlignMask)
808 RETURN_FAILURE(KErrCorrupt); // not aligned within code section
811 // check iTextSize...
812 if(TUint(iTextSize)>TUint(iCodeSize))
813 RETURN_FAILURE(KErrCorrupt);
815 // check iImportOffset...
816 TUint start = iImportOffset;
819 TUint end = start+sizeof(E32ImportSection); // minimum valid size
821 RETURN_FAILURE(KErrCorrupt);
823 RETURN_FAILURE(KErrCorrupt);
824 if(end>uncompressedSize)
825 RETURN_FAILURE(KErrCorrupt);
826 if((start-codeEnd)&pointerAlignMask)
827 RETURN_FAILURE(KErrCorrupt); // not aligned within 'rest of data'
830 // check iCodeRelocOffset...
831 start = iCodeRelocOffset;
834 TUint end = start+sizeof(E32RelocSection); // minimum valid size
836 RETURN_FAILURE(KErrCorrupt);
838 RETURN_FAILURE(KErrCorrupt);
839 if(end>uncompressedSize)
840 RETURN_FAILURE(KErrCorrupt);
841 if((start-codeEnd)&pointerAlignMask)
842 RETURN_FAILURE(KErrCorrupt); // not aligned within 'rest of data'
845 // check iDataRelocOffset...
846 start = iDataRelocOffset;
849 TUint end = start+sizeof(E32RelocSection); // minimum valid size
851 RETURN_FAILURE(KErrCorrupt);
853 RETURN_FAILURE(KErrCorrupt);
854 if(end>uncompressedSize)
855 RETURN_FAILURE(KErrCorrupt);
856 if((start-codeEnd)&pointerAlignMask)
857 RETURN_FAILURE(KErrCorrupt); // not aligned within 'rest of data'
860 // check exception descriptor...
861 if(iExceptionDescriptor&1) // if valid...
862 if(iExceptionDescriptor>=TUint(iCodeSize))
863 RETURN_FAILURE(KErrCorrupt);
865 TInt r = ValidateExportDescription();
870 aUncompressedSize = uncompressedSize;
876 Valdate that the export description is valid.
878 TInt E32ImageHeaderV::ValidateExportDescription() const
880 TUint headerSize = iCodeOffset;
882 // check export description...
883 TUint edSize = iExportDescSize + sizeof(iExportDescSize) + sizeof(iExportDescType);
884 edSize = (edSize+3)&~3;
885 TUint edEnd = _FOFF(E32ImageHeaderV,iExportDescSize)+edSize;
886 if(edEnd!=headerSize)
887 RETURN_FAILURE(KErrCorrupt);
889 // size of bitmap of exports...
890 TUint bitmapSize = (iExportDirCount+7) >> 3;
892 // check export description bitmap...
893 switch(iExportDescType)
895 case KImageHdr_ExpD_NoHoles:
896 // no bitmap to check...
897 E32IMAGEHEADER_TRACE(("ValidateExportDescription NoHoles"));
900 case KImageHdr_ExpD_FullBitmap:
901 // full bitmap present...
902 E32IMAGEHEADER_TRACE(("ValidateExportDescription FullBitmap"));
903 if(bitmapSize!=iExportDescSize)
904 RETURN_FAILURE(KErrCorrupt);
907 case KImageHdr_ExpD_SparseBitmap8:
909 // sparse bitmap present...
910 E32IMAGEHEADER_TRACE(("ValidateExportDescription SparseBitmap8"));
912 // get size of meta-bitmap...
913 TUint metaBitmapSize = (bitmapSize+7) >> 3;
914 if(metaBitmapSize>iExportDescSize)
915 RETURN_FAILURE(KErrCorrupt); // doesn't fit
917 TUint totalSize = metaBitmapSize;
919 // scan meta-bitmap counting extra bytes which should be present...
920 const TUint8* metaBitmap = iExportDesc;
921 const TUint8* metaBitmapEnd = metaBitmap + metaBitmapSize;
922 while(metaBitmap<metaBitmapEnd)
924 TUint bits = *metaBitmap++;
928 ++totalSize; // another byte is present in bitmap
933 if(totalSize!=iExportDescSize)
934 RETURN_FAILURE(KErrCorrupt);
939 E32IMAGEHEADER_TRACE(("ValidateExportDescription ?"));
940 RETURN_FAILURE(KErrNotSupported);
946 Validate a relocation section.
948 @param aBufferStart Start of buffer containing the data after the code part in the image file.
949 @param aBufferSize Size of data at aBufferStart.
950 @param aRelocationInfoOffset File offset for relocation section. (#iCodeRelocOffset or #iDataRelocOffset.)
951 @param aRelocatedSectionSize Size of section being relocated. (#iCodeSize or #iDataSize.)
952 @param[out] aRelocationSection Set to the start of the relocation section in the given buffer.
954 @return KErrNone if relocation section is valid, else KErrCorrupt.
956 TInt E32ImageHeaderV::ValidateRelocations(TAny* aBufferStart, TUint aBufferSize, TUint aRelocationInfoOffset, TUint aRelocatedSectionSize, E32RelocSection*& aRelocationSection) const
958 aRelocationSection = 0;
959 if(!aRelocationInfoOffset)
960 return KErrNone; // no relocations
962 // get alignment requirements...
963 TCpu cpu = (TCpu)iCpuIdentifier;
964 TBool isARM = (cpu==ECpuArmV4 || cpu==ECpuArmV5 || cpu==ECpuArmV6);
965 TUint32 pointerAlignMask = isARM ? 3 : 0; // mask of bits which must be zero for aligned pointers/offsets
967 // buffer pointer to read relocation from...
968 TUint8* bufferStart = (TUint8*)aBufferStart;
969 TUint8* bufferEnd = bufferStart+aBufferSize;
970 TUint baseOffset = iCodeOffset+iCodeSize; // file offset for aBufferStart
971 TUint8* sectionStart = (bufferStart+aRelocationInfoOffset-baseOffset);
972 TUint8* p = sectionStart;
974 // read section header (ValidateHeader has alread checked this is OK)...
975 E32RelocSection* sectionHeader = (E32RelocSection*)p;
976 TUint size = sectionHeader->iSize;
977 TUint relocsRemaining = sectionHeader->iNumberOfRelocs;
978 E32IMAGEHEADER_TRACE(("E32RelocSection 0x%x %d",size,relocsRemaining));
980 RETURN_FAILURE(KErrCorrupt); // not multiple of word size
982 // calculate buffer range for block data...
983 p = (TUint8*)(sectionHeader+1); // start of first block
984 TUint8* sectionEnd = p+size;
986 RETURN_FAILURE(KErrCorrupt); // math overflow
987 if(sectionEnd>bufferEnd)
988 RETURN_FAILURE(KErrCorrupt); // overflows buffer
990 // process each block...
993 E32RelocBlock* block = (E32RelocBlock*)p;
995 // get address of first entry in this block...
996 TUint16* entryPtr = (TUint16*)(block+1);
997 if((TUint8*)entryPtr<(TUint8*)block || (TUint8*)entryPtr>sectionEnd)
998 RETURN_FAILURE(KErrCorrupt); // overflows relocation section
1000 // read block header...
1001 TUint pageOffset = block->iPageOffset;
1002 TUint blockSize = block->iBlockSize;
1003 E32IMAGEHEADER_TRACE(("E32RelocSection block 0x%x 0x%x",pageOffset,blockSize));
1004 if(pageOffset&0xfff)
1005 RETURN_FAILURE(KErrCorrupt); // not page aligned
1006 if(blockSize<sizeof(E32RelocBlock))
1007 RETURN_FAILURE(KErrCorrupt); // blockSize must be at least that of the header just read
1009 RETURN_FAILURE(KErrCorrupt); // not word aligned
1011 // caculate end of entries in this block...
1012 TUint16* entryEnd = (TUint16*)(p+blockSize);
1013 if(entryEnd<entryPtr)
1014 RETURN_FAILURE(KErrCorrupt); // math overflow
1015 if(entryEnd>(TUint16*)sectionEnd)
1016 RETURN_FAILURE(KErrCorrupt); // overflows relocation section
1018 // process each entry in this block...
1019 while(entryPtr<entryEnd)
1021 TUint entry = *entryPtr++;
1022 E32IMAGEHEADER_TRACE(("E32RelocSection entry 0x%04x",entry));
1026 // check relocation type...
1027 TUint entryType = entry&0xf000;
1028 if(entryType!=KTextRelocType && entryType!=KDataRelocType && entryType!=KInferredRelocType)
1029 RETURN_FAILURE(KErrCorrupt);
1031 // check relocation is within section being relocated...
1032 TUint offset = pageOffset+(entry&0x0fff);
1033 if(offset>=aRelocatedSectionSize || offset+4>aRelocatedSectionSize)
1034 RETURN_FAILURE(KErrCorrupt); // not within section
1035 if(offset&pointerAlignMask)
1036 RETURN_FAILURE(KErrCorrupt); // not aligned correctly
1038 // count each relocation processed...
1042 // next sub block...
1043 p = (TUint8*)entryEnd;
1046 // check number of relocations in section header is correct...
1047 E32IMAGEHEADER_TRACE(("E32RelocSection relocsRemaining=%d",relocsRemaining));
1049 RETURN_FAILURE(KErrCorrupt); // incorrect number of entries
1051 aRelocationSection = sectionHeader;
1057 Validate an import section.
1059 For PE format imports, this also verifies that the Import Address Table fits within the code
1062 @param aBufferStart Start of buffer containing the data after the code part in the image file.
1063 @param aBufferSize Size of data at aBufferStart.
1064 @param[out] aBiggestImportCount Largest number of imports the image has from any single dependency.
1066 @return KErrNone if section is valid (or absent), else KErrCorrupt.
1068 TInt E32ImageHeaderV::ValidateImports(TAny* aBufferStart, TUint aBufferSize, TUint& aBiggestImportCount) const
1072 aBiggestImportCount = 0;
1073 return KErrNone; // no imports
1076 // get alignment requirements...
1077 TCpu cpu = (TCpu)iCpuIdentifier;
1078 TBool isARM = (cpu==ECpuArmV4 || cpu==ECpuArmV5 || cpu==ECpuArmV6);
1079 TUint32 pointerAlignMask = isARM ? 3 : 0; // mask of bits which must be zero for aligned pointers/offsets
1081 // buffer pointer to read imports from...
1082 TUint8* bufferStart = (TUint8*)aBufferStart;
1083 TUint8* bufferEnd = bufferStart+aBufferSize;
1084 TUint baseOffset = iCodeOffset+iCodeSize; // file offset for aBufferStart
1085 TUint8* sectionStart = (bufferStart+iImportOffset-baseOffset);
1086 TUint8* p = sectionStart;
1088 // read section header (ValidateHeader has alread checked this is OK)...
1089 E32ImportSection* sectionHeader = (E32ImportSection*)p;
1090 TUint size = sectionHeader->iSize;
1091 E32IMAGEHEADER_TRACE(("E32ImportSection 0x%x",size));
1093 // check section lies within buffer...
1094 p = (TUint8*)(sectionHeader+1); // start of first import block
1095 TUint8* sectionEnd = sectionStart+size;
1097 RETURN_FAILURE(KErrCorrupt); // math overflow or not big enough to contain header
1098 if(sectionEnd>bufferEnd)
1099 RETURN_FAILURE(KErrCorrupt); // overflows buffer
1101 // process each import block...
1102 TUint numDeps = iDllRefTableCount;
1103 TUint biggestImportCount = 0;
1104 TUint totalImports = 0;
1105 TUint importFormat = iFlags&KImageImpFmtMask;
1108 // get block header...
1109 E32ImportBlock* block = (E32ImportBlock*)p;
1110 p = (TUint8*)(block+1);
1111 if(p<(TUint8*)block || p>sectionEnd)
1112 RETURN_FAILURE(KErrCorrupt); // overflows buffer
1114 E32IMAGEHEADER_TRACE(("E32ImportBlock 0x%x %d",block->iOffsetOfDllName,block->iNumberOfImports));
1116 // check import dll name is within section...
1117 TUint8* name = sectionStart+block->iOffsetOfDllName;
1118 if(name<sectionStart || name>=sectionEnd)
1119 RETURN_FAILURE(KErrCorrupt); // not within import section
1120 while(*name++ && name<sectionEnd)
1123 RETURN_FAILURE(KErrCorrupt); // name overflows section
1124 E32IMAGEHEADER_TRACE(("E32ImportBlock %s",sectionStart+block->iOffsetOfDllName));
1126 // process import count...
1127 TUint numberOfImports = block->iNumberOfImports;
1128 if(numberOfImports>=0x80000000u/sizeof(TUint32))
1129 RETURN_FAILURE(KErrCorrupt); // size doesn't fit into a signed integer
1130 if(numberOfImports>biggestImportCount)
1131 biggestImportCount = numberOfImports;
1132 totalImports += numberOfImports;
1134 // process import data...
1136 // PE2 doesn't have any more data...
1137 if(importFormat==KImageImpFmt_PE2)
1140 // get import data range...
1141 TUint32* imports = (TUint32*)p;
1142 TUint32* importsEnd = imports+numberOfImports;
1143 if(importsEnd<imports)
1144 RETURN_FAILURE(KErrCorrupt); // math overflow. Fuzzer can't trigger this because needs aBufferStart to be in to be >0x80000000
1145 if(importsEnd>(TUint32*)sectionEnd)
1146 RETURN_FAILURE(KErrCorrupt); // overflows buffer
1148 // move pointer on to next block...
1149 p = (TUint8*)importsEnd;
1151 if(importFormat==KImageImpFmt_ELF)
1153 // check imports are in code section...
1154 TUint32 limit = iCodeSize-sizeof(TUint32);
1155 while(imports<importsEnd)
1157 TUint32 i = *imports++;
1159 RETURN_FAILURE(KErrCorrupt);
1160 if(i&pointerAlignMask)
1161 RETURN_FAILURE(KErrCorrupt); // not word aligned
1164 else if(importFormat==KImageImpFmt_PE)
1166 // import data is not used, so don't bother checking it
1170 RETURN_FAILURE(KErrCorrupt); // bad import format, Fuzzer can't trigger this because import format checked by header validation
1174 p = (TUint8*)block->NextBlock(importFormat);
1177 // done processing imports; for PE derived files now check import address table (IAT)...
1178 if(importFormat==KImageImpFmt_PE || importFormat==KImageImpFmt_PE2)
1180 if(totalImports>=0x80000000u/sizeof(TUint32))
1181 RETURN_FAILURE(KErrCorrupt); // size doesn't fit into a signed integer
1182 TUint importAddressTable = iTextSize; // offset for IAT
1183 if(importAddressTable&pointerAlignMask)
1184 RETURN_FAILURE(KErrCorrupt); // Fuzzer can't trigger this because PE imports are for X86 which doesn't have alignment restrictions
1185 TUint importAddressTableEnd = importAddressTable+sizeof(TUint32)*totalImports;
1186 if(importAddressTableEnd<importAddressTable || importAddressTableEnd>TUint(iCodeSize))
1187 RETURN_FAILURE(KErrCorrupt); // import address table overflows code part of file
1188 E32IMAGEHEADER_TRACE(("E32ImportSection IAT offsets 0x%x..0x%x",importAddressTable,importAddressTableEnd));
1191 aBiggestImportCount = biggestImportCount;
1199 Validate a whole executable image.
1201 This runs all of the other validation methods in turn.
1203 @param aBufferStart Start of buffer containing the data after the header part of an image file.
1204 @param aBufferSize Size of data at aBufferStart.
1206 @return KErrNone if image is valid, else KErrCorrupt or KErrNotSupported.
1208 TInt E32ImageHeaderV::ValidateWholeImage(TAny* aBufferStart, TUint aBufferSize) const
1210 TUint32 dummyUncompressedSize;
1211 TInt r = ValidateHeader(TotalSize()+aBufferSize,dummyUncompressedSize);
1215 TInt endOfCodeOffset = iCodeSize;
1216 void* restOfFileData = ((TUint8*)aBufferStart)+endOfCodeOffset;
1217 TInt restOfFileSize = aBufferSize-endOfCodeOffset;
1219 E32RelocSection* dummy;
1220 r = ValidateRelocations(restOfFileData,restOfFileSize,iCodeRelocOffset,iCodeSize,dummy);
1223 r = ValidateRelocations(restOfFileData,restOfFileSize,iDataRelocOffset,iDataSize,dummy);
1227 TUint biggestImportCount;
1228 r = ValidateImports(restOfFileData,restOfFileSize,biggestImportCount);
1236 #endif // INCLUDE_E32IMAGEHEADER_IMPLEMENTATION
1239 #endif // __F32IMAGE_H__